Subversion Repositories HelenOS

Rev

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

Rev 3457 Rev 3468
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 IPC message handling.
35
 * @brief   Udebug IPC message handling.
36
 *
36
 *
37
 * This module handles udebug IPC messages and calls the appropriate
37
 * This module handles udebug IPC messages and calls the appropriate
38
 * functions from the udebug_ops module which implement them.
38
 * functions from the udebug_ops module which implement them.
39
 */
39
 */
40
 
40
 
41
#include <proc/task.h>
41
#include <proc/task.h>
42
#include <proc/thread.h>
42
#include <proc/thread.h>
43
#include <arch.h>
43
#include <arch.h>
44
#include <errno.h>
44
#include <errno.h>
45
#include <ipc/ipc.h>
45
#include <ipc/ipc.h>
46
#include <syscall/copy.h>
46
#include <syscall/copy.h>
47
#include <udebug/udebug.h>
47
#include <udebug/udebug.h>
48
#include <udebug/udebug_ops.h>
48
#include <udebug/udebug_ops.h>
49
#include <udebug/udebug_ipc.h>
49
#include <udebug/udebug_ipc.h>
50
 
50
 
51
int udebug_request_preprocess(call_t *call, phone_t *phone)
51
int udebug_request_preprocess(call_t *call, phone_t *phone)
52
{
52
{
53
    switch (IPC_GET_ARG1(call->data)) {
53
    switch (IPC_GET_ARG1(call->data)) {
54
    /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
54
    /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
55
    default:
55
    default:
56
        break;
56
        break;
57
    }
57
    }
58
 
58
 
59
    return 0;
59
    return 0;
60
}
60
}
61
 
61
 
-
 
62
/** Process a BEGIN call.
-
 
63
 *
-
 
64
 * Initiates a debugging session for the current task. The reply
-
 
65
 * to this call may or may not be sent before this function returns.
-
 
66
 *
-
 
67
 * @param call  The call structure.
-
 
68
 */
62
static void udebug_receive_begin(call_t *call)
69
static void udebug_receive_begin(call_t *call)
63
{
70
{
64
    int rc;
71
    int rc;
65
 
72
 
66
    rc = udebug_begin(call);
73
    rc = udebug_begin(call);
67
    if (rc < 0) {
74
    if (rc < 0) {
68
        IPC_SET_RETVAL(call->data, rc);
75
        IPC_SET_RETVAL(call->data, rc);
69
        ipc_answer(&TASK->kernel_box, call);
76
        ipc_answer(&TASK->kernel_box, call);
70
        return;
77
        return;
71
    }
78
    }
72
 
79
 
-
 
80
    /*
-
 
81
     * If the initialization of the debugging session has finished,
-
 
82
     * send a reply.
-
 
83
     */
73
    if (rc != 0) {
84
    if (rc != 0) {
74
        IPC_SET_RETVAL(call->data, 0);
85
        IPC_SET_RETVAL(call->data, 0);
75
        ipc_answer(&TASK->kernel_box, call);
86
        ipc_answer(&TASK->kernel_box, call);
76
    }
87
    }
77
}
88
}
78
 
89
 
-
 
90
/** Process an END call.
-
 
91
 *
-
 
92
 * Terminates the debugging session for the current task.
-
 
93
 * @param call  The call structure.
-
 
94
 */
79
static void udebug_receive_end(call_t *call)
95
static void udebug_receive_end(call_t *call)
80
{
96
{
81
    int rc;
97
    int rc;
82
 
98
 
83
    rc = udebug_end();
99
    rc = udebug_end();
84
 
100
 
85
    IPC_SET_RETVAL(call->data, rc);
101
    IPC_SET_RETVAL(call->data, rc);
86
    ipc_answer(&TASK->kernel_box, call);
102
    ipc_answer(&TASK->kernel_box, call);
87
}
103
}
88
 
104
 
-
 
105
/** Process a SET_EVMASK call.
-
 
106
 *
-
 
107
 * Sets an event mask for the current debugging session.
-
 
108
 * @param call  The call structure.
-
 
109
 */
89
static void udebug_receive_set_evmask(call_t *call)
110
static void udebug_receive_set_evmask(call_t *call)
90
{
111
{
91
    int rc;
112
    int rc;
92
    udebug_evmask_t mask;
113
    udebug_evmask_t mask;
93
 
114
 
94
    mask = IPC_GET_ARG2(call->data);
115
    mask = IPC_GET_ARG2(call->data);
95
    rc = udebug_set_evmask(mask);
116
    rc = udebug_set_evmask(mask);
96
 
117
 
97
    IPC_SET_RETVAL(call->data, rc);
118
    IPC_SET_RETVAL(call->data, rc);
98
    ipc_answer(&TASK->kernel_box, call);
119
    ipc_answer(&TASK->kernel_box, call);
99
}
120
}
100
 
121
 
101
 
122
 
-
 
123
/** Process a GO call.
-
 
124
 *
-
 
125
 * Resumes execution of the specified thread.
-
 
126
 * @param call  The call structure.
-
 
127
 */
102
static void udebug_receive_go(call_t *call)
128
static void udebug_receive_go(call_t *call)
103
{
129
{
104
    thread_t *t;
130
    thread_t *t;
105
    int rc;
131
    int rc;
106
 
132
 
107
    t = (thread_t *)IPC_GET_ARG2(call->data);
133
    t = (thread_t *)IPC_GET_ARG2(call->data);
108
 
134
 
109
    rc = udebug_go(t, call);
135
    rc = udebug_go(t, call);
110
    if (rc < 0) {
136
    if (rc < 0) {
111
        IPC_SET_RETVAL(call->data, rc);
137
        IPC_SET_RETVAL(call->data, rc);
112
        ipc_answer(&TASK->kernel_box, call);
138
        ipc_answer(&TASK->kernel_box, call);
113
        return;
139
        return;
114
    }
140
    }
115
}
141
}
116
 
142
 
-
 
143
/** Process a STOP call.
-
 
144
 *
-
 
145
 * Suspends execution of the specified thread.
-
 
146
 * @param call  The call structure.
-
 
147
 */
117
static void udebug_receive_stop(call_t *call)
148
static void udebug_receive_stop(call_t *call)
118
{
149
{
119
    thread_t *t;
150
    thread_t *t;
120
    int rc;
151
    int rc;
121
 
152
 
122
    t = (thread_t *)IPC_GET_ARG2(call->data);
153
    t = (thread_t *)IPC_GET_ARG2(call->data);
123
 
154
 
124
    rc = udebug_stop(t, call);
155
    rc = udebug_stop(t, call);
125
    IPC_SET_RETVAL(call->data, rc);
156
    IPC_SET_RETVAL(call->data, rc);
126
    ipc_answer(&TASK->kernel_box, call);
157
    ipc_answer(&TASK->kernel_box, call);
127
}
158
}
128
 
159
 
-
 
160
/** Process a THREAD_READ call.
-
 
161
 *
-
 
162
 * Reads the list of hashes of the (userspace) threads in the current task.
-
 
163
 * @param call  The call structure.
-
 
164
 */
129
static void udebug_receive_thread_read(call_t *call)
165
static void udebug_receive_thread_read(call_t *call)
130
{
166
{
131
    unative_t uspace_addr;
167
    unative_t uspace_addr;
132
    unative_t to_copy;
168
    unative_t to_copy;
133
    unsigned total_bytes;
169
    unsigned total_bytes;
134
    unsigned buf_size;
170
    unsigned buf_size;
135
    void *buffer;
171
    void *buffer;
136
    size_t n;
172
    size_t n;
137
    int rc;
173
    int rc;
138
 
174
 
139
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
175
    uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
140
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
176
    buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
141
 
177
 
142
    /*
178
    /*
143
     * Read thread list. Variable n will be filled with actual number
179
     * Read thread list. Variable n will be filled with actual number
144
     * of threads times thread-id size.
180
     * of threads times thread-id size.
145
     */
181
     */
146
    rc = udebug_thread_read(&buffer, buf_size, &n);
182
    rc = udebug_thread_read(&buffer, buf_size, &n);
147
    if (rc < 0) {
183
    if (rc < 0) {
148
        IPC_SET_RETVAL(call->data, rc);
184
        IPC_SET_RETVAL(call->data, rc);
149
        ipc_answer(&TASK->kernel_box, call);
185
        ipc_answer(&TASK->kernel_box, call);
150
        return;
186
        return;
151
    }
187
    }
152
 
188
 
153
    total_bytes = n;
189
    total_bytes = n;
154
 
190
 
155
    /* Copy MAX(buf_size, total_bytes) bytes */
191
    /* Copy MAX(buf_size, total_bytes) bytes */
156
 
192
 
157
    if (buf_size > total_bytes)
193
    if (buf_size > total_bytes)
158
        to_copy = total_bytes;
194
        to_copy = total_bytes;
159
    else
195
    else
160
        to_copy = buf_size;
196
        to_copy = buf_size;
161
 
197
 
162
    /*
198
    /*
163
     * Make use of call->buffer to transfer data to caller's userspace
199
     * Make use of call->buffer to transfer data to caller's userspace
164
     */
200
     */
165
 
201
 
166
    IPC_SET_RETVAL(call->data, 0);
202
    IPC_SET_RETVAL(call->data, 0);
167
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
203
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
168
       same code in process_answer() can be used
204
       same code in process_answer() can be used
169
       (no way to distinguish method in answer) */
205
       (no way to distinguish method in answer) */
170
    IPC_SET_ARG1(call->data, uspace_addr);
206
    IPC_SET_ARG1(call->data, uspace_addr);
171
    IPC_SET_ARG2(call->data, to_copy);
207
    IPC_SET_ARG2(call->data, to_copy);
172
 
208
 
173
    IPC_SET_ARG3(call->data, total_bytes);
209
    IPC_SET_ARG3(call->data, total_bytes);
174
    call->buffer = buffer;
210
    call->buffer = buffer;
175
 
211
 
176
    ipc_answer(&TASK->kernel_box, call);
212
    ipc_answer(&TASK->kernel_box, call);
177
}
213
}
178
 
214
 
-
 
215
/** Process an ARGS_READ call.
-
 
216
 *
-
 
217
 * Reads the argument of a current syscall event (SYSCALL_B or SYSCALL_E).
-
 
218
 * @param call  The call structure.
-
 
219
 */
179
static void udebug_receive_args_read(call_t *call)
220
static void udebug_receive_args_read(call_t *call)
180
{
221
{
181
    thread_t *t;
222
    thread_t *t;
182
    unative_t uspace_addr;
223
    unative_t uspace_addr;
183
    int rc;
224
    int rc;
184
    void *buffer;
225
    void *buffer;
185
 
226
 
186
    t = (thread_t *)IPC_GET_ARG2(call->data);
227
    t = (thread_t *)IPC_GET_ARG2(call->data);
187
 
228
 
188
    rc = udebug_args_read(t, &buffer);
229
    rc = udebug_args_read(t, &buffer);
189
    if (rc != EOK) {
230
    if (rc != EOK) {
190
        IPC_SET_RETVAL(call->data, rc);
231
        IPC_SET_RETVAL(call->data, rc);
191
        ipc_answer(&TASK->kernel_box, call);
232
        ipc_answer(&TASK->kernel_box, call);
192
        return;
233
        return;
193
    }
234
    }
194
 
235
 
195
    /*
236
    /*
196
     * Make use of call->buffer to transfer data to caller's userspace
237
     * Make use of call->buffer to transfer data to caller's userspace
197
     */
238
     */
198
 
239
 
199
    uspace_addr = IPC_GET_ARG3(call->data);
240
    uspace_addr = IPC_GET_ARG3(call->data);
200
 
241
 
201
    IPC_SET_RETVAL(call->data, 0);
242
    IPC_SET_RETVAL(call->data, 0);
202
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
243
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
203
       same code in process_answer() can be used
244
       same code in process_answer() can be used
204
       (no way to distinguish method in answer) */
245
       (no way to distinguish method in answer) */
205
    IPC_SET_ARG1(call->data, uspace_addr);
246
    IPC_SET_ARG1(call->data, uspace_addr);
206
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
247
    IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
207
    call->buffer = buffer;
248
    call->buffer = buffer;
208
 
249
 
209
    ipc_answer(&TASK->kernel_box, call);
250
    ipc_answer(&TASK->kernel_box, call);
210
}
251
}
211
 
252
 
-
 
253
/** Process an MEM_READ call.
-
 
254
 *
-
 
255
 * Reads memory of the current (debugged) task.
-
 
256
 * @param call  The call structure.
-
 
257
 */
212
static void udebug_receive_mem_read(call_t *call)
258
static void udebug_receive_mem_read(call_t *call)
213
{
259
{
214
    unative_t uspace_dst;
260
    unative_t uspace_dst;
215
    unative_t uspace_src;
261
    unative_t uspace_src;
216
    unsigned size;
262
    unsigned size;
217
    void *buffer;
263
    void *buffer;
218
    int rc;
264
    int rc;
219
 
265
 
220
    uspace_dst = IPC_GET_ARG2(call->data);
266
    uspace_dst = IPC_GET_ARG2(call->data);
221
    uspace_src = IPC_GET_ARG3(call->data);
267
    uspace_src = IPC_GET_ARG3(call->data);
222
    size = IPC_GET_ARG4(call->data);
268
    size = IPC_GET_ARG4(call->data);
223
 
269
 
224
    rc = udebug_mem_read(uspace_src, size, &buffer);
270
    rc = udebug_mem_read(uspace_src, size, &buffer);
225
    if (rc < 0) {
271
    if (rc < 0) {
226
        IPC_SET_RETVAL(call->data, rc);
272
        IPC_SET_RETVAL(call->data, rc);
227
        ipc_answer(&TASK->kernel_box, call);
273
        ipc_answer(&TASK->kernel_box, call);
228
        return;
274
        return;
229
    }
275
    }
230
 
276
 
231
    IPC_SET_RETVAL(call->data, 0);
277
    IPC_SET_RETVAL(call->data, 0);
232
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
278
    /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
233
       same code in process_answer() can be used
279
       same code in process_answer() can be used
234
       (no way to distinguish method in answer) */
280
       (no way to distinguish method in answer) */
235
    IPC_SET_ARG1(call->data, uspace_dst);
281
    IPC_SET_ARG1(call->data, uspace_dst);
236
    IPC_SET_ARG2(call->data, size);
282
    IPC_SET_ARG2(call->data, size);
237
    call->buffer = buffer;
283
    call->buffer = buffer;
238
 
284
 
239
    ipc_answer(&TASK->kernel_box, call);
285
    ipc_answer(&TASK->kernel_box, call);
240
}
286
}
241
 
287
 
242
/**
-
 
243
 * Handle a debug call received on the kernel answerbox.
288
/** Handle a debug call received on the kernel answerbox.
244
 *
289
 *
245
 * This is called by the kbox servicing thread.
290
 * This is called by the kbox servicing thread. Verifies that the sender
-
 
291
 * is indeed the debugger and calls the appropriate processing function.
246
 */
292
 */
247
void udebug_call_receive(call_t *call)
293
void udebug_call_receive(call_t *call)
248
{
294
{
249
    int debug_method;
295
    int debug_method;
250
 
296
 
251
    debug_method = IPC_GET_ARG1(call->data);
297
    debug_method = IPC_GET_ARG1(call->data);
252
 
298
 
253
    if (debug_method != UDEBUG_M_BEGIN) {
299
    if (debug_method != UDEBUG_M_BEGIN) {
254
        /*
300
        /*
255
         * Verify that the sender is this task's debugger.
301
         * Verify that the sender is this task's debugger.
256
         * Note that this is the only thread that could change
302
         * Note that this is the only thread that could change
257
         * TASK->debugger. Therefore no locking is necessary
303
         * TASK->debugger. Therefore no locking is necessary
258
         * and the sender can be safely considered valid until
304
         * and the sender can be safely considered valid until
259
         * control exits this function.
305
         * control exits this function.
260
         */
306
         */
261
        if (TASK->udebug.debugger != call->sender) {
307
        if (TASK->udebug.debugger != call->sender) {
262
            IPC_SET_RETVAL(call->data, EINVAL);
308
            IPC_SET_RETVAL(call->data, EINVAL);
263
            ipc_answer(&TASK->kernel_box, call);
309
            ipc_answer(&TASK->kernel_box, call);
264
            return;
310
            return;
265
        }
311
        }
266
    }
312
    }
267
 
313
 
268
    switch (debug_method) {
314
    switch (debug_method) {
269
    case UDEBUG_M_BEGIN:
315
    case UDEBUG_M_BEGIN:
270
        udebug_receive_begin(call);
316
        udebug_receive_begin(call);
271
        break;
317
        break;
272
    case UDEBUG_M_END:
318
    case UDEBUG_M_END:
273
        udebug_receive_end(call);
319
        udebug_receive_end(call);
274
        break;
320
        break;
275
    case UDEBUG_M_SET_EVMASK:
321
    case UDEBUG_M_SET_EVMASK:
276
        udebug_receive_set_evmask(call);
322
        udebug_receive_set_evmask(call);
277
        break;
323
        break;
278
    case UDEBUG_M_GO:
324
    case UDEBUG_M_GO:
279
        udebug_receive_go(call);
325
        udebug_receive_go(call);
280
        break;
326
        break;
281
    case UDEBUG_M_STOP:
327
    case UDEBUG_M_STOP:
282
        udebug_receive_stop(call);
328
        udebug_receive_stop(call);
283
        break;
329
        break;
284
    case UDEBUG_M_THREAD_READ:
330
    case UDEBUG_M_THREAD_READ:
285
        udebug_receive_thread_read(call);
331
        udebug_receive_thread_read(call);
286
        break;
332
        break;
287
    case UDEBUG_M_ARGS_READ:
333
    case UDEBUG_M_ARGS_READ:
288
        udebug_receive_args_read(call);
334
        udebug_receive_args_read(call);
289
        break;
335
        break;
290
    case UDEBUG_M_MEM_READ:
336
    case UDEBUG_M_MEM_READ:
291
        udebug_receive_mem_read(call);
337
        udebug_receive_mem_read(call);
292
        break;
338
        break;
293
    }
339
    }
294
}
340
}
295
 
341
 
296
/** @}
342
/** @}
297
 */
343
 */
298
 
344