Subversion Repositories HelenOS

Rev

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

Rev 3005 Rev 3008
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 debug
29
/** @addtogroup debug
30
 * @{
30
 * @{
31
 */
31
 */
32
/** @file
32
/** @file
33
 */
33
 */
34
 
34
 
35
#include <stdio.h>
35
#include <stdio.h>
36
#include <stdlib.h>
36
#include <stdlib.h>
37
#include <unistd.h>
37
#include <unistd.h>
38
#include <syscall.h>
38
#include <syscall.h>
39
#include <ipc/ipc.h>
39
#include <ipc/ipc.h>
40
#include <fibril.h>
40
#include <fibril.h>
41
#include <errno.h>
41
#include <errno.h>
42
#include <udebug.h>
42
#include <udebug.h>
43
#include <async.h>
43
#include <async.h>
44
#include <string.h>
44
#include <string.h>
45
 
45
 
46
#include "cmd.h"
46
#include "cmd.h"
47
#include "cons.h"
47
#include "cons.h"
48
#include "dthread.h"
48
#include "dthread.h"
49
#include "breakpoint.h"
49
#include "breakpoint.h"
50
#include "include/arch.h"
50
#include "include/arch.h"
51
#include "fib_synch.h"
-
 
52
#include "main.h"
51
#include "main.h"
53
 
52
 
54
void thread_debug_start(unsigned thread_hash);
53
void thread_debug_start(unsigned thread_hash);
55
 
54
 
56
#define IN_BUF_SIZE 64
55
#define IN_BUF_SIZE 64
57
static char in_buf[IN_BUF_SIZE];
56
static char in_buf[IN_BUF_SIZE];
58
 
57
 
59
#define MAX_ARGC 10
58
#define MAX_ARGC 10
60
int cmd_argc;
59
int cmd_argc;
61
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
60
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
62
 
61
 
63
 
62
 
64
int next_thread_id;
63
int next_thread_id;
65
 
64
 
66
int app_phone;
65
int app_phone;
67
volatile bool abort_debug;
66
volatile bool abort_debug;
68
 
67
 
69
volatile int paused;
68
volatile int paused;
70
 
69
 
71
fcv_t go_cv;
-
 
72
 
-
 
73
static void command_split(char *cmd_str)
70
static void command_split(char *cmd_str)
74
{
71
{
75
    char *p = cmd_str;
72
    char *p = cmd_str;
76
 
73
 
77
    if (*p == '\0') {
74
    if (*p == '\0') {
78
        cmd_argc = 0;
75
        cmd_argc = 0;
79
        return;
76
        return;
80
    }
77
    }
81
 
78
 
82
    cmd_argc = 1;
79
    cmd_argc = 1;
83
    cmd_argv[0] = p;
80
    cmd_argv[0] = p;
84
 
81
 
85
    while (*p != '\0') {
82
    while (*p != '\0') {
86
        if (*p == ' ') {
83
        if (*p == ' ') {
87
            cmd_argv[cmd_argc++] = p + 1;
84
            cmd_argv[cmd_argc++] = p + 1;
88
            *p = '\0';
85
            *p = '\0';
89
        }
86
        }
90
        ++p;
87
        ++p;
91
    }
88
    }
92
}
89
}
93
 
90
 
94
static void command_run(void)
91
static void command_run(void)
95
{
92
{
96
    int i;
93
    int i;
97
    int cmp_len;
94
    int cmp_len;
98
    int len;
95
    int len;
99
 
96
 
100
    int idx_found;
97
    int idx_found;
101
    int num_found;
98
    int num_found;
102
 
99
 
103
    len = strlen(cmd_argv[0]);
100
    len = strlen(cmd_argv[0]);
104
    cmp_len = 1;
101
    cmp_len = 1;
105
 
102
 
106
    /* Silence warnings */
103
    /* Silence warnings */
107
    num_found = 0;
104
    num_found = 0;
108
    idx_found = 0;
105
    idx_found = 0;
109
 
106
 
110
    while (cmp_len <= len + 1) {
107
    while (cmp_len <= len + 1) {
111
 
108
 
112
        num_found = 0;
109
        num_found = 0;
113
        i = 0;
110
        i = 0;
114
        while (cmd_table[i].name != NULL) {
111
        while (cmd_table[i].name != NULL) {
115
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
112
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
116
                idx_found = i;
113
                idx_found = i;
117
                ++num_found;
114
                ++num_found;
118
            }
115
            }
119
            ++i;
116
            ++i;
120
        }
117
        }
121
 
118
 
122
        if (num_found < 2) break;
119
        if (num_found < 2) break;
123
 
120
 
124
        ++cmp_len;
121
        ++cmp_len;
125
    }
122
    }
126
 
123
 
127
    if (num_found == 0) {
124
    if (num_found == 0) {
128
        cons_printf("Unknown command. Try one of:\n");
125
        cons_printf("Unknown command. Try one of:\n");
129
        cmd_help(0, NULL);
126
        cmd_help(0, NULL);
130
        return;
127
        return;
131
    }
128
    }
132
 
129
 
133
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
130
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
134
        cons_printf("Command '%s' expects %d arguments\n",
131
        cons_printf("Command '%s' expects %d arguments\n",
135
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
132
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
136
        return;
133
        return;
137
    }
134
    }
138
 
135
 
139
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
136
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
140
}
137
}
141
 
138
 
142
static void thread_stop(void)
139
static void thread_stop(void)
143
{
140
{
144
    dthread_t *dt;
141
    dthread_t *dt;
145
    uintptr_t pc;
142
    uintptr_t pc;
146
 
143
 
147
    dt = dthread_get();
144
    dt = dthread_get();
148
    pc = dthread_get_pc(dt);
145
    pc = dthread_get_pc(dt);
149
    cons_printf("[thread %d] stopped at 0x%lx\n", dt->id, pc);
146
    cons_printf("[thread %d] stopped at 0x%lx\n", dt->id, pc);
150
    dthread_stop_me();
147
    dthread_stop_me();
151
    cons_printf("[thread %d] go\n", dt->id);
148
    cons_printf("[thread %d] go\n", dt->id);
152
}
149
}
153
 
150
 
154
/*
151
/*
155
 * Called by a fibril (from arch code) when a breakpoint is hit.
152
 * Called by a fibril (from arch code) when a breakpoint is hit.
156
 */
153
 */
157
void breakpoint_hit(breakpoint_t *b)
154
void breakpoint_hit(breakpoint_t *b)
158
{
155
{
159
    dthread_t *dt;
156
    dthread_t *dt;
160
 
157
 
161
    dt = dthread_get();
158
    dt = dthread_get();
162
    cons_printf("Thread %d hit breakpoint %d at 0x%lx\n",
159
    cons_printf("Thread %d hit breakpoint %d at 0x%lx\n",
163
        dt->id, b->id, b->addr);
160
        dt->id, b->id, b->addr);
164
    thread_stop();
161
    thread_stop();
165
}
162
}
166
 
163
 
167
/*
164
/*
168
 * Called by a fibril (from arch code) when a single instruction
165
 * Called by a fibril (from arch code) when a single instruction
169
 * in singlestep is executed
166
 * in singlestep is executed
170
 */
167
 */
171
void singlestep_hit(void)
168
void singlestep_hit(void)
172
{
169
{
173
    cons_printf("singlestep hit\n");
170
    cons_printf("singlestep hit\n");
174
    thread_stop();
171
    thread_stop();
175
}
172
}
176
 
173
 
177
static int task_connect(int taskid)
174
static int task_connect(int taskid)
178
{
175
{
179
    int rc;
176
    int rc;
180
    unsigned evmask;
177
    unsigned evmask;
181
 
178
 
182
    cons_printf("ipc_connect_kbox(%d)... ", taskid);
179
    cons_printf("ipc_connect_kbox(%d)... ", taskid);
183
    rc = ipc_connect_kbox(taskid);
180
    rc = ipc_connect_kbox(taskid);
184
    cons_printf("-> %d\n", rc);
181
    cons_printf("-> %d\n", rc);
185
    app_phone = rc;
182
    app_phone = rc;
186
    if (rc < 0) return rc;
183
    if (rc < 0) return rc;
187
 
184
 
188
    cons_printf("udebug_begin()... ");
185
    cons_printf("udebug_begin()... ");
189
    rc = udebug_begin(app_phone);
186
    rc = udebug_begin(app_phone);
190
    cons_printf("-> %d\n", rc);
187
    cons_printf("-> %d\n", rc);
191
    if (rc < 0) return rc;
188
    if (rc < 0) return rc;
192
 
189
 
193
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
190
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
194
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
191
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
195
    rc = udebug_set_evmask(app_phone, evmask);
192
    rc = udebug_set_evmask(app_phone, evmask);
196
    cons_printf("-> %d\n", rc);
193
    cons_printf("-> %d\n", rc);
197
    if (rc < 0) return rc;
194
    if (rc < 0) return rc;
198
 
195
 
199
    return 0;
196
    return 0;
200
}
197
}
201
 
198
 
202
#define THASH_BUF_INIT_LENGTH 32
199
#define THASH_BUF_INIT_LENGTH 32
203
 
200
 
204
static int get_thread_list(thash_t **thash_buf_ptr, int *n)
201
static int get_thread_list(thash_t **thash_buf_ptr, int *n)
205
{
202
{
206
    int rc;
203
    int rc;
207
    size_t tb_copied;
204
    size_t tb_copied;
208
    size_t tb_needed;
205
    size_t tb_needed;
209
    int i;
206
    int i;
210
    size_t tb_size;
207
    size_t tb_size;
211
    thash_t *thash_buf;
208
    thash_t *thash_buf;
212
 
209
 
213
    tb_size = THASH_BUF_INIT_LENGTH * sizeof(thash_t);
210
    tb_size = THASH_BUF_INIT_LENGTH * sizeof(thash_t);
214
    thash_buf = malloc(tb_size);
211
    thash_buf = malloc(tb_size);
215
 
212
 
216
    rc = udebug_thread_read(app_phone, thash_buf,
213
    rc = udebug_thread_read(app_phone, thash_buf,
217
        tb_size, &tb_copied, &tb_needed);
214
        tb_size, &tb_copied, &tb_needed);
218
    if (rc < 0) return rc;
215
    if (rc < 0) return rc;
219
 
216
 
220
    if (tb_needed > tb_size) {
217
    if (tb_needed > tb_size) {
221
        /* Larger buffer needed  */
218
        /* Larger buffer needed  */
222
 
219
 
223
        free(thash_buf);
220
        free(thash_buf);
224
 
221
 
225
        tb_size = tb_needed;
222
        tb_size = tb_needed;
226
        thash_buf = malloc(tb_size);
223
        thash_buf = malloc(tb_size);
227
 
224
 
228
        if (!thash_buf) {
225
        if (!thash_buf) {
229
            printf("malloc failed\n");
226
            printf("malloc failed\n");
230
            exit(1);
227
            exit(1);
231
        }
228
        }
232
 
229
 
233
        /* Try again */
230
        /* Try again */
234
       
231
       
235
        rc = udebug_thread_read(app_phone, thash_buf,
232
        rc = udebug_thread_read(app_phone, thash_buf,
236
            tb_size, &tb_copied, &tb_needed);
233
            tb_size, &tb_copied, &tb_needed);
237
 
234
 
238
        if (rc < 0) return rc;
235
        if (rc < 0) return rc;
239
    }
236
    }
240
 
237
 
241
    *n = tb_copied / sizeof(thash_t);
238
    *n = tb_copied / sizeof(thash_t);
242
 
239
 
243
    cons_printf("thread hashes:");
240
    cons_printf("thread hashes:");
244
 
241
 
245
    for (i = 0; i < *n; ++i) {
242
    for (i = 0; i < *n; ++i) {
246
        cons_printf("0x%x\n", thash_buf[i]);
243
        cons_printf("0x%x\n", thash_buf[i]);
247
    }
244
    }
248
 
245
 
249
    cons_printf("Total of %u threads\n", *n);
246
    cons_printf("Total of %u threads\n", *n);
250
 
247
 
251
    *thash_buf_ptr = thash_buf;
248
    *thash_buf_ptr = thash_buf;
252
 
249
 
253
    return 0;
250
    return 0;
254
}
251
}
255
 
252
 
256
static void event_thread_b(unsigned hash)
253
static void event_thread_b(unsigned hash)
257
{
254
{
258
    async_serialize_start();
255
    async_serialize_start();
259
    cons_printf("new thread, hash 0x%x\n", hash);
256
    cons_printf("new thread, hash 0x%x\n", hash);
260
    async_serialize_end();
257
    async_serialize_end();
261
 
258
 
262
    thread_debug_start(hash);
259
    thread_debug_start(hash);
263
}
260
}
264
 
261
 
265
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
262
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
266
{
263
{
267
    switch (ev_type) {
264
    switch (ev_type) {
268
    case UDEBUG_EVENT_STOP:
265
    case UDEBUG_EVENT_STOP:
269
        cons_printf("stop event\n");
266
        cons_printf("stop event\n");
270
        thread_stop();
267
        thread_stop();
271
        break;
268
        break;
272
    case UDEBUG_EVENT_THREAD_B:
269
    case UDEBUG_EVENT_THREAD_B:
273
        event_thread_b(val0);
270
        event_thread_b(val0);
274
        break;
271
        break;
275
    case UDEBUG_EVENT_THREAD_E:
272
    case UDEBUG_EVENT_THREAD_E:
276
        cons_printf("thread 0x%x exited\n", val0);
273
        cons_printf("thread 0x%x exited\n", val0);
277
        abort_debug = true;
274
        abort_debug = true;
278
        break;
275
        break;
279
    case UDEBUG_EVENT_BREAKPOINT:
276
    case UDEBUG_EVENT_BREAKPOINT:
280
        arch_event_breakpoint(thash);
277
        arch_event_breakpoint(thash);
281
        break;
278
        break;
282
    case UDEBUG_EVENT_TRAP:
279
    case UDEBUG_EVENT_TRAP:
283
        arch_event_trap(dthread_get());
280
        arch_event_trap(dthread_get());
284
        break;
281
        break;
285
    default:
282
    default:
286
        cons_printf("unknown event type %d\n", ev_type);
283
        cons_printf("unknown event type %d\n", ev_type);
287
        break;
284
        break;
288
    }
285
    }
289
}
286
}
290
 
287
 
291
static int debug_loop(void *dt_arg)
288
static int debug_loop(void *dt_arg)
292
{
289
{
293
    int rc;
290
    int rc;
294
    udebug_event_t ev_type;
291
    udebug_event_t ev_type;
295
    unsigned val0, val1;
292
    unsigned val0, val1;
296
    dthread_t *dt;
293
    dthread_t *dt;
297
 
294
 
298
    dt = (dthread_t *)dt_arg;
295
    dt = (dthread_t *)dt_arg;
299
 
296
 
300
    cons_printf("debug_loop(%d)\n", dt->id);
297
    cons_printf("debug_loop(%d)\n", dt->id);
301
 
298
 
302
    while (!abort_debug) {
299
    while (!abort_debug) {
303
 
300
 
304
        /* Run thread until an event occurs */
301
        /* Run thread until an event occurs */
305
        rc = udebug_go(app_phone, dt->hash, &ev_type, &val0, &val1);
302
        rc = udebug_go(app_phone, dt->hash, &ev_type, &val0, &val1);
306
 
303
 
307
        if (ev_type == UDEBUG_EVENT_FINISHED) {
304
        if (ev_type == UDEBUG_EVENT_FINISHED) {
308
            cons_printf("thread %u debugging finished\n", dt->id);
305
            cons_printf("thread %u debugging finished\n", dt->id);
309
            break;
306
            break;
310
        }
307
        }
311
        if (rc >= 0) debug_event(dt->hash, ev_type, val0);
308
        if (rc >= 0) debug_event(dt->hash, ev_type, val0);
312
    }
309
    }
313
 
310
 
314
    cons_printf("debug_loop(%d) exiting\n", dt->id);
311
    cons_printf("debug_loop(%d) exiting\n", dt->id);
315
    return 0;
312
    return 0;
316
}
313
}
317
 
314
 
318
void thread_debug_start(unsigned thash)
315
void thread_debug_start(unsigned thash)
319
{
316
{
320
    fid_t fid;
317
    fid_t fid;
321
    dthread_t *dt;
318
    dthread_t *dt;
322
 
319
 
323
    dt = dthread_new(thash);
320
    dt = dthread_new(thash);
324
 
321
 
325
    fid = fibril_create(debug_loop, (void *)dt);
322
    fid = fibril_create(debug_loop, (void *)dt);
326
    if (fid == 0) {
323
    if (fid == 0) {
327
        cons_printf("Warning: Failed creating fibril\n");
324
        cons_printf("Warning: Failed creating fibril\n");
328
    }
325
    }
329
    dt->fid = fid;
326
    dt->fid = fid;
330
 
327
 
331
    fibril_add_ready(fid);
328
    fibril_add_ready(fid);
332
}
329
}
333
 
330
 
334
static void debug_active_task(void)
331
static void debug_active_task(void)
335
{
332
{
336
    int taskid;
333
    int taskid;
337
    int i;
334
    int i;
338
    int rc;
335
    int rc;
339
 
336
 
340
    thash_t *thash_buffer;
337
    thash_t *thash_buffer;
341
    int n_threads;
338
    int n_threads;
342
 
339
 
343
    cons_printf("Breakpoint Debugger\n");
340
    cons_printf("Breakpoint Debugger\n");
344
    cons_printf("Press 'c' to connect\n");
341
    cons_printf("Press 'c' to connect\n");
345
    while ((i = getchar()) != 'c')
342
    while ((i = getchar()) != 'c')
346
        putchar(i);
343
        putchar(i);
347
 
344
 
348
    taskid = 14;
345
    taskid = 14;
349
    rc = task_connect(taskid);
346
    rc = task_connect(taskid);
350
    if (rc < 0) {
347
    if (rc < 0) {
351
        cons_printf("Failed to connect to task %d\n", taskid);
348
        cons_printf("Failed to connect to task %d\n", taskid);
352
        return;
349
        return;
353
    }
350
    }
354
 
351
 
355
    cons_printf("Connected to task %d\n", taskid);
352
    cons_printf("Connected to task %d\n", taskid);
356
 
353
 
357
    rc = get_thread_list(&thash_buffer, &n_threads);
354
    rc = get_thread_list(&thash_buffer, &n_threads);
358
    if (rc < 0) {
355
    if (rc < 0) {
359
        cons_printf("Failed to get thread list\n", rc);
356
        cons_printf("Failed to get thread list\n", rc);
360
        return;
357
        return;
361
    }
358
    }
362
 
359
 
363
    abort_debug = false;
360
    abort_debug = false;
364
 
361
 
365
    for (i = 0; i < n_threads; i++) {
362
    for (i = 0; i < n_threads; i++) {
366
        thread_debug_start(thash_buffer[i]);
363
        thread_debug_start(thash_buffer[i]);
367
    }
364
    }
368
 
365
 
369
    while (!quit) {
366
    while (!quit) {
370
        cons_read_line(in_buf, IN_BUF_SIZE);
367
        cons_read_line(in_buf, IN_BUF_SIZE);
371
        command_split(in_buf);
368
        command_split(in_buf);
372
        if (cmd_argc == 0) continue;
369
        if (cmd_argc == 0) continue;
373
 
370
 
374
        command_run();
371
        command_run();
375
    }
372
    }
376
 
373
 
377
    cons_printf("terminate debugging session...\n");
374
    cons_printf("terminate debugging session...\n");
378
    abort_debug = true;
375
    abort_debug = true;
379
    udebug_end(app_phone);
376
    udebug_end(app_phone);
380
    ipc_hangup(app_phone);
377
    ipc_hangup(app_phone);
381
 
378
 
382
    cons_printf("done\n");
379
    cons_printf("done\n");
383
    return;
380
    return;
384
}
381
}
385
 
382
 
386
static void main_init(void)
383
static void main_init(void)
387
{
384
{
388
    next_thread_id = 1;
385
    next_thread_id = 1;
389
    paused = 0;
386
    paused = 0;
390
   
387
   
391
    list_initialize(&dthreads);
388
    list_initialize(&dthreads);
392
    breakpoint_init();
389
    breakpoint_init();
393
    cwt = NULL;
390
    cwt = NULL;
394
 
-
 
395
    fcv_init(&go_cv);
-
 
396
}
391
}
397
 
392
 
398
int main(void)
393
int main(void)
399
{
394
{
400
    main_init();
395
    main_init();
401
 
396
 
402
    while (1) {
397
    while (1) {
403
        debug_active_task();
398
        debug_active_task();
404
    }
399
    }
405
}
400
}
406
 
401
 
407
/** @}
402
/** @}
408
 */
403
 */
409
 
404