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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fafb8e5 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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