Subversion Repositories HelenOS

Rev

Rev 4658 | Rev 4660 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3438 svoboda 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
 
29
/** @addtogroup trace
30
 * @{
31
 */
32
/** @file
33
 */
34
 
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <unistd.h>
38
#include <ipc/ipc.h>
39
#include <fibril.h>
40
#include <errno.h>
41
#include <udebug.h>
42
#include <async.h>
3447 svoboda 43
#include <task.h>
4496 decky 44
#include <mem.h>
45
#include <string.h>
4659 svoboda 46
#include <bool.h>
3470 svoboda 47
#include <loader/loader.h>
4653 svoboda 48
#include <io/console.h>
49
#include <io/keycode.h>
4654 svoboda 50
#include <fibril_sync.h>
3438 svoboda 51
 
3485 jermar 52
#include <libc.h>
53
 
3438 svoboda 54
// Temporary: service and method names
55
#include "proto.h"
56
#include <ipc/services.h>
57
#include "../../srv/vfs/vfs.h"
3747 svoboda 58
#include <ipc/console.h>
3438 svoboda 59
 
60
#include "syscalls.h"
61
#include "ipcp.h"
62
#include "errors.h"
3444 svoboda 63
#include "trace.h"
3438 svoboda 64
 
65
#define THBUF_SIZE 64
3454 svoboda 66
uintptr_t thread_hash_buf[THBUF_SIZE];
67
int n_threads;
3438 svoboda 68
 
69
int next_thread_id;
70
 
71
int phoneid;
4659 svoboda 72
bool abort_trace;
3438 svoboda 73
 
3454 svoboda 74
uintptr_t thash;
4659 svoboda 75
static bool paused;
76
static fibril_condvar_t state_cv;
77
static fibril_mutex_t state_lock;
3438 svoboda 78
 
4659 svoboda 79
static bool cev_valid;
80
static console_event_t cev;
4656 svoboda 81
 
3454 svoboda 82
void thread_trace_start(uintptr_t thread_hash);
3438 svoboda 83
 
84
static proto_t *proto_console;
3444 svoboda 85
static task_id_t task_id;
3470 svoboda 86
static loader_t *task_ldr;
4659 svoboda 87
static bool task_wait_for;
3438 svoboda 88
 
3444 svoboda 89
/** Combination of events/data to print. */
90
display_mask_t display_mask;
91
 
3470 svoboda 92
static int program_run_fibril(void *arg);
4656 svoboda 93
static int cev_fibril(void *arg);
3470 svoboda 94
 
95
static void program_run(void)
3438 svoboda 96
{
3470 svoboda 97
    fid_t fid;
98
 
99
    fid = fibril_create(program_run_fibril, NULL);
100
    if (fid == 0) {
101
        printf("Error creating fibril\n");
102
        exit(1);
103
    }
104
 
105
    fibril_add_ready(fid);
106
}
107
 
4656 svoboda 108
static void cev_fibril_start(void)
109
{
110
    fid_t fid;
111
 
112
    fid = fibril_create(cev_fibril, NULL);
113
    if (fid == 0) {
114
        printf("Error creating fibril\n");
115
        exit(1);
116
    }
117
 
118
    fibril_add_ready(fid);
119
}
120
 
3470 svoboda 121
static int program_run_fibril(void *arg)
122
{
3438 svoboda 123
    int rc;
124
 
3470 svoboda 125
    /*
126
     * This must be done in background as it will block until
127
     * we let the task reply to this call.
128
     */
129
    rc = loader_run(task_ldr);
130
    if (rc != 0) {
131
        printf("Error running program\n");
132
        exit(1);
133
    }
134
 
135
    free(task_ldr);
136
    task_ldr = NULL;
137
 
138
    printf("program_run_fibril exiting\n");
139
    return 0;
140
}
141
 
142
 
143
static int connect_task(task_id_t task_id)
144
{
145
    int rc;
146
 
3438 svoboda 147
    rc = ipc_connect_kbox(task_id);
3439 svoboda 148
 
149
    if (rc == ENOTSUP) {
150
        printf("You do not have userspace debugging support "
151
            "compiled in the kernel.\n");
152
        printf("Compile kernel with 'Support for userspace debuggers' "
153
            "(CONFIG_UDEBUG) enabled.\n");
3442 svoboda 154
        return rc;
3439 svoboda 155
    }
156
 
3442 svoboda 157
    if (rc < 0) {
158
        printf("Error connecting\n");
159
        printf("ipc_connect_task(%lld) -> %d ", task_id, rc);
160
        return rc;
161
    }
162
 
3438 svoboda 163
    phoneid = rc;
164
 
165
    rc = udebug_begin(phoneid);
3442 svoboda 166
    if (rc < 0) {
167
        printf("udebug_begin() -> %d\n", rc);
168
        return rc;
169
    }
3438 svoboda 170
 
171
    rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
3442 svoboda 172
    if (rc < 0) {
173
        printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
174
        return rc;
175
    }
3438 svoboda 176
 
177
    return 0;
178
}
179
 
180
static int get_thread_list(void)
181
{
182
    int rc;
183
    size_t tb_copied;
184
    size_t tb_needed;
185
    int i;
186
 
187
    rc = udebug_thread_read(phoneid, thread_hash_buf,
188
        THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
3442 svoboda 189
    if (rc < 0) {
190
        printf("udebug_thread_read() -> %d\n", rc);
191
        return rc;
192
    }
3438 svoboda 193
 
3454 svoboda 194
    n_threads = tb_copied / sizeof(uintptr_t);
3438 svoboda 195
 
3442 svoboda 196
    printf("Threads:");
197
    for (i = 0; i < n_threads; i++) {
3454 svoboda 198
        printf(" [%d] (hash 0x%lx)", 1+i, thread_hash_buf[i]);
3438 svoboda 199
    }
3454 svoboda 200
    printf("\ntotal of %u threads\n", tb_needed / sizeof(uintptr_t));
3438 svoboda 201
 
202
    return 0;
203
}
204
 
3455 svoboda 205
void val_print(sysarg_t val, val_type_t v_type)
3438 svoboda 206
{
3452 svoboda 207
    switch (v_type) {
208
    case V_VOID:
209
        printf("<void>");
210
        break;
211
 
212
    case V_INTEGER:
3455 svoboda 213
        printf("%ld", val);
3452 svoboda 214
        break;
215
 
216
    case V_HASH:
3470 svoboda 217
    case V_PTR:
3455 svoboda 218
        printf("0x%08lx", val);
3452 svoboda 219
        break;
220
 
221
    case V_ERRNO:
222
        if (val >= -15 && val <= 0) {
3455 svoboda 223
            printf("%ld %s (%s)", val,
3452 svoboda 224
                err_desc[-val].name,
225
                err_desc[-val].desc);
3438 svoboda 226
        } else {
3455 svoboda 227
            printf("%ld", val);
3438 svoboda 228
        }
3452 svoboda 229
        break;
230
    case V_INT_ERRNO:
231
        if (val >= -15 && val < 0) {
3455 svoboda 232
            printf("%ld %s (%s)", val,
3452 svoboda 233
                err_desc[-val].name,
234
                err_desc[-val].desc);
3438 svoboda 235
        } else {
3455 svoboda 236
            printf("%ld", val);
3438 svoboda 237
        }
3452 svoboda 238
        break;
239
 
240
    case V_CHAR:
241
        if (val >= 0x20 && val < 0x7f) {
242
            printf("'%c'", val);
243
        } else {
244
            switch (val) {
245
            case '\a': printf("'\\a'"); break;
246
            case '\b': printf("'\\b'"); break;
247
            case '\n': printf("'\\n'"); break;
248
            case '\r': printf("'\\r'"); break;
249
            case '\t': printf("'\\t'"); break;
250
            case '\\': printf("'\\\\'"); break;
3455 svoboda 251
            default: printf("'\\x%02lX'", val); break;
3452 svoboda 252
            }
253
        }
254
        break;
3438 svoboda 255
    }
3452 svoboda 256
}
257
 
258
 
3455 svoboda 259
static void print_sc_retval(sysarg_t retval, val_type_t val_type)
3452 svoboda 260
{
261
    printf(" -> ");
262
    val_print(retval, val_type);
3438 svoboda 263
    putchar('\n');
264
}
265
 
3454 svoboda 266
static void print_sc_args(sysarg_t *sc_args, int n)
3438 svoboda 267
{
268
    int i;
269
 
270
    putchar('(');
3454 svoboda 271
    if (n > 0) printf("%ld", sc_args[0]);
3452 svoboda 272
    for (i = 1; i < n; i++) {
3454 svoboda 273
        printf(", %ld", sc_args[i]);
3438 svoboda 274
    }
275
    putchar(')');
276
}
277
 
3454 svoboda 278
static void sc_ipc_call_async_fast(sysarg_t *sc_args, sysarg_t sc_rc)
3438 svoboda 279
{
280
    ipc_call_t call;
3454 svoboda 281
    ipcarg_t phoneid;
3438 svoboda 282
 
283
    if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
284
        return;
285
 
286
    phoneid = sc_args[0];
287
 
288
    IPC_SET_METHOD(call, sc_args[1]);
289
    IPC_SET_ARG1(call, sc_args[2]);
290
    IPC_SET_ARG2(call, sc_args[3]);
291
    IPC_SET_ARG3(call, sc_args[4]);
292
    IPC_SET_ARG4(call, sc_args[5]);
293
    IPC_SET_ARG5(call, 0);
294
 
295
    ipcp_call_out(phoneid, &call, sc_rc);
296
}
297
 
3454 svoboda 298
static void sc_ipc_call_async_slow(sysarg_t *sc_args, sysarg_t sc_rc)
3438 svoboda 299
{
300
    ipc_call_t call;
301
    int rc;
302
 
303
    if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
304
        return;
305
 
306
    memset(&call, 0, sizeof(call));
307
    rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
308
 
309
    if (rc >= 0) {
310
        ipcp_call_out(sc_args[0], &call, sc_rc);
311
    }
312
}
313
 
3454 svoboda 314
static void sc_ipc_call_sync_fast(sysarg_t *sc_args)
3438 svoboda 315
{
316
    ipc_call_t question, reply;
317
    int rc;
318
    int phoneidx;
319
 
320
//  printf("sc_ipc_call_sync_fast()\n");
321
    phoneidx = sc_args[0];
322
 
323
    IPC_SET_METHOD(question, sc_args[1]);
324
    IPC_SET_ARG1(question, sc_args[2]);
325
    IPC_SET_ARG2(question, sc_args[3]);
326
    IPC_SET_ARG3(question, sc_args[4]);
327
    IPC_SET_ARG4(question, 0);
328
    IPC_SET_ARG5(question, 0);
329
 
330
//  printf("memset\n");
331
    memset(&reply, 0, sizeof(reply));
332
//  printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
333
//      phoneid, &reply.args, sc_args[5], sizeof(reply.args));
334
    rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
335
//  printf("dmr->%d\n", rc);
336
    if (rc < 0) return;
337
 
338
//  printf("call ipc_call_sync\n");
339
    ipcp_call_sync(phoneidx, &question, &reply);
340
}
341
 
3454 svoboda 342
static void sc_ipc_call_sync_slow(sysarg_t *sc_args)
3438 svoboda 343
{
344
    ipc_call_t question, reply;
345
    int rc;
346
 
347
    memset(&question, 0, sizeof(question));
348
    rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args));
349
    printf("dmr->%d\n", rc);
350
    if (rc < 0) return;
351
 
352
    memset(&reply, 0, sizeof(reply));
353
    rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args));
354
    printf("dmr->%d\n", rc);
355
    if (rc < 0) return;
356
 
357
    ipcp_call_sync(sc_args[0], &question, &reply);
358
}
359
 
3454 svoboda 360
static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc)
3438 svoboda 361
{
362
    ipc_call_t call;
363
    int rc;
364
 
365
    if (sc_rc == 0) return;
366
 
367
    memset(&call, 0, sizeof(call));
368
    rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
369
//  printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
370
//      phoneid, (int)&call, sc_args[0], sizeof(call), rc);
371
 
372
    if (rc >= 0) {
373
        ipcp_call_in(&call, sc_rc);
374
    }
375
}
376
 
3454 svoboda 377
static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
378
    unsigned sc_id, sysarg_t sc_rc)
3438 svoboda 379
{
3454 svoboda 380
    sysarg_t sc_args[6];
3438 svoboda 381
    int rc;
382
 
383
    /* Read syscall arguments */
384
    rc = udebug_args_read(phoneid, thread_hash, sc_args);
385
 
386
    async_serialize_start();
387
 
388
//  printf("[%d] ", thread_id);
389
 
390
    if (rc < 0) {
391
        printf("error\n");
392
        async_serialize_end();
393
        return;
394
    }
395
 
3444 svoboda 396
    if ((display_mask & DM_SYSCALL) != 0) {
397
        /* Print syscall name and arguments */
398
        printf("%s", syscall_desc[sc_id].name);
399
        print_sc_args(sc_args, syscall_desc[sc_id].n_args);
400
    }
3438 svoboda 401
 
402
    async_serialize_end();
403
}
404
 
3454 svoboda 405
static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
406
    unsigned sc_id, sysarg_t sc_rc)
3438 svoboda 407
{
3454 svoboda 408
    sysarg_t sc_args[6];
3438 svoboda 409
    int rv_type;
410
    int rc;
411
 
412
    /* Read syscall arguments */
413
    rc = udebug_args_read(phoneid, thread_hash, sc_args);
414
 
415
    async_serialize_start();
416
 
417
//  printf("[%d] ", thread_id);
418
 
419
    if (rc < 0) {
420
        printf("error\n");
421
        async_serialize_end();
422
        return;
423
    }
424
 
3444 svoboda 425
    if ((display_mask & DM_SYSCALL) != 0) {
426
        /* Print syscall return value */
427
        rv_type = syscall_desc[sc_id].rv_type;
428
        print_sc_retval(sc_rc, rv_type);
429
    }
3438 svoboda 430
 
431
    switch (sc_id) {
432
    case SYS_IPC_CALL_ASYNC_FAST:
433
        sc_ipc_call_async_fast(sc_args, sc_rc);
434
        break;
435
    case SYS_IPC_CALL_ASYNC_SLOW:
436
        sc_ipc_call_async_slow(sc_args, sc_rc);
437
        break;
438
    case SYS_IPC_CALL_SYNC_FAST:
439
        sc_ipc_call_sync_fast(sc_args);
440
        break;
441
    case SYS_IPC_CALL_SYNC_SLOW:
442
        sc_ipc_call_sync_slow(sc_args);
443
        break;
444
    case SYS_IPC_WAIT:
445
        sc_ipc_wait(sc_args, sc_rc);
446
        break;
447
    default:
448
        break;
449
    }
450
 
451
    async_serialize_end();
452
}
453
 
3454 svoboda 454
static void event_thread_b(uintptr_t hash)
3438 svoboda 455
{
456
    async_serialize_start();
3454 svoboda 457
    printf("New thread, hash 0x%lx\n", hash);
3438 svoboda 458
    async_serialize_end();
459
 
460
    thread_trace_start(hash);
461
}
462
 
463
static int trace_loop(void *thread_hash_arg)
464
{
465
    int rc;
466
    unsigned ev_type;
3454 svoboda 467
    uintptr_t thread_hash;
3438 svoboda 468
    unsigned thread_id;
3454 svoboda 469
    sysarg_t val0, val1;
3438 svoboda 470
 
3454 svoboda 471
    thread_hash = (uintptr_t)thread_hash_arg;
3438 svoboda 472
    thread_id = next_thread_id++;
473
 
3605 svoboda 474
    printf("Start tracing thread [%d] (hash 0x%lx).\n", thread_id, thread_hash);
3438 svoboda 475
 
476
    while (!abort_trace) {
477
 
4656 svoboda 478
        fibril_mutex_lock(&state_lock);
3603 svoboda 479
        if (paused) {
4654 svoboda 480
            printf("Thread [%d] paused. Press R to resume.\n",
481
                thread_id);
482
 
483
            while (paused)
4656 svoboda 484
                fibril_condvar_wait(&state_cv, &state_lock);
4654 svoboda 485
 
486
            printf("Thread [%d] resumed.\n", thread_id);
3603 svoboda 487
        }
4656 svoboda 488
        fibril_mutex_unlock(&state_lock);
3603 svoboda 489
 
3438 svoboda 490
        /* Run thread until an event occurs */
491
        rc = udebug_go(phoneid, thread_hash,
492
            &ev_type, &val0, &val1);
493
 
494
//      printf("rc = %d, ev_type=%d\n", rc, ev_type);
495
        if (ev_type == UDEBUG_EVENT_FINISHED) {
3442 svoboda 496
            /* Done tracing this thread */
3438 svoboda 497
            break;
498
        }
499
 
500
        if (rc >= 0) {
501
            switch (ev_type) {
502
            case UDEBUG_EVENT_SYSCALL_B:
503
                event_syscall_b(thread_id, thread_hash, val0, (int)val1);
504
                break;
505
            case UDEBUG_EVENT_SYSCALL_E:
506
                event_syscall_e(thread_id, thread_hash, val0, (int)val1);
507
                break;
508
            case UDEBUG_EVENT_STOP:
3442 svoboda 509
                printf("Stop event\n");
4656 svoboda 510
                fibril_mutex_lock(&state_lock);
4659 svoboda 511
                paused = true;
4656 svoboda 512
                fibril_mutex_unlock(&state_lock);
3438 svoboda 513
                break;
514
            case UDEBUG_EVENT_THREAD_B:
515
                event_thread_b(val0);
516
                break;
517
            case UDEBUG_EVENT_THREAD_E:
3605 svoboda 518
                printf("Thread 0x%lx exited.\n", val0);
4656 svoboda 519
                fibril_mutex_lock(&state_lock);
4659 svoboda 520
                abort_trace = true;
4656 svoboda 521
                fibril_condvar_broadcast(&state_cv);
522
                fibril_mutex_unlock(&state_lock);
3438 svoboda 523
                break;
524
            default:
3605 svoboda 525
                printf("Unknown event type %d.\n", ev_type);
3438 svoboda 526
                break;
527
            }
528
        }
529
 
530
    }
531
 
3605 svoboda 532
    printf("Finished tracing thread [%d].\n", thread_id);
3438 svoboda 533
    return 0;
534
}
535
 
3454 svoboda 536
void thread_trace_start(uintptr_t thread_hash)
3438 svoboda 537
{
538
    fid_t fid;
539
 
540
    thash = thread_hash;
541
 
542
    fid = fibril_create(trace_loop, (void *)thread_hash);
543
    if (fid == 0) {
544
        printf("Warning: Failed creating fibril\n");
545
    }
546
    fibril_add_ready(fid);
547
}
548
 
3470 svoboda 549
static loader_t *preload_task(const char *path, char *const argv[],
550
    task_id_t *task_id)
3438 svoboda 551
{
3470 svoboda 552
    loader_t *ldr;
553
    int rc;
554
 
555
    /* Spawn a program loader */   
3897 svoboda 556
    ldr = loader_connect();
3470 svoboda 557
    if (ldr == NULL)
558
        return 0;
559
 
560
    /* Get task ID. */
561
    rc = loader_get_task_id(ldr, task_id);
562
    if (rc != EOK)
563
        goto error;
564
 
565
    /* Send program pathname */
566
    rc = loader_set_pathname(ldr, path);
567
    if (rc != EOK)
568
        goto error;
569
 
570
    /* Send arguments */
571
    rc = loader_set_args(ldr, argv);
572
    if (rc != EOK)
573
        goto error;
574
 
4655 svoboda 575
    /* Send default files */
576
    fdi_node_t *files[4];
577
    fdi_node_t stdin_node;
578
    fdi_node_t stdout_node;
579
    fdi_node_t stderr_node;
580
 
581
    if ((stdin != NULL) && (fnode(stdin, &stdin_node) == EOK))
582
        files[0] = &stdin_node;
583
    else
584
        files[0] = NULL;
585
 
586
    if ((stdout != NULL) && (fnode(stdout, &stdout_node) == EOK))
587
        files[1] = &stdout_node;
588
    else
589
        files[1] = NULL;
590
 
591
    if ((stderr != NULL) && (fnode(stderr, &stderr_node) == EOK))
592
        files[2] = &stderr_node;
593
    else
594
        files[2] = NULL;
595
 
596
    files[3] = NULL;
597
 
598
    rc = loader_set_files(ldr, files);
599
    if (rc != EOK)
600
        goto error;
601
 
3470 svoboda 602
    /* Load the program. */
603
    rc = loader_load_program(ldr);
604
    if (rc != EOK)
605
        goto error;
606
 
607
    /* Success */
608
    return ldr;
609
 
610
    /* Error exit */
611
error:
612
    loader_abort(ldr);
613
    free(ldr);
614
    return NULL;
615
}
616
 
4656 svoboda 617
static int cev_fibril(void *arg)
618
{
619
    (void) arg;
620
 
621
    while (true) {
622
        fibril_mutex_lock(&state_lock);
623
        while (cev_valid)
624
            fibril_condvar_wait(&state_cv, &state_lock);
625
        fibril_mutex_unlock(&state_lock);
626
 
627
        if (!console_get_event(fphone(stdin), &cev))
628
            return -1;
629
 
630
        fibril_mutex_lock(&state_lock);
4659 svoboda 631
        cev_valid = true;
4656 svoboda 632
        fibril_condvar_broadcast(&state_cv);
633
        fibril_mutex_unlock(&state_lock);      
634
    }
635
}
636
 
3470 svoboda 637
static void trace_task(task_id_t task_id)
638
{
4653 svoboda 639
    console_event_t ev;
640
    bool done;
3438 svoboda 641
    int i;
642
    int rc;
643
 
644
    ipcp_init();
645
 
3442 svoboda 646
    /*
647
     * User apps now typically have console on phone 3.
648
     * (Phones 1 and 2 are used by the loader).
649
     */
650
    ipcp_connection_set(3, 0, proto_console);
651
 
3438 svoboda 652
    rc = get_thread_list();
653
    if (rc < 0) {
654
        printf("Failed to get thread list (error %d)\n", rc);
655
        return;
656
    }
657
 
4659 svoboda 658
    abort_trace = false;
3438 svoboda 659
 
660
    for (i = 0; i < n_threads; i++) {
661
        thread_trace_start(thread_hash_buf[i]);
662
    }
663
 
4653 svoboda 664
    done = false;
665
 
666
    while (!done) {
4656 svoboda 667
        fibril_mutex_lock(&state_lock);
668
        while (!cev_valid && !abort_trace)
669
            fibril_condvar_wait(&state_cv, &state_lock);
670
        fibril_mutex_unlock(&state_lock);
4653 svoboda 671
 
4656 svoboda 672
        ev = cev;
673
 
674
        fibril_mutex_lock(&state_lock);
675
        cev_valid = false;
676
        fibril_condvar_broadcast(&state_cv);
677
        fibril_mutex_unlock(&state_lock);
678
 
679
        if (abort_trace)
680
            break;
681
 
4653 svoboda 682
        if (ev.type != KEY_PRESS)
683
            continue;
684
 
685
        switch (ev.key) {
686
        case KC_Q:
687
            done = true;
688
            break;
689
        case KC_P:
3603 svoboda 690
            printf("Pause...\n");
3438 svoboda 691
            rc = udebug_stop(phoneid, thash);
4654 svoboda 692
            if (rc != EOK)
693
                printf("Error: stop -> %d\n", rc);
4653 svoboda 694
            break;
695
        case KC_R:
4656 svoboda 696
            fibril_mutex_lock(&state_lock);
4659 svoboda 697
            paused = false;
4656 svoboda 698
            fibril_condvar_broadcast(&state_cv);
699
            fibril_mutex_unlock(&state_lock);
3603 svoboda 700
            printf("Resume...\n");
4653 svoboda 701
            break;
3438 svoboda 702
        }
703
    }
704
 
3442 svoboda 705
    printf("\nTerminate debugging session...\n");
4659 svoboda 706
    abort_trace = true;
3438 svoboda 707
    udebug_end(phoneid);
708
    ipc_hangup(phoneid);
709
 
710
    ipcp_cleanup();
711
 
3442 svoboda 712
    printf("Done\n");
3438 svoboda 713
    return;
714
}
715
 
716
static void main_init(void)
717
{
718
    proto_t *p;
719
    oper_t *o;
720
 
3452 svoboda 721
    val_type_t arg_def[OPER_MAX_ARGS] = {
722
        V_INTEGER,
723
        V_INTEGER,
724
        V_INTEGER,
725
        V_INTEGER,
726
        V_INTEGER      
727
    };
728
 
729
    val_type_t resp_def[OPER_MAX_ARGS] = {
730
        V_INTEGER,
731
        V_INTEGER,
732
        V_INTEGER,
733
        V_INTEGER,
3905 svoboda 734
        V_INTEGER
3452 svoboda 735
    };
736
 
3438 svoboda 737
    next_thread_id = 1;
4659 svoboda 738
    paused = false;
739
    cev_valid = false;
3438 svoboda 740
 
4656 svoboda 741
    fibril_mutex_initialize(&state_lock);
742
    fibril_condvar_initialize(&state_cv);
743
 
3438 svoboda 744
    proto_init();
745
 
746
    p = proto_new("vfs");
3452 svoboda 747
    o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
4584 jermar 748
    proto_add_oper(p, VFS_IN_READ, o);
3452 svoboda 749
    o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
4584 jermar 750
    proto_add_oper(p, VFS_IN_WRITE, o);
3452 svoboda 751
    o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 752
    proto_add_oper(p, VFS_IN_TRUNCATE, o);
3452 svoboda 753
    o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 754
    proto_add_oper(p, VFS_IN_MOUNT, o);
3452 svoboda 755
/*  o = oper_new("unmount", 0, arg_def);
4584 jermar 756
    proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
3850 svoboda 757
    o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def);
4584 jermar 758
    proto_add_oper(p, VFS_IN_OPEN, o);
3850 svoboda 759
    o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 760
    proto_add_oper(p, VFS_IN_CLOSE, o);
3850 svoboda 761
    o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 762
    proto_add_oper(p, VFS_IN_SEEK, o);
3850 svoboda 763
    o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 764
    proto_add_oper(p, VFS_IN_MKDIR, o);
3850 svoboda 765
    o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 766
    proto_add_oper(p, VFS_IN_UNLINK, o);
3850 svoboda 767
    o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
4584 jermar 768
    proto_add_oper(p, VFS_IN_RENAME, o);
3438 svoboda 769
 
770
    proto_register(SERVICE_VFS, p);
771
 
772
    p = proto_new("console");
3905 svoboda 773
    resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
774
    resp_def[2] = V_INTEGER; resp_def[3] = V_CHAR;
775
    o = oper_new("getkey", 0, arg_def, V_ERRNO, 4, resp_def);
3452 svoboda 776
 
777
    arg_def[0] = V_CHAR;
778
    o = oper_new("clear", 0, arg_def, V_VOID, 0, resp_def);
3438 svoboda 779
    proto_add_oper(p, CONSOLE_CLEAR, o);
3452 svoboda 780
 
781
    arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
782
    o = oper_new("goto", 2, arg_def, V_VOID, 0, resp_def);
3438 svoboda 783
    proto_add_oper(p, CONSOLE_GOTO, o);
3452 svoboda 784
 
785
    resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
786
    o = oper_new("getsize", 0, arg_def, V_INTEGER, 2, resp_def);
4489 decky 787
    proto_add_oper(p, CONSOLE_GET_SIZE, o);
3452 svoboda 788
 
3767 svoboda 789
    arg_def[0] = V_INTEGER;
3850 svoboda 790
    o = oper_new("set_style", 1, arg_def, V_VOID, 0, resp_def);
3767 svoboda 791
    proto_add_oper(p, CONSOLE_SET_STYLE, o);
792
    arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER; arg_def[2] = V_INTEGER;
3850 svoboda 793
    o = oper_new("set_color", 3, arg_def, V_VOID, 0, resp_def);
3767 svoboda 794
    proto_add_oper(p, CONSOLE_SET_COLOR, o);
3452 svoboda 795
    arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
3850 svoboda 796
    o = oper_new("set_rgb_color", 2, arg_def, V_VOID, 0, resp_def);
3767 svoboda 797
    proto_add_oper(p, CONSOLE_SET_RGB_COLOR, o);
3452 svoboda 798
    o = oper_new("cursor_visibility", 1, arg_def, V_VOID, 0, resp_def);
3438 svoboda 799
    proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
800
 
801
    proto_console = p;
802
    proto_register(SERVICE_CONSOLE, p);
803
}
804
 
805
static void print_syntax()
806
{
3447 svoboda 807
    printf("Syntax:\n");
808
    printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
809
    printf("or\ttrace [+<events>] -t <task_id>\n");
3444 svoboda 810
    printf("Events: (default is +tp)\n");
811
    printf("\n");
812
    printf("\tt ... Thread creation and termination\n");
813
    printf("\ts ... System calls\n");
814
    printf("\ti ... Low-level IPC\n");
815
    printf("\tp ... Protocol level\n");
816
    printf("\n");
3447 svoboda 817
    printf("Examples:\n");
818
    printf("\ttrace +s /app/tetris\n");
819
    printf("\ttrace +tsip -t 12\n");
3438 svoboda 820
}
821
 
3444 svoboda 822
static display_mask_t parse_display_mask(char *text)
3438 svoboda 823
{
3444 svoboda 824
    display_mask_t dm;
825
    char *c;
826
 
827
    c = text;
828
 
829
    while (*c) {
830
        switch (*c) {
831
        case 't': dm = dm | DM_THREAD; break;
832
        case 's': dm = dm | DM_SYSCALL; break;
833
        case 'i': dm = dm | DM_IPC; break;
834
        case 'p': dm = dm | DM_SYSTEM | DM_USER; break;
835
        default:
3605 svoboda 836
            printf("Unexpected event type '%c'.\n", *c);
3444 svoboda 837
            exit(1);
838
        }
839
 
840
        ++c;
841
    }
842
 
843
    return dm;
844
}
845
 
846
static int parse_args(int argc, char *argv[])
847
{
848
    char *arg;
3438 svoboda 849
    char *err_p;
850
 
3447 svoboda 851
    task_id = 0;
852
 
3444 svoboda 853
    --argc; ++argv;
854
 
3447 svoboda 855
    while (argc > 0) {
3444 svoboda 856
        arg = *argv;
857
        if (arg[0] == '+') {
858
            display_mask = parse_display_mask(&arg[1]);
3447 svoboda 859
        } else if (arg[0] == '-') {
860
            if (arg[1] == 't') {
861
                /* Trace an already running task */
862
                --argc; ++argv;
863
                task_id = strtol(*argv, &err_p, 10);
3470 svoboda 864
                task_ldr = NULL;
4659 svoboda 865
                task_wait_for = false;
3447 svoboda 866
                if (*err_p) {
867
                    printf("Task ID syntax error\n");
868
                    print_syntax();
869
                    return -1;
870
                }
871
            } else {
872
                printf("Uknown option '%s'\n", arg[0]);
873
                print_syntax();
874
                return -1;
875
            }
3444 svoboda 876
        } else {
3447 svoboda 877
            break;
3444 svoboda 878
        }
879
 
880
        --argc; ++argv;
881
    }
882
 
3447 svoboda 883
    if (task_id != 0) {
3454 svoboda 884
        if (argc == 0) return 0;
3447 svoboda 885
        printf("Extra arguments\n");
3438 svoboda 886
        print_syntax();
3447 svoboda 887
        return -1;
3438 svoboda 888
    }
889
 
3447 svoboda 890
    if (argc < 1) {
891
        printf("Missing argument\n");
3438 svoboda 892
        print_syntax();
3444 svoboda 893
        return -1;
3438 svoboda 894
    }
895
 
3470 svoboda 896
    /* Preload the specified program file. */
3447 svoboda 897
    printf("Spawning '%s' with arguments:\n", *argv);
898
    {
899
        char **cp = argv;
900
        while (*cp) printf("'%s'\n", *cp++);
901
    }
3470 svoboda 902
    task_ldr = preload_task(*argv, argv, &task_id);
4659 svoboda 903
    task_wait_for = true;
3447 svoboda 904
 
3444 svoboda 905
    return 0;
906
}
907
 
908
int main(int argc, char *argv[])
909
{
3470 svoboda 910
    int rc;
4658 svoboda 911
    task_exit_t texit;
912
    int retval;
3470 svoboda 913
 
3444 svoboda 914
    printf("System Call / IPC Tracer\n");
3605 svoboda 915
    printf("Controls: Q - Quit, P - Pause, R - Resume\n");
3444 svoboda 916
 
917
    display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
918
 
919
    if (parse_args(argc, argv) < 0)
920
        return 1;
921
 
3438 svoboda 922
    main_init();
3444 svoboda 923
 
3470 svoboda 924
    rc = connect_task(task_id);
925
    if (rc < 0) {
3605 svoboda 926
        printf("Failed connecting to task %lld.\n", task_id);
3470 svoboda 927
        return 1;
928
    }
929
 
3605 svoboda 930
    printf("Connected to task %lld.\n", task_id);
3470 svoboda 931
 
4658 svoboda 932
    if (task_ldr != NULL)
3470 svoboda 933
        program_run();
934
 
4656 svoboda 935
    cev_fibril_start();
3470 svoboda 936
    trace_task(task_id);
937
 
4658 svoboda 938
    if (task_wait_for) {
939
        printf("Waiting for task to exit.\n");
940
 
941
        rc = task_wait(task_id, &texit, &retval);
942
        if (rc != EOK) {
943
            printf("Failed waiting for task.\n");
944
            return -1;
945
        }
946
 
947
        if (texit == TASK_EXIT_NORMAL) {
948
            printf("Task exited normally, return value %d.\n",
949
                retval);
950
        } else {
951
            printf("Task exited unexpectedly.\n");
952
        }
953
    }
954
 
3444 svoboda 955
    return 0;
3438 svoboda 956
}
957
 
958
/** @}
959
 */