Subversion Repositories HelenOS

Rev

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

Rev 2870 Rev 2894
-
 
1
/*
-
 
2
 * Copyright (c) 2008 Jiri Svoboda
-
 
3
 * All rights reserved.
-
 
4
 *
-
 
5
 * Redistribution and use in source and binary forms, with or without
-
 
6
 * modification, are permitted provided that the following conditions
-
 
7
 * are met:
-
 
8
 *
-
 
9
 * - Redistributions of source code must retain the above copyright
-
 
10
 *   notice, this list of conditions and the following disclaimer.
-
 
11
 * - Redistributions in binary form must reproduce the above copyright
-
 
12
 *   notice, this list of conditions and the following disclaimer in the
-
 
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
-
 
15
 *   derived from this software without specific prior written permission.
-
 
16
 *
-
 
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
-
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 
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
-
 
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
-
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
 
27
 */
-
 
28
 
1
/** @addtogroup generic
29
/** @addtogroup generic
2
 * @{
30
 * @{
3
 */
31
 */
4
 
32
 
5
/**
33
/**
6
 * @file
34
 * @file
7
 * @brief   Tdebug.
35
 * @brief   Udebug.
8
 */
36
 */
9
 
37
 
10
#include <synch/waitq.h>
38
#include <synch/waitq.h>
11
#include <console/klog.h>
39
#include <console/klog.h>
12
#include <udebug/udebug.h>
40
#include <udebug/udebug.h>
13
#include <errno.h>
41
#include <errno.h>
14
#include <arch.h>
42
#include <arch.h>
15
 
43
 
16
void udebug_stoppable_begin(void)
44
void udebug_stoppable_begin(void)
17
{
45
{
18
    int nsc;
46
    int nsc;
19
    call_t *db_call;
47
    call_t *db_call;
20
    ipl_t ipl;
48
    ipl_t ipl;
21
 
49
 
22
    ipl = interrupts_disable();
50
    ipl = interrupts_disable();
23
    spinlock_lock(&TASK->lock);
51
    spinlock_lock(&TASK->lock);
24
 
52
 
25
    nsc = --TASK->not_stoppable_count;
53
    nsc = --TASK->not_stoppable_count;
26
    db_call = TASK->debug_begin_call;
54
    db_call = TASK->debug_begin_call;
27
 
55
 
28
    if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
56
    if (TASK->dt_state == UDEBUG_TS_BEGINNING) {
29
        klog_printf("udebug_stoppable_begin");
57
        klog_printf("udebug_stoppable_begin");
30
        klog_printf(" - nsc := %d", nsc);
58
        klog_printf(" - nsc := %d", nsc);
31
    }
59
    }
32
 
60
 
33
    if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
61
    if (TASK->dt_state == UDEBUG_TS_BEGINNING && nsc == 0) {
34
        TASK->dt_state = UDEBUG_TS_ACTIVE;
62
        TASK->dt_state = UDEBUG_TS_ACTIVE;
35
        TASK->debug_begin_call = NULL;
63
        TASK->debug_begin_call = NULL;
36
        spinlock_unlock(&TASK->lock);
64
        spinlock_unlock(&TASK->lock);
37
        interrupts_restore(ipl);
65
        interrupts_restore(ipl);
38
 
66
 
39
        IPC_SET_RETVAL(db_call->data, 0);
67
        IPC_SET_RETVAL(db_call->data, 0);
40
        klog_printf("udebug_stoppable_begin/ipc_answer");
68
        klog_printf("udebug_stoppable_begin/ipc_answer");
41
        ipc_answer(&TASK->answerbox, db_call);     
69
        ipc_answer(&TASK->answerbox, db_call);     
42
    } else {
70
    } else {
43
            spinlock_unlock(&TASK->lock);
71
            spinlock_unlock(&TASK->lock);
44
        interrupts_restore(ipl);
72
        interrupts_restore(ipl);
45
    }
73
    }
46
}
74
}
47
 
75
 
48
void udebug_stoppable_end(void)
76
void udebug_stoppable_end(void)
49
{
77
{
50
    ipl_t ipl;
78
    ipl_t ipl;
51
 
79
 
52
restart:
80
restart:
53
    ipl = interrupts_disable();
81
    ipl = interrupts_disable();
54
    spinlock_lock(&TASK->lock);
82
    spinlock_lock(&TASK->lock);
55
 
83
 
56
    if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
84
    if ((TASK->dt_state == UDEBUG_TS_BEGINNING ||
57
        TASK->dt_state == UDEBUG_TS_ACTIVE) &&
85
        TASK->dt_state == UDEBUG_TS_ACTIVE) &&
58
        THREAD->debug_stop == true) {
86
        THREAD->debug_stop == true) {
59
        TASK->debug_begin_call = NULL;
87
        TASK->debug_begin_call = NULL;
60
        spinlock_unlock(&TASK->lock);
88
        spinlock_unlock(&TASK->lock);
61
        interrupts_restore(ipl);
89
        interrupts_restore(ipl);
62
 
90
 
63
        klog_printf("udebug_stoppable_end: waitq_sleep");
91
        klog_printf("udebug_stoppable_end: waitq_sleep");
64
        waitq_sleep(&THREAD->go_wq);
92
        waitq_sleep(&THREAD->go_wq);
65
        goto restart;
93
        goto restart;
66
        /* must try again - have to lose stoppability atomically */
94
        /* must try again - have to lose stoppability atomically */
67
    } else {
95
    } else {
68
        ++TASK->not_stoppable_count;
96
        ++TASK->not_stoppable_count;
69
        spinlock_unlock(&TASK->lock);
97
        spinlock_unlock(&TASK->lock);
70
        interrupts_restore(ipl);
98
        interrupts_restore(ipl);
71
    }
99
    }
72
}
100
}
73
 
101
 
74
void udebug_syscall_event(unative_t a1, unative_t a2, unative_t a3,
102
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)
103
    unative_t a4, unative_t a5, unative_t a6, unative_t id, unative_t rc)
76
{
104
{
77
    call_t *call;
105
    call_t *call;
78
    ipl_t ipl;
106
    ipl_t ipl;
79
 
107
 
80
    ipl = interrupts_disable();
108
    ipl = interrupts_disable();
81
    spinlock_lock(&THREAD->debug_lock);
109
    spinlock_lock(&THREAD->debug_lock);
82
 
110
 
83
    /* Must only generate events when in debugging session and have go */
111
    /* Must only generate events when in debugging session and have go */
84
    if (THREAD->debug_active != true ||
112
    if (THREAD->debug_active != true ||
85
        THREAD->debug_stop == true) {
113
        THREAD->debug_stop == true) {
86
        spinlock_unlock(&THREAD->debug_lock);
114
        spinlock_unlock(&THREAD->debug_lock);
87
        interrupts_restore(ipl);
115
        interrupts_restore(ipl);
88
        return;
116
        return;
89
    }
117
    }
90
 
118
 
91
    klog_printf("udebug_syscall_event");
119
    klog_printf("udebug_syscall_event");
92
    call = THREAD->debug_go_call;
120
    call = THREAD->debug_go_call;
93
    IPC_SET_RETVAL(call->data, 0);
121
    IPC_SET_RETVAL(call->data, 0);
94
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL);
122
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_SYSCALL);
95
    IPC_SET_ARG2(call->data, id);
123
    IPC_SET_ARG2(call->data, id);
96
    IPC_SET_ARG3(call->data, rc);
124
    IPC_SET_ARG3(call->data, rc);
97
    klog_printf("udebug_syscall_event/ipc_answer");
125
    klog_printf("udebug_syscall_event/ipc_answer");
98
 
126
 
99
    THREAD->syscall_args[0] = a1;
127
    THREAD->syscall_args[0] = a1;
100
    THREAD->syscall_args[1] = a2;
128
    THREAD->syscall_args[1] = a2;
101
    THREAD->syscall_args[2] = a3;
129
    THREAD->syscall_args[2] = a3;
102
    THREAD->syscall_args[3] = a4;
130
    THREAD->syscall_args[3] = a4;
103
    THREAD->syscall_args[4] = a5;
131
    THREAD->syscall_args[4] = a5;
104
    THREAD->syscall_args[5] = a6;
132
    THREAD->syscall_args[5] = a6;
105
 
133
 
106
    /*
134
    /*
107
     * Make sure debug_stop is true when going to sleep
135
     * Make sure debug_stop is true when going to sleep
108
     * in case we get woken up by DEBUG_END. (At which
136
     * in case we get woken up by DEBUG_END. (At which
109
     * point it must be back to the initial true value).
137
     * point it must be back to the initial true value).
110
     */
138
     */
111
    THREAD->debug_stop = true;
139
    THREAD->debug_stop = true;
112
 
140
 
113
    THREAD->cur_event = UDEBUG_EVENT_SYSCALL;
141
    THREAD->cur_event = UDEBUG_EVENT_SYSCALL;
114
    spinlock_unlock(&THREAD->debug_lock);
142
    spinlock_unlock(&THREAD->debug_lock);
115
 
143
 
116
    spinlock_lock(&TASK->lock);
144
    spinlock_lock(&TASK->lock);
117
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
145
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
118
    spinlock_unlock(&TASK->lock);
146
    spinlock_unlock(&TASK->lock);
119
 
147
 
120
    interrupts_restore(ipl);
148
    interrupts_restore(ipl);
121
 
149
 
122
    waitq_sleep(&THREAD->go_wq);
150
    waitq_sleep(&THREAD->go_wq);
123
}
151
}
124
 
152
 
125
void udebug_new_thread_event(struct thread *t)
153
void udebug_new_thread_event(struct thread *t)
126
{
154
{
127
    call_t *call;
155
    call_t *call;
128
    ipl_t ipl;
156
    ipl_t ipl;
129
 
157
 
130
    ipl = interrupts_disable();
158
    ipl = interrupts_disable();
131
    spinlock_lock(&THREAD->debug_lock);
159
    spinlock_lock(&THREAD->debug_lock);
132
 
160
 
133
    klog_printf("udebug_new_thread_event");
161
    klog_printf("udebug_new_thread_event");
134
    klog_printf("- check state");
162
    klog_printf("- check state");
135
 
163
 
136
    /* Must only generate events when in debugging session */
164
    /* Must only generate events when in debugging session */
137
    if (THREAD->debug_active != true) {
165
    if (THREAD->debug_active != true) {
138
        klog_printf("- debug_active: %s, debug_stop: %s",
166
        klog_printf("- debug_active: %s, debug_stop: %s",
139
            THREAD->debug_active ? "yes(+)" : "no(-)",
167
            THREAD->debug_active ? "yes(+)" : "no(-)",
140
            THREAD->debug_stop ? "yes(-)" : "no(+)");
168
            THREAD->debug_stop ? "yes(-)" : "no(+)");
141
        spinlock_unlock(&THREAD->debug_lock);
169
        spinlock_unlock(&THREAD->debug_lock);
142
        interrupts_restore(ipl);
170
        interrupts_restore(ipl);
143
        return;
171
        return;
144
    }
172
    }
145
 
173
 
146
    klog_printf("- trigger event");
174
    klog_printf("- trigger event");
147
 
175
 
148
    call = THREAD->debug_go_call;
176
    call = THREAD->debug_go_call;
149
    IPC_SET_RETVAL(call->data, 0);
177
    IPC_SET_RETVAL(call->data, 0);
150
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
178
    IPC_SET_ARG1(call->data, UDEBUG_EVENT_NEW_THREAD);
151
    IPC_SET_ARG2(call->data, (unative_t)t);
179
    IPC_SET_ARG2(call->data, (unative_t)t);
152
 
180
 
153
    /*
181
    /*
154
     * Make sure debug_stop is true when going to sleep
182
     * Make sure debug_stop is true when going to sleep
155
     * in case we get woken up by DEBUG_END. (At which
183
     * in case we get woken up by DEBUG_END. (At which
156
     * point it must be back to the initial true value).
184
     * point it must be back to the initial true value).
157
     */
185
     */
158
    THREAD->debug_stop = true;
186
    THREAD->debug_stop = true;
159
 
187
 
160
    THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
188
    THREAD->cur_event = UDEBUG_EVENT_NEW_THREAD;
161
    spinlock_unlock(&THREAD->debug_lock);
189
    spinlock_unlock(&THREAD->debug_lock);
162
 
190
 
163
    spinlock_lock(&TASK->lock);
191
    spinlock_lock(&TASK->lock);
164
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
192
    ipc_answer(&TASK->answerbox, THREAD->debug_go_call);
165
    spinlock_unlock(&TASK->lock);
193
    spinlock_unlock(&TASK->lock);
166
 
194
 
167
    interrupts_restore(ipl);
195
    interrupts_restore(ipl);
168
    klog_printf("- sleep");
196
    klog_printf("- sleep");
169
 
197
 
170
    waitq_sleep(&THREAD->go_wq);
198
    waitq_sleep(&THREAD->go_wq);
171
}
199
}
172
 
200
 
173
/**
201
/**
174
 * Terminate task debugging session.
202
 * Terminate task debugging session.
175
 *
203
 *
176
 * \param ta Must be already locked and interrupts must be disabled.
204
 * \param ta Must be already locked and interrupts must be disabled.
177
 * \return Zero on success or negative error code.
205
 * \return Zero on success or negative error code.
178
 */
206
 */
179
int udebug_task_cleanup(struct task *ta)
207
int udebug_task_cleanup(struct task *ta)
180
{
208
{
181
    thread_t *t;
209
    thread_t *t;
182
    link_t *cur;
210
    link_t *cur;
183
    int flags;
211
    int flags;
184
 
212
 
185
    klog_printf("udebug_task_cleanup()");
213
    klog_printf("udebug_task_cleanup()");
186
    klog_printf("task %llu", ta->taskid);
214
    klog_printf("task %llu", ta->taskid);
187
 
215
 
188
    if (ta->dt_state == UDEBUG_TS_BEGINNING &&
216
    if (ta->dt_state == UDEBUG_TS_BEGINNING &&
189
        ta->dt_state != UDEBUG_TS_ACTIVE) {
217
        ta->dt_state != UDEBUG_TS_ACTIVE) {
190
        klog_printf("udebug_task_cleanup(): task not being debugged");
218
        klog_printf("udebug_task_cleanup(): task not being debugged");
191
        return EINVAL;
219
        return EINVAL;
192
    }
220
    }
193
 
221
 
194
    /* Finish debugging of all userspace threads */
222
    /* Finish debugging of all userspace threads */
195
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
223
    for (cur = ta->th_head.next; cur != &ta->th_head; cur = cur->next) {
196
        t = list_get_instance(cur, thread_t, th_link);
224
        t = list_get_instance(cur, thread_t, th_link);
197
 
225
 
198
        spinlock_lock(&t->debug_lock);
226
        spinlock_lock(&t->debug_lock);
199
        spinlock_lock(&t->lock);
227
        spinlock_lock(&t->lock);
200
 
228
 
201
        flags = t->flags;
229
        flags = t->flags;
202
 
230
 
203
        spinlock_unlock(&t->lock);
231
        spinlock_unlock(&t->lock);
204
 
232
 
205
        /* Only process userspace threads */
233
        /* Only process userspace threads */
206
        if ((flags & THREAD_FLAG_USPACE) != 0) {
234
        if ((flags & THREAD_FLAG_USPACE) != 0) {
207
            /* Prevent any further debug activity in thread */
235
            /* Prevent any further debug activity in thread */
208
            t->debug_active = false;
236
            t->debug_active = false;
209
            t->cur_event = 0;   /* none */
237
            t->cur_event = 0;   /* none */
210
 
238
 
211
            /* Still has go? */
239
            /* Still has go? */
212
            if (t->debug_stop == false) {
240
            if (t->debug_stop == false) {
213
                /*
241
                /*
214
                * Yes, so clear go. As debug_active == false,
242
                * Yes, so clear go. As debug_active == false,
215
                 * this doesn't affect anything.
243
                 * this doesn't affect anything.
216
                 */
244
                 */
217
                t->debug_stop = true;  
245
                t->debug_stop = true;  
218
 
246
 
219
                /* Answer GO call */
247
                /* Answer GO call */
220
                klog_printf("answer GO call with EVENT_FINISHED");
248
                klog_printf("answer GO call with EVENT_FINISHED");
221
                IPC_SET_RETVAL(t->debug_go_call->data, 0);
249
                IPC_SET_RETVAL(t->debug_go_call->data, 0);
222
                IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
250
                IPC_SET_ARG1(t->debug_go_call->data, UDEBUG_EVENT_FINISHED);
223
                ipc_answer(&ta->answerbox, t->debug_go_call);
251
                ipc_answer(&ta->answerbox, t->debug_go_call);
224
            } else {
252
            } else {
225
                /*
253
                /*
226
                 * Debug_stop is already at initial value.
254
                 * Debug_stop is already at initial value.
227
                 * Yet this means the thread needs waking up.
255
                 * Yet this means the thread needs waking up.
228
                 */
256
                 */
229
 
257
 
230
                /*
258
                /*
231
                 * t's lock must not be held when calling
259
                 * t's lock must not be held when calling
232
                 * waitq_wakeup.
260
                 * waitq_wakeup.
233
                 */
261
                 */
234
                waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
262
                waitq_wakeup(&t->go_wq, WAKEUP_FIRST);
235
            }
263
            }
236
        }
264
        }
237
        spinlock_unlock(&t->debug_lock);
265
        spinlock_unlock(&t->debug_lock);
238
    }
266
    }
239
 
267
 
240
    ta->dt_state = UDEBUG_TS_INACTIVE;
268
    ta->dt_state = UDEBUG_TS_INACTIVE;
241
    ta->debugger = NULL;
269
    ta->debugger = NULL;
242
 
270
 
243
    return 0;
271
    return 0;
244
}
272
}
245
 
273
 
246
 
274
 
247
/** @}
275
/** @}
248
 */
276
 */
249
 
277