~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to kernel/generic/src/udebug/udebug_ipc.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2008 Jiri Svoboda
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup generic
 
30
 * @{
 
31
 */
 
32
 
 
33
/**
 
34
 * @file
 
35
 * @brief       Udebug IPC message handling.
 
36
 *
 
37
 * This module handles udebug IPC messages and calls the appropriate
 
38
 * functions from the udebug_ops module which implement them.
 
39
 */
 
40
 
 
41
#include <proc/task.h>
 
42
#include <proc/thread.h>
 
43
#include <arch.h>
 
44
#include <errno.h>
 
45
#include <ipc/ipc.h>
 
46
#include <syscall/copy.h>
 
47
#include <udebug/udebug.h>
 
48
#include <udebug/udebug_ops.h>
 
49
#include <udebug/udebug_ipc.h>
 
50
 
 
51
int udebug_request_preprocess(call_t *call, phone_t *phone)
 
52
{
 
53
        switch (IPC_GET_ARG1(call->data)) {
 
54
        /* future UDEBUG_M_REGS_WRITE, UDEBUG_M_MEM_WRITE: */
 
55
        default:
 
56
                break;
 
57
        }
 
58
 
 
59
        return 0;
 
60
}
 
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
 */
 
69
static void udebug_receive_begin(call_t *call)
 
70
{
 
71
        int rc;
 
72
 
 
73
        rc = udebug_begin(call);
 
74
        if (rc < 0) {
 
75
                IPC_SET_RETVAL(call->data, rc);
 
76
                ipc_answer(&TASK->kb.box, call);
 
77
                return;
 
78
        }
 
79
 
 
80
        /*
 
81
         * If the initialization of the debugging session has finished,
 
82
         * send a reply.
 
83
         */
 
84
        if (rc != 0) {
 
85
                IPC_SET_RETVAL(call->data, 0);
 
86
                ipc_answer(&TASK->kb.box, call);
 
87
        }
 
88
}
 
89
 
 
90
/** Process an END call.
 
91
 *
 
92
 * Terminates the debugging session for the current task.
 
93
 * @param call  The call structure.
 
94
 */
 
95
static void udebug_receive_end(call_t *call)
 
96
{
 
97
        int rc;
 
98
 
 
99
        rc = udebug_end();
 
100
 
 
101
        IPC_SET_RETVAL(call->data, rc);
 
102
        ipc_answer(&TASK->kb.box, call);
 
103
}
 
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
 */
 
110
static void udebug_receive_set_evmask(call_t *call)
 
111
{
 
112
        int rc;
 
113
        udebug_evmask_t mask;
 
114
 
 
115
        mask = IPC_GET_ARG2(call->data);
 
116
        rc = udebug_set_evmask(mask);
 
117
 
 
118
        IPC_SET_RETVAL(call->data, rc);
 
119
        ipc_answer(&TASK->kb.box, call);
 
120
}
 
121
 
 
122
 
 
123
/** Process a GO call.
 
124
 *
 
125
 * Resumes execution of the specified thread.
 
126
 * @param call  The call structure.
 
127
 */
 
128
static void udebug_receive_go(call_t *call)
 
129
{
 
130
        thread_t *t;
 
131
        int rc;
 
132
 
 
133
        t = (thread_t *)IPC_GET_ARG2(call->data);
 
134
 
 
135
        rc = udebug_go(t, call);
 
136
        if (rc < 0) {
 
137
                IPC_SET_RETVAL(call->data, rc);
 
138
                ipc_answer(&TASK->kb.box, call);
 
139
                return;
 
140
        }
 
141
}
 
142
 
 
143
/** Process a STOP call.
 
144
 *
 
145
 * Suspends execution of the specified thread.
 
146
 * @param call  The call structure.
 
147
 */
 
148
static void udebug_receive_stop(call_t *call)
 
149
{
 
150
        thread_t *t;
 
151
        int rc;
 
152
 
 
153
        t = (thread_t *)IPC_GET_ARG2(call->data);
 
154
 
 
155
        rc = udebug_stop(t, call);
 
156
        IPC_SET_RETVAL(call->data, rc);
 
157
        ipc_answer(&TASK->kb.box, call);
 
158
}
 
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
 */
 
165
static void udebug_receive_thread_read(call_t *call)
 
166
{
 
167
        unative_t uspace_addr;
 
168
        unative_t to_copy;
 
169
        unsigned total_bytes;
 
170
        unsigned buf_size;
 
171
        void *buffer;
 
172
        size_t n;
 
173
        int rc;
 
174
 
 
175
        uspace_addr = IPC_GET_ARG2(call->data); /* Destination address */
 
176
        buf_size = IPC_GET_ARG3(call->data);    /* Dest. buffer size */
 
177
 
 
178
        /*
 
179
         * Read thread list. Variable n will be filled with actual number
 
180
         * of threads times thread-id size.
 
181
         */
 
182
        rc = udebug_thread_read(&buffer, buf_size, &n);
 
183
        if (rc < 0) {
 
184
                IPC_SET_RETVAL(call->data, rc);
 
185
                ipc_answer(&TASK->kb.box, call);
 
186
                return;
 
187
        }
 
188
 
 
189
        total_bytes = n;
 
190
 
 
191
        /* Copy MAX(buf_size, total_bytes) bytes */
 
192
 
 
193
        if (buf_size > total_bytes)
 
194
                to_copy = total_bytes;
 
195
        else
 
196
                to_copy = buf_size;
 
197
 
 
198
        /*
 
199
         * Make use of call->buffer to transfer data to caller's userspace
 
200
         */
 
201
 
 
202
        IPC_SET_RETVAL(call->data, 0);
 
203
        /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
 
204
           same code in process_answer() can be used 
 
205
           (no way to distinguish method in answer) */
 
206
        IPC_SET_ARG1(call->data, uspace_addr);
 
207
        IPC_SET_ARG2(call->data, to_copy);
 
208
 
 
209
        IPC_SET_ARG3(call->data, total_bytes);
 
210
        call->buffer = buffer;
 
211
 
 
212
        ipc_answer(&TASK->kb.box, call);
 
213
}
 
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
 */
 
220
static void udebug_receive_args_read(call_t *call)
 
221
{
 
222
        thread_t *t;
 
223
        unative_t uspace_addr;
 
224
        int rc;
 
225
        void *buffer;
 
226
 
 
227
        t = (thread_t *)IPC_GET_ARG2(call->data);
 
228
 
 
229
        rc = udebug_args_read(t, &buffer);
 
230
        if (rc != EOK) {
 
231
                IPC_SET_RETVAL(call->data, rc);
 
232
                ipc_answer(&TASK->kb.box, call);
 
233
                return;
 
234
        }
 
235
 
 
236
        /*
 
237
         * Make use of call->buffer to transfer data to caller's userspace
 
238
         */
 
239
 
 
240
        uspace_addr = IPC_GET_ARG3(call->data);
 
241
 
 
242
        IPC_SET_RETVAL(call->data, 0);
 
243
        /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
 
244
           same code in process_answer() can be used 
 
245
           (no way to distinguish method in answer) */
 
246
        IPC_SET_ARG1(call->data, uspace_addr);
 
247
        IPC_SET_ARG2(call->data, 6 * sizeof(unative_t));
 
248
        call->buffer = buffer;
 
249
 
 
250
        ipc_answer(&TASK->kb.box, call);
 
251
}
 
252
 
 
253
/** Process an MEM_READ call.
 
254
 *
 
255
 * Reads memory of the current (debugged) task.
 
256
 * @param call  The call structure.
 
257
 */
 
258
static void udebug_receive_mem_read(call_t *call)
 
259
{
 
260
        unative_t uspace_dst;
 
261
        unative_t uspace_src;
 
262
        unsigned size;
 
263
        void *buffer;
 
264
        int rc;
 
265
 
 
266
        uspace_dst = IPC_GET_ARG2(call->data);
 
267
        uspace_src = IPC_GET_ARG3(call->data);
 
268
        size = IPC_GET_ARG4(call->data);
 
269
 
 
270
        rc = udebug_mem_read(uspace_src, size, &buffer);
 
271
        if (rc < 0) {
 
272
                IPC_SET_RETVAL(call->data, rc);
 
273
                ipc_answer(&TASK->kb.box, call);
 
274
                return;
 
275
        }
 
276
 
 
277
        IPC_SET_RETVAL(call->data, 0);
 
278
        /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that
 
279
           same code in process_answer() can be used 
 
280
           (no way to distinguish method in answer) */
 
281
        IPC_SET_ARG1(call->data, uspace_dst);
 
282
        IPC_SET_ARG2(call->data, size);
 
283
        call->buffer = buffer;
 
284
 
 
285
        ipc_answer(&TASK->kb.box, call);
 
286
}
 
287
 
 
288
/** Handle a debug call received on the kernel answerbox.
 
289
 *
 
290
 * This is called by the kbox servicing thread. Verifies that the sender
 
291
 * is indeed the debugger and calls the appropriate processing function.
 
292
 */
 
293
void udebug_call_receive(call_t *call)
 
294
{
 
295
        int debug_method;
 
296
 
 
297
        debug_method = IPC_GET_ARG1(call->data);
 
298
 
 
299
        if (debug_method != UDEBUG_M_BEGIN) {
 
300
                /*
 
301
                 * Verify that the sender is this task's debugger.
 
302
                 * Note that this is the only thread that could change
 
303
                 * TASK->debugger. Therefore no locking is necessary
 
304
                 * and the sender can be safely considered valid until
 
305
                 * control exits this function.
 
306
                 */
 
307
                if (TASK->udebug.debugger != call->sender) {
 
308
                        IPC_SET_RETVAL(call->data, EINVAL);
 
309
                        ipc_answer(&TASK->kb.box, call);
 
310
                        return; 
 
311
                }
 
312
        }
 
313
 
 
314
        switch (debug_method) {
 
315
        case UDEBUG_M_BEGIN:
 
316
                udebug_receive_begin(call);
 
317
                break;
 
318
        case UDEBUG_M_END:
 
319
                udebug_receive_end(call);
 
320
                break;
 
321
        case UDEBUG_M_SET_EVMASK:
 
322
                udebug_receive_set_evmask(call);
 
323
                break;
 
324
        case UDEBUG_M_GO:
 
325
                udebug_receive_go(call);
 
326
                break;
 
327
        case UDEBUG_M_STOP:
 
328
                udebug_receive_stop(call);
 
329
                break;
 
330
        case UDEBUG_M_THREAD_READ:
 
331
                udebug_receive_thread_read(call);
 
332
                break;
 
333
        case UDEBUG_M_ARGS_READ:
 
334
                udebug_receive_args_read(call);
 
335
                break;
 
336
        case UDEBUG_M_MEM_READ:
 
337
                udebug_receive_mem_read(call);
 
338
                break;
 
339
        }
 
340
}
 
341
 
 
342
/** @}
 
343
 */