Subversion Repositories HelenOS

Rev

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

Rev 3536 Rev 3597
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 <libarch/syscall.h>
38
#include <libarch/syscall.h>
39
#include <ipc/ipc.h>
39
#include <ipc/ipc.h>
40
#include <fibril.h>
40
#include <fibril.h>
41
#include <loader/loader.h>
41
#include <loader/loader.h>
42
#include <errno.h>
42
#include <errno.h>
43
#include <udebug.h>
43
#include <udebug.h>
44
#include <async.h>
44
#include <async.h>
45
#include <string.h>
45
#include <string.h>
46
 
46
 
47
#include "cmd.h"
47
#include "cmd.h"
48
#include "cons.h"
48
#include "cons.h"
49
#include "dthread.h"
49
#include "dthread.h"
50
#include "breakpoint.h"
50
#include "breakpoint.h"
51
#include "include/arch.h"
51
#include "include/arch.h"
52
#include "main.h"
52
#include "main.h"
53
 
53
 
54
void thread_debug_start(unsigned thread_hash);
54
void thread_debug_start(unsigned thread_hash);
55
 
55
 
56
#define IN_BUF_SIZE 64
56
#define IN_BUF_SIZE 64
57
static char in_buf[IN_BUF_SIZE];
57
static char in_buf[IN_BUF_SIZE];
58
 
58
 
59
#define MAX_ARGC 10
59
#define MAX_ARGC 10
60
int cmd_argc;
60
int cmd_argc;
61
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
61
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
62
 
62
 
63
 
63
 
64
int next_thread_id;
64
int next_thread_id;
65
 
65
 
66
int app_phone;
66
int app_phone;
67
volatile bool abort_debug;
67
volatile bool abort_debug;
68
 
68
 
69
volatile int paused;
69
volatile int paused;
70
 
70
 
71
static task_id_t task_id;
71
static task_id_t task_id;
72
static loader_t *task_ldr;
72
static loader_t *task_ldr;
73
 
73
 
74
static int program_run_fibril(void *arg);
74
static int program_run_fibril(void *arg);
75
 
75
 
76
static void program_run(void)
76
static void program_run(void)
77
{
77
{
78
    fid_t fid;
78
    fid_t fid;
79
 
79
 
80
    fid = fibril_create(program_run_fibril, NULL);
80
    fid = fibril_create(program_run_fibril, NULL);
81
    if (fid == 0) {
81
    if (fid == 0) {
82
        printf("Error creating fibril\n");
82
        printf("Error creating fibril\n");
83
        exit(1);
83
        exit(1);
84
    }
84
    }
85
 
85
 
86
    fibril_add_ready(fid);
86
    fibril_add_ready(fid);
87
}
87
}
88
 
88
 
89
static int program_run_fibril(void *arg)
89
static int program_run_fibril(void *arg)
90
{
90
{
91
    int rc;
91
    int rc;
92
 
92
 
93
    /*
93
    /*
94
     * This must be done in background as it will block until
94
     * This must be done in background as it will block until
95
     * we let the task reply to this call.
95
     * we let the task reply to this call.
96
     */
96
     */
97
    rc = loader_run(task_ldr);
97
    rc = loader_run(task_ldr);
98
    if (rc != 0) {
98
    if (rc != 0) {
99
        printf("Error running program\n");
99
        printf("Error running program\n");
100
        exit(1);
100
        exit(1);
101
    }
101
    }
102
 
102
 
103
    free(task_ldr);
103
    free(task_ldr);
104
    task_ldr = NULL;
104
    task_ldr = NULL;
105
 
105
 
106
    return 0;
106
    return 0;
107
}
107
}
108
 
108
 
109
static loader_t *preload_task(const char *path, char *const argv[],
109
static loader_t *preload_task(const char *path, char *const argv[],
110
    task_id_t *task_id)
110
    task_id_t *task_id)
111
{
111
{
112
    loader_t *ldr;
112
    loader_t *ldr;
113
    int rc;
113
    int rc;
114
 
114
 
115
    /* Spawn a program loader */   
115
    /* Spawn a program loader */   
116
    ldr = loader_spawn();
116
    ldr = loader_spawn(path);
117
    if (ldr == NULL)
117
    if (ldr == NULL)
118
        return 0;
118
        return 0;
119
 
119
 
120
    /* Get task ID. */
120
    /* Get task ID. */
121
    rc = loader_get_task_id(ldr, task_id);
121
    rc = loader_get_task_id(ldr, task_id);
122
    if (rc != EOK)
122
    if (rc != EOK)
123
        goto error;
123
        goto error;
124
 
124
 
125
    /* Send program pathname */
125
    /* Send program pathname */
126
    rc = loader_set_pathname(ldr, path);
126
    rc = loader_set_pathname(ldr, path);
127
    if (rc != EOK)
127
    if (rc != EOK)
128
        goto error;
128
        goto error;
129
 
129
 
130
    /* Send arguments */
130
    /* Send arguments */
131
    rc = loader_set_args(ldr, argv);
131
    rc = loader_set_args(ldr, argv);
132
    if (rc != EOK)
132
    if (rc != EOK)
133
        goto error;
133
        goto error;
134
 
134
 
135
    /* Load the program. */
135
    /* Load the program. */
136
    rc = loader_load_program(ldr);
136
    rc = loader_load_program(ldr);
137
    if (rc != EOK)
137
    if (rc != EOK)
138
        goto error;
138
        goto error;
139
 
139
 
140
    /* Success */
140
    /* Success */
141
    return ldr;
141
    return ldr;
142
 
142
 
143
    /* Error exit */
143
    /* Error exit */
144
error:
144
error:
145
    loader_abort(ldr);
145
    loader_abort(ldr);
146
    free(ldr);
146
    free(ldr);
147
    return NULL;
147
    return NULL;
148
}
148
}
149
 
149
 
150
 
150
 
151
static void command_split(char *cmd_str)
151
static void command_split(char *cmd_str)
152
{
152
{
153
    char *p = cmd_str;
153
    char *p = cmd_str;
154
 
154
 
155
    if (*p == '\0') {
155
    if (*p == '\0') {
156
        cmd_argc = 0;
156
        cmd_argc = 0;
157
        return;
157
        return;
158
    }
158
    }
159
 
159
 
160
    cmd_argc = 1;
160
    cmd_argc = 1;
161
    cmd_argv[0] = p;
161
    cmd_argv[0] = p;
162
 
162
 
163
    while (*p != '\0') {
163
    while (*p != '\0') {
164
        if (*p == ' ') {
164
        if (*p == ' ') {
165
            cmd_argv[cmd_argc++] = p + 1;
165
            cmd_argv[cmd_argc++] = p + 1;
166
            *p = '\0';
166
            *p = '\0';
167
        }
167
        }
168
        ++p;
168
        ++p;
169
    }
169
    }
170
}
170
}
171
 
171
 
172
static void command_run(void)
172
static void command_run(void)
173
{
173
{
174
    int i;
174
    int i;
175
    int cmp_len;
175
    int cmp_len;
176
    int len;
176
    int len;
177
 
177
 
178
    int idx_found;
178
    int idx_found;
179
    int num_found;
179
    int num_found;
180
 
180
 
181
    len = strlen(cmd_argv[0]);
181
    len = strlen(cmd_argv[0]);
182
    cmp_len = 1;
182
    cmp_len = 1;
183
 
183
 
184
    /* Silence warnings */
184
    /* Silence warnings */
185
    num_found = 0;
185
    num_found = 0;
186
    idx_found = 0;
186
    idx_found = 0;
187
 
187
 
188
    while (cmp_len <= len + 1) {
188
    while (cmp_len <= len + 1) {
189
 
189
 
190
        num_found = 0;
190
        num_found = 0;
191
        i = 0;
191
        i = 0;
192
        while (cmd_table[i].name != NULL) {
192
        while (cmd_table[i].name != NULL) {
193
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
193
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
194
                idx_found = i;
194
                idx_found = i;
195
                ++num_found;
195
                ++num_found;
196
            }
196
            }
197
            ++i;
197
            ++i;
198
        }
198
        }
199
 
199
 
200
        if (num_found < 2) break;
200
        if (num_found < 2) break;
201
 
201
 
202
        ++cmp_len;
202
        ++cmp_len;
203
    }
203
    }
204
 
204
 
205
    if (num_found == 0) {
205
    if (num_found == 0) {
206
        cons_printf("Unknown command. Try one of:\n");
206
        cons_printf("Unknown command. Try one of:\n");
207
        cmd_help(0, NULL);
207
        cmd_help(0, NULL);
208
        return;
208
        return;
209
    }
209
    }
210
 
210
 
211
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
211
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
212
        cons_printf("Command '%s' expects %d arguments\n",
212
        cons_printf("Command '%s' expects %d arguments\n",
213
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
213
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
214
        return;
214
        return;
215
    }
215
    }
216
 
216
 
217
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
217
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
218
}
218
}
219
 
219
 
220
static void thread_stop(void)
220
static void thread_stop(void)
221
{
221
{
222
    dthread_t *dt;
222
    dthread_t *dt;
223
    uintptr_t pc;
223
    uintptr_t pc;
224
 
224
 
225
    dt = dthread_get();
225
    dt = dthread_get();
226
    pc = dthread_get_pc(dt);
226
    pc = dthread_get_pc(dt);
227
    cons_printf("[thread %d] stopped at 0x%lx\n", dt->id, pc);
227
    cons_printf("[thread %d] stopped at 0x%lx\n", dt->id, pc);
228
    dthread_stop_me();
228
    dthread_stop_me();
229
    cons_printf("[thread %d] go\n", dt->id);
229
    cons_printf("[thread %d] go\n", dt->id);
230
}
230
}
231
 
231
 
232
/*
232
/*
233
 * Called by a fibril (from arch code) when a breakpoint is hit.
233
 * Called by a fibril (from arch code) when a breakpoint is hit.
234
 */
234
 */
235
void breakpoint_hit(breakpoint_t *b)
235
void breakpoint_hit(breakpoint_t *b)
236
{
236
{
237
    dthread_t *dt;
237
    dthread_t *dt;
238
 
238
 
239
    dt = dthread_get();
239
    dt = dthread_get();
240
    cons_printf("Thread %d hit breakpoint %d at 0x%lx\n",
240
    cons_printf("Thread %d hit breakpoint %d at 0x%lx\n",
241
        dt->id, b->id, b->addr);
241
        dt->id, b->id, b->addr);
242
    thread_stop();
242
    thread_stop();
243
}
243
}
244
 
244
 
245
/*
245
/*
246
 * Called by a fibril (from arch code) when a single instruction
246
 * Called by a fibril (from arch code) when a single instruction
247
 * in singlestep is executed
247
 * in singlestep is executed
248
 */
248
 */
249
void singlestep_hit(void)
249
void singlestep_hit(void)
250
{
250
{
251
    cons_printf("singlestep hit\n");
251
    cons_printf("singlestep hit\n");
252
    thread_stop();
252
    thread_stop();
253
}
253
}
254
 
254
 
255
static int connect_task(task_id_t task_id)
255
static int connect_task(task_id_t task_id)
256
{
256
{
257
    int rc;
257
    int rc;
258
    unsigned evmask;
258
    unsigned evmask;
259
 
259
 
260
    cons_printf("ipc_connect_kbox(%;;d)... ", task_id);
260
    cons_printf("ipc_connect_kbox(%;;d)... ", task_id);
261
    rc = ipc_connect_kbox(task_id);
261
    rc = ipc_connect_kbox(task_id);
262
    cons_printf("-> %d\n", rc);
262
    cons_printf("-> %d\n", rc);
263
    app_phone = rc;
263
    app_phone = rc;
264
    if (rc < 0) return rc;
264
    if (rc < 0) return rc;
265
 
265
 
266
    cons_printf("udebug_begin()... ");
266
    cons_printf("udebug_begin()... ");
267
    rc = udebug_begin(app_phone);
267
    rc = udebug_begin(app_phone);
268
    cons_printf("-> %d\n", rc);
268
    cons_printf("-> %d\n", rc);
269
    if (rc < 0) return rc;
269
    if (rc < 0) return rc;
270
 
270
 
271
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
271
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
272
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
272
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
273
    rc = udebug_set_evmask(app_phone, evmask);
273
    rc = udebug_set_evmask(app_phone, evmask);
274
    cons_printf("-> %d\n", rc);
274
    cons_printf("-> %d\n", rc);
275
    if (rc < 0) return rc;
275
    if (rc < 0) return rc;
276
 
276
 
277
    return 0;
277
    return 0;
278
}
278
}
279
 
279
 
280
#define THASH_BUF_INIT_LENGTH 32
280
#define THASH_BUF_INIT_LENGTH 32
281
 
281
 
282
static int get_thread_list(thash_t **thash_buf_ptr, int *n)
282
static int get_thread_list(thash_t **thash_buf_ptr, int *n)
283
{
283
{
284
    int rc;
284
    int rc;
285
    size_t tb_copied;
285
    size_t tb_copied;
286
    size_t tb_needed;
286
    size_t tb_needed;
287
    int i;
287
    int i;
288
    size_t tb_size;
288
    size_t tb_size;
289
    thash_t *thash_buf;
289
    thash_t *thash_buf;
290
 
290
 
291
    tb_size = THASH_BUF_INIT_LENGTH * sizeof(thash_t);
291
    tb_size = THASH_BUF_INIT_LENGTH * sizeof(thash_t);
292
    thash_buf = malloc(tb_size);
292
    thash_buf = malloc(tb_size);
293
 
293
 
294
    rc = udebug_thread_read(app_phone, thash_buf,
294
    rc = udebug_thread_read(app_phone, thash_buf,
295
        tb_size, &tb_copied, &tb_needed);
295
        tb_size, &tb_copied, &tb_needed);
296
    if (rc < 0) return rc;
296
    if (rc < 0) return rc;
297
 
297
 
298
    if (tb_needed > tb_size) {
298
    if (tb_needed > tb_size) {
299
        /* Larger buffer needed  */
299
        /* Larger buffer needed  */
300
 
300
 
301
        free(thash_buf);
301
        free(thash_buf);
302
 
302
 
303
        tb_size = tb_needed;
303
        tb_size = tb_needed;
304
        thash_buf = malloc(tb_size);
304
        thash_buf = malloc(tb_size);
305
 
305
 
306
        if (!thash_buf) {
306
        if (!thash_buf) {
307
            printf("malloc failed\n");
307
            printf("malloc failed\n");
308
            exit(1);
308
            exit(1);
309
        }
309
        }
310
 
310
 
311
        /* Try again */
311
        /* Try again */
312
       
312
       
313
        rc = udebug_thread_read(app_phone, thash_buf,
313
        rc = udebug_thread_read(app_phone, thash_buf,
314
            tb_size, &tb_copied, &tb_needed);
314
            tb_size, &tb_copied, &tb_needed);
315
 
315
 
316
        if (rc < 0) return rc;
316
        if (rc < 0) return rc;
317
    }
317
    }
318
 
318
 
319
    *n = tb_copied / sizeof(thash_t);
319
    *n = tb_copied / sizeof(thash_t);
320
 
320
 
321
    cons_printf("thread hashes:");
321
    cons_printf("thread hashes:");
322
 
322
 
323
    for (i = 0; i < *n; ++i) {
323
    for (i = 0; i < *n; ++i) {
324
        cons_printf("0x%x\n", thash_buf[i]);
324
        cons_printf("0x%x\n", thash_buf[i]);
325
    }
325
    }
326
 
326
 
327
    cons_printf("Total of %u threads\n", *n);
327
    cons_printf("Total of %u threads\n", *n);
328
 
328
 
329
    *thash_buf_ptr = thash_buf;
329
    *thash_buf_ptr = thash_buf;
330
 
330
 
331
    return 0;
331
    return 0;
332
}
332
}
333
 
333
 
334
static void event_thread_b(unsigned hash)
334
static void event_thread_b(unsigned hash)
335
{
335
{
336
    async_serialize_start();
336
    async_serialize_start();
337
    cons_printf("new thread, hash 0x%x\n", hash);
337
    cons_printf("new thread, hash 0x%x\n", hash);
338
    async_serialize_end();
338
    async_serialize_end();
339
 
339
 
340
    thread_debug_start(hash);
340
    thread_debug_start(hash);
341
}
341
}
342
 
342
 
343
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
343
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
344
{
344
{
345
    switch (ev_type) {
345
    switch (ev_type) {
346
    case UDEBUG_EVENT_STOP:
346
    case UDEBUG_EVENT_STOP:
347
        cons_printf("stop event\n");
347
        cons_printf("stop event\n");
348
        thread_stop();
348
        thread_stop();
349
        break;
349
        break;
350
    case UDEBUG_EVENT_THREAD_B:
350
    case UDEBUG_EVENT_THREAD_B:
351
        event_thread_b(val0);
351
        event_thread_b(val0);
352
        break;
352
        break;
353
    case UDEBUG_EVENT_THREAD_E:
353
    case UDEBUG_EVENT_THREAD_E:
354
        cons_printf("thread 0x%x exited\n", val0);
354
        cons_printf("thread 0x%x exited\n", val0);
355
        abort_debug = true;
355
        abort_debug = true;
356
        break;
356
        break;
357
    case UDEBUG_EVENT_BREAKPOINT:
357
    case UDEBUG_EVENT_BREAKPOINT:
358
        arch_event_breakpoint(thash);
358
        arch_event_breakpoint(thash);
359
        break;
359
        break;
360
    case UDEBUG_EVENT_TRAP:
360
    case UDEBUG_EVENT_TRAP:
361
        arch_event_trap(dthread_get());
361
        arch_event_trap(dthread_get());
362
        break;
362
        break;
363
    default:
363
    default:
364
        cons_printf("unknown event type %d\n", ev_type);
364
        cons_printf("unknown event type %d\n", ev_type);
365
        break;
365
        break;
366
    }
366
    }
367
}
367
}
368
 
368
 
369
static int debug_loop(void *dt_arg)
369
static int debug_loop(void *dt_arg)
370
{
370
{
371
    int rc;
371
    int rc;
372
    udebug_event_t ev_type;
372
    udebug_event_t ev_type;
373
    unsigned val0, val1;
373
    unsigned val0, val1;
374
    dthread_t *dt;
374
    dthread_t *dt;
375
 
375
 
376
    dt = (dthread_t *)dt_arg;
376
    dt = (dthread_t *)dt_arg;
377
 
377
 
378
    cons_printf("debug_loop(%d)\n", dt->id);
378
    cons_printf("debug_loop(%d)\n", dt->id);
379
 
379
 
380
    while (!abort_debug) {
380
    while (!abort_debug) {
381
 
381
 
382
        /* Run thread until an event occurs */
382
        /* Run thread until an event occurs */
383
        rc = udebug_go(app_phone, dt->hash, &ev_type, &val0, &val1);
383
        rc = udebug_go(app_phone, dt->hash, &ev_type, &val0, &val1);
384
 
384
 
385
        if (ev_type == UDEBUG_EVENT_FINISHED) {
385
        if (ev_type == UDEBUG_EVENT_FINISHED) {
386
            cons_printf("thread %u debugging finished\n", dt->id);
386
            cons_printf("thread %u debugging finished\n", dt->id);
387
            break;
387
            break;
388
        }
388
        }
389
        if (rc >= 0) debug_event(dt->hash, ev_type, val0);
389
        if (rc >= 0) debug_event(dt->hash, ev_type, val0);
390
    }
390
    }
391
 
391
 
392
    cons_printf("debug_loop(%d) exiting\n", dt->id);
392
    cons_printf("debug_loop(%d) exiting\n", dt->id);
393
    return 0;
393
    return 0;
394
}
394
}
395
 
395
 
396
void thread_debug_start(unsigned thash)
396
void thread_debug_start(unsigned thash)
397
{
397
{
398
    fid_t fid;
398
    fid_t fid;
399
    dthread_t *dt;
399
    dthread_t *dt;
400
 
400
 
401
    dt = dthread_new(thash);
401
    dt = dthread_new(thash);
402
 
402
 
403
    fid = fibril_create(debug_loop, (void *)dt);
403
    fid = fibril_create(debug_loop, (void *)dt);
404
    if (fid == 0) {
404
    if (fid == 0) {
405
        cons_printf("Warning: Failed creating fibril\n");
405
        cons_printf("Warning: Failed creating fibril\n");
406
    }
406
    }
407
    dt->fid = fid;
407
    dt->fid = fid;
408
 
408
 
409
    fibril_add_ready(fid);
409
    fibril_add_ready(fid);
410
}
410
}
411
 
411
 
412
static void debug_task(task_id_t task_id)
412
static void debug_task(task_id_t task_id)
413
{
413
{
414
    int i;
414
    int i;
415
    int rc;
415
    int rc;
416
 
416
 
417
    thash_t *thash_buffer;
417
    thash_t *thash_buffer;
418
    int n_threads;
418
    int n_threads;
419
 
419
 
420
    rc = get_thread_list(&thash_buffer, &n_threads);
420
    rc = get_thread_list(&thash_buffer, &n_threads);
421
    if (rc < 0) {
421
    if (rc < 0) {
422
        cons_printf("Failed to get thread list\n", rc);
422
        cons_printf("Failed to get thread list\n", rc);
423
        return;
423
        return;
424
    }
424
    }
425
 
425
 
426
    abort_debug = false;
426
    abort_debug = false;
427
 
427
 
428
    for (i = 0; i < n_threads; i++) {
428
    for (i = 0; i < n_threads; i++) {
429
        thread_debug_start(thash_buffer[i]);
429
        thread_debug_start(thash_buffer[i]);
430
    }
430
    }
431
 
431
 
432
    while (!quit) {
432
    while (!quit) {
433
        cons_read_line(in_buf, IN_BUF_SIZE);
433
        cons_read_line(in_buf, IN_BUF_SIZE);
434
        command_split(in_buf);
434
        command_split(in_buf);
435
        if (cmd_argc == 0) continue;
435
        if (cmd_argc == 0) continue;
436
 
436
 
437
        command_run();
437
        command_run();
438
    }
438
    }
439
 
439
 
440
    cons_printf("terminate debugging session...\n");
440
    cons_printf("terminate debugging session...\n");
441
    abort_debug = true;
441
    abort_debug = true;
442
    udebug_end(app_phone);
442
    udebug_end(app_phone);
443
    ipc_hangup(app_phone);
443
    ipc_hangup(app_phone);
444
 
444
 
445
    cons_printf("done\n");
445
    cons_printf("done\n");
446
    return;
446
    return;
447
}
447
}
448
 
448
 
449
static void main_init(void)
449
static void main_init(void)
450
{
450
{
451
    next_thread_id = 1;
451
    next_thread_id = 1;
452
    paused = 0;
452
    paused = 0;
453
   
453
   
454
    list_initialize(&dthreads);
454
    list_initialize(&dthreads);
455
    breakpoint_init();
455
    breakpoint_init();
456
    cwt = NULL;
456
    cwt = NULL;
457
}
457
}
458
 
458
 
459
static void print_syntax()
459
static void print_syntax()
460
{
460
{
461
    printf("Syntax:\n");
461
    printf("Syntax:\n");
462
    printf("\tdebug <executable> [<arg1> [...]]\n");
462
    printf("\tdebug <executable> [<arg1> [...]]\n");
463
    printf("or\tdebug -t <task_id>\n");
463
    printf("or\tdebug -t <task_id>\n");
464
}
464
}
465
 
465
 
466
static int parse_args(int argc, char *argv[])
466
static int parse_args(int argc, char *argv[])
467
{
467
{
468
    char *arg;
468
    char *arg;
469
    char *err_p;
469
    char *err_p;
470
 
470
 
471
    task_id = 0;
471
    task_id = 0;
472
 
472
 
473
    --argc; ++argv;
473
    --argc; ++argv;
474
 
474
 
475
    while (argc > 0) {
475
    while (argc > 0) {
476
        arg = *argv;
476
        arg = *argv;
477
        if (arg[0] == '-') {
477
        if (arg[0] == '-') {
478
            if (arg[1] == 't') {
478
            if (arg[1] == 't') {
479
                /* Trace an already running task */
479
                /* Trace an already running task */
480
                --argc; ++argv;
480
                --argc; ++argv;
481
                task_id = strtol(*argv, &err_p, 10);
481
                task_id = strtol(*argv, &err_p, 10);
482
                task_ldr = NULL;
482
                task_ldr = NULL;
483
                if (*err_p) {
483
                if (*err_p) {
484
                    printf("Task ID syntax error\n");
484
                    printf("Task ID syntax error\n");
485
                    print_syntax();
485
                    print_syntax();
486
                    return -1;
486
                    return -1;
487
                }
487
                }
488
            } else {
488
            } else {
489
                printf("Uknown option '%s'\n", arg[0]);
489
                printf("Uknown option '%s'\n", arg[0]);
490
                print_syntax();
490
                print_syntax();
491
                return -1;
491
                return -1;
492
            }
492
            }
493
        } else {
493
        } else {
494
            break;
494
            break;
495
        }
495
        }
496
 
496
 
497
        --argc; ++argv;
497
        --argc; ++argv;
498
    }
498
    }
499
 
499
 
500
    if (task_id != 0) {
500
    if (task_id != 0) {
501
        if (argc == 0) return 0;
501
        if (argc == 0) return 0;
502
        printf("Extra arguments\n");
502
        printf("Extra arguments\n");
503
        print_syntax();
503
        print_syntax();
504
        return -1;
504
        return -1;
505
    }
505
    }
506
 
506
 
507
    if (argc < 1) {
507
    if (argc < 1) {
508
        printf("Missing argument\n");
508
        printf("Missing argument\n");
509
        print_syntax();
509
        print_syntax();
510
        return -1;
510
        return -1;
511
    }
511
    }
512
 
512
 
513
    /* Preload the specified program file. */
513
    /* Preload the specified program file. */
514
    printf("Spawning '%s' with arguments:\n", *argv);
514
    printf("Spawning '%s' with arguments:\n", *argv);
515
    {
515
    {
516
        char **cp = argv;
516
        char **cp = argv;
517
        while (*cp) printf("'%s'\n", *cp++);
517
        while (*cp) printf("'%s'\n", *cp++);
518
    }
518
    }
519
    task_ldr = preload_task(*argv, argv, &task_id);
519
    task_ldr = preload_task(*argv, argv, &task_id);
520
 
520
 
521
    return 0;
521
    return 0;
522
}
522
}
523
 
523
 
524
int main(int argc, char *argv[])
524
int main(int argc, char *argv[])
525
{
525
{
526
    int rc;
526
    int rc;
527
 
527
 
528
    cons_printf("Breakpoint Debugger\n");
528
    cons_printf("Breakpoint Debugger\n");
529
 
529
 
530
    main_init();
530
    main_init();
531
 
531
 
532
    if (parse_args(argc, argv) < 0)
532
    if (parse_args(argc, argv) < 0)
533
        return 1;
533
        return 1;
534
 
534
 
535
    rc = connect_task(task_id);
535
    rc = connect_task(task_id);
536
    if (rc < 0) {
536
    if (rc < 0) {
537
        printf("Failed connecting to task %lld\n", task_id);
537
        printf("Failed connecting to task %lld\n", task_id);
538
        return 1;
538
        return 1;
539
    }
539
    }
540
 
540
 
541
    cons_printf("Connected to task %lld\n", task_id);
541
    cons_printf("Connected to task %lld\n", task_id);
542
 
542
 
543
    if (task_ldr != NULL) {
543
    if (task_ldr != NULL) {
544
        program_run();
544
        program_run();
545
    }
545
    }
546
 
546
 
547
    debug_task(task_id);
547
    debug_task(task_id);
548
 
548
 
549
    return 0;
549
    return 0;
550
}
550
}
551
 
551
 
552
/** @}
552
/** @}
553
 */
553
 */
554
 
554