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