Subversion Repositories HelenOS

Rev

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

Rev 3018 Rev 3026
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
 */
36
 */
37
 
37
 
38
#include <console/klog.h>
38
#include <console/klog.h>
39
#include <proc/task.h>
39
#include <proc/task.h>
40
#include <proc/thread.h>
40
#include <proc/thread.h>
41
#include <arch.h>
41
#include <arch.h>
42
#include <errno.h>
42
#include <errno.h>
43
#include <syscall/copy.h>
43
#include <syscall/copy.h>
44
#include <ipc/ipc.h>
44
#include <ipc/ipc.h>
45
#include <udebug/udebug.h>
45
#include <udebug/udebug.h>
46
#include <udebug/udebug_ops.h>
46
#include <udebug/udebug_ops.h>
47
 
47
 
48
/**
48
/**
49
 * Prepare a thread for a debugging operation.
49
 * Prepare a thread for a debugging operation.
50
 *
50
 *
51
 * Simply put, return thread t with t->udebug.lock held,
51
 * Simply put, return thread t with t->udebug.lock held,
52
 * but only if it verifies all conditions.
52
 * but only if it verifies all conditions.
53
 *
53
 *
54
 * Specifically, verifies that thread t exists, is a userspace thread,
54
 * Specifically, verifies that thread t exists, is a userspace thread,
55
 * and belongs to the current task (TASK). Verifies, that the thread
55
 * and belongs to the current task (TASK). Verifies, that the thread
56
 * has (or hasn't) go according to having_go (typically false).
56
 * 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 is true
57
 * It also locks t->udebug.lock, making sure that t->udebug.debug_active
58
 * - that the thread is in a valid debugging session.
58
 * is true - that the thread is in a valid debugging session.
59
 *
59
 *
60
 * Returns EOK if all went well, or an error code otherwise.
60
 * With this verified and the t->udebug.lock mutex held, it is ensured
61
 * Interrupts must be already disabled when calling this function.
61
 * that the thread cannot leave the debugging session, let alone cease
-
 
62
 * to exist.
-
 
63
 *
-
 
64
 * In this function, holding the TASK->udebug.lock mutex prevents the
-
 
65
 * thread from leaving the debugging session, while relaxing from
-
 
66
 * the t->lock spinlock to the t->udebug.lock mutex.
62
 *
67
 *
63
 * Note: This function sports complicated locking.
68
 * Returns EOK if all went well, or an error code otherwise.
64
 */
69
 */
65
static int _thread_op_begin(thread_t *t, bool having_go)
70
static int _thread_op_begin(thread_t *t, bool having_go)
66
{
71
{
67
    int rc;
-
 
68
    task_id_t taskid;
72
    task_id_t taskid;
-
 
73
    ipl_t ipl;
69
 
74
 
70
    taskid = TASK->taskid;
75
    taskid = TASK->taskid;
71
 
76
 
-
 
77
    mutex_lock(&TASK->udebug.lock);
-
 
78
 
72
    /* Must lock threads_lock to ensure continued existence of the thread */
79
    /* thread_exists() must be called with threads_lock held */
-
 
80
    ipl = interrupts_disable();
73
    spinlock_lock(&threads_lock);
81
    spinlock_lock(&threads_lock);
74
 
82
 
75
    if (!thread_exists(t)) {
83
    if (!thread_exists(t)) {
76
        spinlock_unlock(&threads_lock);
84
        spinlock_unlock(&threads_lock);
-
 
85
        interrupts_restore(ipl);
-
 
86
        mutex_unlock(&TASK->udebug.lock);
77
        return ENOENT;
87
        return ENOENT;
78
    }
88
    }
79
 
89
 
80
    spinlock_lock(&t->udebug.lock);
90
    /* t->lock is enough to ensure the thread's existence */
81
    spinlock_lock(&t->lock);
91
    spinlock_lock(&t->lock);
82
   
-
 
83
    /* Now verify that it's the current task */
-
 
84
    if (t->task != TASK) {
-
 
85
        /* No such thread belonging to callee */
92
    spinlock_unlock(&threads_lock);
86
        rc = ENOENT;
-
 
87
        goto error_exit;
-
 
88
    }
-
 
89
 
93
 
90
    /* Verify that 't' is a userspace thread */
94
    /* Verify that 't' is a userspace thread */
91
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
95
    if ((t->flags & THREAD_FLAG_USPACE) == 0) {
92
        /* It's not, deny its existence */
96
        /* It's not, deny its existence */
-
 
97
        spinlock_unlock(&t->lock);
93
        rc = ENOENT;
98
        interrupts_restore(ipl);
-
 
99
        mutex_unlock(&TASK->udebug.lock);
94
        goto error_exit;
100
        return ENOENT;
95
    }
101
    }
96
 
102
 
-
 
103
    /* Verify debugging state */
97
    if ((t->udebug.debug_active != true) || (!t->udebug.stop != having_go)) {
104
    if (t->udebug.debug_active != true) {
98
        /* Not in debugging session or undesired GO state */
105
        /* Not in debugging session or undesired GO state */
-
 
106
        spinlock_unlock(&t->lock);
99
        rc = EINVAL;
107
        interrupts_restore(ipl);
-
 
108
        mutex_unlock(&TASK->udebug.lock);
100
        goto error_exit;
109
        return ENOENT;
101
    }
110
    }
102
 
111
 
-
 
112
    /*
103
    spinlock_unlock(&threads_lock);
113
     * Since the thread has debug_active == true, TASK->udebug.lock
-
 
114
     * is enough to ensure its existence and that debug_active remains
-
 
115
     * true.
-
 
116
     */
104
    spinlock_unlock(&t->lock);
117
    spinlock_unlock(&t->lock);
-
 
118
    interrupts_restore(ipl);
105
 
119
 
106
    /* Only t->udebug.lock left */
120
    /* Only mutex TASK->udebug.lock left */
-
 
121
   
-
 
122
    /* Now verify that the thread belongs to the current task */
-
 
123
    if (t->task != TASK) {
-
 
124
        /* No such thread belonging this task*/
-
 
125
        mutex_unlock(&TASK->udebug.lock);
-
 
126
        return ENOENT;
-
 
127
    }
107
 
128
 
-
 
129
    /*
-
 
130
     * Now we need to grab the thread's debug lock for synchronization
-
 
131
     * of the threads stoppability/stop state.
-
 
132
     */
108
    return EOK; /* All went well */
133
    mutex_lock(&t->udebug.lock);
109
 
134
 
-
 
135
    /* The big task mutex is no longer needed */
-
 
136
    mutex_unlock(&TASK->udebug.lock);
110
 
137
 
111
    /* Executed when a check on the thread fails */
138
    if (!t->udebug.stop != having_go) {
112
error_exit:
-
 
113
    spinlock_unlock(&t->lock);
139
        /* Not in debugging session or undesired GO state */
114
    spinlock_unlock(&t->udebug.lock);
140
        mutex_unlock(&t->udebug.lock);
115
    spinlock_unlock(&threads_lock);
141
        return EINVAL;
-
 
142
    }
116
 
143
 
117
    /* No locks left here */
144
    /* Only t->udebug.lock left */
-
 
145
 
118
    return rc;  /* Some errors occured */
146
    return EOK; /* All went well */
119
}
147
}
120
 
148
 
121
 
149
 
122
static void _thread_op_end(thread_t *t)
150
static void _thread_op_end(thread_t *t)
123
{
151
{
124
    spinlock_unlock(&t->udebug.lock);
152
    mutex_unlock(&t->udebug.lock);
125
}
153
}
126
 
154
 
127
/**
155
/**
128
 * \return 0 (ok, but not done yet), 1 (done) or negative error code.
156
 * \return 0 (ok, but not done yet), 1 (done) or negative error code.
129
 */
157
 */
130
int udebug_begin(call_t *call)
158
int udebug_begin(call_t *call)
131
{
159
{
132
    ipl_t ipl;
-
 
133
    int reply;
160
    int reply;
134
 
161
 
135
    thread_t *t;
162
    thread_t *t;
136
    link_t *cur;
163
    link_t *cur;
137
 
164
 
138
    klog_printf("udebug_begin()");
165
    klog_printf("udebug_begin()");
139
 
166
 
140
    mutex_lock(&TASK->udebug.lock);
167
    mutex_lock(&TASK->udebug.lock);
141
    klog_printf("debugging task %llu", TASK->taskid);
168
    klog_printf("debugging task %llu", TASK->taskid);
142
 
169
 
143
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
170
    if (TASK->udebug.dt_state != UDEBUG_TS_INACTIVE) {
144
        mutex_unlock(&TASK->udebug.lock);
171
        mutex_unlock(&TASK->udebug.lock);
145
        klog_printf("udebug_begin(): busy error");
172
        klog_printf("udebug_begin(): busy error");
146
 
173
 
147
        return EBUSY;
174
        return EBUSY;
148
    }
175
    }
149
 
176
 
150
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
177
    TASK->udebug.dt_state = UDEBUG_TS_BEGINNING;
151
    TASK->udebug.begin_call = call;
178
    TASK->udebug.begin_call = call;
152
    TASK->udebug.debugger = call->sender;
179
    TASK->udebug.debugger = call->sender;
153
 
180
 
154
    if (TASK->udebug.not_stoppable_count == 0) {
181
    if (TASK->udebug.not_stoppable_count == 0) {
155
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
182
        TASK->udebug.dt_state = UDEBUG_TS_ACTIVE;
156
        TASK->udebug.begin_call = NULL;
183
        TASK->udebug.begin_call = NULL;
157
        reply = 1; /* immediate reply */
184
        reply = 1; /* immediate reply */
158
    } else {
185
    } else {
159
        reply = 0; /* no reply */
186
        reply = 0; /* no reply */
160
    }
187
    }
161
   
188
   
162
    /* Set udebug.debug_active on all of the task's userspace threads */
189
    /* Set udebug.debug_active on all of the task's userspace threads */
163
 
190
 
164
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
191
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
165
        t = list_get_instance(cur, thread_t, th_link);
192
        t = list_get_instance(cur, thread_t, th_link);
166
 
193
 
167
        ipl = interrupts_disable();
-
 
168
        spinlock_lock(&t->udebug.lock);
194
        mutex_lock(&t->udebug.lock);
169
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
195
        if ((t->flags & THREAD_FLAG_USPACE) != 0)
170
            t->udebug.debug_active = true;
196
            t->udebug.debug_active = true;
171
        spinlock_unlock(&t->udebug.lock);
197
        mutex_unlock(&t->udebug.lock);
172
        interrupts_restore(ipl);
-
 
173
    }
198
    }
174
 
199
 
175
    mutex_unlock(&TASK->udebug.lock);
200
    mutex_unlock(&TASK->udebug.lock);
176
 
201
 
177
    klog_printf("udebug_begin() done (%s)",
202
    klog_printf("udebug_begin() done (%s)",
178
        reply ? "reply" : "stoppability wait");
203
        reply ? "reply" : "stoppability wait");
179
 
204
 
180
    return reply;
205
    return reply;
181
}
206
}
182
 
207
 
183
int udebug_end(void)
208
int udebug_end(void)
184
{
209
{
185
    int rc;
210
    int rc;
186
 
211
 
187
    klog_printf("udebug_end()");
212
    klog_printf("udebug_end()");
188
 
213
 
189
    mutex_lock(&TASK->udebug.lock);
214
    mutex_lock(&TASK->udebug.lock);
190
    klog_printf("task %llu", TASK->taskid);
215
    klog_printf("task %llu", TASK->taskid);
191
 
216
 
192
    rc = udebug_task_cleanup(TASK);
217
    rc = udebug_task_cleanup(TASK);
193
 
218
 
194
    mutex_unlock(&TASK->udebug.lock);
219
    mutex_unlock(&TASK->udebug.lock);
195
 
220
 
196
    return rc;
221
    return rc;
197
}
222
}
198
 
223
 
199
int udebug_set_evmask(udebug_evmask_t mask)
224
int udebug_set_evmask(udebug_evmask_t mask)
200
{
225
{
201
    klog_printf("udebug_set_mask()");
226
    klog_printf("udebug_set_mask()");
202
 
227
 
203
    klog_printf("debugging task %llu", TASK->taskid);
228
    klog_printf("debugging task %llu", TASK->taskid);
204
 
229
 
205
    mutex_lock(&TASK->udebug.lock);
230
    mutex_lock(&TASK->udebug.lock);
206
 
231
 
207
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
232
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
208
        mutex_unlock(&TASK->udebug.lock);
233
        mutex_unlock(&TASK->udebug.lock);
209
        klog_printf("udebug_set_mask(): not active debuging session");
234
        klog_printf("udebug_set_mask(): not active debuging session");
210
 
235
 
211
        return EINVAL;
236
        return EINVAL;
212
    }
237
    }
213
 
238
 
214
    TASK->udebug.evmask = mask;
239
    TASK->udebug.evmask = mask;
215
 
240
 
216
    mutex_unlock(&TASK->udebug.lock);
241
    mutex_unlock(&TASK->udebug.lock);
217
 
242
 
218
    return 0;
243
    return 0;
219
}
244
}
220
 
245
 
221
 
246
 
222
int udebug_go(thread_t *t, call_t *call)
247
int udebug_go(thread_t *t, call_t *call)
223
{
248
{
224
    ipl_t ipl;
-
 
225
    int rc;
249
    int rc;
226
 
250
 
227
//  klog_printf("udebug_go()");
251
//  klog_printf("udebug_go()");
228
 
252
 
229
    ipl = interrupts_disable();
-
 
230
 
-
 
231
    /* On success, this will lock t->udebug.lock */
253
    /* On success, this will lock t->udebug.lock */
232
    rc = _thread_op_begin(t, false);
254
    rc = _thread_op_begin(t, false);
233
    if (rc != EOK) {
255
    if (rc != EOK) {
234
        interrupts_restore(ipl);
-
 
235
        return rc;
256
        return rc;
236
    }
257
    }
237
 
258
 
238
    t->udebug.go_call = call;
259
    t->udebug.go_call = call;
239
    t->udebug.stop = false;
260
    t->udebug.stop = false;
240
    t->udebug.cur_event = 0;    /* none */
261
    t->udebug.cur_event = 0;    /* none */
241
 
262
 
242
    /*
263
    /*
243
     * Neither t's lock nor threads_lock may be held during wakeup
264
     * Neither t's lock nor threads_lock may be held during wakeup
244
     */
265
     */
245
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
266
    waitq_wakeup(&t->udebug.go_wq, WAKEUP_FIRST);
246
 
267
 
247
    _thread_op_end(t);
268
    _thread_op_end(t);
248
    interrupts_restore(ipl);
-
 
249
 
269
 
250
    return 0;
270
    return 0;
251
}
271
}
252
 
272
 
253
int udebug_stop(thread_t *t, call_t *call)
273
int udebug_stop(thread_t *t, call_t *call)
254
{
274
{
255
    ipl_t ipl;
-
 
256
    int rc;
275
    int rc;
257
 
276
 
258
    klog_printf("udebug_stop()");
277
    klog_printf("udebug_stop()");
259
    mutex_lock(&TASK->udebug.lock);
278
    mutex_lock(&TASK->udebug.lock);
260
 
279
 
261
    ipl = interrupts_disable();
-
 
262
 
-
 
263
    /*
280
    /*
264
     * On success, this will lock t->udebug.lock. Note that this makes sure
281
     * On success, this will lock t->udebug.lock. Note that this makes sure
265
     * the thread is not stopped.
282
     * the thread is not stopped.
266
     */
283
     */
267
    rc = _thread_op_begin(t, true);
284
    rc = _thread_op_begin(t, true);
268
    if (rc != EOK) {
285
    if (rc != EOK) {
269
        interrupts_restore(ipl);
-
 
270
        return rc;
286
        return rc;
271
    }
287
    }
272
 
288
 
273
    /* Take GO away from the thread */
289
    /* Take GO away from the thread */
274
    t->udebug.stop = true;
290
    t->udebug.stop = true;
275
 
291
 
276
    if (!t->udebug.stoppable) {
292
    if (!t->udebug.stoppable) {
277
        /* Answer will be sent when the thread becomes stoppable */
293
        /* Answer will be sent when the thread becomes stoppable */
278
        _thread_op_end(t);
294
        _thread_op_end(t);
279
        interrupts_restore(ipl);
-
 
280
        return 0;
295
        return 0;
281
    }
296
    }
282
 
297
 
283
    /*
298
    /*
284
     * Answer GO call
299
     * Answer GO call
285
     */
300
     */
286
    klog_printf("udebug_stop - answering go call");
301
    klog_printf("udebug_stop - answering go call");
287
 
302
 
288
    /* Make sure nobody takes this call away from us */
303
    /* Make sure nobody takes this call away from us */
289
    call = t->udebug.go_call;
304
    call = t->udebug.go_call;
290
    t->udebug.go_call = NULL;
305
    t->udebug.go_call = NULL;
291
 
306
 
292
    IPC_SET_RETVAL(call->data, 0);
307
    IPC_SET_RETVAL(call->data, 0);
293
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
308
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_STOP);
294
    klog_printf("udebug_stop/ipc_answer");
309
    klog_printf("udebug_stop/ipc_answer");
295
 
310
 
296
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
311
    THREAD->udebug.cur_event = UDEBUG_EVENT_STOP;
297
 
312
 
298
    _thread_op_end(t);
313
    _thread_op_end(t);
299
    interrupts_restore(ipl);
-
 
300
 
314
 
301
    ipc_answer(&TASK->answerbox, call);
315
    ipc_answer(&TASK->answerbox, call);
302
    mutex_unlock(&TASK->udebug.lock);
316
    mutex_unlock(&TASK->udebug.lock);
303
 
317
 
304
    klog_printf("udebog_stop/done");
318
    klog_printf("udebog_stop/done");
305
    return 0;
319
    return 0;
306
}
320
}
307
 
321
 
308
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
322
int udebug_thread_read(void **buffer, size_t buf_size, size_t *n)
309
{
323
{
310
    thread_t *t;
324
    thread_t *t;
311
    link_t *cur;
325
    link_t *cur;
312
    unative_t tid;
326
    unative_t tid;
313
    unsigned copied_ids;
327
    unsigned copied_ids;
314
    ipl_t ipl;
328
    ipl_t ipl;
315
    unative_t *id_buffer;
329
    unative_t *id_buffer;
316
    int flags;
330
    int flags;
317
    size_t max_ids;
331
    size_t max_ids;
318
 
332
 
319
    klog_printf("udebug_thread_read()");
333
    klog_printf("udebug_thread_read()");
320
 
334
 
321
    /* Allocate a buffer to hold thread IDs */
335
    /* Allocate a buffer to hold thread IDs */
322
    id_buffer = malloc(buf_size, 0);
336
    id_buffer = malloc(buf_size, 0);
323
 
337
 
324
    mutex_lock(&TASK->udebug.lock);
338
    mutex_lock(&TASK->udebug.lock);
325
 
339
 
326
    /* Verify task state */
340
    /* Verify task state */
327
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
341
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
328
        mutex_unlock(&TASK->udebug.lock);
342
        mutex_unlock(&TASK->udebug.lock);
329
        return EINVAL;
343
        return EINVAL;
330
    }
344
    }
331
 
345
 
332
    ipl = interrupts_disable();
346
    ipl = interrupts_disable();
333
    spinlock_lock(&TASK->lock);
347
    spinlock_lock(&TASK->lock);
334
    /* Copy down the thread IDs */
348
    /* Copy down the thread IDs */
335
 
349
 
336
    max_ids = buf_size / sizeof(unative_t);
350
    max_ids = buf_size / sizeof(unative_t);
337
    copied_ids = 0;
351
    copied_ids = 0;
338
 
352
 
-
 
353
    /* FIXME: make sure the thread isn't past debug shutdown... */
339
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
354
    for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) {
340
        /* Do not write past end of buffer */
355
        /* Do not write past end of buffer */
341
        if (copied_ids >= max_ids) break;
356
        if (copied_ids >= max_ids) break;
342
 
357
 
343
        t = list_get_instance(cur, thread_t, th_link);
358
        t = list_get_instance(cur, thread_t, th_link);
344
 
359
 
345
        spinlock_lock(&t->lock);
360
        spinlock_lock(&t->lock);
346
        flags = t->flags;
361
        flags = t->flags;
347
        spinlock_unlock(&t->lock);
362
        spinlock_unlock(&t->lock);
348
 
363
 
349
        /* Not interested in kernel threads */
364
        /* Not interested in kernel threads */
350
        if ((flags & THREAD_FLAG_USPACE) != 0) {
365
        if ((flags & THREAD_FLAG_USPACE) != 0) {
351
            /* Using thread struct pointer as identification hash */
366
            /* Using thread struct pointer as identification hash */
352
            tid = (unative_t) t;
367
            tid = (unative_t) t;
353
            id_buffer[copied_ids++] = tid;
368
            id_buffer[copied_ids++] = tid;
354
        }
369
        }
355
    }
370
    }
356
 
371
 
357
    spinlock_unlock(&TASK->lock);
372
    spinlock_unlock(&TASK->lock);
358
    interrupts_restore(ipl);
373
    interrupts_restore(ipl);
359
 
374
 
360
    mutex_unlock(&TASK->udebug.lock);
375
    mutex_unlock(&TASK->udebug.lock);
361
 
376
 
362
    *buffer = id_buffer;
377
    *buffer = id_buffer;
363
    *n = copied_ids * sizeof(unative_t);
378
    *n = copied_ids * sizeof(unative_t);
364
 
379
 
365
    return 0;
380
    return 0;
366
}
381
}
367
 
382
 
368
int udebug_args_read(thread_t *t, void **buffer)
383
int udebug_args_read(thread_t *t, void **buffer)
369
{
384
{
370
    int rc;
385
    int rc;
371
    ipl_t ipl;
-
 
372
    unative_t *arg_buffer;
386
    unative_t *arg_buffer;
373
 
387
 
374
    klog_printf("udebug_args_read()");
388
//  klog_printf("udebug_args_read()");
375
 
389
 
376
    /* Prepare a buffer to hold the arguments */
390
    /* Prepare a buffer to hold the arguments */
377
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
391
    arg_buffer = malloc(6 * sizeof(unative_t), 0);
378
 
392
 
379
    ipl = interrupts_disable();
-
 
380
 
-
 
381
    /* On success, this will lock t->udebug.lock */
393
    /* On success, this will lock t->udebug.lock */
382
    rc = _thread_op_begin(t, false);
394
    rc = _thread_op_begin(t, false);
383
    if (rc != EOK) {
395
    if (rc != EOK) {
384
        interrupts_restore(ipl);
-
 
385
        return rc;
396
        return rc;
386
    }
397
    }
387
 
398
 
388
    /* Additionally we need to verify that we are inside a syscall */
399
    /* Additionally we need to verify that we are inside a syscall */
389
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
400
    if (t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_B &&
390
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
401
        t->udebug.cur_event != UDEBUG_EVENT_SYSCALL_E) {
391
        _thread_op_end(t);
402
        _thread_op_end(t);
392
        interrupts_restore(ipl);
-
 
393
 
-
 
394
        return EINVAL;
403
        return EINVAL;
395
    }
404
    }
396
 
405
 
397
    /* Copy to a local buffer before releasing the lock */
406
    /* Copy to a local buffer before releasing the lock */
398
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
407
    memcpy(arg_buffer, t->udebug.syscall_args, 6 * sizeof(unative_t));
399
 
408
 
400
    _thread_op_end(t);
409
    _thread_op_end(t);
401
    interrupts_restore(ipl);
-
 
402
 
410
 
403
    *buffer = arg_buffer;
411
    *buffer = arg_buffer;
404
    return 0;
412
    return 0;
405
}
413
}
406
 
414
 
407
int udebug_regs_read(thread_t *t, void *buffer)
415
int udebug_regs_read(thread_t *t, void *buffer)
408
{
416
{
409
    istate_t *state;
417
    istate_t *state;
410
    int rc;
418
    int rc;
411
    ipl_t ipl;
-
 
412
 
419
 
413
    klog_printf("udebug_regs_read()");
420
//  klog_printf("udebug_regs_read()");
414
 
-
 
415
    ipl = interrupts_disable();
-
 
416
 
421
 
417
    /* On success, this will lock t->udebug.lock */
422
    /* On success, this will lock t->udebug.lock */
418
    rc = _thread_op_begin(t, false);
423
    rc = _thread_op_begin(t, false);
419
    if (rc != EOK) {
424
    if (rc != EOK) {
420
        interrupts_restore(ipl);
-
 
421
        return rc;
425
        return rc;
422
    }
426
    }
423
 
427
 
424
    state = t->udebug.uspace_state;
428
    state = t->udebug.uspace_state;
425
    if (state == NULL) {
429
    if (state == NULL) {
426
        _thread_op_end(t);
430
        _thread_op_end(t);
427
        interrupts_restore(ipl);
-
 
428
        klog_printf("udebug_regs_read() - istate not available");
431
        klog_printf("udebug_regs_read() - istate not available");
429
        return EBUSY;
432
        return EBUSY;
430
    }
433
    }
431
 
434
 
432
    /* Copy to the allocated buffer */
435
    /* Copy to the allocated buffer */
433
    memcpy(buffer, state, sizeof(istate_t));
436
    memcpy(buffer, state, sizeof(istate_t));
434
 
437
 
435
    _thread_op_end(t);
438
    _thread_op_end(t);
436
    interrupts_restore(ipl);
-
 
437
 
439
 
438
    return 0;
440
    return 0;
439
}
441
}
440
 
442
 
441
int udebug_regs_write(thread_t *t, void *buffer)
443
int udebug_regs_write(thread_t *t, void *buffer)
442
{
444
{
443
    int rc;
445
    int rc;
444
    istate_t *state;
446
    istate_t *state;
445
    ipl_t ipl;
-
 
446
 
447
 
447
    klog_printf("udebug_regs_write()");
448
    klog_printf("udebug_regs_write()");
448
 
449
 
449
    /* Try to change the thread's uspace_state */
450
    /* Try to change the thread's uspace_state */
450
 
451
 
451
    ipl = interrupts_disable();
-
 
452
 
-
 
453
    /* On success, this will lock t->udebug.lock */
452
    /* On success, this will lock t->udebug.lock */
454
    rc = _thread_op_begin(t, false);
453
    rc = _thread_op_begin(t, false);
455
    if (rc != EOK) {
454
    if (rc != EOK) {
456
        klog_printf("error locking thread");
455
        klog_printf("error locking thread");
457
        interrupts_restore(ipl);
-
 
458
        return rc;
456
        return rc;
459
    }
457
    }
460
 
458
 
461
    state = t->udebug.uspace_state;
459
    state = t->udebug.uspace_state;
462
    if (state == NULL) {
460
    if (state == NULL) {
463
        _thread_op_end(t);
461
        _thread_op_end(t);
464
        interrupts_restore(ipl);
-
 
465
        klog_printf("udebug_regs_write() - istate not available");
462
        klog_printf("udebug_regs_write() - istate not available");
466
 
-
 
467
        return EBUSY;
463
        return EBUSY;
468
    }
464
    }
469
 
465
 
470
    memcpy(t->udebug.uspace_state, buffer, sizeof(istate_t));
466
    memcpy(t->udebug.uspace_state, buffer, sizeof(istate_t));
471
 
467
 
472
    _thread_op_end(t);
468
    _thread_op_end(t);
473
    interrupts_restore(ipl);
-
 
474
 
469
 
475
    return 0;
470
    return 0;
476
}
471
}
477
 
472
 
478
 
473
 
479
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
474
int udebug_mem_read(unative_t uspace_addr, size_t n, void **buffer)
480
{
475
{
481
    void *data_buffer;
476
    void *data_buffer;
482
    int rc;
477
    int rc;
483
 
478
 
484
    /* Verify task state */
479
    /* Verify task state */
485
    mutex_lock(&TASK->udebug.lock);
480
    mutex_lock(&TASK->udebug.lock);
486
 
481
 
487
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
482
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
488
        mutex_unlock(&TASK->udebug.lock);
483
        mutex_unlock(&TASK->udebug.lock);
489
        return EBUSY;
484
        return EBUSY;
490
    }
485
    }
491
 
486
 
492
    data_buffer = malloc(n, 0);
487
    data_buffer = malloc(n, 0);
493
 
488
 
494
//  klog_printf("udebug_mem_read: src=%u, size=%u", uspace_addr, n);
489
//  klog_printf("udebug_mem_read: src=%u, size=%u", uspace_addr, n);
495
 
490
 
496
    /* NOTE: this is not strictly from a syscall... but that shouldn't
491
    /* NOTE: this is not strictly from a syscall... but that shouldn't
497
     * be a problem */
492
     * be a problem */
498
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
493
    rc = copy_from_uspace(data_buffer, (void *)uspace_addr, n);
499
    mutex_unlock(&TASK->udebug.lock);
494
    mutex_unlock(&TASK->udebug.lock);
500
 
495
 
501
    if (rc != 0) return rc;
496
    if (rc != 0) return rc;
502
 
497
 
503
    *buffer = data_buffer;
498
    *buffer = data_buffer;
504
    return 0;
499
    return 0;
505
}
500
}
506
 
501
 
507
int udebug_mem_write(unative_t uspace_addr, void *data, size_t n)
502
int udebug_mem_write(unative_t uspace_addr, void *data, size_t n)
508
{
503
{
509
    int rc;
504
    int rc;
510
 
505
 
511
    klog_printf("udebug_mem_write()");
506
    klog_printf("udebug_mem_write()");
512
 
507
 
513
    /* Verify task state */
508
    /* Verify task state */
514
    mutex_lock(&TASK->udebug.lock);
509
    mutex_lock(&TASK->udebug.lock);
515
 
510
 
516
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
511
    if (TASK->udebug.dt_state != UDEBUG_TS_ACTIVE) {
517
        mutex_unlock(&TASK->udebug.lock);
512
        mutex_unlock(&TASK->udebug.lock);
518
        return EBUSY;
513
        return EBUSY;
519
    }
514
    }
520
   
515
   
521
    klog_printf("dst=%u, size=%u", uspace_addr, n);
516
    klog_printf("dst=%u, size=%u", uspace_addr, n);
522
 
517
 
523
    /* NOTE: this is not strictly from a syscall... but that shouldn't
518
    /* NOTE: this is not strictly from a syscall... but that shouldn't
524
     * be a problem */
519
     * be a problem */
525
//  rc = copy_to_uspace((void *)uspace_addr, data, n);
520
//  rc = copy_to_uspace((void *)uspace_addr, data, n);
526
//  if (rc) return rc;
521
//  if (rc) return rc;
527
 
522
 
528
    rc = as_debug_write(uspace_addr, data, n);
523
    rc = as_debug_write(uspace_addr, data, n);
529
 
524
 
530
    mutex_unlock(&TASK->udebug.lock);
525
    mutex_unlock(&TASK->udebug.lock);
531
 
526
 
532
    return rc;
527
    return rc;
533
}
528
}
534
 
529
 
535
/** @}
530
/** @}
536
 */
531
 */
537
 
532