Rev 2870 | Rev 2886 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2870 | Rev 2885 | ||
---|---|---|---|
1 | /** @addtogroup generic |
1 | /** @addtogroup generic |
2 | * @{ |
2 | * @{ |
3 | */ |
3 | */ |
4 | 4 | ||
5 | /** |
5 | /** |
6 | * @file |
6 | * @file |
7 | * @brief Tdebug. |
7 | * @brief Tdebug. |
8 | */ |
8 | */ |
9 | 9 | ||
10 | #include <console/klog.h> |
10 | #include <console/klog.h> |
11 | #include <proc/task.h> |
11 | #include <proc/task.h> |
12 | #include <proc/thread.h> |
12 | #include <proc/thread.h> |
13 | #include <arch.h> |
13 | #include <arch.h> |
14 | #include <errno.h> |
14 | #include <errno.h> |
15 | #include <ipc/ipc.h> |
15 | #include <ipc/ipc.h> |
16 | #include <syscall/copy.h> |
16 | #include <syscall/copy.h> |
17 | #include <udebug/udebug.h> |
17 | #include <udebug/udebug.h> |
18 | #include <udebug/udebug_ipc.h> |
18 | #include <udebug/udebug_ipc.h> |
19 | 19 | ||
20 | /** |
20 | /** |
21 | * Get a phone's callee task id. |
21 | * Get a phone's callee task id. |
22 | * |
22 | * |
23 | * This will return the id of the task to which the phone |
23 | * This will return the id of the task to which the phone |
24 | * is connected. |
24 | * is connected. |
25 | * |
25 | * |
26 | * Interrupts must be already disabled. |
26 | * Interrupts must be already disabled. |
27 | */ |
27 | */ |
28 | static task_id_t get_callee_task_id(phone_t *phone) |
28 | static task_id_t get_callee_task_id(phone_t *phone) |
29 | { |
29 | { |
30 | answerbox_t *box; |
30 | answerbox_t *box; |
31 | task_id_t taskid; |
31 | task_id_t taskid; |
32 | 32 | ||
33 | spinlock_lock(&phone->lock); |
33 | spinlock_lock(&phone->lock); |
34 | if (phone->state != IPC_PHONE_CONNECTED) { |
34 | if (phone->state != IPC_PHONE_CONNECTED) { |
35 | spinlock_unlock(&phone->lock); |
35 | spinlock_unlock(&phone->lock); |
36 | return NULL; |
36 | return NULL; |
37 | } |
37 | } |
38 | 38 | ||
39 | box = phone->callee; |
39 | box = phone->callee; |
40 | 40 | ||
41 | spinlock_lock(&box->lock); |
41 | spinlock_lock(&box->lock); |
42 | taskid = box->task->taskid; |
42 | taskid = box->task->taskid; |
43 | spinlock_unlock(&box->lock); |
43 | spinlock_unlock(&box->lock); |
44 | spinlock_unlock(&phone->lock); |
44 | spinlock_unlock(&phone->lock); |
45 | 45 | ||
46 | return taskid; |
46 | return taskid; |
47 | } |
47 | } |
48 | 48 | ||
49 | /** |
49 | /** |
50 | * Get and lock a phone's callee task. |
- | |
51 | * |
- | |
52 | * This will return a pointer to the task to which the phone |
- | |
53 | * is connected. It will lock the task, making sure it exists. |
- | |
54 | * |
- | |
55 | * Interrupts must be already disabled. |
- | |
56 | */ |
- | |
57 | static task_t *get_lock_callee_task(phone_t *phone) |
- | |
58 | { |
- | |
59 | task_t *ta; |
- | |
60 | task_id_t taskid; |
- | |
61 | - | ||
62 | taskid = get_callee_task_id(phone); |
- | |
63 | - | ||
64 | spinlock_lock(&tasks_lock); |
- | |
65 | ta = task_find_by_id(taskid); |
- | |
66 | if (ta == NULL) { |
- | |
67 | spinlock_unlock(&tasks_lock); |
- | |
68 | return NULL; |
- | |
69 | } |
- | |
70 | - | ||
71 | spinlock_lock(&ta->lock); |
- | |
72 | spinlock_unlock(&tasks_lock); |
- | |
73 | - | ||
74 | return ta; |
- | |
75 | } |
- | |
76 | - | ||
77 | /** |
- | |
78 | * Prepare a thread for a debugging operation. |
50 | * Prepare a thread for a debugging operation. |
79 | * |
51 | * |
80 | * Simply put, return thread t with t->debug_lock held, |
52 | * Simply put, return thread t with t->debug_lock held, |
81 | * but only if it verifies all conditions. |
53 | * but only if it verifies all conditions. |
82 | * |
54 | * |
83 | * Specifically, verifies that thread t exists, is a userspace thread, |
55 | * Specifically, verifies that thread t exists, is a userspace thread, |
84 | * belongs to the callee of 'phone'. It also locks t->debug_lock, |
56 | * belongs to the callee of 'phone'. It also locks t->debug_lock, |
85 | * making sure that t->debug_active is true - that the thread is |
57 | * making sure that t->debug_active is true - that the thread is |
86 | * in a valid debugging session. |
58 | * in a valid debugging session. |
87 | * |
59 | * |
88 | * Returns EOK if all went well, or an error code otherwise. |
60 | * Returns EOK if all went well, or an error code otherwise. |
89 | * Interrupts must be already disabled when calling this function. |
61 | * Interrupts must be already disabled when calling this function. |
90 | * |
62 | * |
91 | * Note: This function sports complicated locking. |
63 | * Note: This function sports complicated locking. |
92 | */ |
64 | */ |
93 | static int _thread_op_begin(phone_t *phone, thread_t *t) |
65 | static int _thread_op_begin(phone_t *phone, thread_t *t) |
94 | { |
66 | { |
95 | int rc; |
67 | int rc; |
96 | task_id_t taskid; |
68 | task_id_t taskid; |
97 | int task_match; |
69 | int task_match; |
98 | DEADLOCK_PROBE_INIT(p_tasklock); |
70 | DEADLOCK_PROBE_INIT(p_tasklock); |
99 | 71 | ||
100 | taskid = get_callee_task_id(phone); |
72 | taskid = get_callee_task_id(phone); |
101 | 73 | ||
102 | /* Need to lock down the thread and than it's owner task */ |
74 | /* Need to lock down the thread and than it's owner task */ |
103 | grab_locks: |
75 | grab_locks: |
104 | spinlock_lock(&threads_lock); |
76 | spinlock_lock(&threads_lock); |
105 | 77 | ||
106 | if (!thread_exists(t)) { |
78 | if (!thread_exists(t)) { |
107 | spinlock_unlock(&threads_lock); |
79 | spinlock_unlock(&threads_lock); |
108 | return ENOENT; |
80 | return ENOENT; |
109 | } |
81 | } |
110 | 82 | ||
111 | spinlock_lock(&t->debug_lock); |
83 | spinlock_lock(&t->debug_lock); |
112 | spinlock_lock(&t->lock); |
84 | spinlock_lock(&t->lock); |
113 | 85 | ||
114 | if (!spinlock_trylock(&t->task->lock)) { |
86 | if (!spinlock_trylock(&t->task->lock)) { |
115 | spinlock_unlock(&t->lock); |
87 | spinlock_unlock(&t->lock); |
116 | spinlock_unlock(&t->debug_lock); |
88 | spinlock_unlock(&t->debug_lock); |
117 | DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD); |
89 | DEADLOCK_PROBE(p_tasklock, DEADLOCK_THRESHOLD); |
118 | goto grab_locks; /* avoid deadlock */ |
90 | goto grab_locks; /* avoid deadlock */ |
119 | } |
91 | } |
120 | 92 | ||
121 | /* Now verify that it's the callee */ |
93 | /* Now verify that it's the callee */ |
122 | task_match = (t->task->taskid == taskid); |
94 | task_match = (t->task->taskid == taskid); |
123 | 95 | ||
124 | spinlock_unlock(&t->task->lock); |
96 | spinlock_unlock(&t->task->lock); |
125 | 97 | ||
126 | if (!task_match) { |
98 | if (!task_match) { |
127 | /* No such thread belonging to callee */ |
99 | /* No such thread belonging to callee */ |
128 | rc = ENOENT; |
100 | rc = ENOENT; |
129 | goto error_exit; |
101 | goto error_exit; |
130 | } |
102 | } |
131 | 103 | ||
132 | /* Verify that 't' is a userspace thread */ |
104 | /* Verify that 't' is a userspace thread */ |
133 | if ((t->flags & THREAD_FLAG_USPACE) == 0) { |
105 | if ((t->flags & THREAD_FLAG_USPACE) == 0) { |
134 | /* It's not, deny its existence */ |
106 | /* It's not, deny its existence */ |
135 | rc = ENOENT; |
107 | rc = ENOENT; |
136 | goto error_exit; |
108 | goto error_exit; |
137 | } |
109 | } |
138 | 110 | ||
139 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
111 | if ((t->debug_active != true) || (t->debug_stop != true)) { |
140 | /* Not in debugging session or already has GO */ |
112 | /* Not in debugging session or already has GO */ |
141 | rc = ENOENT; |
113 | rc = ENOENT; |
142 | goto error_exit; |
114 | goto error_exit; |
143 | } |
115 | } |
144 | 116 | ||
145 | spinlock_unlock(&threads_lock); |
117 | spinlock_unlock(&threads_lock); |
146 | spinlock_unlock(&t->lock); |
118 | spinlock_unlock(&t->lock); |
147 | 119 | ||
148 | /* Only t->debug_lock left */ |
120 | /* Only t->debug_lock left */ |
149 | 121 | ||
150 | return EOK; /* All went well */ |
122 | return EOK; /* All went well */ |
151 | 123 | ||
152 | 124 | ||
153 | /* Executed when a check on the thread fails */ |
125 | /* Executed when a check on the thread fails */ |
154 | error_exit: |
126 | error_exit: |
155 | spinlock_unlock(&t->lock); |
127 | spinlock_unlock(&t->lock); |
156 | spinlock_unlock(&t->debug_lock); |
128 | spinlock_unlock(&t->debug_lock); |
157 | spinlock_unlock(&threads_lock); |
129 | spinlock_unlock(&threads_lock); |
158 | 130 | ||
159 | /* No locks left here */ |
131 | /* No locks left here */ |
160 | return rc; /* Some errors occured */ |
132 | return rc; /* Some errors occured */ |
161 | } |
133 | } |
162 | 134 | ||
163 | static void _thread_op_end(thread_t *t) |
135 | static void _thread_op_end(thread_t *t) |
164 | { |
136 | { |
165 | spinlock_unlock(&t->debug_lock); |
137 | spinlock_unlock(&t->debug_lock); |
166 | } |
138 | } |
167 | 139 | ||
168 | static int udebug_rp_begin(call_t *call, phone_t *phone) |
- | |
169 | { |
- | |
170 | task_t *ta; |
- | |
171 | ipl_t ipl; |
- | |
172 | int rc; |
- | |
173 | - | ||
174 | thread_t *t; |
- | |
175 | link_t *cur; |
- | |
176 | - | ||
177 | klog_printf("debug_begin()"); |
- | |
178 | - | ||
179 | ipl = interrupts_disable(); |
- | |
180 | ta = get_lock_callee_task(phone); |
- | |
181 | klog_printf("debugging task %llu", ta->taskid); |
- | |
182 | - | ||
183 | if (ta->dt_state != UDEBUG_TS_INACTIVE) { |
- | |
184 | spinlock_unlock(&ta->lock); |
- | |
185 | interrupts_restore(ipl); |
- | |
186 | klog_printf("debug_begin(): busy error"); |
- | |
187 | return EBUSY; |
- | |
188 | } |
- | |
189 | - | ||
190 | ta->dt_state = UDEBUG_TS_BEGINNING; |
- | |
191 | ta->debug_begin_call = call; |
- | |
192 | ta->debugger = call->sender; |
- | |
193 | - | ||
194 | if (ta->not_stoppable_count == 0) { |
- | |
195 | ta->dt_state = UDEBUG_TS_ACTIVE; |
- | |
196 | ta->debug_begin_call = NULL; |
- | |
197 | rc = 1; /* actually we need backsend with 0 retval */ |
- | |
198 | } else { |
- | |
199 | rc = 0; /* no backsend */ |
- | |
200 | } |
- | |
201 | - | ||
202 | /* Set debug_active on all of the task's userspace threads */ |
- | |
203 | - | ||
204 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
- | |
205 | t = list_get_instance(cur, thread_t, th_link); |
- | |
206 | - | ||
207 | spinlock_lock(&t->debug_lock); |
- | |
208 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
- | |
209 | t->debug_active = true; |
- | |
210 | spinlock_unlock(&t->debug_lock); |
- | |
211 | } |
- | |
212 | - | ||
213 | spinlock_unlock(&ta->lock); |
- | |
214 | interrupts_restore(ipl); |
- | |
215 | - | ||
216 | klog_printf("debug_begin() done (%s)", |
- | |
217 | rc ? "backsend" : "stoppability wait"); |
- | |
218 | - | ||
219 | return rc; |
- | |
220 | } |
- | |
221 | - | ||
222 | static int udebug_rp_end(call_t *call, phone_t *phone) |
- | |
223 | { |
- | |
224 | task_t *ta; |
- | |
225 | ipl_t ipl; |
- | |
226 | int rc; |
- | |
227 | - | ||
228 | klog_printf("udebug_rp_end()"); |
- | |
229 | - | ||
230 | ipl = interrupts_disable(); |
- | |
231 | ta = get_lock_callee_task(phone); |
- | |
232 | - | ||
233 | rc = udebug_task_cleanup(ta); |
- | |
234 | - | ||
235 | klog_printf("task %llu", ta->taskid); |
- | |
236 | - | ||
237 | spinlock_unlock(&ta->lock); |
- | |
238 | interrupts_restore(ipl); |
- | |
239 | - | ||
240 | if (rc < 0) { |
- | |
241 | return EINVAL; |
- | |
242 | } |
- | |
243 | - | ||
244 | IPC_SET_RETVAL(call->data, 0); |
- | |
245 | - | ||
246 | klog_printf("udebug_rp_end() done\n"); |
- | |
247 | - | ||
248 | return 1; |
- | |
249 | } |
- | |
250 | - | ||
251 | - | ||
252 | static int udebug_rp_go(call_t *call, phone_t *phone) |
140 | static int udebug_rp_go(call_t *call, phone_t *phone) |
253 | { |
141 | { |
254 | thread_t *t; |
142 | thread_t *t; |
255 | ipl_t ipl; |
143 | ipl_t ipl; |
256 | int rc; |
144 | int rc; |
257 | 145 | ||
258 | klog_printf("debug_go()"); |
146 | klog_printf("debug_go()"); |
259 | 147 | ||
260 | t = (thread_t *)IPC_GET_ARG2(call->data); |
148 | t = (thread_t *)IPC_GET_ARG2(call->data); |
261 | 149 | ||
262 | ipl = interrupts_disable(); |
150 | ipl = interrupts_disable(); |
263 | 151 | ||
264 | /* On success, this will lock t->debug_lock */ |
152 | /* On success, this will lock t->debug_lock */ |
265 | rc = _thread_op_begin(phone, t); |
153 | rc = _thread_op_begin(phone, t); |
266 | if (rc != EOK) { |
154 | if (rc != EOK) { |
267 | interrupts_restore(ipl); |
155 | interrupts_restore(ipl); |
268 | return rc; |
156 | return rc; |
269 | } |
157 | } |
270 | 158 | ||
271 | t->debug_go_call = call; |
159 | t->debug_go_call = call; |
272 | t->debug_stop = false; |
160 | t->debug_stop = false; |
273 | t->cur_event = 0; /* none */ |
161 | t->cur_event = 0; /* none */ |
274 | 162 | ||
275 | /* |
163 | /* |
276 | * Neither t's lock nor threads_lock may be held during wakeup |
164 | * Neither t's lock nor threads_lock may be held during wakeup |
277 | */ |
165 | */ |
278 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
166 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
279 | 167 | ||
280 | _thread_op_end(t); |
168 | _thread_op_end(t); |
281 | interrupts_restore(ipl); |
169 | interrupts_restore(ipl); |
282 | 170 | ||
283 | return 0; /* no backsend */ |
171 | return 0; /* no backsend */ |
284 | } |
172 | } |
285 | 173 | ||
286 | static int udebug_rp_args_read(call_t *call, phone_t *phone) |
174 | static int udebug_rp_args_read(call_t *call, phone_t *phone) |
287 | { |
175 | { |
288 | thread_t *t; |
176 | thread_t *t; |
289 | void *uspace_buffer; |
177 | void *uspace_buffer; |
290 | int rc; |
178 | int rc; |
291 | ipl_t ipl; |
179 | ipl_t ipl; |
292 | unative_t buffer[6]; |
180 | unative_t buffer[6]; |
293 | 181 | ||
294 | klog_printf("debug_args_read()"); |
182 | klog_printf("debug_args_read()"); |
295 | 183 | ||
296 | t = (thread_t *)IPC_GET_ARG2(call->data); |
184 | t = (thread_t *)IPC_GET_ARG2(call->data); |
297 | 185 | ||
298 | ipl = interrupts_disable(); |
186 | ipl = interrupts_disable(); |
299 | 187 | ||
300 | /* On success, this will lock t->debug_lock */ |
188 | /* On success, this will lock t->debug_lock */ |
301 | rc = _thread_op_begin(phone, t); |
189 | rc = _thread_op_begin(phone, t); |
302 | if (rc != EOK) { |
190 | if (rc != EOK) { |
303 | interrupts_restore(ipl); |
191 | interrupts_restore(ipl); |
304 | return rc; |
192 | return rc; |
305 | } |
193 | } |
306 | 194 | ||
307 | /* Additionally we need to verify that we are inside a syscall */ |
195 | /* Additionally we need to verify that we are inside a syscall */ |
308 | if (t->cur_event != UDEBUG_EVENT_SYSCALL) { |
196 | if (t->cur_event != UDEBUG_EVENT_SYSCALL) { |
309 | _thread_op_end(t); |
197 | _thread_op_end(t); |
310 | interrupts_restore(ipl); |
198 | interrupts_restore(ipl); |
311 | return EINVAL; |
199 | return EINVAL; |
312 | } |
200 | } |
313 | 201 | ||
314 | /* Copy to a local buffer before releasing the lock */ |
202 | /* Copy to a local buffer before releasing the lock */ |
315 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
203 | memcpy(buffer, t->syscall_args, 6 * sizeof(unative_t)); |
316 | 204 | ||
317 | _thread_op_end(t); |
205 | _thread_op_end(t); |
318 | interrupts_restore(ipl); |
206 | interrupts_restore(ipl); |
319 | 207 | ||
320 | /* Now copy to userspace */ |
208 | /* Now copy to userspace */ |
321 | 209 | ||
322 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
210 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
323 | 211 | ||
324 | rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t)); |
212 | rc = copy_to_uspace(uspace_buffer, buffer, 6 * sizeof(unative_t)); |
325 | if (rc != 0) { |
213 | if (rc != 0) { |
326 | klog_printf("debug_args_read() - copy failed"); |
214 | klog_printf("debug_args_read() - copy failed"); |
327 | return rc; |
215 | return rc; |
328 | } |
216 | } |
329 | 217 | ||
330 | klog_printf("debug_args_read() done"); |
218 | klog_printf("debug_args_read() done"); |
331 | return 1; /* actually need becksend with retval 0 */ |
219 | return 1; /* actually need becksend with retval 0 */ |
332 | } |
220 | } |
333 | 221 | ||
334 | static int udebug_rp_regs_read(call_t *call, phone_t *phone) |
222 | static int udebug_rp_regs_read(call_t *call, phone_t *phone) |
335 | { |
223 | { |
336 | thread_t *t; |
224 | thread_t *t; |
337 | void *uspace_buffer; |
225 | void *uspace_buffer; |
338 | unative_t to_copy; |
226 | unative_t to_copy; |
339 | int rc; |
227 | int rc; |
340 | istate_t *state; |
228 | istate_t *state; |
341 | istate_t state_copy; |
229 | istate_t state_copy; |
342 | ipl_t ipl; |
230 | ipl_t ipl; |
343 | 231 | ||
344 | klog_printf("debug_regs_read()"); |
232 | klog_printf("debug_regs_read()"); |
345 | 233 | ||
346 | t = (thread_t *) IPC_GET_ARG2(call->data); |
234 | t = (thread_t *) IPC_GET_ARG2(call->data); |
347 | 235 | ||
348 | ipl = interrupts_disable(); |
236 | ipl = interrupts_disable(); |
349 | 237 | ||
350 | /* On success, this will lock t->debug_lock */ |
238 | /* On success, this will lock t->debug_lock */ |
351 | rc = _thread_op_begin(phone, t); |
239 | rc = _thread_op_begin(phone, t); |
352 | if (rc != EOK) { |
240 | if (rc != EOK) { |
353 | interrupts_restore(ipl); |
241 | interrupts_restore(ipl); |
354 | return rc; |
242 | return rc; |
355 | } |
243 | } |
356 | 244 | ||
357 | state = t->uspace_state; |
245 | state = t->uspace_state; |
358 | if (state == NULL) { |
246 | if (state == NULL) { |
359 | _thread_op_end(t); |
247 | _thread_op_end(t); |
360 | interrupts_restore(ipl); |
248 | interrupts_restore(ipl); |
361 | klog_printf("debug_regs_read() - istate not available"); |
249 | klog_printf("debug_regs_read() - istate not available"); |
362 | return EBUSY; |
250 | return EBUSY; |
363 | } |
251 | } |
364 | 252 | ||
365 | /* Copy to a local buffer so that we can release the lock */ |
253 | /* Copy to a local buffer so that we can release the lock */ |
366 | memcpy(&state_copy, state, sizeof(state_copy)); |
254 | memcpy(&state_copy, state, sizeof(state_copy)); |
367 | _thread_op_end(t); |
255 | _thread_op_end(t); |
368 | interrupts_restore(ipl); |
256 | interrupts_restore(ipl); |
369 | 257 | ||
370 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
258 | uspace_buffer = (void *)IPC_GET_ARG3(call->data); |
371 | to_copy = IPC_GET_ARG4(call->data); |
259 | to_copy = IPC_GET_ARG4(call->data); |
372 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
260 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
373 | 261 | ||
374 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
262 | rc = copy_to_uspace(uspace_buffer, &state_copy, to_copy); |
375 | if (rc != 0) { |
263 | if (rc != 0) { |
376 | klog_printf("debug_regs_read() - copy failed"); |
264 | klog_printf("debug_regs_read() - copy failed"); |
377 | return rc; |
265 | return rc; |
378 | } |
266 | } |
379 | 267 | ||
380 | IPC_SET_ARG1(call->data, to_copy); |
268 | IPC_SET_ARG1(call->data, to_copy); |
381 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
269 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
382 | 270 | ||
383 | klog_printf("debug_regs_read() done"); |
271 | klog_printf("debug_regs_read() done"); |
384 | return 1; /* actually need becksend with retval 0 */ |
272 | return 1; /* actually need becksend with retval 0 */ |
385 | } |
273 | } |
386 | 274 | ||
387 | 275 | ||
388 | 276 | ||
389 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
277 | static int udebug_rp_regs_write(call_t *call, phone_t *phone) |
390 | { |
278 | { |
391 | thread_t *t; |
279 | thread_t *t; |
392 | void *uspace_data; |
280 | void *uspace_data; |
393 | unative_t to_copy; |
281 | unative_t to_copy; |
394 | int rc; |
282 | int rc; |
395 | istate_t *state; |
283 | istate_t *state; |
396 | istate_t data_copy; |
284 | istate_t data_copy; |
397 | ipl_t ipl; |
285 | ipl_t ipl; |
398 | 286 | ||
399 | klog_printf("debug_regs_write()"); |
287 | klog_printf("debug_regs_write()"); |
400 | 288 | ||
401 | /* First copy to a local buffer */ |
289 | /* First copy to a local buffer */ |
402 | 290 | ||
403 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
291 | uspace_data = (void *)IPC_GET_ARG3(call->data); |
404 | to_copy = IPC_GET_ARG4(call->data); |
292 | to_copy = IPC_GET_ARG4(call->data); |
405 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
293 | if (to_copy > sizeof(istate_t)) to_copy = sizeof(istate_t); |
406 | 294 | ||
407 | rc = copy_from_uspace(&data_copy, uspace_data, to_copy); |
295 | rc = copy_from_uspace(&data_copy, uspace_data, to_copy); |
408 | if (rc != 0) { |
296 | if (rc != 0) { |
409 | klog_printf("debug_regs_write() - copy failed"); |
297 | klog_printf("debug_regs_write() - copy failed"); |
410 | return rc; |
298 | return rc; |
411 | } |
299 | } |
412 | 300 | ||
413 | /* Now try to change the thread's uspace_state */ |
301 | /* Now try to change the thread's uspace_state */ |
414 | 302 | ||
415 | ipl = interrupts_disable(); |
303 | ipl = interrupts_disable(); |
416 | t = (thread_t *) IPC_GET_ARG2(call->data); |
304 | t = (thread_t *) IPC_GET_ARG2(call->data); |
417 | 305 | ||
418 | /* On success, this will lock t->debug_lock */ |
306 | /* On success, this will lock t->debug_lock */ |
419 | rc = _thread_op_begin(phone, t); |
307 | rc = _thread_op_begin(phone, t); |
420 | if (rc != EOK) { |
308 | if (rc != EOK) { |
421 | interrupts_restore(ipl); |
309 | interrupts_restore(ipl); |
422 | return rc; |
310 | return rc; |
423 | } |
311 | } |
424 | 312 | ||
425 | state = t->uspace_state; |
313 | state = t->uspace_state; |
426 | if (state == NULL) { |
314 | if (state == NULL) { |
427 | _thread_op_end(t); |
315 | _thread_op_end(t); |
428 | interrupts_restore(ipl); |
316 | interrupts_restore(ipl); |
429 | klog_printf("debug_regs_write() - istate not available"); |
317 | klog_printf("debug_regs_write() - istate not available"); |
430 | return EBUSY; |
318 | return EBUSY; |
431 | } |
319 | } |
432 | 320 | ||
433 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
321 | memcpy(t->uspace_state, &data_copy, sizeof(t->uspace_state)); |
434 | 322 | ||
435 | _thread_op_end(t); |
323 | _thread_op_end(t); |
436 | interrupts_restore(ipl); |
324 | interrupts_restore(ipl); |
437 | 325 | ||
438 | /* Set answer values */ |
326 | /* Set answer values */ |
439 | 327 | ||
440 | IPC_SET_ARG1(call->data, to_copy); |
328 | IPC_SET_ARG1(call->data, to_copy); |
441 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
329 | IPC_SET_ARG2(call->data, sizeof(istate_t)); |
442 | 330 | ||
443 | klog_printf("debug_regs_write() done"); |
331 | klog_printf("debug_regs_write() done"); |
444 | return 1; /* actually need becksend with retval 0 */ |
332 | return 1; /* actually need becksend with retval 0 */ |
445 | } |
333 | } |
446 | 334 | ||
447 | static int udebug_rp_thread_read(call_t *call, phone_t *phone) |
335 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
- | 336 | { |
|
- | 337 | void *uspace_data; |
|
- | 338 | unative_t to_copy; |
|
- | 339 | int rc; |
|
- | 340 | void *buffer; |
|
- | 341 | ||
- | 342 | klog_printf("udebug_rp_mem_write()"); |
|
- | 343 | ||
- | 344 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
|
- | 345 | to_copy = IPC_GET_ARG4(call->data); |
|
- | 346 | ||
- | 347 | buffer = malloc(to_copy, 0); // ??? |
|
- | 348 | ||
- | 349 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
|
- | 350 | if (rc != 0) { |
|
- | 351 | klog_printf(" - copy failed"); |
|
- | 352 | return rc; |
|
- | 353 | } |
|
- | 354 | ||
- | 355 | call->buffer = buffer; |
|
- | 356 | ||
- | 357 | klog_printf(" - done"); |
|
- | 358 | return 1; /* actually need becksend with retval 0 */ |
|
- | 359 | } |
|
- | 360 | ||
- | 361 | ||
- | 362 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
|
448 | { |
363 | { |
- | 364 | int rc; |
|
- | 365 | ||
- | 366 | switch (IPC_GET_ARG1(call->data)) { |
|
- | 367 | case UDEBUG_M_GO: |
|
- | 368 | rc = udebug_rp_go(call, phone); |
|
- | 369 | return rc; |
|
- | 370 | case UDEBUG_M_ARGS_READ: |
|
- | 371 | rc = udebug_rp_args_read(call, phone); |
|
- | 372 | return rc; |
|
- | 373 | case UDEBUG_M_REGS_READ: |
|
- | 374 | rc = udebug_rp_regs_read(call, phone); |
|
- | 375 | return rc; |
|
- | 376 | case UDEBUG_M_REGS_WRITE: |
|
- | 377 | rc = udebug_rp_regs_write(call, phone); |
|
- | 378 | return rc; |
|
- | 379 | case UDEBUG_M_MEM_WRITE: |
|
- | 380 | rc = udebug_rp_mem_write(call, phone); |
|
- | 381 | return rc; |
|
- | 382 | default: |
|
- | 383 | break; |
|
- | 384 | } |
|
- | 385 | ||
- | 386 | return 0; |
|
- | 387 | } |
|
- | 388 | ||
- | 389 | static void udebug_receive_begin(call_t *call) |
|
- | 390 | { |
|
- | 391 | ipl_t ipl; |
|
- | 392 | int reply; |
|
- | 393 | ||
449 | thread_t *t; |
394 | thread_t *t; |
450 | link_t *cur; |
395 | link_t *cur; |
- | 396 | ||
- | 397 | klog_printf("debug_begin()"); |
|
- | 398 | ||
- | 399 | ipl = interrupts_disable(); |
|
- | 400 | klog_printf("debugging task %llu", TASK->taskid); |
|
- | 401 | ||
- | 402 | spinlock_lock(&TASK->lock); |
|
- | 403 | ||
- | 404 | if (TASK->dt_state != UDEBUG_TS_INACTIVE) { |
|
- | 405 | spinlock_unlock(&TASK->lock); |
|
- | 406 | interrupts_restore(ipl); |
|
- | 407 | klog_printf("debug_begin(): busy error"); |
|
- | 408 | ||
- | 409 | IPC_SET_RETVAL(call->data, EBUSY); |
|
- | 410 | ipc_answer(&TASK->kernel_box, call); |
|
- | 411 | } |
|
- | 412 | ||
- | 413 | TASK->dt_state = UDEBUG_TS_BEGINNING; |
|
- | 414 | TASK->debug_begin_call = call; |
|
- | 415 | TASK->debugger = call->sender; |
|
- | 416 | ||
- | 417 | if (TASK->not_stoppable_count == 0) { |
|
- | 418 | TASK->dt_state = UDEBUG_TS_ACTIVE; |
|
- | 419 | TASK->debug_begin_call = NULL; |
|
- | 420 | reply = 1; /* immediate reply */ |
|
451 | task_t *ta; |
421 | } else { |
- | 422 | reply = 0; /* no reply */ |
|
- | 423 | } |
|
- | 424 | ||
- | 425 | /* Set debug_active on all of the task's userspace threads */ |
|
- | 426 | ||
- | 427 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
|
- | 428 | t = list_get_instance(cur, thread_t, th_link); |
|
- | 429 | ||
- | 430 | spinlock_lock(&t->debug_lock); |
|
- | 431 | if ((t->flags & THREAD_FLAG_USPACE) != 0) |
|
- | 432 | t->debug_active = true; |
|
- | 433 | spinlock_unlock(&t->debug_lock); |
|
- | 434 | } |
|
- | 435 | ||
- | 436 | spinlock_unlock(&TASK->lock); |
|
452 | unative_t *uspace_buffer; |
437 | interrupts_restore(ipl); |
- | 438 | ||
- | 439 | klog_printf("debug_begin() done (%s)", |
|
- | 440 | reply ? "reply" : "stoppability wait"); |
|
- | 441 | ||
- | 442 | if (reply) ipc_answer(&TASK->kernel_box, call); |
|
- | 443 | } |
|
- | 444 | ||
- | 445 | static void udebug_receive_end(call_t *call) |
|
- | 446 | { |
|
453 | unative_t to_copy; |
447 | ipl_t ipl; |
454 | int rc; |
448 | int rc; |
- | 449 | ||
- | 450 | klog_printf("udebug_receive_end()"); |
|
- | 451 | ||
- | 452 | ipl = interrupts_disable(); |
|
- | 453 | spinlock_lock(&TASK->lock); |
|
- | 454 | ||
- | 455 | rc = udebug_task_cleanup(TASK); |
|
- | 456 | ||
- | 457 | klog_printf("task %llu", TASK->taskid); |
|
- | 458 | ||
- | 459 | spinlock_unlock(&TASK->lock); |
|
- | 460 | interrupts_restore(ipl); |
|
- | 461 | ||
- | 462 | if (rc < 0) { |
|
- | 463 | IPC_SET_RETVAL(call->data, EINVAL); |
|
- | 464 | ipc_answer(&TASK->kernel_box, call); |
|
- | 465 | return; |
|
- | 466 | } |
|
- | 467 | ||
- | 468 | IPC_SET_RETVAL(call->data, 0); |
|
- | 469 | ipc_answer(&TASK->kernel_box, call); |
|
- | 470 | } |
|
- | 471 | ||
- | 472 | static void udebug_receive_thread_read(call_t *call) |
|
- | 473 | { |
|
- | 474 | thread_t *t; |
|
- | 475 | link_t *cur; |
|
- | 476 | unative_t uspace_addr; |
|
- | 477 | unative_t to_copy; |
|
455 | unsigned total_bytes; |
478 | unsigned total_bytes; |
456 | unsigned buf_size; |
479 | unsigned buf_size; |
457 | unative_t tid; |
480 | unative_t tid; |
458 | unsigned num_threads, copied_ids; |
481 | unsigned num_threads, copied_ids; |
459 | ipl_t ipl; |
482 | ipl_t ipl; |
460 | unative_t *buffer; |
483 | unative_t *buffer; |
461 | int flags; |
484 | int flags; |
462 | 485 | ||
463 | klog_printf("debug_thread_read()"); |
486 | klog_printf("debug_thread_read()"); |
464 | 487 | ||
465 | ipl = interrupts_disable(); |
488 | ipl = interrupts_disable(); |
466 | ta = get_lock_callee_task(phone); |
489 | spinlock_lock(&TASK->lock); |
467 | 490 | ||
468 | /* Verify task state */ |
491 | /* Verify task state */ |
469 | if (ta->dt_state != UDEBUG_TS_ACTIVE) { |
492 | if (TASK->dt_state != UDEBUG_TS_ACTIVE) { |
470 | spinlock_unlock(&ta->lock); |
493 | spinlock_unlock(&TASK->lock); |
471 | interrupts_restore(ipl); |
494 | interrupts_restore(ipl); |
- | 495 | ||
- | 496 | IPC_SET_RETVAL(call->data, EINVAL); |
|
- | 497 | ipc_answer(&TASK->kernel_box, call); |
|
472 | return EBUSY; |
498 | return; |
473 | } |
499 | } |
474 | 500 | ||
475 | /* Count the threads first */ |
501 | /* Count the threads first */ |
476 | 502 | ||
477 | num_threads = 0; |
503 | num_threads = 0; |
478 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
504 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
479 | /* Count all threads, to be on the safe side */ |
505 | /* Count all threads, to be on the safe side */ |
480 | ++num_threads; |
506 | ++num_threads; |
481 | } |
507 | } |
482 | 508 | ||
483 | /* Allocate a buffer and copy down the threads' ids */ |
509 | /* Allocate a buffer and copy down the threads' ids */ |
484 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
510 | buffer = malloc(num_threads * sizeof(unative_t), 0); // ??? |
485 | 511 | ||
486 | copied_ids = 0; |
512 | copied_ids = 0; |
487 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
513 | for (cur = TASK->th_head.next; cur != &TASK->th_head; cur = cur->next) { |
488 | t = list_get_instance(cur, thread_t, th_link); |
514 | t = list_get_instance(cur, thread_t, th_link); |
489 | 515 | ||
490 | spinlock_lock(&t->lock); |
516 | spinlock_lock(&t->lock); |
491 | flags = t->flags; |
517 | flags = t->flags; |
492 | spinlock_unlock(&t->lock); |
518 | spinlock_unlock(&t->lock); |
493 | 519 | ||
494 | /* Not interested in kernel threads */ |
520 | /* Not interested in kernel threads */ |
495 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
521 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
496 | /* Using thread struct pointer for identification */ |
522 | /* Using thread struct pointer for identification */ |
497 | tid = (unative_t) t; |
523 | tid = (unative_t) t; |
498 | buffer[copied_ids++] = tid; |
524 | buffer[copied_ids++] = tid; |
499 | } |
525 | } |
500 | } |
526 | } |
501 | 527 | ||
502 | spinlock_unlock(&ta->lock); |
528 | spinlock_unlock(&TASK->lock); |
503 | interrupts_restore(ipl); |
529 | interrupts_restore(ipl); |
504 | 530 | ||
- | 531 | /* |
|
505 | /* Now copy to userspace */ |
532 | * Prepare data and send it back through call->buffer |
- | 533 | */ |
|
506 | 534 | ||
507 | uspace_buffer = (void *)IPC_GET_ARG2(call->data); |
535 | uspace_addr = IPC_GET_ARG2(call->data); |
508 | buf_size = IPC_GET_ARG3(call->data); |
536 | buf_size = IPC_GET_ARG3(call->data); |
509 | 537 | ||
510 | total_bytes = copied_ids * sizeof(unative_t); |
538 | total_bytes = copied_ids * sizeof(unative_t); |
511 | 539 | ||
512 | if (buf_size > total_bytes) |
540 | if (buf_size > total_bytes) |
513 | to_copy = total_bytes; |
541 | to_copy = total_bytes; |
514 | else |
542 | else |
515 | to_copy = buf_size; |
543 | to_copy = buf_size; |
516 | 544 | ||
517 | rc = copy_to_uspace(uspace_buffer, buffer, to_copy); |
- | |
518 | free(buffer); |
- | |
519 | - | ||
520 | if (rc != 0) { |
- | |
521 | klog_printf("debug_thread_read() - copy failed"); |
- | |
522 | return rc; |
- | |
523 | } |
- | |
524 | - | ||
525 | IPC_SET_ARG1(call->data, to_copy); |
545 | IPC_SET_RETVAL(call->data, 0); |
526 | IPC_SET_ARG2(call->data, total_bytes); |
546 | /* ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
527 | - | ||
528 | klog_printf("debug_thread_read() done"); |
547 | same code in process_answer() can be used |
529 | return 1; /* actually need becksend with retval 0 */ |
548 | (no way to distinguish method in answer) */ |
530 | } |
- | |
531 | - | ||
532 | static int udebug_rp_mem_write(call_t *call, phone_t *phone) |
- | |
533 | { |
- | |
534 | void *uspace_data; |
- | |
535 | unative_t to_copy; |
- | |
536 | int rc; |
- | |
537 | void *buffer; |
- | |
538 | - | ||
539 | klog_printf("udebug_rp_mem_write()"); |
- | |
540 | - | ||
541 | uspace_data = (void *)IPC_GET_ARG2(call->data); |
- | |
542 | to_copy = IPC_GET_ARG4(call->data); |
549 | IPC_SET_ARG1(call->data, uspace_addr); |
543 | - | ||
544 | buffer = malloc(to_copy, 0); // ??? |
- | |
545 | - | ||
546 | rc = copy_from_uspace(buffer, uspace_data, to_copy); |
550 | IPC_SET_ARG2(call->data, to_copy); |
547 | if (rc != 0) { |
- | |
548 | klog_printf(" - copy failed"); |
- | |
549 | return rc; |
- | |
550 | } |
- | |
551 | 551 | ||
- | 552 | IPC_SET_ARG3(call->data, total_bytes); |
|
552 | call->buffer = buffer; |
553 | call->buffer = (void *)buffer; |
553 | 554 | ||
554 | klog_printf(" - done"); |
555 | ipc_answer(&TASK->kernel_box, call); |
555 | return 1; /* actually need becksend with retval 0 */ |
- | |
556 | } |
556 | } |
557 | 557 | ||
558 | 558 | ||
559 | int udebug_request_preprocess(call_t *call, phone_t *phone) |
- | |
560 | { |
- | |
561 | int rc; |
- | |
562 | - | ||
563 | switch (IPC_GET_ARG1(call->data)) { |
- | |
564 | case UDEBUG_M_BEGIN: |
- | |
565 | rc = udebug_rp_begin(call, phone); |
- | |
566 | return rc; |
- | |
567 | case UDEBUG_M_END: |
- | |
568 | rc = udebug_rp_end(call, phone); |
- | |
569 | return rc; |
- | |
570 | case UDEBUG_M_GO: |
- | |
571 | rc = udebug_rp_go(call, phone); |
- | |
572 | return rc; |
- | |
573 | case UDEBUG_M_ARGS_READ: |
- | |
574 | rc = udebug_rp_args_read(call, phone); |
- | |
575 | return rc; |
- | |
576 | case UDEBUG_M_REGS_READ: |
- | |
577 | rc = udebug_rp_regs_read(call, phone); |
- | |
578 | return rc; |
- | |
579 | case UDEBUG_M_REGS_WRITE: |
- | |
580 | rc = udebug_rp_regs_write(call, phone); |
- | |
581 | return rc; |
- | |
582 | case UDEBUG_M_THREAD_READ: |
- | |
583 | rc = udebug_rp_thread_read(call, phone); |
- | |
584 | return rc; |
- | |
585 | case UDEBUG_M_MEM_WRITE: |
- | |
586 | rc = udebug_rp_mem_write(call, phone); |
- | |
587 | return rc; |
- | |
588 | default: |
- | |
589 | break; |
- | |
590 | } |
- | |
591 | - | ||
592 | return 0; |
- | |
593 | } |
- | |
594 | - | ||
595 | static void udebug_receive_mem_read(call_t *call) |
559 | static void udebug_receive_mem_read(call_t *call) |
596 | { |
560 | { |
597 | unative_t uspace_dst; |
561 | unative_t uspace_dst; |
598 | void *uspace_ptr; |
562 | void *uspace_ptr; |
599 | unsigned size; |
563 | unsigned size; |
600 | void *buffer; |
564 | void *buffer; |
601 | int rc; |
565 | int rc; |
602 | 566 | ||
603 | klog_printf("debug_mem_read()"); |
567 | klog_printf("debug_mem_read()"); |
604 | uspace_dst = IPC_GET_ARG2(call->data); |
568 | uspace_dst = IPC_GET_ARG2(call->data); |
605 | uspace_ptr = (void *)IPC_GET_ARG3(call->data); |
569 | uspace_ptr = (void *)IPC_GET_ARG3(call->data); |
606 | size = IPC_GET_ARG4(call->data); |
570 | size = IPC_GET_ARG4(call->data); |
607 | 571 | ||
608 | buffer = malloc(size, 0); // ??? |
572 | buffer = malloc(size, 0); // ??? |
609 | klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size); |
573 | klog_printf("debug_mem_read: src=%u, size=%u", uspace_ptr, size); |
610 | 574 | ||
611 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
575 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
612 | * be a problem */ |
576 | * be a problem */ |
613 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
577 | rc = copy_from_uspace(buffer, uspace_ptr, size); |
614 | if (rc) { |
578 | if (rc) { |
615 | IPC_SET_RETVAL(call->data, rc); |
579 | IPC_SET_RETVAL(call->data, rc); |
616 | return; |
580 | return; |
617 | } |
581 | } |
618 | 582 | ||
619 | klog_printf("first word: %u", *((unative_t *)buffer)); |
583 | klog_printf("first word: %u", *((unative_t *)buffer)); |
620 | 584 | ||
621 | IPC_SET_RETVAL(call->data, 0); |
585 | IPC_SET_RETVAL(call->data, 0); |
622 | /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
586 | /* Hack: ARG1=dest, ARG2=size as in IPC_M_DATA_READ so that |
623 | same code in process_answer() can be used |
587 | same code in process_answer() can be used |
624 | (no way to distinguish method in answer) */ |
588 | (no way to distinguish method in answer) */ |
625 | IPC_SET_ARG1(call->data, uspace_dst); |
589 | IPC_SET_ARG1(call->data, uspace_dst); |
626 | IPC_SET_ARG2(call->data, size); |
590 | IPC_SET_ARG2(call->data, size); |
627 | call->buffer = buffer; |
591 | call->buffer = buffer; |
628 | 592 | ||
629 | ipc_answer(&TASK->kernel_box, call); |
593 | ipc_answer(&TASK->kernel_box, call); |
630 | } |
594 | } |
631 | 595 | ||
632 | static void udebug_receive_mem_write(call_t *call) |
596 | static void udebug_receive_mem_write(call_t *call) |
633 | { |
597 | { |
634 | void *uspace_dst; |
598 | void *uspace_dst; |
635 | unsigned size; |
599 | unsigned size; |
636 | void *buffer; |
600 | void *buffer; |
637 | int rc; |
601 | int rc; |
638 | udebug_task_state_t dts; |
602 | udebug_task_state_t dts; |
639 | 603 | ||
640 | klog_printf("udebug_receive_mem_write()"); |
604 | klog_printf("udebug_receive_mem_write()"); |
641 | 605 | ||
642 | /* Verify task state */ |
606 | /* Verify task state */ |
643 | spinlock_lock(&TASK->lock); |
607 | spinlock_lock(&TASK->lock); |
644 | dts = TASK->dt_state; |
608 | dts = TASK->dt_state; |
645 | spinlock_unlock(&TASK->lock); |
609 | spinlock_unlock(&TASK->lock); |
646 | 610 | ||
647 | if (dts != UDEBUG_TS_ACTIVE) { |
611 | if (dts != UDEBUG_TS_ACTIVE) { |
648 | IPC_SET_RETVAL(call->data, EBUSY); |
612 | IPC_SET_RETVAL(call->data, EBUSY); |
649 | ipc_answer(&TASK->kernel_box, call); |
613 | ipc_answer(&TASK->kernel_box, call); |
650 | return; |
614 | return; |
651 | } |
615 | } |
652 | 616 | ||
653 | uspace_dst = (void *)IPC_GET_ARG3(call->data); |
617 | uspace_dst = (void *)IPC_GET_ARG3(call->data); |
654 | size = IPC_GET_ARG4(call->data); |
618 | size = IPC_GET_ARG4(call->data); |
655 | 619 | ||
656 | buffer = call->buffer; |
620 | buffer = call->buffer; |
657 | klog_printf("dst=%u, size=%u", uspace_dst, size); |
621 | klog_printf("dst=%u, size=%u", uspace_dst, size); |
658 | 622 | ||
659 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
623 | /* NOTE: this is not strictly from a syscall... but that shouldn't |
660 | * be a problem */ |
624 | * be a problem */ |
661 | rc = copy_to_uspace(uspace_dst, buffer, size); |
625 | rc = copy_to_uspace(uspace_dst, buffer, size); |
662 | if (rc) { |
626 | if (rc) { |
663 | IPC_SET_RETVAL(call->data, rc); |
627 | IPC_SET_RETVAL(call->data, rc); |
664 | ipc_answer(&TASK->kernel_box, call); |
628 | ipc_answer(&TASK->kernel_box, call); |
665 | return; |
629 | return; |
666 | } |
630 | } |
667 | 631 | ||
668 | IPC_SET_RETVAL(call->data, 0); |
632 | IPC_SET_RETVAL(call->data, 0); |
669 | 633 | ||
670 | free(call->buffer); |
634 | free(call->buffer); |
671 | call->buffer = NULL; |
635 | call->buffer = NULL; |
672 | 636 | ||
673 | ipc_answer(&TASK->kernel_box, call); |
637 | ipc_answer(&TASK->kernel_box, call); |
674 | } |
638 | } |
675 | 639 | ||
676 | 640 | ||
677 | /** |
641 | /** |
678 | * Handle a debug call received on the kernel answerbox. |
642 | * Handle a debug call received on the kernel answerbox. |
679 | * |
643 | * |
680 | * This is called by the kbox servicing thread. |
644 | * This is called by the kbox servicing thread. |
681 | */ |
645 | */ |
682 | void udebug_call_receive(call_t *call) |
646 | void udebug_call_receive(call_t *call) |
683 | { |
647 | { |
684 | int debug_method; |
648 | int debug_method; |
685 | 649 | ||
686 | debug_method = IPC_GET_ARG1(call->data); |
650 | debug_method = IPC_GET_ARG1(call->data); |
687 | 651 | ||
688 | switch (debug_method) { |
652 | switch (debug_method) { |
- | 653 | case UDEBUG_M_BEGIN: |
|
- | 654 | udebug_receive_begin(call); |
|
- | 655 | break; |
|
- | 656 | case UDEBUG_M_END: |
|
- | 657 | udebug_receive_end(call); |
|
- | 658 | break; |
|
- | 659 | case UDEBUG_M_THREAD_READ: |
|
- | 660 | udebug_receive_thread_read(call); |
|
- | 661 | break; |
|
689 | case UDEBUG_M_MEM_READ: |
662 | case UDEBUG_M_MEM_READ: |
690 | udebug_receive_mem_read(call); |
663 | udebug_receive_mem_read(call); |
691 | break; |
664 | break; |
692 | case UDEBUG_M_MEM_WRITE: |
665 | case UDEBUG_M_MEM_WRITE: |
693 | udebug_receive_mem_write(call); |
666 | udebug_receive_mem_write(call); |
694 | break; |
667 | break; |
695 | } |
668 | } |
696 | } |
669 | } |
697 | 670 | ||
698 | /** @} |
671 | /** @} |
699 | */ |
672 | */ |
700 | 673 |