Subversion Repositories HelenOS

Rev

Rev 3665 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

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