source: mainline/uspace/app/trace/trace.c@ cf9a1e2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since cf9a1e2 was cf9a1e2, checked in by Jiri Svoboda <jiri@…>, 6 years ago

Fix use of unitialized variable

Found by gcc -Og

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