Rev 2901 | Rev 2903 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 2901 | Rev 2902 | ||
---|---|---|---|
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. |
35 | * @brief Udebug. |
36 | */ |
36 | */ |
37 | 37 | ||
38 | #include <synch/waitq.h> |
38 | #include <synch/waitq.h> |
39 | #include <console/klog.h> |
39 | #include <console/klog.h> |
40 | #include <udebug/udebug.h> |
40 | #include <udebug/udebug.h> |
41 | #include <errno.h> |
41 | #include <errno.h> |
42 | #include <arch.h> |
42 | #include <arch.h> |
43 | 43 | ||
44 | void udebug_stoppable_begin(void) |
44 | void udebug_stoppable_begin(void) |
45 | { |
45 | { |
46 | int nsc; |
46 | int nsc; |
47 | call_t *db_call, *go_call; |
47 | call_t *db_call, *go_call; |
48 | ipl_t ipl; |
48 | ipl_t ipl; |
49 | 49 | ||
- | 50 | ASSERT(THREAD); |
|
- | 51 | ASSERT(TASK); |
|
- | 52 | ||
50 | ipl = interrupts_disable(); |
53 | ipl = interrupts_disable(); |
51 | spinlock_lock(&TASK->lock); |
54 | spinlock_lock(&TASK->lock); |
52 | 55 | ||
53 | nsc = --TASK->not_stoppable_count; |
56 | nsc = --TASK->not_stoppable_count; |
54 | db_call = TASK->debug_begin_call; |
- | |
55 | 57 | ||
56 | if (TASK->dt_state == UDEBUG_TS_BEGINNING) { |
58 | if (TASK->dt_state == UDEBUG_TS_BEGINNING) { |
57 | klog_printf("udebug_stoppable_begin"); |
59 | klog_printf("udebug_stoppable_begin"); |
58 | klog_printf(" - nsc := %d", nsc); |
60 | klog_printf(" - nsc := %d", nsc); |
59 | } |
61 | } |
60 | 62 | ||
61 | if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
63 | if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
62 | /* |
64 | /* |
63 | * This was the last non-stoppable thread. Reply to |
65 | * This was the last non-stoppable thread. Reply to |
64 | * DEBUG_BEGIN call. |
66 | * DEBUG_BEGIN call. |
65 | */ |
67 | */ |
66 | 68 | ||
- | 69 | db_call = TASK->debug_begin_call; |
|
- | 70 | ASSERT(db_call); |
|
- | 71 | ||
67 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
72 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
68 | spinlock_lock(&THREAD->debug_lock); |
73 | spinlock_lock(&THREAD->debug_lock); |
69 | THREAD->debug_stoppable = true; |
74 | THREAD->debug_stoppable = true; |
70 | spinlock_unlock(&THREAD->debug_lock); |
75 | spinlock_unlock(&THREAD->debug_lock); |
71 | 76 | ||
72 | TASK->dt_state = UDEBUG_TS_ACTIVE; |
77 | TASK->dt_state = UDEBUG_TS_ACTIVE; |
73 | TASK->debug_begin_call = NULL; |
78 | TASK->debug_begin_call = NULL; |
74 | spinlock_unlock(&TASK->lock); |
79 | spinlock_unlock(&TASK->lock); |
75 | interrupts_restore(ipl); |
80 | interrupts_restore(ipl); |
76 | 81 | ||
77 | IPC_SET_RETVAL(db_call->data, 0); |
82 | IPC_SET_RETVAL(db_call->data, 0); |
78 | klog_printf("udebug_stoppable_begin/ipc_answer"); |
83 | klog_printf("udebug_stoppable_begin/ipc_answer"); |
79 | ipc_answer(&TASK->answerbox, db_call); |
84 | ipc_answer(&TASK->answerbox, db_call); |
80 | 85 | ||
81 | } else if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
86 | } else if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
82 | /* |
87 | /* |
83 | * Active debugging session |
88 | * Active debugging session |
84 | */ |
89 | */ |
85 | 90 | ||
86 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
91 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
87 | spinlock_lock(&THREAD->debug_lock); |
92 | spinlock_lock(&THREAD->debug_lock); |
88 | THREAD->debug_stoppable = true; |
93 | THREAD->debug_stoppable = true; |
89 | 94 | ||
90 | if (THREAD->debug_stop) { |
95 | if (THREAD->debug_active && THREAD->debug_stop) { |
91 | /* |
96 | /* |
92 | * Thread was requested to stop - answer go call |
97 | * Thread was requested to stop - answer go call |
93 | */ |
98 | */ |
94 | 99 | ||
95 | /* Make sure nobody takes this call away from us */ |
100 | /* Make sure nobody takes this call away from us */ |
96 | go_call = THREAD->debug_go_call; |
101 | go_call = THREAD->debug_go_call; |
97 | THREAD->debug_go_call = NULL; |
102 | THREAD->debug_go_call = NULL; |
- | 103 | ASSERT(go_call); |
|
98 | 104 | ||
99 | IPC_SET_RETVAL(go_call->data, 0); |
105 | IPC_SET_RETVAL(go_call->data, 0); |
100 | IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); |
106 | IPC_SET_ARG1(go_call->data, UDEBUG_EVENT_STOP); |
101 | 107 | ||
102 | THREAD->cur_event = UDEBUG_EVENT_STOP; |
108 | THREAD->cur_event = UDEBUG_EVENT_STOP; |
103 | spinlock_unlock(&THREAD->debug_lock); |
109 | spinlock_unlock(&THREAD->debug_lock); |
104 | 110 | ||
105 | ipc_answer(&TASK->answerbox, go_call); |
111 | ipc_answer(&TASK->answerbox, go_call); |
106 | 112 | ||
107 | spinlock_unlock(&TASK->lock); |
113 | spinlock_unlock(&TASK->lock); |
108 | interrupts_restore(ipl); |
114 | interrupts_restore(ipl); |
109 | } else { |
115 | } else { |
110 | /* |
116 | /* |
111 | * No stop request - nothing happens. |
117 | * No stop request - nothing happens. |
112 | */ |
118 | */ |
113 | spinlock_unlock(&THREAD->debug_lock); |
119 | spinlock_unlock(&THREAD->debug_lock); |
114 | spinlock_unlock(&TASK->lock); |
120 | spinlock_unlock(&TASK->lock); |
115 | interrupts_restore(ipl); |
121 | interrupts_restore(ipl); |
116 | } |
122 | } |
117 | } else { |
123 | } else { |
118 | /* |
124 | /* |
119 | * All other cases - nothing special happens. |
125 | * All other cases - nothing special happens. |
120 | */ |
126 | */ |
121 | 127 | ||
122 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
128 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
123 | spinlock_lock(&THREAD->debug_lock); |
129 | spinlock_lock(&THREAD->debug_lock); |
124 | THREAD->debug_stoppable = true; |
130 | THREAD->debug_stoppable = true; |
125 | spinlock_unlock(&THREAD->debug_lock); |
131 | spinlock_unlock(&THREAD->debug_lock); |
126 | 132 | ||
127 | spinlock_unlock(&TASK->lock); |
133 | spinlock_unlock(&TASK->lock); |
128 | interrupts_restore(ipl); |
134 | interrupts_restore(ipl); |
129 | } |
135 | } |
130 | } |
136 | } |
131 | 137 | ||
132 | void udebug_stoppable_end(void) |
138 | void udebug_stoppable_end(void) |
133 | { |
139 | { |
134 | ipl_t ipl; |
140 | ipl_t ipl; |
135 | 141 | ||
136 | restart: |
142 | restart: |
137 | ipl = interrupts_disable(); |
143 | ipl = interrupts_disable(); |
138 | spinlock_lock(&TASK->lock); |
144 | spinlock_lock(&TASK->lock); |
139 | 145 | ||
140 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
146 | /* Lock order OK, THREAD->debug_lock is after TASK->lock */ |
141 | spinlock_lock(&THREAD->debug_lock); |
147 | spinlock_lock(&THREAD->debug_lock); |
142 | 148 | ||
143 | if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
149 | if (TASK->dt_state == UDEBUG_TS_ACTIVE) { |
144 | klog_printf("udebug_stoppable_end"); |
150 | klog_printf("udebug_stoppable_end"); |
145 | klog_printf("debug_stop=%d", THREAD->debug_stop); |
151 | klog_printf("debug_stop=%d", THREAD->debug_stop); |
146 | } |
152 | } |
147 | 153 | ||
148 | if ((TASK->dt_state == UDEBUG_TS_BEGINNING || |
- | |
149 | TASK->dt_state == UDEBUG_TS_ACTIVE) && |
154 | if (THREAD->debug_active && |
150 | THREAD->debug_stop == true) { |
155 | THREAD->debug_stop == true) { |
151 | TASK->debug_begin_call = NULL; |
156 | TASK->debug_begin_call = NULL; |
152 | spinlock_unlock(&THREAD->debug_lock); |
157 | spinlock_unlock(&THREAD->debug_lock); |
153 | spinlock_unlock(&TASK->lock); |
158 | spinlock_unlock(&TASK->lock); |
154 | interrupts_restore(ipl); |
159 | interrupts_restore(ipl); |
155 | 160 | ||
156 | klog_printf("udebug_stoppable_end: waitq_sleep"); |
161 | klog_printf("udebug_stoppable_end: waitq_sleep"); |
157 | waitq_sleep(&THREAD->go_wq); |
162 | waitq_sleep(&THREAD->go_wq); |
158 | goto restart; |
163 | goto restart; |
159 | /* must try again - have to lose stoppability atomically */ |
164 | /* must try again - have to lose stoppability atomically */ |
160 | } else { |
165 | } else { |
161 | ++TASK->not_stoppable_count; |
166 | ++TASK->not_stoppable_count; |
162 | THREAD->debug_stoppable = false; |
167 | THREAD->debug_stoppable = false; |
163 | 168 | ||
164 | spinlock_unlock(&THREAD->debug_lock); |
169 | spinlock_unlock(&THREAD->debug_lock); |
165 | spinlock_unlock(&TASK->lock); |
170 | spinlock_unlock(&TASK->lock); |
166 | interrupts_restore(ipl); |
171 | interrupts_restore(ipl); |
167 | } |
172 | } |
168 | } |
173 | } |
169 | 174 | ||
170 | void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3, |
175 | void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3, |
171 | unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc, |
176 | unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc, |
172 | bool end_variant) |
177 | bool end_variant) |
173 | { |
178 | { |
174 | call_t *call; |
179 | call_t *call; |
175 | ipl_t ipl; |
180 | ipl_t ipl; |
176 | udebug_event_t etype; |
181 | udebug_event_t etype; |
177 | 182 | ||
178 | etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; |
183 | etype = end_variant ? UDEBUG_EVENT_SYSCALL_E : UDEBUG_EVENT_SYSCALL_B; |
179 | 184 | ||
180 | ipl = interrupts_disable(); |
185 | ipl = interrupts_disable(); |
181 | spinlock_lock(&THREAD->debug_lock); |
186 | spinlock_lock(&THREAD->debug_lock); |
182 | 187 | ||
183 | /* Must only generate events when in debugging session and have go */ |
188 | /* Must only generate events when in debugging session and have go */ |
184 | if (THREAD->debug_active != true || |
189 | if (THREAD->debug_active != true || |
185 | THREAD->debug_stop == true || |
190 | THREAD->debug_stop == true || |
186 | (TASK->debug_evmask & UDEBUG_EVMASK(etype)) == 0) { |
191 | (TASK->debug_evmask & UDEBUG_EVMASK(etype)) == 0) { |
187 | spinlock_unlock(&THREAD->debug_lock); |
192 | spinlock_unlock(&THREAD->debug_lock); |
188 | interrupts_restore(ipl); |
193 | interrupts_restore(ipl); |
189 | return; |
194 | return; |
190 | } |
195 | } |
191 | 196 | ||
192 | klog_printf("udebug_syscall_event"); |
197 | klog_printf("udebug_syscall_event"); |
193 | call = THREAD->debug_go_call; |
198 | call = THREAD->debug_go_call; |
194 | IPC_SET_RETVAL(call->data, 0); |
199 | IPC_SET_RETVAL(call->data, 0); |
195 | IPC_SET_ARG1(call->data, etype); |
200 | IPC_SET_ARG1(call->data, etype); |
196 | IPC_SET_ARG2(call->data, id); |
201 | IPC_SET_ARG2(call->data, id); |
197 | IPC_SET_ARG3(call->data, rc); |
202 | IPC_SET_ARG3(call->data, rc); |
198 | klog_printf("udebug_syscall_event/ipc_answer"); |
203 | klog_printf("udebug_syscall_event/ipc_answer"); |
199 | 204 | ||
200 | THREAD->syscall_args[0] = a1; |
205 | THREAD->syscall_args[0] = a1; |
201 | THREAD->syscall_args[1] = a2; |
206 | THREAD->syscall_args[1] = a2; |
202 | THREAD->syscall_args[2] = a3; |
207 | THREAD->syscall_args[2] = a3; |
203 | THREAD->syscall_args[3] = a4; |
208 | THREAD->syscall_args[3] = a4; |
204 | THREAD->syscall_args[4] = a5; |
209 | THREAD->syscall_args[4] = a5; |
205 | THREAD->syscall_args[5] = a6; |
210 | THREAD->syscall_args[5] = a6; |
206 | 211 | ||
207 | /* |
212 | /* |
208 | * Make sure debug_stop is true when going to sleep |
213 | * Make sure debug_stop is true when going to sleep |
209 | * in case we get woken up by DEBUG_END. (At which |
214 | * in case we get woken up by DEBUG_END. (At which |
210 | * point it must be back to the initial true value). |
215 | * point it must be back to the initial true value). |
211 | */ |
216 | */ |
212 | THREAD->debug_stop = true; |
217 | THREAD->debug_stop = true; |
213 | 218 | ||
214 | THREAD->cur_event = etype; |
219 | THREAD->cur_event = etype; |
215 | spinlock_unlock(&THREAD->debug_lock); |
220 | spinlock_unlock(&THREAD->debug_lock); |
216 | 221 | ||
217 | spinlock_lock(&TASK->lock); |
222 | spinlock_lock(&TASK->lock); |
218 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
223 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
219 | spinlock_unlock(&TASK->lock); |
224 | spinlock_unlock(&TASK->lock); |
220 | 225 | ||
221 | interrupts_restore(ipl); |
226 | interrupts_restore(ipl); |
222 | 227 | ||
223 | waitq_sleep(&THREAD->go_wq); |
228 | waitq_sleep(&THREAD->go_wq); |
224 | } |
229 | } |
225 | 230 | ||
226 | void udebug_new_thread_event(struct thread *t) |
231 | void udebug_new_thread_event(struct thread *t) |
227 | { |
232 | { |
228 | call_t *call; |
233 | call_t *call; |
229 | ipl_t ipl; |
234 | ipl_t ipl; |
230 | 235 | ||
231 | ipl = interrupts_disable(); |
236 | ipl = interrupts_disable(); |
232 | spinlock_lock(&THREAD->debug_lock); |
237 | spinlock_lock(&THREAD->debug_lock); |
233 | 238 | ||
234 | klog_printf("udebug_new_thread_event"); |
239 | klog_printf("udebug_new_thread_event"); |
235 | klog_printf("- check state"); |
240 | klog_printf("- check state"); |
236 | 241 | ||
237 | /* Must only generate events when in debugging session */ |
242 | /* Must only generate events when in debugging session */ |
238 | if (THREAD->debug_active != true) { |
243 | if (THREAD->debug_active != true) { |
239 | klog_printf("- debug_active: %s, debug_stop: %s", |
244 | klog_printf("- debug_active: %s, debug_stop: %s", |
240 | THREAD->debug_active ? "yes(+)" : "no(-)", |
245 | THREAD->debug_active ? "yes(+)" : "no(-)", |
241 | THREAD->debug_stop ? "yes(-)" : "no(+)"); |
246 | THREAD->debug_stop ? "yes(-)" : "no(+)"); |
242 | spinlock_unlock(&THREAD->debug_lock); |
247 | spinlock_unlock(&THREAD->debug_lock); |
243 | interrupts_restore(ipl); |
248 | interrupts_restore(ipl); |
244 | return; |
249 | return; |
245 | } |
250 | } |
246 | 251 | ||
247 | klog_printf("- trigger event"); |
252 | klog_printf("- trigger event"); |
248 | 253 | ||
249 | call = THREAD->debug_go_call; |
254 | call = THREAD->debug_go_call; |
250 | IPC_SET_RETVAL(call->data, 0); |
255 | IPC_SET_RETVAL(call->data, 0); |
251 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD); |
256 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD); |
252 | IPC_SET_ARG2(call->data, (unative_t)t); |
257 | IPC_SET_ARG2(call->data, (unative_t)t); |
253 | 258 | ||
254 | /* |
259 | /* |
255 | * Make sure debug_stop is true when going to sleep |
260 | * Make sure debug_stop is true when going to sleep |
256 | * in case we get woken up by DEBUG_END. (At which |
261 | * in case we get woken up by DEBUG_END. (At which |
257 | * point it must be back to the initial true value). |
262 | * point it must be back to the initial true value). |
258 | */ |
263 | */ |
259 | THREAD->debug_stop = true; |
264 | THREAD->debug_stop = true; |
260 | 265 | ||
261 | THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD; |
266 | THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD; |
262 | spinlock_unlock(&THREAD->debug_lock); |
267 | spinlock_unlock(&THREAD->debug_lock); |
263 | 268 | ||
264 | spinlock_lock(&TASK->lock); |
269 | spinlock_lock(&TASK->lock); |
265 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
270 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
266 | spinlock_unlock(&TASK->lock); |
271 | spinlock_unlock(&TASK->lock); |
267 | 272 | ||
268 | interrupts_restore(ipl); |
273 | interrupts_restore(ipl); |
269 | klog_printf("- sleep"); |
274 | klog_printf("- sleep"); |
270 | 275 | ||
271 | waitq_sleep(&THREAD->go_wq); |
276 | waitq_sleep(&THREAD->go_wq); |
272 | } |
277 | } |
273 | 278 | ||
274 | /** |
279 | /** |
275 | * Terminate task debugging session. |
280 | * Terminate task debugging session. |
276 | * |
281 | * |
277 | * \param ta Must be already locked and interrupts must be disabled. |
282 | * \param ta Must be already locked and interrupts must be disabled. |
278 | * \return Zero on success or negative error code. |
283 | * \return Zero on success or negative error code. |
279 | */ |
284 | */ |
280 | int udebug_task_cleanup(struct task *ta) |
285 | int udebug_task_cleanup(struct task *ta) |
281 | { |
286 | { |
282 | thread_t *t; |
287 | thread_t *t; |
283 | link_t *cur; |
288 | link_t *cur; |
284 | int flags; |
289 | int flags; |
285 | 290 | ||
286 | klog_printf("udebug_task_cleanup()"); |
291 | klog_printf("udebug_task_cleanup()"); |
287 | klog_printf("task %llu", ta->taskid); |
292 | klog_printf("task %llu", ta->taskid); |
288 | 293 | ||
289 | if (ta->dt_state == UDEBUG_TS_BEGINNING && |
294 | if (ta->dt_state == UDEBUG_TS_BEGINNING && |
290 | ta->dt_state != UDEBUG_TS_ACTIVE) { |
295 | ta->dt_state != UDEBUG_TS_ACTIVE) { |
291 | klog_printf("udebug_task_cleanup(): task not being debugged"); |
296 | klog_printf("udebug_task_cleanup(): task not being debugged"); |
292 | return EINVAL; |
297 | return EINVAL; |
293 | } |
298 | } |
294 | 299 | ||
295 | /* Finish debugging of all userspace threads */ |
300 | /* Finish debugging of all userspace threads */ |
296 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
301 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
297 | t = list_get_instance(cur, thread_t, th_link); |
302 | t = list_get_instance(cur, thread_t, th_link); |
298 | 303 | ||
299 | spinlock_lock(&t->debug_lock); |
304 | spinlock_lock(&t->debug_lock); |
300 | spinlock_lock(&t->lock); |
305 | spinlock_lock(&t->lock); |
301 | 306 | ||
302 | flags = t->flags; |
307 | flags = t->flags; |
303 | 308 | ||
304 | spinlock_unlock(&t->lock); |
309 | spinlock_unlock(&t->lock); |
305 | 310 | ||
306 | /* Only process userspace threads */ |
311 | /* Only process userspace threads */ |
307 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
312 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
308 | /* Prevent any further debug activity in thread */ |
313 | /* Prevent any further debug activity in thread */ |
309 | t->debug_active = false; |
314 | t->debug_active = false; |
310 | t->cur_event = 0; /* none */ |
315 | t->cur_event = 0; /* none */ |
311 | 316 | ||
312 | /* Still has go? */ |
317 | /* Still has go? */ |
313 | if (t->debug_stop == false) { |
318 | if (t->debug_stop == false) { |
314 | /* |
319 | /* |
315 | * Yes, so clear go. As debug_active == false, |
320 | * Yes, so clear go. As debug_active == false, |
316 | * this doesn't affect anything. |
321 | * this doesn't affect anything. |
317 | */ |
322 | */ |
318 | t->debug_stop = true; |
323 | t->debug_stop = true; |
319 | 324 | ||
320 | /* Answer GO call */ |
325 | /* Answer GO call */ |
321 | klog_printf("answer GO call with EVENT_FINISHED"); |
326 | klog_printf("answer GO call with EVENT_FINISHED"); |
322 | IPC_SET_RETVAL(t->debug_go_call->data, 0); |
327 | IPC_SET_RETVAL(t->debug_go_call->data, 0); |
323 | IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED); |
328 | IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED); |
324 | ipc_answer(&ta->answerbox, t->debug_go_call); |
329 | ipc_answer(&ta->answerbox, t->debug_go_call); |
325 | } else { |
330 | } else { |
326 | /* |
331 | /* |
327 | * Debug_stop is already at initial value. |
332 | * Debug_stop is already at initial value. |
328 | * Yet this means the thread needs waking up. |
333 | * Yet this means the thread needs waking up. |
329 | */ |
334 | */ |
330 | 335 | ||
331 | /* |
336 | /* |
332 | * t's lock must not be held when calling |
337 | * t's lock must not be held when calling |
333 | * waitq_wakeup. |
338 | * waitq_wakeup. |
334 | */ |
339 | */ |
335 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
340 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
336 | } |
341 | } |
337 | } |
342 | } |
338 | spinlock_unlock(&t->debug_lock); |
343 | spinlock_unlock(&t->debug_lock); |
339 | } |
344 | } |
340 | 345 | ||
341 | ta->dt_state = UDEBUG_TS_INACTIVE; |
346 | ta->dt_state = UDEBUG_TS_INACTIVE; |
342 | ta->debugger = NULL; |
347 | ta->debugger = NULL; |
343 | 348 | ||
344 | return 0; |
349 | return 0; |
345 | } |
350 | } |
346 | 351 | ||
347 | 352 | ||
348 | /** @} |
353 | /** @} |
349 | */ |
354 | */ |
350 | 355 |