source: mainline/uspace/app/trace/trace.c@ 4c35a76

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 4c35a76 was 7171760, checked in by Jakub Jermar <jakub@…>, 14 years ago

Rework the way how open files are passed from parent task to child.

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