Subversion Repositories HelenOS

Rev

Rev 2867 | Rev 2894 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 2867 Rev 2870
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 <synch/waitq.h>
10
#include <synch/waitq.h>
11
#include <console/klog.h>
11
#include <console/klog.h>
12
#include <udebug/udebug.h>
12
#include <udebug/udebug.h>
-
 
13
#include <errno.h>
13
#include <arch.h>
14
#include <arch.h>
14
 
15
 
15
void udebug_stoppable_begin(void)
16
void udebug_stoppable_begin(void)
16
{
17
{
17
    int nsc;
18
    int nsc;
18
    call_t *db_call;
19
    call_t *db_call;
19
    ipl_t ipl;
20
    ipl_t ipl;
20
 
21
 
21
    ipl = interrupts_disable();
22
    ipl = interrupts_disable();
22
    spinlock_lock(&TASK->lock);
23
    spinlock_lock(&TASK->lock);
23
 
24
 
24
    nsc = --TASK->not_stoppable_count;
25
    nsc = --TASK->not_stoppable_count;
25
    db_call = TASK->debug_begin_call;
26
    db_call = TASK->debug_begin_call;
26
 
27
 
27
    if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
28
    if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
28
        klog_printf("udebug_stoppable_begin");
29
        klog_printf("udebug_stoppable_begin");
29
        klog_printf(" - nsc := %d", nsc);
30
        klog_printf(" - nsc := %d", nsc);
30
    }
31
    }
31
 
32
 
32
    if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
33
    if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
33
        TASK->dt_state = UDEBUG_TS_ACTIVE;
34
        TASK->dt_state = UDEBUG_TS_ACTIVE;
34
        TASK->debug_begin_call = NULL;
35
        TASK->debug_begin_call = NULL;
35
        spinlock_unlock(&TASK->lock);
36
        spinlock_unlock(&TASK->lock);
36
        interrupts_restore(ipl);
37
        interrupts_restore(ipl);
37
 
38
 
38
        IPC_SET_RETVAL(db_call->data, 0);
39
        IPC_SET_RETVAL(db_call->data, 0);
39
        klog_printf("udebug_stoppable_begin/ipc_answer");
40
        klog_printf("udebug_stoppable_begin/ipc_answer");
40
        ipc_answer(&TASK->answerbox, db_call);     
41
        ipc_answer(&TASK->answerbox, db_call);     
41
    } else {
42
    } else {
42
            spinlock_unlock(&TASK->lock);
43
            spinlock_unlock(&TASK->lock);
43
        interrupts_restore(ipl);
44
        interrupts_restore(ipl);
44
    }
45
    }
45
}
46
}
46
 
47
 
47
void udebug_stoppable_end(void)
48
void udebug_stoppable_end(void)
48
{
49
{
49
    ipl_t ipl;
50
    ipl_t ipl;
50
 
51
 
51
restart:
52
restart:
52
    ipl = interrupts_disable();
53
    ipl = interrupts_disable();
53
    spinlock_lock(&TASK->lock);
54
    spinlock_lock(&TASK->lock);
54
 
55
 
55
    if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
56
    if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
56
        TASK->dt_state == UDEBUG_TS_ACTIVE) &&
57
        TASK->dt_state == UDEBUG_TS_ACTIVE) &&
57
        THREAD->debug_stop == true) {
58
        THREAD->debug_stop == true) {
58
        TASK->debug_begin_call = NULL;
59
        TASK->debug_begin_call = NULL;
59
        spinlock_unlock(&TASK->lock);
60
        spinlock_unlock(&TASK->lock);
60
        interrupts_restore(ipl);
61
        interrupts_restore(ipl);
61
 
62
 
62
        klog_printf("udebug_stoppable_end: waitq_sleep");
63
        klog_printf("udebug_stoppable_end: waitq_sleep");
63
        waitq_sleep(&THREAD->go_wq);
64
        waitq_sleep(&THREAD->go_wq);
64
        goto restart;
65
        goto restart;
65
        /* must try again - have to lose stoppability atomically */
66
        /* must try again - have to lose stoppability atomically */
66
    } else {
67
    } else {
67
        ++TASK->not_stoppable_count;
68
        ++TASK->not_stoppable_count;
68
        spinlock_unlock(&TASK->lock);
69
        spinlock_unlock(&TASK->lock);
69
        interrupts_restore(ipl);
70
        interrupts_restore(ipl);
70
    }
71
    }
71
}
72
}
72
 
73
 
73
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
74
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
74
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc)
75
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc)
75
{
76
{
76
    call_t *call;
77
    call_t *call;
77
    ipl_t ipl;
78
    ipl_t ipl;
78
 
79
 
79
    ipl = interrupts_disable();
80
    ipl = interrupts_disable();
80
    spinlock_lock(&THREAD->debug_lock);
81
    spinlock_lock(&THREAD->debug_lock);
81
 
82
 
82
    /* Must only generate events when in debugging session and have go */
83
    /* Must only generate events when in debugging session and have go */
83
    if (THREAD->debug_active != true ||
84
    if (THREAD->debug_active != true ||
84
        THREAD->debug_stop == true) {
85
        THREAD->debug_stop == true) {
85
        spinlock_unlock(&THREAD->debug_lock);
86
        spinlock_unlock(&THREAD->debug_lock);
86
        interrupts_restore(ipl);
87
        interrupts_restore(ipl);
87
        return;
88
        return;
88
    }
89
    }
89
 
90
 
90
    klog_printf("udebug_syscall_event");
91
    klog_printf("udebug_syscall_event");
91
    call = THREAD->debug_go_call;
92
    call = THREAD->debug_go_call;
92
    IPC_SET_RETVAL(call->data, 0);
93
    IPC_SET_RETVAL(call->data, 0);
93
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL);
94
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL);
94
    IPC_SET_ARG2(call->data, id);
95
    IPC_SET_ARG2(call->data, id);
95
    IPC_SET_ARG3(call->data, rc);
96
    IPC_SET_ARG3(call->data, rc);
96
    klog_printf("udebug_syscall_event/ipc_answer");
97
    klog_printf("udebug_syscall_event/ipc_answer");
97
 
98
 
98
    THREAD->syscall_args[0] = a1;
99
    THREAD->syscall_args[0] = a1;
99
    THREAD->syscall_args[1] = a2;
100
    THREAD->syscall_args[1] = a2;
100
    THREAD->syscall_args[2] = a3;
101
    THREAD->syscall_args[2] = a3;
101
    THREAD->syscall_args[3] = a4;
102
    THREAD->syscall_args[3] = a4;
102
    THREAD->syscall_args[4] = a5;
103
    THREAD->syscall_args[4] = a5;
103
    THREAD->syscall_args[5] = a6;
104
    THREAD->syscall_args[5] = a6;
104
 
105
 
105
    /*
106
    /*
106
     * Make sure debug_stop is true when going to sleep
107
     * Make sure debug_stop is true when going to sleep
107
     * in case we get woken up by DEBUG_END. (At which
108
     * in case we get woken up by DEBUG_END. (At which
108
     * point it must be back to the initial true value).
109
     * point it must be back to the initial true value).
109
     */
110
     */
110
    THREAD->debug_stop = true;
111
    THREAD->debug_stop = true;
111
 
112
 
112
    THREAD->cur_event = UDEBUG_EVENT_SYSCALL;
113
    THREAD->cur_event = UDEBUG_EVENT_SYSCALL;
113
    spinlock_unlock(&THREAD->debug_lock);
114
    spinlock_unlock(&THREAD->debug_lock);
114
 
115
 
115
    spinlock_lock(&TASK->lock);
116
    spinlock_lock(&TASK->lock);
116
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
117
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
117
    spinlock_unlock(&TASK->lock);
118
    spinlock_unlock(&TASK->lock);
118
 
119
 
119
    interrupts_restore(ipl);
120
    interrupts_restore(ipl);
120
 
121
 
121
    waitq_sleep(&THREAD->go_wq);
122
    waitq_sleep(&THREAD->go_wq);
122
}
123
}
123
 
124
 
124
void udebug_new_thread_event(struct thread *t)
125
void udebug_new_thread_event(struct thread *t)
125
{
126
{
126
    call_t *call;
127
    call_t *call;
127
    ipl_t ipl;
128
    ipl_t ipl;
128
 
129
 
129
    ipl = interrupts_disable();
130
    ipl = interrupts_disable();
130
    spinlock_lock(&THREAD->debug_lock);
131
    spinlock_lock(&THREAD->debug_lock);
131
 
132
 
132
    klog_printf("udebug_new_thread_event");
133
    klog_printf("udebug_new_thread_event");
133
    klog_printf("- check state");
134
    klog_printf("- check state");
134
 
135
 
135
    /* Must only generate events when in debugging session */
136
    /* Must only generate events when in debugging session */
136
    if (THREAD->debug_active != true) {
137
    if (THREAD->debug_active != true) {
137
        klog_printf("- debug_active: %s, debug_stop: %s",
138
        klog_printf("- debug_active: %s, debug_stop: %s",
138
            THREAD->debug_active ? "yes(+)" : "no(-)",
139
            THREAD->debug_active ? "yes(+)" : "no(-)",
139
            THREAD->debug_stop ? "yes(-)" : "no(+)");
140
            THREAD->debug_stop ? "yes(-)" : "no(+)");
140
        spinlock_unlock(&THREAD->debug_lock);
141
        spinlock_unlock(&THREAD->debug_lock);
141
        interrupts_restore(ipl);
142
        interrupts_restore(ipl);
142
        return;
143
        return;
143
    }
144
    }
144
 
145
 
145
    klog_printf("- trigger event");
146
    klog_printf("- trigger event");
146
 
147
 
147
    call = THREAD->debug_go_call;
148
    call = THREAD->debug_go_call;
148
    IPC_SET_RETVAL(call->data, 0);
149
    IPC_SET_RETVAL(call->data, 0);
149
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
150
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
150
    IPC_SET_ARG2(call->data, (unative_t)t);
151
    IPC_SET_ARG2(call->data, (unative_t)t);
151
 
152
 
152
    /*
153
    /*
153
     * Make sure debug_stop is true when going to sleep
154
     * Make sure debug_stop is true when going to sleep
154
     * in case we get woken up by DEBUG_END. (At which
155
     * in case we get woken up by DEBUG_END. (At which
155
     * point it must be back to the initial true value).
156
     * point it must be back to the initial true value).
156
     */
157
     */
157
    THREAD->debug_stop = true;
158
    THREAD->debug_stop = true;
158
 
159
 
159
    THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
160
    THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
160
    spinlock_unlock(&THREAD->debug_lock);
161
    spinlock_unlock(&THREAD->debug_lock);
161
 
162
 
162
    spinlock_lock(&TASK->lock);
163
    spinlock_lock(&TASK->lock);
163
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
164
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
164
    spinlock_unlock(&TASK->lock);
165
    spinlock_unlock(&TASK->lock);
165
 
166
 
166
    interrupts_restore(ipl);
167
    interrupts_restore(ipl);
167
    klog_printf("- sleep");
168
    klog_printf("- sleep");
168
 
169
 
169
    waitq_sleep(&THREAD->go_wq);
170
    waitq_sleep(&THREAD->go_wq);
170
}
171
}
-
 
172
 
-
 
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;
-
 
184
 
-
 
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
}
171
 
245
 
172
 
246
 
173
/** @}
247
/** @}
174
 */
248
 */
175
 
249