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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c9a7adc was 01900b6, checked in by Martin Decky <martin@…>, 6 years ago

Use an optional output argument instead of errno to propagate the error

The use of errno is troublesome in all other than top-level library
functions since the value in errno might get overwritten by subsequent
inner calls on the error path (e.g. cleanup, deallocation, etc.). The
optional output argument makes it possible to explicitly ignore the
error code if it is not needed, but still to pass it reliably back to
the original caller.

This change affecs async_connect_me_to(),
async_connect_me_to_blocking(), async_connect_kbox(), service_connect(),
service_connect_blocking() and loader_connect().

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