Subversion Repositories HelenOS

Rev

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

Rev 2936 Rev 2937
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 "include/arch.h"
48
#include "include/arch.h"
49
#include "fib_synch.h"
49
#include "fib_synch.h"
50
#include "main.h"
50
#include "main.h"
51
 
51
 
52
void thread_debug_start(unsigned thread_hash);
52
void thread_debug_start(unsigned thread_hash);
53
 
53
 
54
#define IN_BUF_SIZE 64
54
#define IN_BUF_SIZE 64
55
static char in_buf[IN_BUF_SIZE];
55
static char in_buf[IN_BUF_SIZE];
56
 
56
 
57
#define MAX_ARGC 10
57
#define MAX_ARGC 10
58
int cmd_argc;
58
int cmd_argc;
59
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
59
char *cmd_argv[MAX_ARGC + 1];   /* need one spare field for cmd_split() */
60
 
60
 
61
#define THBUF_SIZE 64
61
#define THBUF_SIZE 64
62
thash_t thread_hash_buf[THBUF_SIZE];
62
thash_t thread_hash_buf[THBUF_SIZE];
-
 
63
 
-
 
64
#define MAX_THREADS 64
-
 
65
thash_t thread_hash[MAX_THREADS];
-
 
66
int thread_id[MAX_THREADS];
63
unsigned n_threads;
67
unsigned n_threads;
-
 
68
int cwt; /* index into thread_hash/thread_id */
64
 
69
 
65
int next_thread_id;
70
int next_thread_id;
66
 
71
 
67
int app_phone;
72
int app_phone;
68
volatile bool abort_debug;
73
volatile bool abort_debug;
69
 
74
 
70
thash_t thash;
75
thash_t thash;
71
volatile int paused;
76
volatile int paused;
72
 
77
 
73
breakpoint_t brk_list[MAX_BRKPTS];
78
breakpoint_t brk_list[MAX_BRKPTS];
74
int lifted_brkpt;
79
int lifted_brkpt;
75
 
80
 
76
fcv_t go_cv;
81
fcv_t go_cv;
77
 
82
 
78
void command_split(char *cmd_str)
83
void command_split(char *cmd_str)
79
{
84
{
80
    char *p = cmd_str;
85
    char *p = cmd_str;
81
 
86
 
82
    if (*p == '\0') {
87
    if (*p == '\0') {
83
        cmd_argc = 0;
88
        cmd_argc = 0;
84
        return;
89
        return;
85
    }
90
    }
86
 
91
 
87
    cmd_argc = 1;
92
    cmd_argc = 1;
88
    cmd_argv[0] = p;
93
    cmd_argv[0] = p;
89
 
94
 
90
    while (*p != '\0') {
95
    while (*p != '\0') {
91
        if (*p == ' ') {
96
        if (*p == ' ') {
92
            cmd_argv[cmd_argc++] = p + 1;
97
            cmd_argv[cmd_argc++] = p + 1;
93
            *p = '\0';
98
            *p = '\0';
94
        }
99
        }
95
        ++p;
100
        ++p;
96
    }
101
    }
97
}
102
}
98
 
103
 
99
void command_run(void)
104
void command_run(void)
100
{
105
{
101
    int i;
106
    int i;
102
    int cmp_len;
107
    int cmp_len;
103
    int len;
108
    int len;
104
 
109
 
105
    int idx_found;
110
    int idx_found;
106
    int num_found;
111
    int num_found;
107
 
112
 
108
    len = strlen(cmd_argv[0]);
113
    len = strlen(cmd_argv[0]);
109
    cmp_len = 1;
114
    cmp_len = 1;
110
 
115
 
111
    while (cmp_len <= len + 1) {
116
    while (cmp_len <= len + 1) {
112
 
117
 
113
        num_found = 0;
118
        num_found = 0;
114
        i = 0;
119
        i = 0;
115
        while (cmd_table[i].name != NULL) {
120
        while (cmd_table[i].name != NULL) {
116
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
121
            if (strncmp(cmd_table[i].name, cmd_argv[0], cmp_len) == 0) {
117
                idx_found = i;
122
                idx_found = i;
118
                ++num_found;
123
                ++num_found;
119
            }
124
            }
120
            ++i;
125
            ++i;
121
        }
126
        }
122
 
127
 
123
        if (num_found < 2) break;
128
        if (num_found < 2) break;
124
 
129
 
125
        --cmp_len;
130
        --cmp_len;
126
    }
131
    }
127
 
132
 
128
    if (num_found == 0) {
133
    if (num_found == 0) {
129
        cons_printf("Unknown command. Try one of:\n");
134
        cons_printf("Unknown command. Try one of:\n");
130
        cmd_help(0, NULL);
135
        cmd_help(0, NULL);
131
        return;
136
        return;
132
    }
137
    }
133
 
138
 
134
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
139
    if (cmd_argc - 1 != cmd_table[idx_found].argc) {
135
        cons_printf("Command '%s' expects %d arguments\n",
140
        cons_printf("Command '%s' expects %d arguments\n",
136
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
141
        cmd_table[idx_found].name, cmd_table[idx_found].argc);
137
        return;
142
        return;
138
    }
143
    }
139
 
144
 
140
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
145
    (*cmd_table[idx_found].proc)(cmd_argc, cmd_argv);
141
}
146
}
142
 
147
 
143
void thread_stop(void)
148
void thread_stop(void)
144
{
149
{
145
    cons_printf("[t] stopped\n");
150
    cons_printf("[t] stopped\n");
146
    fcv_wait(&go_cv);
151
    fcv_wait(&go_cv);
147
    cons_printf("[t] go\n");
152
    cons_printf("[t] go\n");
148
}
153
}
149
 
154
 
150
/*
155
/*
151
 * Called by a fibril (from arch code) when a breakpoint is hit.
156
 * Called by a fibril (from arch code) when a breakpoint is hit.
152
 */
157
 */
153
void breakpoint_hit(void)
158
void breakpoint_hit(void)
154
{
159
{
155
    cons_printf("breakpoint hit\n");
160
    cons_printf("breakpoint hit\n");
156
    thread_stop();
161
    thread_stop();
157
}
162
}
158
 
163
 
159
int task_connect(int taskid)
164
int task_connect(int taskid)
160
{
165
{
161
    int rc;
166
    int rc;
162
    unsigned evmask;
167
    unsigned evmask;
163
 
168
 
164
    cons_printf("ipc_connect_kbox(%d)... ", taskid);
169
    cons_printf("ipc_connect_kbox(%d)... ", taskid);
165
    rc = ipc_connect_kbox(taskid);
170
    rc = ipc_connect_kbox(taskid);
166
    cons_printf("-> %d\n", rc);
171
    cons_printf("-> %d\n", rc);
167
    app_phone = rc;
172
    app_phone = rc;
168
    if (rc < 0) return rc;
173
    if (rc < 0) return rc;
169
 
174
 
170
    cons_printf("udebug_begin()... ");
175
    cons_printf("udebug_begin()... ");
171
    rc = udebug_begin(app_phone);
176
    rc = udebug_begin(app_phone);
172
    cons_printf("-> %d\n", rc);
177
    cons_printf("-> %d\n", rc);
173
    if (rc < 0) return rc;
178
    if (rc < 0) return rc;
174
 
179
 
175
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
180
    evmask = UDEBUG_EM_ALL & ~(UDEBUG_EM_SYSCALL_B | UDEBUG_EM_SYSCALL_E);
176
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
181
    cons_printf("udebug_set_evmask(0x%x)... ", evmask);
177
    rc = udebug_set_evmask(app_phone, evmask);
182
    rc = udebug_set_evmask(app_phone, evmask);
178
    cons_printf("-> %d\n", rc);
183
    cons_printf("-> %d\n", rc);
179
    if (rc < 0) return rc;
184
    if (rc < 0) return rc;
180
 
185
 
181
    return 0;
186
    return 0;
182
}
187
}
183
 
188
 
184
int get_thread_list(void)
189
int get_thread_list(void)
185
{
190
{
186
    int rc;
191
    int rc;
187
    int tb_copied;
192
    int tb_copied;
188
    int tb_needed;
193
    int tb_needed;
189
    int i;
194
    int i;
-
 
195
    int n;
190
 
196
 
191
    cons_printf("send IPC_M_DEBUG_THREAD_READ message\n");
197
    cons_printf("send IPC_M_DEBUG_THREAD_READ message\n");
192
    rc = udebug_thread_read(app_phone, (unsigned)thread_hash_buf,
198
    rc = udebug_thread_read(app_phone, (unsigned)thread_hash_buf,
193
        THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
199
        THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
194
    cons_printf("-> %d\n", rc);
200
    cons_printf("-> %d\n", rc);
195
    if (rc < 0) return rc;
201
    if (rc < 0) return rc;
196
 
202
 
197
    n_threads = tb_copied / sizeof(unsigned);
203
    n = tb_copied / sizeof(unsigned);
198
 
204
 
199
    cons_printf("thread IDs:");
205
    cons_printf("thread IDs:");
200
    for (i=0; i<n_threads; i++) {
206
    for (i=0; i<n; i++) {
201
        cons_printf(" %u", thread_hash_buf[i]);
207
        cons_printf(" %u", thread_hash_buf[i]);
202
    }
208
    }
203
    cons_printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
209
    cons_printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
204
 
210
 
205
    return 0;
211
    return n;
206
}
212
}
207
 
213
 
208
void event_thread_b(unsigned hash)
214
void event_thread_b(unsigned hash)
209
{
215
{
210
    async_serialize_start();
216
    async_serialize_start();
211
    cons_printf("new thread, hash 0x%x\n", hash);
217
    cons_printf("new thread, hash 0x%x\n", hash);
212
    async_serialize_end();
218
    async_serialize_end();
213
 
219
 
214
    thread_debug_start(hash);
220
    thread_debug_start(hash);
215
}
221
}
216
 
222
 
217
static unsigned buffer[1024];
223
static unsigned buffer[1024];
218
 
224
 
219
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
225
static void debug_event(thash_t thash, udebug_event_t ev_type, sysarg_t val0)
220
{
226
{
221
    switch (ev_type) {
227
    switch (ev_type) {
222
    case UDEBUG_EVENT_STOP:
228
    case UDEBUG_EVENT_STOP:
223
        cons_printf("stop event\n");
229
        cons_printf("stop event\n");
224
        cons_printf("waiting for resume\n");
230
        cons_printf("waiting for resume\n");
225
        while (paused) {
231
        while (paused) {
226
            usleep(1000000);
232
            usleep(1000000);
227
            fibril_yield();
233
            fibril_yield();
228
            cons_printf(".");
234
            cons_printf(".");
229
        }
235
        }
230
        cons_printf("resumed\n");
236
        cons_printf("resumed\n");
231
        break;
237
        break;
232
    case UDEBUG_EVENT_THREAD_B:
238
    case UDEBUG_EVENT_THREAD_B:
233
        event_thread_b(val0);
239
        event_thread_b(val0);
234
        break;
240
        break;
235
    case UDEBUG_EVENT_THREAD_E:
241
    case UDEBUG_EVENT_THREAD_E:
236
        cons_printf("thread 0x%x exited\n", val0);
242
        cons_printf("thread 0x%x exited\n", val0);
237
        abort_debug = true;
243
        abort_debug = true;
238
        break;
244
        break;
239
    case UDEBUG_EVENT_BREAKPOINT:
245
    case UDEBUG_EVENT_BREAKPOINT:
240
        arch_event_breakpoint(thash);
246
        arch_event_breakpoint(thash);
241
        break;
247
        break;
242
    case UDEBUG_EVENT_TRAP:
248
    case UDEBUG_EVENT_TRAP:
243
        arch_event_trap(thash);
249
        arch_event_trap(thash);
244
        break;
250
        break;
245
    default:
251
    default:
246
        cons_printf("unknown event type %d\n", ev_type);
252
        cons_printf("unknown event type %d\n", ev_type);
247
        break;
253
        break;
248
    }
254
    }
249
}
255
}
250
 
256
 
251
void debug_loop(void *thread_hash_arg)
257
void debug_loop(void *thread_buf_idx_arg)
252
{
258
{
253
    int rc;
259
    int rc;
254
    udebug_event_t ev_type;
260
    udebug_event_t ev_type;
255
    unsigned thread_hash;
261
    unsigned thread_buf_idx;
256
    unsigned thread_id;
262
    thash_t thash;
-
 
263
    int tid;
257
    unsigned val0, val1;
264
    unsigned val0, val1;
258
 
265
 
259
    thread_hash = (unsigned)thread_hash_arg;
266
    thread_buf_idx = (unsigned)thread_buf_idx_arg;
-
 
267
 
-
 
268
    thash = thread_hash[thread_buf_idx];
260
    thread_id = next_thread_id++;
269
    tid = thread_id[thread_buf_idx];
261
 
270
 
262
    cons_printf("debug_loop(%d)\n", thread_id);
271
    cons_printf("debug_loop(%d)\n", tid);
263
 
272
 
264
    while (!abort_debug) {
273
    while (!abort_debug) {
265
 
274
 
266
        /* Run thread until an event occurs */
275
        /* Run thread until an event occurs */
267
        rc = udebug_go(app_phone, thread_hash,
276
        rc = udebug_go(app_phone, thash,
268
            &ev_type, &val0, &val1);
277
            &ev_type, &val0, &val1);
269
 
278
 
270
        if (ev_type == UDEBUG_EVENT_FINISHED) {
279
        if (ev_type == UDEBUG_EVENT_FINISHED) {
271
            cons_printf("thread %u debugging finished\n", thread_id);
280
            cons_printf("thread %u debugging finished\n", tid);
272
            break;
281
            break;
273
        }
282
        }
274
        if (rc >= 0) debug_event(thread_hash, ev_type, val0);
283
        if (rc >= 0) debug_event(thash, ev_type, val0);
275
    }
284
    }
276
 
285
 
277
    cons_printf("debug_loop(%d) exiting\n", thread_id);
286
    cons_printf("debug_loop(%d) exiting\n", thread_id);
278
}
287
}
279
 
288
 
280
void thread_debug_start(unsigned thread_hash)
289
void thread_debug_start(unsigned thash)
281
{
290
{
282
    fid_t fid;
291
    fid_t fid;
283
 
292
 
284
    thash = thread_hash;
293
    thread_hash[n_threads] = thash;
-
 
294
    thread_id[n_threads] = next_thread_id++;
285
 
295
 
286
    fid = fibril_create(debug_loop, (void *)thread_hash);
296
    fid = fibril_create(debug_loop, (void *)n_threads++);
287
    if (fid == 0) {
297
    if (fid == 0) {
288
        cons_printf("Warning: Failed creating fibril\n");
298
        cons_printf("Warning: Failed creating fibril\n");
289
    }
299
    }
290
    fibril_add_ready(fid);
300
    fibril_add_ready(fid);
291
}
301
}
292
 
302
 
293
void debug_active_task(void)
303
void debug_active_task(void)
294
{
304
{
295
    int taskid;
305
    int taskid;
296
    int i;
306
    int i;
297
    int rc;
307
    int rc;
298
    int c;
308
    int c;
299
 
309
 
300
    cons_printf("Breakpoint Debugger\n");
310
    cons_printf("Breakpoint Debugger\n");
301
    cons_printf("Press 'c' to connect\n");
311
    cons_printf("Press 'c' to connect\n");
302
    while ((i = getchar()) != 'c')
312
    while ((i = getchar()) != 'c')
303
        putchar(i);
313
        putchar(i);
304
 
314
 
305
    taskid = 14;
315
    taskid = 14;
306
    rc = task_connect(taskid);
316
    rc = task_connect(taskid);
307
    if (rc < 0) {
317
    if (rc < 0) {
308
        cons_printf("Failed to connect to task %d\n", taskid);
318
        cons_printf("Failed to connect to task %d\n", taskid);
309
        return;
319
        return;
310
    }
320
    }
311
 
321
 
312
    cons_printf("Connected to task %d\n", taskid);
322
    cons_printf("Connected to task %d\n", taskid);
313
 
323
 
314
    rc = get_thread_list();
324
    rc = get_thread_list();
315
    if (rc < 0) {
325
    if (rc < 0) {
316
        cons_printf("Failed to get thread list (error %d)\n", rc);
326
        cons_printf("Failed to get thread list (error %d)\n", rc);
317
        return;
327
        return;
318
    }
328
    }
319
 
329
 
320
    abort_debug = false;
330
    abort_debug = false;
321
 
331
 
322
    for (i = 0; i < n_threads; i++) {
332
    for (i = 0; i < rc; i++) {
323
        thread_debug_start(thread_hash_buf[i]);
333
        thread_debug_start(thread_hash_buf[i]);
324
    }
334
    }
325
 
335
 
326
    while (!quit) {
336
    while (!quit) {
327
        cons_read_line(in_buf, IN_BUF_SIZE);
337
        cons_read_line(in_buf, IN_BUF_SIZE);
328
        command_split(in_buf);
338
        command_split(in_buf);
329
        if (cmd_argc == 0) continue;
339
        if (cmd_argc == 0) continue;
330
 
340
 
331
        command_run();
341
        command_run();
332
    }
342
    }
333
 
343
 
334
    cons_printf("terminate debugging session...\n");
344
    cons_printf("terminate debugging session...\n");
335
    abort_debug = true;
345
    abort_debug = true;
336
    udebug_end(app_phone);
346
    udebug_end(app_phone);
337
    ipc_hangup(app_phone);
347
    ipc_hangup(app_phone);
338
 
348
 
339
    cons_printf("done\n");
349
    cons_printf("done\n");
340
    return;
350
    return;
341
}
351
}
342
 
352
 
343
static void main_init(void)
353
static void main_init(void)
344
{
354
{
345
    next_thread_id = 1;
355
    next_thread_id = 1;
346
    paused = 0;
356
    paused = 0;
347
 
357
 
348
    fcv_init(&go_cv);
358
    fcv_init(&go_cv);
349
}
359
}
350
 
360
 
351
int main(void)
361
int main(void)
352
{
362
{
353
    main_init();
363
    main_init();
354
 
364
 
355
    while (1) {
365
    while (1) {
356
        debug_active_task();
366
        debug_active_task();
357
    }
367
    }
358
}
368
}
359
 
369
 
360
/** @}
370
/** @}
361
 */
371
 */
362
 
372