source: mainline/uspace/app/trace/trace.c@ 38d150e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 38d150e was 7b8f933, checked in by Jakub Jermar <jakub@…>, 8 years ago

Fix wrongly-inverted condition

  • Property mode set to 100644
File size: 18.1 KB
RevLine 
[9a1b20c]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>
[8d2dd7f2]37#include <stdbool.h>
38#include <stdint.h>
39#include <stddef.h>
[7354b5e]40#include <inttypes.h>
[9a1b20c]41#include <fibril.h>
42#include <errno.h>
43#include <udebug.h>
44#include <async.h>
[47e0a05b]45#include <task.h>
[3bf907a]46#include <mem.h>
[19f857a]47#include <str.h>
[4470e26]48#include <loader/loader.h>
[9d8a1ed]49#include <io/console.h>
50#include <io/keycode.h>
[1e4cada]51#include <fibril_synch.h>
[df02460]52#include <vfs/vfs.h>
[9a1b20c]53
[f2ef7fd]54#include <libc.h>
55
[28a3e74]56/* Temporary: service and method names */
[9a1b20c]57#include "proto.h"
58#include <ipc/services.h>
[6afc9d7]59#include <ipc/vfs.h>
[d3e6935]60#include <ipc/console.h>
[9a1b20c]61
62#include "syscalls.h"
63#include "ipcp.h"
64#include "errors.h"
[1643855]65#include "trace.h"
[9a1b20c]66
67#define THBUF_SIZE 64
[a5c3f73]68uintptr_t thread_hash_buf[THBUF_SIZE];
69int n_threads;
[9a1b20c]70
71int next_thread_id;
72
[c8404d4]73ipc_call_t thread_ipc_req[THBUF_SIZE];
74
[79ae36dd]75async_sess_t *sess;
[9ad5b5cc]76bool abort_trace;
[9a1b20c]77
[a5c3f73]78uintptr_t thash;
[9ad5b5cc]79static bool paused;
80static fibril_condvar_t state_cv;
81static fibril_mutex_t state_lock;
[84683fdc]82
[9ad5b5cc]83static bool cev_valid;
[79ae36dd]84static kbd_event_t cev;
[9a1b20c]85
[a5c3f73]86void thread_trace_start(uintptr_t thread_hash);
[9a1b20c]87
[1643855]88static task_id_t task_id;
[4470e26]89static loader_t *task_ldr;
[9ad5b5cc]90static bool task_wait_for;
[1643855]91
92/** Combination of events/data to print. */
93display_mask_t display_mask;
[9a1b20c]94
[4470e26]95static int program_run_fibril(void *arg);
[84683fdc]96static int cev_fibril(void *arg);
[4470e26]97
98static void program_run(void)
99{
100 fid_t fid;
101
102 fid = fibril_create(program_run_fibril, NULL);
103 if (fid == 0) {
104 printf("Error creating fibril\n");
105 exit(1);
106 }
107
108 fibril_add_ready(fid);
109}
110
[84683fdc]111static void cev_fibril_start(void)
112{
113 fid_t fid;
114
115 fid = fibril_create(cev_fibril, NULL);
116 if (fid == 0) {
117 printf("Error creating fibril\n");
118 exit(1);
119 }
120
121 fibril_add_ready(fid);
122}
123
[4470e26]124static int program_run_fibril(void *arg)
125{
126 int rc;
127
128 /*
129 * This must be done in background as it will block until
130 * we let the task reply to this call.
131 */
132 rc = loader_run(task_ldr);
133 if (rc != 0) {
134 printf("Error running program\n");
135 exit(1);
136 }
137
138 task_ldr = NULL;
139
140 printf("program_run_fibril exiting\n");
141 return 0;
142}
143
144
145static int connect_task(task_id_t task_id)
[9a1b20c]146{
[79ae36dd]147 async_sess_t *ksess = async_connect_kbox(task_id);
148
149 if (!ksess) {
150 if (errno == ENOTSUP) {
151 printf("You do not have userspace debugging support "
152 "compiled in the kernel.\n");
153 printf("Compile kernel with 'Support for userspace debuggers' "
154 "(CONFIG_UDEBUG) enabled.\n");
155 return errno;
156 }
157
[c9a29d6]158 printf("Error connecting\n");
[79ae36dd]159 printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, errno);
160 return errno;
[fb9b0b0]161 }
[79ae36dd]162
163 int rc = udebug_begin(ksess);
[c9a29d6]164 if (rc < 0) {
165 printf("udebug_begin() -> %d\n", rc);
166 return rc;
167 }
[79ae36dd]168
169 rc = udebug_set_evmask(ksess, UDEBUG_EM_ALL);
[c9a29d6]170 if (rc < 0) {
171 printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
172 return rc;
173 }
[79ae36dd]174
175 sess = ksess;
[9a1b20c]176 return 0;
177}
178
179static int get_thread_list(void)
180{
181 int rc;
182 size_t tb_copied;
183 size_t tb_needed;
184 int i;
185
[79ae36dd]186 rc = udebug_thread_read(sess, thread_hash_buf,
[9a1b20c]187 THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
[c9a29d6]188 if (rc < 0) {
189 printf("udebug_thread_read() -> %d\n", rc);
190 return rc;
191 }
[9a1b20c]192
[a5c3f73]193 n_threads = tb_copied / sizeof(uintptr_t);
[9a1b20c]194
[c9a29d6]195 printf("Threads:");
196 for (i = 0; i < n_threads; i++) {
[7e752b2]197 printf(" [%d] (hash %p)", 1 + i, (void *) thread_hash_buf[i]);
[9a1b20c]198 }
[7e752b2]199 printf("\ntotal of %zu threads\n", tb_needed / sizeof(uintptr_t));
[9a1b20c]200
201 return 0;
202}
203
[356acd0]204void val_print(sysarg_t val, val_type_t v_type)
[9a1b20c]205{
[f019cc07]206 long sval;
207
208 sval = (long) val;
209
[abf3564]210 switch (v_type) {
211 case V_VOID:
212 printf("<void>");
213 break;
214
215 case V_INTEGER:
[f019cc07]216 printf("%ld", sval);
[abf3564]217 break;
218
219 case V_HASH:
[4470e26]220 case V_PTR:
[7e752b2]221 printf("%p", (void *) val);
[abf3564]222 break;
223
224 case V_ERRNO:
[f019cc07]225 if (sval >= -15 && sval <= 0) {
226 printf("%ld %s (%s)", sval,
227 err_desc[-sval].name,
228 err_desc[-sval].desc);
[9a1b20c]229 } else {
[f019cc07]230 printf("%ld", sval);
[9a1b20c]231 }
[abf3564]232 break;
233 case V_INT_ERRNO:
[f019cc07]234 if (sval >= -15 && sval < 0) {
235 printf("%ld %s (%s)", sval,
236 err_desc[-sval].name,
237 err_desc[-sval].desc);
[abf3564]238 } else {
[f019cc07]239 printf("%ld", sval);
[abf3564]240 }
241 break;
242
243 case V_CHAR:
[f019cc07]244 if (sval >= 0x20 && sval < 0x7f) {
[7e752b2]245 printf("'%c'", (char) sval);
[9a1b20c]246 } else {
[f019cc07]247 switch (sval) {
[abf3564]248 case '\a': printf("'\\a'"); break;
249 case '\b': printf("'\\b'"); break;
250 case '\n': printf("'\\n'"); break;
251 case '\r': printf("'\\r'"); break;
252 case '\t': printf("'\\t'"); break;
253 case '\\': printf("'\\\\'"); break;
[7e752b2]254 default: printf("'\\x%02" PRIxn "'", val); break;
[abf3564]255 }
[9a1b20c]256 }
[abf3564]257 break;
[9a1b20c]258 }
[abf3564]259}
260
261
[356acd0]262static void print_sc_retval(sysarg_t retval, val_type_t val_type)
[abf3564]263{
264 printf(" -> ");
265 val_print(retval, val_type);
[9a1b20c]266 putchar('\n');
267}
268
[a5c3f73]269static void print_sc_args(sysarg_t *sc_args, int n)
[9a1b20c]270{
271 int i;
272
273 putchar('(');
[7e752b2]274 if (n > 0) printf("%" PRIun, sc_args[0]);
[abf3564]275 for (i = 1; i < n; i++) {
[7e752b2]276 printf(", %" PRIun, sc_args[i]);
[9a1b20c]277 }
278 putchar(')');
279}
280
[a5c3f73]281static void sc_ipc_call_async_fast(sysarg_t *sc_args, sysarg_t sc_rc)
[9a1b20c]282{
283 ipc_call_t call;
[96b02eb9]284 sysarg_t phoneid;
[9a1b20c]285
[7b8f933]286 if (sc_rc != (sysarg_t) EOK)
[9a1b20c]287 return;
288
289 phoneid = sc_args[0];
290
[228e490]291 IPC_SET_IMETHOD(call, sc_args[1]);
[9a1b20c]292 IPC_SET_ARG1(call, sc_args[2]);
293 IPC_SET_ARG2(call, sc_args[3]);
294 IPC_SET_ARG3(call, sc_args[4]);
295 IPC_SET_ARG4(call, sc_args[5]);
296 IPC_SET_ARG5(call, 0);
297
298 ipcp_call_out(phoneid, &call, sc_rc);
299}
300
[a5c3f73]301static void sc_ipc_call_async_slow(sysarg_t *sc_args, sysarg_t sc_rc)
[9a1b20c]302{
303 ipc_call_t call;
304 int rc;
305
[7b8f933]306 if (sc_rc != (sysarg_t) EOK)
[9a1b20c]307 return;
308
309 memset(&call, 0, sizeof(call));
[79ae36dd]310 rc = udebug_mem_read(sess, &call.args, sc_args[1], sizeof(call.args));
[9a1b20c]311
312 if (rc >= 0) {
313 ipcp_call_out(sc_args[0], &call, sc_rc);
314 }
315}
316
[a5c3f73]317static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc)
[9a1b20c]318{
319 ipc_call_t call;
320 int rc;
321
322 if (sc_rc == 0) return;
323
324 memset(&call, 0, sizeof(call));
[79ae36dd]325 rc = udebug_mem_read(sess, &call, sc_args[0], sizeof(call));
326
327 if (rc >= 0)
[9a1b20c]328 ipcp_call_in(&call, sc_rc);
329}
330
[a5c3f73]331static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
332 unsigned sc_id, sysarg_t sc_rc)
[9a1b20c]333{
[a5c3f73]334 sysarg_t sc_args[6];
[9a1b20c]335 int rc;
336
337 /* Read syscall arguments */
[79ae36dd]338 rc = udebug_args_read(sess, thread_hash, sc_args);
[9a1b20c]339
340 if (rc < 0) {
341 printf("error\n");
342 return;
343 }
344
[1643855]345 if ((display_mask & DM_SYSCALL) != 0) {
346 /* Print syscall name and arguments */
[a3b339b4]347 if (syscall_desc_defined(sc_id)) {
348 printf("%s", syscall_desc[sc_id].name);
349 print_sc_args(sc_args, syscall_desc[sc_id].n_args);
350 }
351 else {
352 printf("unknown_syscall<%d>", sc_id);
353 print_sc_args(sc_args, 6);
354 }
[1643855]355 }
[9a1b20c]356}
357
[a5c3f73]358static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
359 unsigned sc_id, sysarg_t sc_rc)
[9a1b20c]360{
[a5c3f73]361 sysarg_t sc_args[6];
[9a1b20c]362 int rv_type;
363 int rc;
364
365 /* Read syscall arguments */
[79ae36dd]366 rc = udebug_args_read(sess, thread_hash, sc_args);
[9a1b20c]367
368// printf("[%d] ", thread_id);
369
370 if (rc < 0) {
371 printf("error\n");
372 return;
373 }
374
[1643855]375 if ((display_mask & DM_SYSCALL) != 0) {
376 /* Print syscall return value */
[a3b339b4]377 if (syscall_desc_defined(sc_id))
378 rv_type = syscall_desc[sc_id].rv_type;
379 else
380 rv_type = V_PTR;
[1643855]381 print_sc_retval(sc_rc, rv_type);
382 }
[9a1b20c]383
384 switch (sc_id) {
385 case SYS_IPC_CALL_ASYNC_FAST:
386 sc_ipc_call_async_fast(sc_args, sc_rc);
387 break;
388 case SYS_IPC_CALL_ASYNC_SLOW:
389 sc_ipc_call_async_slow(sc_args, sc_rc);
390 break;
391 case SYS_IPC_WAIT:
392 sc_ipc_wait(sc_args, sc_rc);
393 break;
394 default:
395 break;
396 }
397}
398
[a5c3f73]399static void event_thread_b(uintptr_t hash)
[9a1b20c]400{
[7e752b2]401 printf("New thread, hash %p\n", (void *) hash);
[9a1b20c]402 thread_trace_start(hash);
403}
404
405static int trace_loop(void *thread_hash_arg)
406{
407 int rc;
408 unsigned ev_type;
[a5c3f73]409 uintptr_t thread_hash;
[9a1b20c]410 unsigned thread_id;
[a5c3f73]411 sysarg_t val0, val1;
[9a1b20c]412
[a5c3f73]413 thread_hash = (uintptr_t)thread_hash_arg;
[9a1b20c]414 thread_id = next_thread_id++;
[c8404d4]415 if (thread_id >= THBUF_SIZE) {
416 printf("Too many threads.\n");
417 return ELIMIT;
418 }
[9a1b20c]419
[7e752b2]420 printf("Start tracing thread [%u] (hash %p).\n",
421 thread_id, (void *) thread_hash);
[9a1b20c]422
423 while (!abort_trace) {
424
[84683fdc]425 fibril_mutex_lock(&state_lock);
[741fd16]426 if (paused) {
[7e752b2]427 printf("Thread [%u] paused. Press R to resume.\n",
[654a30a]428 thread_id);
429
430 while (paused)
[84683fdc]431 fibril_condvar_wait(&state_cv, &state_lock);
[654a30a]432
[7e752b2]433 printf("Thread [%u] resumed.\n", thread_id);
[741fd16]434 }
[84683fdc]435 fibril_mutex_unlock(&state_lock);
[741fd16]436
[9a1b20c]437 /* Run thread until an event occurs */
[79ae36dd]438 rc = udebug_go(sess, thread_hash,
[9a1b20c]439 &ev_type, &val0, &val1);
440
441// printf("rc = %d, ev_type=%d\n", rc, ev_type);
442 if (ev_type == UDEBUG_EVENT_FINISHED) {
[c9a29d6]443 /* Done tracing this thread */
[9a1b20c]444 break;
445 }
446
447 if (rc >= 0) {
448 switch (ev_type) {
449 case UDEBUG_EVENT_SYSCALL_B:
450 event_syscall_b(thread_id, thread_hash, val0, (int)val1);
451 break;
452 case UDEBUG_EVENT_SYSCALL_E:
453 event_syscall_e(thread_id, thread_hash, val0, (int)val1);
454 break;
455 case UDEBUG_EVENT_STOP:
[c9a29d6]456 printf("Stop event\n");
[84683fdc]457 fibril_mutex_lock(&state_lock);
[9ad5b5cc]458 paused = true;
[84683fdc]459 fibril_mutex_unlock(&state_lock);
[9a1b20c]460 break;
461 case UDEBUG_EVENT_THREAD_B:
462 event_thread_b(val0);
463 break;
464 case UDEBUG_EVENT_THREAD_E:
[7e752b2]465 printf("Thread %" PRIun " exited.\n", val0);
[84683fdc]466 fibril_mutex_lock(&state_lock);
[9ad5b5cc]467 abort_trace = true;
[84683fdc]468 fibril_condvar_broadcast(&state_cv);
469 fibril_mutex_unlock(&state_lock);
[9a1b20c]470 break;
471 default:
[ef687799]472 printf("Unknown event type %d.\n", ev_type);
[9a1b20c]473 break;
474 }
475 }
476
477 }
478
[ef687799]479 printf("Finished tracing thread [%d].\n", thread_id);
[9a1b20c]480 return 0;
481}
482
[a5c3f73]483void thread_trace_start(uintptr_t thread_hash)
[9a1b20c]484{
485 fid_t fid;
486
487 thash = thread_hash;
488
489 fid = fibril_create(trace_loop, (void *)thread_hash);
490 if (fid == 0) {
491 printf("Warning: Failed creating fibril\n");
492 }
493 fibril_add_ready(fid);
494}
495
[a000878c]496static loader_t *preload_task(const char *path, char **argv,
[4470e26]497 task_id_t *task_id)
[9a1b20c]498{
[4470e26]499 loader_t *ldr;
[9a1b20c]500 int rc;
501
[a000878c]502 /* Spawn a program loader */
[08b777e]503 ldr = loader_connect();
[4470e26]504 if (ldr == NULL)
[a3b339b4]505 return NULL;
[4470e26]506
507 /* Get task ID. */
508 rc = loader_get_task_id(ldr, task_id);
509 if (rc != EOK)
510 goto error;
511
[5126f80]512 /* Send program. */
[bb9ec2d]513 rc = loader_set_program_path(ldr, path);
[4470e26]514 if (rc != EOK)
515 goto error;
516
517 /* Send arguments */
[a000878c]518 rc = loader_set_args(ldr, (const char **) argv);
[4470e26]519 if (rc != EOK)
520 goto error;
521
[8e1dc00]522 /* Send default files */
[5126f80]523 int fd_root;
[7171760]524 int fd_stdin;
525 int fd_stdout;
526 int fd_stderr;
[8e1dc00]527
[5126f80]528 fd_root = vfs_root();
529 if (fd_root >= 0) {
530 rc = loader_add_inbox(ldr, "root", fd_root);
[9c4cf0d]531 vfs_put(fd_root);
[5126f80]532 if (rc != EOK)
533 goto error;
534 }
535
[bb9ec2d]536 if ((stdin != NULL) && (vfs_fhandle(stdin, &fd_stdin) == EOK)) {
537 rc = loader_add_inbox(ldr, "stdin", fd_stdin);
538 if (rc != EOK)
539 goto error;
540 }
[8e1dc00]541
[bb9ec2d]542 if ((stdout != NULL) && (vfs_fhandle(stdout, &fd_stdout) == EOK)) {
543 rc = loader_add_inbox(ldr, "stdout", fd_stdout);
544 if (rc != EOK)
545 goto error;
546 }
[8e1dc00]547
[bb9ec2d]548 if ((stderr != NULL) && (vfs_fhandle(stderr, &fd_stderr) == EOK)) {
549 rc = loader_add_inbox(ldr, "stderr", fd_stderr);
550 if (rc != EOK)
551 goto error;
552 }
[8e1dc00]553
[4470e26]554 /* Load the program. */
555 rc = loader_load_program(ldr);
556 if (rc != EOK)
557 goto error;
558
559 /* Success */
560 return ldr;
561
562 /* Error exit */
563error:
564 loader_abort(ldr);
565 return NULL;
566}
[9a1b20c]567
[84683fdc]568static int cev_fibril(void *arg)
569{
[07b7c48]570 cons_event_t event;
571
[84683fdc]572 (void) arg;
[79ae36dd]573
574 console_ctrl_t *console = console_init(stdin, stdout);
575
[84683fdc]576 while (true) {
577 fibril_mutex_lock(&state_lock);
578 while (cev_valid)
579 fibril_condvar_wait(&state_cv, &state_lock);
580 fibril_mutex_unlock(&state_lock);
[79ae36dd]581
[07b7c48]582 if (!console_get_event(console, &event))
[84683fdc]583 return -1;
[79ae36dd]584
[07b7c48]585 if (event.type == CEV_KEY) {
586 fibril_mutex_lock(&state_lock);
587 cev = event.ev.key;
588 cev_valid = true;
589 fibril_condvar_broadcast(&state_cv);
590 fibril_mutex_unlock(&state_lock);
591 }
[84683fdc]592 }
593}
594
[4470e26]595static void trace_task(task_id_t task_id)
596{
[79ae36dd]597 kbd_event_t ev;
[9d8a1ed]598 bool done;
[4470e26]599 int i;
600 int rc;
[9a1b20c]601
602 ipcp_init();
[c9a29d6]603
[9a1b20c]604 rc = get_thread_list();
605 if (rc < 0) {
606 printf("Failed to get thread list (error %d)\n", rc);
607 return;
608 }
609
[9ad5b5cc]610 abort_trace = false;
[9a1b20c]611
612 for (i = 0; i < n_threads; i++) {
613 thread_trace_start(thread_hash_buf[i]);
614 }
615
[9d8a1ed]616 done = false;
617
618 while (!done) {
[84683fdc]619 fibril_mutex_lock(&state_lock);
620 while (!cev_valid && !abort_trace)
621 fibril_condvar_wait(&state_cv, &state_lock);
622 fibril_mutex_unlock(&state_lock);
623
624 ev = cev;
625
626 fibril_mutex_lock(&state_lock);
627 cev_valid = false;
628 fibril_condvar_broadcast(&state_cv);
629 fibril_mutex_unlock(&state_lock);
630
631 if (abort_trace)
632 break;
[9d8a1ed]633
634 if (ev.type != KEY_PRESS)
635 continue;
636
637 switch (ev.key) {
638 case KC_Q:
639 done = true;
640 break;
641 case KC_P:
[741fd16]642 printf("Pause...\n");
[79ae36dd]643 rc = udebug_stop(sess, thash);
[654a30a]644 if (rc != EOK)
645 printf("Error: stop -> %d\n", rc);
[9d8a1ed]646 break;
647 case KC_R:
[84683fdc]648 fibril_mutex_lock(&state_lock);
[9ad5b5cc]649 paused = false;
[84683fdc]650 fibril_condvar_broadcast(&state_cv);
651 fibril_mutex_unlock(&state_lock);
[741fd16]652 printf("Resume...\n");
[9d8a1ed]653 break;
[7c014d1]654 default:
655 break;
[9a1b20c]656 }
657 }
658
[c9a29d6]659 printf("\nTerminate debugging session...\n");
[9ad5b5cc]660 abort_trace = true;
[79ae36dd]661 udebug_end(sess);
662 async_hangup(sess);
[9a1b20c]663
664 ipcp_cleanup();
665
[c9a29d6]666 printf("Done\n");
[9a1b20c]667 return;
668}
669
670static void main_init(void)
671{
672 proto_t *p;
673 oper_t *o;
674
[abf3564]675 val_type_t arg_def[OPER_MAX_ARGS] = {
676 V_INTEGER,
677 V_INTEGER,
678 V_INTEGER,
679 V_INTEGER,
680 V_INTEGER
681 };
682
683 val_type_t resp_def[OPER_MAX_ARGS] = {
684 V_INTEGER,
685 V_INTEGER,
686 V_INTEGER,
687 V_INTEGER,
[fa09449]688 V_INTEGER
[abf3564]689 };
690
[9a1b20c]691 next_thread_id = 1;
[9ad5b5cc]692 paused = false;
693 cev_valid = false;
[84683fdc]694
695 fibril_mutex_initialize(&state_lock);
696 fibril_condvar_initialize(&state_cv);
[9a1b20c]697
698 proto_init();
699
700 p = proto_new("vfs");
[58898d1d]701 o = oper_new("read", 3, arg_def, V_ERRNO, 1, resp_def);
[4198f9c3]702 proto_add_oper(p, VFS_IN_READ, o);
[58898d1d]703 o = oper_new("write", 3, arg_def, V_ERRNO, 1, resp_def);
[4198f9c3]704 proto_add_oper(p, VFS_IN_WRITE, o);
[9c4cf0d]705 o = oper_new("vfs_resize", 5, arg_def, V_ERRNO, 0, resp_def);
[67e881c]706 proto_add_oper(p, VFS_IN_RESIZE, o);
[9c4cf0d]707 o = oper_new("vfs_stat", 1, arg_def, V_ERRNO, 0, resp_def);
[fe91f66]708 proto_add_oper(p, VFS_IN_STAT, o);
[9c4cf0d]709 o = oper_new("vfs_put", 1, arg_def, V_ERRNO, 0, resp_def);
710 proto_add_oper(p, VFS_IN_PUT, o);
711 o = oper_new("vfs_mount", 2, arg_def, V_ERRNO, 0, resp_def);
[4198f9c3]712 proto_add_oper(p, VFS_IN_MOUNT, o);
[abf3564]713/* o = oper_new("unmount", 0, arg_def);
[4198f9c3]714 proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
[9c4cf0d]715 o = oper_new("vfs_sync", 1, arg_def, V_ERRNO, 0, resp_def);
[a5facfb]716 proto_add_oper(p, VFS_IN_SYNC, o);
[741a7af9]717 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
[4198f9c3]718 proto_add_oper(p, VFS_IN_RENAME, o);
[9c4cf0d]719 o = oper_new("vfs_statfs", 0, arg_def, V_ERRNO, 0, resp_def);
[5930e3f]720 proto_add_oper(p, VFS_IN_STATFS, o);
[9c4cf0d]721 o = oper_new("vfs_walk", 2, arg_def, V_INT_ERRNO, 0, resp_def);
[ff8c87c]722 proto_add_oper(p, VFS_IN_WALK, o);
[9c4cf0d]723 o = oper_new("vfs_open", 2, arg_def, V_ERRNO, 0, resp_def);
[fe91f66]724 proto_add_oper(p, VFS_IN_OPEN, o);
[9c4cf0d]725 o = oper_new("vfs_unlink", 3, arg_def, V_ERRNO, 0, resp_def);
[fe91f66]726 proto_add_oper(p, VFS_IN_UNLINK, o);
[9a1b20c]727
728 proto_register(SERVICE_VFS, p);
729}
730
[193d280c]731static void print_syntax(void)
[9a1b20c]732{
[47e0a05b]733 printf("Syntax:\n");
734 printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
735 printf("or\ttrace [+<events>] -t <task_id>\n");
[1643855]736 printf("Events: (default is +tp)\n");
737 printf("\n");
738 printf("\tt ... Thread creation and termination\n");
739 printf("\ts ... System calls\n");
740 printf("\ti ... Low-level IPC\n");
741 printf("\tp ... Protocol level\n");
742 printf("\n");
[47e0a05b]743 printf("Examples:\n");
744 printf("\ttrace +s /app/tetris\n");
745 printf("\ttrace +tsip -t 12\n");
[9a1b20c]746}
747
[a000878c]748static display_mask_t parse_display_mask(const char *text)
[9a1b20c]749{
[f1cc9db]750 display_mask_t dm = 0;
[a000878c]751 const char *c = text;
752
[1643855]753 while (*c) {
754 switch (*c) {
[a000878c]755 case 't':
756 dm = dm | DM_THREAD;
757 break;
758 case 's':
759 dm = dm | DM_SYSCALL;
760 break;
761 case 'i':
762 dm = dm | DM_IPC;
763 break;
764 case 'p':
765 dm = dm | DM_SYSTEM | DM_USER;
766 break;
[1643855]767 default:
[ef687799]768 printf("Unexpected event type '%c'.\n", *c);
[1643855]769 exit(1);
770 }
[a000878c]771
[1643855]772 ++c;
773 }
[a000878c]774
[1643855]775 return dm;
776}
777
778static int parse_args(int argc, char *argv[])
779{
[9a1b20c]780 char *err_p;
781
[47e0a05b]782 task_id = 0;
783
[a000878c]784 --argc;
785 ++argv;
[1643855]786
[47e0a05b]787 while (argc > 0) {
[a000878c]788 char *arg = *argv;
[1643855]789 if (arg[0] == '+') {
790 display_mask = parse_display_mask(&arg[1]);
[47e0a05b]791 } else if (arg[0] == '-') {
792 if (arg[1] == 't') {
793 /* Trace an already running task */
[a000878c]794 --argc;
795 ++argv;
[47e0a05b]796 task_id = strtol(*argv, &err_p, 10);
[4470e26]797 task_ldr = NULL;
[9ad5b5cc]798 task_wait_for = false;
[47e0a05b]799 if (*err_p) {
800 printf("Task ID syntax error\n");
801 print_syntax();
802 return -1;
803 }
804 } else {
[7e752b2]805 printf("Uknown option '%c'\n", arg[0]);
[47e0a05b]806 print_syntax();
807 return -1;
808 }
[1643855]809 } else {
[47e0a05b]810 break;
[1643855]811 }
[a000878c]812
813 --argc;
814 ++argv;
[1643855]815 }
816
[47e0a05b]817 if (task_id != 0) {
[a000878c]818 if (argc == 0)
819 return 0;
[47e0a05b]820 printf("Extra arguments\n");
[9a1b20c]821 print_syntax();
[47e0a05b]822 return -1;
[9a1b20c]823 }
824
[47e0a05b]825 if (argc < 1) {
826 printf("Missing argument\n");
[9a1b20c]827 print_syntax();
[1643855]828 return -1;
[9a1b20c]829 }
830
[4470e26]831 /* Preload the specified program file. */
[47e0a05b]832 printf("Spawning '%s' with arguments:\n", *argv);
[a000878c]833
834 char **cp = argv;
835 while (*cp)
836 printf("'%s'\n", *cp++);
837
[4470e26]838 task_ldr = preload_task(*argv, argv, &task_id);
[9ad5b5cc]839 task_wait_for = true;
[47e0a05b]840
[1643855]841 return 0;
842}
843
844int main(int argc, char *argv[])
845{
[4470e26]846 int rc;
[6e3a44a]847 task_exit_t texit;
848 int retval;
[4470e26]849
[1643855]850 printf("System Call / IPC Tracer\n");
[ef687799]851 printf("Controls: Q - Quit, P - Pause, R - Resume\n");
[1643855]852
853 display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
854
855 if (parse_args(argc, argv) < 0)
856 return 1;
857
[9a1b20c]858 main_init();
[4470e26]859
860 rc = connect_task(task_id);
861 if (rc < 0) {
[7e752b2]862 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
[4470e26]863 return 1;
864 }
865
[7e752b2]866 printf("Connected to task %" PRIu64 ".\n", task_id);
[4470e26]867
[6e3a44a]868 if (task_ldr != NULL)
[4470e26]869 program_run();
870
[84683fdc]871 cev_fibril_start();
[4470e26]872 trace_task(task_id);
[1643855]873
[6e3a44a]874 if (task_wait_for) {
875 printf("Waiting for task to exit.\n");
876
[1c635d6]877 rc = task_wait_task_id(task_id, &texit, &retval);
[6e3a44a]878 if (rc != EOK) {
879 printf("Failed waiting for task.\n");
880 return -1;
881 }
882
883 if (texit == TASK_EXIT_NORMAL) {
884 printf("Task exited normally, return value %d.\n",
885 retval);
886 } else {
887 printf("Task exited unexpectedly.\n");
888 }
889 }
890
[1643855]891 return 0;
[9a1b20c]892}
893
894/** @}
895 */
Note: See TracBrowser for help on using the repository browser.