Rev 2867 | Rev 2898 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
2801 | svoboda | 1 | /** @addtogroup generic |
2 | * @{ |
||
3 | */ |
||
4 | |||
5 | /** |
||
6 | * @file |
||
7 | * @brief Tdebug. |
||
8 | */ |
||
9 | |||
10 | #include <synch/waitq.h> |
||
11 | #include <console/klog.h> |
||
2813 | svoboda | 12 | #include <udebug/udebug.h> |
2870 | svoboda | 13 | #include <errno.h> |
2801 | svoboda | 14 | #include <arch.h> |
15 | |||
2804 | svoboda | 16 | void udebug_stoppable_begin(void) |
2801 | svoboda | 17 | { |
2804 | svoboda | 18 | int nsc; |
19 | call_t *db_call; |
||
2823 | svoboda | 20 | ipl_t ipl; |
2804 | svoboda | 21 | |
2823 | svoboda | 22 | ipl = interrupts_disable(); |
2804 | svoboda | 23 | spinlock_lock(&TASK->lock); |
24 | |||
25 | nsc = --TASK->not_stoppable_count; |
||
26 | db_call = TASK->debug_begin_call; |
||
27 | |||
2825 | svoboda | 28 | if (TASK->dt_state == UDEBUG_TS_BEGINNING) { |
2804 | svoboda | 29 | klog_printf("udebug_stoppable_begin"); |
30 | klog_printf(" - nsc := %d", nsc); |
||
31 | } |
||
32 | |||
2825 | svoboda | 33 | if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) { |
34 | TASK->dt_state = UDEBUG_TS_ACTIVE; |
||
2801 | svoboda | 35 | TASK->debug_begin_call = NULL; |
2804 | svoboda | 36 | spinlock_unlock(&TASK->lock); |
2823 | svoboda | 37 | interrupts_restore(ipl); |
2804 | svoboda | 38 | |
39 | IPC_SET_RETVAL(db_call->data, 0); |
||
40 | klog_printf("udebug_stoppable_begin/ipc_answer"); |
||
41 | ipc_answer(&TASK->answerbox, db_call); |
||
42 | } else { |
||
43 | spinlock_unlock(&TASK->lock); |
||
2823 | svoboda | 44 | interrupts_restore(ipl); |
2804 | svoboda | 45 | } |
46 | } |
||
47 | |||
48 | void udebug_stoppable_end(void) |
||
49 | { |
||
2823 | svoboda | 50 | ipl_t ipl; |
51 | |||
2804 | svoboda | 52 | restart: |
2823 | svoboda | 53 | ipl = interrupts_disable(); |
2804 | svoboda | 54 | spinlock_lock(&TASK->lock); |
55 | |||
2825 | svoboda | 56 | if ((TASK->dt_state == UDEBUG_TS_BEGINNING || |
57 | TASK->dt_state == UDEBUG_TS_ACTIVE) && |
||
58 | THREAD->debug_stop == true) { |
||
2804 | svoboda | 59 | TASK->debug_begin_call = NULL; |
60 | spinlock_unlock(&TASK->lock); |
||
2823 | svoboda | 61 | interrupts_restore(ipl); |
62 | |||
2804 | svoboda | 63 | klog_printf("udebug_stoppable_end: waitq_sleep"); |
2801 | svoboda | 64 | waitq_sleep(&THREAD->go_wq); |
2804 | svoboda | 65 | goto restart; |
66 | /* must try again - have to lose stoppability atomically */ |
||
67 | } else { |
||
68 | ++TASK->not_stoppable_count; |
||
69 | spinlock_unlock(&TASK->lock); |
||
2823 | svoboda | 70 | interrupts_restore(ipl); |
2801 | svoboda | 71 | } |
72 | } |
||
73 | |||
2805 | svoboda | 74 | void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3, |
75 | unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc) |
||
2801 | svoboda | 76 | { |
2805 | svoboda | 77 | call_t *call; |
2823 | svoboda | 78 | ipl_t ipl; |
2805 | svoboda | 79 | |
2823 | svoboda | 80 | ipl = interrupts_disable(); |
2848 | svoboda | 81 | spinlock_lock(&THREAD->debug_lock); |
2823 | svoboda | 82 | |
2854 | svoboda | 83 | /* Must only generate events when in debugging session and have go */ |
2867 | svoboda | 84 | if (THREAD->debug_active != true || |
85 | THREAD->debug_stop == true) { |
||
86 | spinlock_unlock(&THREAD->debug_lock); |
||
87 | interrupts_restore(ipl); |
||
88 | return; |
||
89 | } |
||
2804 | svoboda | 90 | |
2867 | svoboda | 91 | klog_printf("udebug_syscall_event"); |
92 | call = THREAD->debug_go_call; |
||
93 | IPC_SET_RETVAL(call->data, 0); |
||
94 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL); |
||
95 | IPC_SET_ARG2(call->data, id); |
||
96 | IPC_SET_ARG3(call->data, rc); |
||
97 | klog_printf("udebug_syscall_event/ipc_answer"); |
||
2805 | svoboda | 98 | |
2867 | svoboda | 99 | THREAD->syscall_args[0] = a1; |
100 | THREAD->syscall_args[1] = a2; |
||
101 | THREAD->syscall_args[2] = a3; |
||
102 | THREAD->syscall_args[3] = a4; |
||
103 | THREAD->syscall_args[4] = a5; |
||
104 | THREAD->syscall_args[5] = a6; |
||
2866 | svoboda | 105 | |
2867 | svoboda | 106 | /* |
107 | * Make sure debug_stop is true when going to sleep |
||
108 | * in case we get woken up by DEBUG_END. (At which |
||
109 | * point it must be back to the initial true value). |
||
110 | */ |
||
111 | THREAD->debug_stop = true; |
||
2825 | svoboda | 112 | |
2867 | svoboda | 113 | THREAD->cur_event = UDEBUG_EVENT_SYSCALL; |
114 | spinlock_unlock(&THREAD->debug_lock); |
||
2834 | svoboda | 115 | |
2867 | svoboda | 116 | spinlock_lock(&TASK->lock); |
117 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
||
118 | spinlock_unlock(&TASK->lock); |
||
2823 | svoboda | 119 | |
2867 | svoboda | 120 | interrupts_restore(ipl); |
121 | |||
122 | waitq_sleep(&THREAD->go_wq); |
||
123 | } |
||
124 | |||
125 | void udebug_new_thread_event(struct thread *t) |
||
126 | { |
||
127 | call_t *call; |
||
128 | ipl_t ipl; |
||
129 | |||
130 | ipl = interrupts_disable(); |
||
131 | spinlock_lock(&THREAD->debug_lock); |
||
132 | |||
133 | klog_printf("udebug_new_thread_event"); |
||
134 | klog_printf("- check state"); |
||
135 | |||
136 | /* Must only generate events when in debugging session */ |
||
137 | if (THREAD->debug_active != true) { |
||
138 | klog_printf("- debug_active: %s, debug_stop: %s", |
||
139 | THREAD->debug_active ? "yes(+)" : "no(-)", |
||
140 | THREAD->debug_stop ? "yes(-)" : "no(+)"); |
||
2848 | svoboda | 141 | spinlock_unlock(&THREAD->debug_lock); |
2823 | svoboda | 142 | interrupts_restore(ipl); |
2867 | svoboda | 143 | return; |
2801 | svoboda | 144 | } |
2867 | svoboda | 145 | |
146 | klog_printf("- trigger event"); |
||
147 | |||
148 | call = THREAD->debug_go_call; |
||
149 | IPC_SET_RETVAL(call->data, 0); |
||
150 | IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD); |
||
151 | IPC_SET_ARG2(call->data, (unative_t)t); |
||
152 | |||
153 | /* |
||
154 | * Make sure debug_stop is true when going to sleep |
||
155 | * in case we get woken up by DEBUG_END. (At which |
||
156 | * point it must be back to the initial true value). |
||
157 | */ |
||
158 | THREAD->debug_stop = true; |
||
159 | |||
160 | THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD; |
||
161 | spinlock_unlock(&THREAD->debug_lock); |
||
162 | |||
163 | spinlock_lock(&TASK->lock); |
||
164 | ipc_answer(&TASK->answerbox, THREAD->debug_go_call); |
||
165 | spinlock_unlock(&TASK->lock); |
||
166 | |||
167 | interrupts_restore(ipl); |
||
168 | klog_printf("- sleep"); |
||
169 | |||
170 | waitq_sleep(&THREAD->go_wq); |
||
2801 | svoboda | 171 | } |
172 | |||
2870 | svoboda | 173 | /** |
174 | * Terminate task debugging session. |
||
175 | * |
||
176 | * \param ta Must be already locked and interrupts must be disabled. |
||
177 | * \return Zero on success or negative error code. |
||
178 | */ |
||
179 | int udebug_task_cleanup(struct task *ta) |
||
180 | { |
||
181 | thread_t *t; |
||
182 | link_t *cur; |
||
183 | int flags; |
||
2867 | svoboda | 184 | |
2870 | svoboda | 185 | klog_printf("udebug_task_cleanup()"); |
186 | klog_printf("task %llu", ta->taskid); |
||
187 | |||
188 | if (ta->dt_state == UDEBUG_TS_BEGINNING && |
||
189 | ta->dt_state != UDEBUG_TS_ACTIVE) { |
||
190 | klog_printf("udebug_task_cleanup(): task not being debugged"); |
||
191 | return EINVAL; |
||
192 | } |
||
193 | |||
194 | /* Finish debugging of all userspace threads */ |
||
195 | for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) { |
||
196 | t = list_get_instance(cur, thread_t, th_link); |
||
197 | |||
198 | spinlock_lock(&t->debug_lock); |
||
199 | spinlock_lock(&t->lock); |
||
200 | |||
201 | flags = t->flags; |
||
202 | |||
203 | spinlock_unlock(&t->lock); |
||
204 | |||
205 | /* Only process userspace threads */ |
||
206 | if ((flags & THREAD_FLAG_USPACE) != 0) { |
||
207 | /* Prevent any further debug activity in thread */ |
||
208 | t->debug_active = false; |
||
209 | t->cur_event = 0; /* none */ |
||
210 | |||
211 | /* Still has go? */ |
||
212 | if (t->debug_stop == false) { |
||
213 | /* |
||
214 | * Yes, so clear go. As debug_active == false, |
||
215 | * this doesn't affect anything. |
||
216 | */ |
||
217 | t->debug_stop = true; |
||
218 | |||
219 | /* Answer GO call */ |
||
220 | klog_printf("answer GO call with EVENT_FINISHED"); |
||
221 | IPC_SET_RETVAL(t->debug_go_call->data, 0); |
||
222 | IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED); |
||
223 | ipc_answer(&ta->answerbox, t->debug_go_call); |
||
224 | } else { |
||
225 | /* |
||
226 | * Debug_stop is already at initial value. |
||
227 | * Yet this means the thread needs waking up. |
||
228 | */ |
||
229 | |||
230 | /* |
||
231 | * t's lock must not be held when calling |
||
232 | * waitq_wakeup. |
||
233 | */ |
||
234 | waitq_wakeup(&t->go_wq, WAKEUP_FIRST); |
||
235 | } |
||
236 | } |
||
237 | spinlock_unlock(&t->debug_lock); |
||
238 | } |
||
239 | |||
240 | ta->dt_state = UDEBUG_TS_INACTIVE; |
||
241 | ta->debugger = NULL; |
||
242 | |||
243 | return 0; |
||
244 | } |
||
245 | |||
246 | |||
2801 | svoboda | 247 | /** @} |
248 | */ |