00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <unistd.h>
00038 #include <fibril.h>
00039 #include <errno.h>
00040 #include <udebug.h>
00041 #include <async.h>
00042 #include <task.h>
00043 #include <mem.h>
00044 #include <str.h>
00045 #include <bool.h>
00046 #include <loader/loader.h>
00047 #include <io/console.h>
00048 #include <io/keycode.h>
00049 #include <fibril_synch.h>
00050 #include <sys/types.h>
00051 #include <sys/typefmt.h>
00052
00053 #include <libc.h>
00054
00055
00056 #include "proto.h"
00057 #include <ipc/services.h>
00058 #include "../../srv/vfs/vfs.h"
00059 #include <ipc/console.h>
00060
00061 #include "syscalls.h"
00062 #include "ipcp.h"
00063 #include "errors.h"
00064 #include "trace.h"
00065
00066 #define THBUF_SIZE 64
00067 uintptr_t thread_hash_buf[THBUF_SIZE];
00068 int n_threads;
00069
00070 int next_thread_id;
00071
00072 ipc_call_t thread_ipc_req[THBUF_SIZE];
00073
00074 int phoneid;
00075 bool abort_trace;
00076
00077 uintptr_t thash;
00078 static bool paused;
00079 static fibril_condvar_t state_cv;
00080 static fibril_mutex_t state_lock;
00081
00082 static bool cev_valid;
00083 static console_event_t cev;
00084
00085 void thread_trace_start(uintptr_t thread_hash);
00086
00087 static proto_t *proto_console;
00088 static task_id_t task_id;
00089 static loader_t *task_ldr;
00090 static bool task_wait_for;
00091
00093 display_mask_t display_mask;
00094
00095 static int program_run_fibril(void *arg);
00096 static int cev_fibril(void *arg);
00097
00098 static void program_run(void)
00099 {
00100 fid_t fid;
00101
00102 fid = fibril_create(program_run_fibril, NULL);
00103 if (fid == 0) {
00104 printf("Error creating fibril\n");
00105 exit(1);
00106 }
00107
00108 fibril_add_ready(fid);
00109 }
00110
00111 static void cev_fibril_start(void)
00112 {
00113 fid_t fid;
00114
00115 fid = fibril_create(cev_fibril, NULL);
00116 if (fid == 0) {
00117 printf("Error creating fibril\n");
00118 exit(1);
00119 }
00120
00121 fibril_add_ready(fid);
00122 }
00123
00124 static int program_run_fibril(void *arg)
00125 {
00126 int rc;
00127
00128
00129
00130
00131
00132 rc = loader_run(task_ldr);
00133 if (rc != 0) {
00134 printf("Error running program\n");
00135 exit(1);
00136 }
00137
00138 free(task_ldr);
00139 task_ldr = NULL;
00140
00141 printf("program_run_fibril exiting\n");
00142 return 0;
00143 }
00144
00145
00146 static int connect_task(task_id_t task_id)
00147 {
00148 int rc;
00149
00150 rc = async_connect_kbox(task_id);
00151
00152 if (rc == ENOTSUP) {
00153 printf("You do not have userspace debugging support "
00154 "compiled in the kernel.\n");
00155 printf("Compile kernel with 'Support for userspace debuggers' "
00156 "(CONFIG_UDEBUG) enabled.\n");
00157 return rc;
00158 }
00159
00160 if (rc < 0) {
00161 printf("Error connecting\n");
00162 printf("ipc_connect_task(%" PRIu64 ") -> %d ", task_id, rc);
00163 return rc;
00164 }
00165
00166 phoneid = rc;
00167
00168 rc = udebug_begin(phoneid);
00169 if (rc < 0) {
00170 printf("udebug_begin() -> %d\n", rc);
00171 return rc;
00172 }
00173
00174 rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
00175 if (rc < 0) {
00176 printf("udebug_set_evmask(0x%x) -> %d\n ", UDEBUG_EM_ALL, rc);
00177 return rc;
00178 }
00179
00180 return 0;
00181 }
00182
00183 static int get_thread_list(void)
00184 {
00185 int rc;
00186 size_t tb_copied;
00187 size_t tb_needed;
00188 int i;
00189
00190 rc = udebug_thread_read(phoneid, thread_hash_buf,
00191 THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
00192 if (rc < 0) {
00193 printf("udebug_thread_read() -> %d\n", rc);
00194 return rc;
00195 }
00196
00197 n_threads = tb_copied / sizeof(uintptr_t);
00198
00199 printf("Threads:");
00200 for (i = 0; i < n_threads; i++) {
00201 printf(" [%d] (hash %p)", 1 + i, (void *) thread_hash_buf[i]);
00202 }
00203 printf("\ntotal of %zu threads\n", tb_needed / sizeof(uintptr_t));
00204
00205 return 0;
00206 }
00207
00208 void val_print(sysarg_t val, val_type_t v_type)
00209 {
00210 long sval;
00211
00212 sval = (long) val;
00213
00214 switch (v_type) {
00215 case V_VOID:
00216 printf("<void>");
00217 break;
00218
00219 case V_INTEGER:
00220 printf("%ld", sval);
00221 break;
00222
00223 case V_HASH:
00224 case V_PTR:
00225 printf("%p", (void *) val);
00226 break;
00227
00228 case V_ERRNO:
00229 if (sval >= -15 && sval <= 0) {
00230 printf("%ld %s (%s)", sval,
00231 err_desc[-sval].name,
00232 err_desc[-sval].desc);
00233 } else {
00234 printf("%ld", sval);
00235 }
00236 break;
00237 case V_INT_ERRNO:
00238 if (sval >= -15 && sval < 0) {
00239 printf("%ld %s (%s)", sval,
00240 err_desc[-sval].name,
00241 err_desc[-sval].desc);
00242 } else {
00243 printf("%ld", sval);
00244 }
00245 break;
00246
00247 case V_CHAR:
00248 if (sval >= 0x20 && sval < 0x7f) {
00249 printf("'%c'", (char) sval);
00250 } else {
00251 switch (sval) {
00252 case '\a': printf("'\\a'"); break;
00253 case '\b': printf("'\\b'"); break;
00254 case '\n': printf("'\\n'"); break;
00255 case '\r': printf("'\\r'"); break;
00256 case '\t': printf("'\\t'"); break;
00257 case '\\': printf("'\\\\'"); break;
00258 default: printf("'\\x%02" PRIxn "'", val); break;
00259 }
00260 }
00261 break;
00262 }
00263 }
00264
00265
00266 static void print_sc_retval(sysarg_t retval, val_type_t val_type)
00267 {
00268 printf(" -> ");
00269 val_print(retval, val_type);
00270 putchar('\n');
00271 }
00272
00273 static void print_sc_args(sysarg_t *sc_args, int n)
00274 {
00275 int i;
00276
00277 putchar('(');
00278 if (n > 0) printf("%" PRIun, sc_args[0]);
00279 for (i = 1; i < n; i++) {
00280 printf(", %" PRIun, sc_args[i]);
00281 }
00282 putchar(')');
00283 }
00284
00285 static void sc_ipc_call_async_fast(sysarg_t *sc_args, sysarg_t sc_rc)
00286 {
00287 ipc_call_t call;
00288 sysarg_t phoneid;
00289
00290 if (sc_rc == (sysarg_t) IPC_CALLRET_FATAL ||
00291 sc_rc == (sysarg_t) IPC_CALLRET_TEMPORARY)
00292 return;
00293
00294 phoneid = sc_args[0];
00295
00296 IPC_SET_IMETHOD(call, sc_args[1]);
00297 IPC_SET_ARG1(call, sc_args[2]);
00298 IPC_SET_ARG2(call, sc_args[3]);
00299 IPC_SET_ARG3(call, sc_args[4]);
00300 IPC_SET_ARG4(call, sc_args[5]);
00301 IPC_SET_ARG5(call, 0);
00302
00303 ipcp_call_out(phoneid, &call, sc_rc);
00304 }
00305
00306 static void sc_ipc_call_async_slow(sysarg_t *sc_args, sysarg_t sc_rc)
00307 {
00308 ipc_call_t call;
00309 int rc;
00310
00311 if (sc_rc == (sysarg_t) IPC_CALLRET_FATAL ||
00312 sc_rc == (sysarg_t) IPC_CALLRET_TEMPORARY)
00313 return;
00314
00315 memset(&call, 0, sizeof(call));
00316 rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
00317
00318 if (rc >= 0) {
00319 ipcp_call_out(sc_args[0], &call, sc_rc);
00320 }
00321 }
00322
00323 static void sc_ipc_call_sync_fast(sysarg_t *sc_args)
00324 {
00325 ipc_call_t question, reply;
00326 int rc;
00327 int phoneidx;
00328
00329
00330 phoneidx = sc_args[0];
00331
00332 IPC_SET_IMETHOD(question, sc_args[1]);
00333 IPC_SET_ARG1(question, sc_args[2]);
00334 IPC_SET_ARG2(question, sc_args[3]);
00335 IPC_SET_ARG3(question, sc_args[4]);
00336 IPC_SET_ARG4(question, 0);
00337 IPC_SET_ARG5(question, 0);
00338
00339
00340 memset(&reply, 0, sizeof(reply));
00341
00342
00343 rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
00344
00345 if (rc < 0) return;
00346
00347
00348 ipcp_call_sync(phoneidx, &question, &reply);
00349 }
00350
00351 static void sc_ipc_call_sync_slow_b(unsigned thread_id, sysarg_t *sc_args)
00352 {
00353 ipc_call_t question;
00354 int rc;
00355
00356 memset(&question, 0, sizeof(question));
00357 rc = udebug_mem_read(phoneid, &question.args, sc_args[1],
00358 sizeof(question.args));
00359
00360 if (rc < 0) {
00361 printf("Error: mem_read->%d\n", rc);
00362 return;
00363 }
00364
00365 thread_ipc_req[thread_id] = question;
00366 }
00367
00368 static void sc_ipc_call_sync_slow_e(unsigned thread_id, sysarg_t *sc_args)
00369 {
00370 ipc_call_t reply;
00371 int rc;
00372
00373 memset(&reply, 0, sizeof(reply));
00374 rc = udebug_mem_read(phoneid, &reply.args, sc_args[2],
00375 sizeof(reply.args));
00376
00377 if (rc < 0) {
00378 printf("Error: mem_read->%d\n", rc);
00379 return;
00380 }
00381
00382 ipcp_call_sync(sc_args[0], &thread_ipc_req[thread_id], &reply);
00383 }
00384
00385 static void sc_ipc_wait(sysarg_t *sc_args, int sc_rc)
00386 {
00387 ipc_call_t call;
00388 int rc;
00389
00390 if (sc_rc == 0) return;
00391
00392 memset(&call, 0, sizeof(call));
00393 rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
00394
00395
00396
00397 if (rc >= 0) {
00398 ipcp_call_in(&call, sc_rc);
00399 }
00400 }
00401
00402 static void event_syscall_b(unsigned thread_id, uintptr_t thread_hash,
00403 unsigned sc_id, sysarg_t sc_rc)
00404 {
00405 sysarg_t sc_args[6];
00406 int rc;
00407
00408
00409 rc = udebug_args_read(phoneid, thread_hash, sc_args);
00410
00411 async_serialize_start();
00412
00413
00414
00415 if (rc < 0) {
00416 printf("error\n");
00417 async_serialize_end();
00418 return;
00419 }
00420
00421 if ((display_mask & DM_SYSCALL) != 0) {
00422
00423 printf("%s", syscall_desc[sc_id].name);
00424 print_sc_args(sc_args, syscall_desc[sc_id].n_args);
00425 }
00426
00427 switch (sc_id) {
00428 case SYS_IPC_CALL_SYNC_SLOW:
00429 sc_ipc_call_sync_slow_b(thread_id, sc_args);
00430 break;
00431 default:
00432 break;
00433 }
00434
00435 async_serialize_end();
00436 }
00437
00438 static void event_syscall_e(unsigned thread_id, uintptr_t thread_hash,
00439 unsigned sc_id, sysarg_t sc_rc)
00440 {
00441 sysarg_t sc_args[6];
00442 int rv_type;
00443 int rc;
00444
00445
00446 rc = udebug_args_read(phoneid, thread_hash, sc_args);
00447
00448 async_serialize_start();
00449
00450
00451
00452 if (rc < 0) {
00453 printf("error\n");
00454 async_serialize_end();
00455 return;
00456 }
00457
00458 if ((display_mask & DM_SYSCALL) != 0) {
00459
00460 rv_type = syscall_desc[sc_id].rv_type;
00461 print_sc_retval(sc_rc, rv_type);
00462 }
00463
00464 switch (sc_id) {
00465 case SYS_IPC_CALL_ASYNC_FAST:
00466 sc_ipc_call_async_fast(sc_args, sc_rc);
00467 break;
00468 case SYS_IPC_CALL_ASYNC_SLOW:
00469 sc_ipc_call_async_slow(sc_args, sc_rc);
00470 break;
00471 case SYS_IPC_CALL_SYNC_FAST:
00472 sc_ipc_call_sync_fast(sc_args);
00473 break;
00474 case SYS_IPC_CALL_SYNC_SLOW:
00475 sc_ipc_call_sync_slow_e(thread_id, sc_args);
00476 break;
00477 case SYS_IPC_WAIT:
00478 sc_ipc_wait(sc_args, sc_rc);
00479 break;
00480 default:
00481 break;
00482 }
00483
00484 async_serialize_end();
00485 }
00486
00487 static void event_thread_b(uintptr_t hash)
00488 {
00489 async_serialize_start();
00490 printf("New thread, hash %p\n", (void *) hash);
00491 async_serialize_end();
00492
00493 thread_trace_start(hash);
00494 }
00495
00496 static int trace_loop(void *thread_hash_arg)
00497 {
00498 int rc;
00499 unsigned ev_type;
00500 uintptr_t thread_hash;
00501 unsigned thread_id;
00502 sysarg_t val0, val1;
00503
00504 thread_hash = (uintptr_t)thread_hash_arg;
00505 thread_id = next_thread_id++;
00506 if (thread_id >= THBUF_SIZE) {
00507 printf("Too many threads.\n");
00508 return ELIMIT;
00509 }
00510
00511 printf("Start tracing thread [%u] (hash %p).\n",
00512 thread_id, (void *) thread_hash);
00513
00514 while (!abort_trace) {
00515
00516 fibril_mutex_lock(&state_lock);
00517 if (paused) {
00518 printf("Thread [%u] paused. Press R to resume.\n",
00519 thread_id);
00520
00521 while (paused)
00522 fibril_condvar_wait(&state_cv, &state_lock);
00523
00524 printf("Thread [%u] resumed.\n", thread_id);
00525 }
00526 fibril_mutex_unlock(&state_lock);
00527
00528
00529 rc = udebug_go(phoneid, thread_hash,
00530 &ev_type, &val0, &val1);
00531
00532
00533 if (ev_type == UDEBUG_EVENT_FINISHED) {
00534
00535 break;
00536 }
00537
00538 if (rc >= 0) {
00539 switch (ev_type) {
00540 case UDEBUG_EVENT_SYSCALL_B:
00541 event_syscall_b(thread_id, thread_hash, val0, (int)val1);
00542 break;
00543 case UDEBUG_EVENT_SYSCALL_E:
00544 event_syscall_e(thread_id, thread_hash, val0, (int)val1);
00545 break;
00546 case UDEBUG_EVENT_STOP:
00547 printf("Stop event\n");
00548 fibril_mutex_lock(&state_lock);
00549 paused = true;
00550 fibril_mutex_unlock(&state_lock);
00551 break;
00552 case UDEBUG_EVENT_THREAD_B:
00553 event_thread_b(val0);
00554 break;
00555 case UDEBUG_EVENT_THREAD_E:
00556 printf("Thread %" PRIun " exited.\n", val0);
00557 fibril_mutex_lock(&state_lock);
00558 abort_trace = true;
00559 fibril_condvar_broadcast(&state_cv);
00560 fibril_mutex_unlock(&state_lock);
00561 break;
00562 default:
00563 printf("Unknown event type %d.\n", ev_type);
00564 break;
00565 }
00566 }
00567
00568 }
00569
00570 printf("Finished tracing thread [%d].\n", thread_id);
00571 return 0;
00572 }
00573
00574 void thread_trace_start(uintptr_t thread_hash)
00575 {
00576 fid_t fid;
00577
00578 thash = thread_hash;
00579
00580 fid = fibril_create(trace_loop, (void *)thread_hash);
00581 if (fid == 0) {
00582 printf("Warning: Failed creating fibril\n");
00583 }
00584 fibril_add_ready(fid);
00585 }
00586
00587 static loader_t *preload_task(const char *path, char **argv,
00588 task_id_t *task_id)
00589 {
00590 loader_t *ldr;
00591 int rc;
00592
00593
00594 ldr = loader_connect();
00595 if (ldr == NULL)
00596 return 0;
00597
00598
00599 rc = loader_get_task_id(ldr, task_id);
00600 if (rc != EOK)
00601 goto error;
00602
00603
00604 rc = loader_set_pathname(ldr, path);
00605 if (rc != EOK)
00606 goto error;
00607
00608
00609 rc = loader_set_args(ldr, (const char **) argv);
00610 if (rc != EOK)
00611 goto error;
00612
00613
00614 fdi_node_t *files[4];
00615 fdi_node_t stdin_node;
00616 fdi_node_t stdout_node;
00617 fdi_node_t stderr_node;
00618
00619 if ((stdin != NULL) && (fnode(stdin, &stdin_node) == EOK))
00620 files[0] = &stdin_node;
00621 else
00622 files[0] = NULL;
00623
00624 if ((stdout != NULL) && (fnode(stdout, &stdout_node) == EOK))
00625 files[1] = &stdout_node;
00626 else
00627 files[1] = NULL;
00628
00629 if ((stderr != NULL) && (fnode(stderr, &stderr_node) == EOK))
00630 files[2] = &stderr_node;
00631 else
00632 files[2] = NULL;
00633
00634 files[3] = NULL;
00635
00636 rc = loader_set_files(ldr, files);
00637 if (rc != EOK)
00638 goto error;
00639
00640
00641 rc = loader_load_program(ldr);
00642 if (rc != EOK)
00643 goto error;
00644
00645
00646 return ldr;
00647
00648
00649 error:
00650 loader_abort(ldr);
00651 free(ldr);
00652 return NULL;
00653 }
00654
00655 static int cev_fibril(void *arg)
00656 {
00657 (void) arg;
00658
00659 while (true) {
00660 fibril_mutex_lock(&state_lock);
00661 while (cev_valid)
00662 fibril_condvar_wait(&state_cv, &state_lock);
00663 fibril_mutex_unlock(&state_lock);
00664
00665 if (!console_get_event(fphone(stdin), &cev))
00666 return -1;
00667
00668 fibril_mutex_lock(&state_lock);
00669 cev_valid = true;
00670 fibril_condvar_broadcast(&state_cv);
00671 fibril_mutex_unlock(&state_lock);
00672 }
00673 }
00674
00675 static void trace_task(task_id_t task_id)
00676 {
00677 console_event_t ev;
00678 bool done;
00679 int i;
00680 int rc;
00681
00682 ipcp_init();
00683
00684
00685
00686
00687
00688 ipcp_connection_set(3, 0, proto_console);
00689
00690 rc = get_thread_list();
00691 if (rc < 0) {
00692 printf("Failed to get thread list (error %d)\n", rc);
00693 return;
00694 }
00695
00696 abort_trace = false;
00697
00698 for (i = 0; i < n_threads; i++) {
00699 thread_trace_start(thread_hash_buf[i]);
00700 }
00701
00702 done = false;
00703
00704 while (!done) {
00705 fibril_mutex_lock(&state_lock);
00706 while (!cev_valid && !abort_trace)
00707 fibril_condvar_wait(&state_cv, &state_lock);
00708 fibril_mutex_unlock(&state_lock);
00709
00710 ev = cev;
00711
00712 fibril_mutex_lock(&state_lock);
00713 cev_valid = false;
00714 fibril_condvar_broadcast(&state_cv);
00715 fibril_mutex_unlock(&state_lock);
00716
00717 if (abort_trace)
00718 break;
00719
00720 if (ev.type != KEY_PRESS)
00721 continue;
00722
00723 switch (ev.key) {
00724 case KC_Q:
00725 done = true;
00726 break;
00727 case KC_P:
00728 printf("Pause...\n");
00729 rc = udebug_stop(phoneid, thash);
00730 if (rc != EOK)
00731 printf("Error: stop -> %d\n", rc);
00732 break;
00733 case KC_R:
00734 fibril_mutex_lock(&state_lock);
00735 paused = false;
00736 fibril_condvar_broadcast(&state_cv);
00737 fibril_mutex_unlock(&state_lock);
00738 printf("Resume...\n");
00739 break;
00740 }
00741 }
00742
00743 printf("\nTerminate debugging session...\n");
00744 abort_trace = true;
00745 udebug_end(phoneid);
00746 async_hangup(phoneid);
00747
00748 ipcp_cleanup();
00749
00750 printf("Done\n");
00751 return;
00752 }
00753
00754 static void main_init(void)
00755 {
00756 proto_t *p;
00757 oper_t *o;
00758
00759 val_type_t arg_def[OPER_MAX_ARGS] = {
00760 V_INTEGER,
00761 V_INTEGER,
00762 V_INTEGER,
00763 V_INTEGER,
00764 V_INTEGER
00765 };
00766
00767 val_type_t resp_def[OPER_MAX_ARGS] = {
00768 V_INTEGER,
00769 V_INTEGER,
00770 V_INTEGER,
00771 V_INTEGER,
00772 V_INTEGER
00773 };
00774
00775 next_thread_id = 1;
00776 paused = false;
00777 cev_valid = false;
00778
00779 fibril_mutex_initialize(&state_lock);
00780 fibril_condvar_initialize(&state_cv);
00781
00782 proto_init();
00783
00784 p = proto_new("vfs");
00785 o = oper_new("open", 2, arg_def, V_INT_ERRNO, 0, resp_def);
00786 proto_add_oper(p, VFS_IN_OPEN, o);
00787 o = oper_new("open_node", 4, arg_def, V_INT_ERRNO, 0, resp_def);
00788 proto_add_oper(p, VFS_IN_OPEN_NODE, o);
00789 o = oper_new("read", 1, arg_def, V_ERRNO, 1, resp_def);
00790 proto_add_oper(p, VFS_IN_READ, o);
00791 o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
00792 proto_add_oper(p, VFS_IN_WRITE, o);
00793 o = oper_new("seek", 3, arg_def, V_ERRNO, 0, resp_def);
00794 proto_add_oper(p, VFS_IN_SEEK, o);
00795 o = oper_new("truncate", 5, arg_def, V_ERRNO, 0, resp_def);
00796 proto_add_oper(p, VFS_IN_TRUNCATE, o);
00797 o = oper_new("fstat", 1, arg_def, V_ERRNO, 0, resp_def);
00798 proto_add_oper(p, VFS_IN_FSTAT, o);
00799 o = oper_new("close", 1, arg_def, V_ERRNO, 0, resp_def);
00800 proto_add_oper(p, VFS_IN_CLOSE, o);
00801 o = oper_new("mount", 2, arg_def, V_ERRNO, 0, resp_def);
00802 proto_add_oper(p, VFS_IN_MOUNT, o);
00803
00804
00805 o = oper_new("sync", 1, arg_def, V_ERRNO, 0, resp_def);
00806 proto_add_oper(p, VFS_IN_SYNC, o);
00807 o = oper_new("mkdir", 1, arg_def, V_ERRNO, 0, resp_def);
00808 proto_add_oper(p, VFS_IN_MKDIR, o);
00809 o = oper_new("unlink", 0, arg_def, V_ERRNO, 0, resp_def);
00810 proto_add_oper(p, VFS_IN_UNLINK, o);
00811 o = oper_new("rename", 0, arg_def, V_ERRNO, 0, resp_def);
00812 proto_add_oper(p, VFS_IN_RENAME, o);
00813 o = oper_new("stat", 0, arg_def, V_ERRNO, 0, resp_def);
00814 proto_add_oper(p, VFS_IN_STAT, o);
00815
00816 proto_register(SERVICE_VFS, p);
00817
00818 p = proto_new("console");
00819
00820 o = oper_new("write", 1, arg_def, V_ERRNO, 1, resp_def);
00821 proto_add_oper(p, VFS_IN_WRITE, o);
00822
00823 resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
00824 resp_def[2] = V_INTEGER; resp_def[3] = V_CHAR;
00825 o = oper_new("getkey", 0, arg_def, V_ERRNO, 4, resp_def);
00826
00827 arg_def[0] = V_CHAR;
00828 o = oper_new("clear", 0, arg_def, V_VOID, 0, resp_def);
00829 proto_add_oper(p, CONSOLE_CLEAR, o);
00830
00831 arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
00832 o = oper_new("goto", 2, arg_def, V_VOID, 0, resp_def);
00833 proto_add_oper(p, CONSOLE_GOTO, o);
00834
00835 resp_def[0] = V_INTEGER; resp_def[1] = V_INTEGER;
00836 o = oper_new("getsize", 0, arg_def, V_INTEGER, 2, resp_def);
00837 proto_add_oper(p, CONSOLE_GET_SIZE, o);
00838
00839 arg_def[0] = V_INTEGER;
00840 o = oper_new("set_style", 1, arg_def, V_VOID, 0, resp_def);
00841 proto_add_oper(p, CONSOLE_SET_STYLE, o);
00842 arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER; arg_def[2] = V_INTEGER;
00843 o = oper_new("set_color", 3, arg_def, V_VOID, 0, resp_def);
00844 proto_add_oper(p, CONSOLE_SET_COLOR, o);
00845 arg_def[0] = V_INTEGER; arg_def[1] = V_INTEGER;
00846 o = oper_new("set_rgb_color", 2, arg_def, V_VOID, 0, resp_def);
00847 proto_add_oper(p, CONSOLE_SET_RGB_COLOR, o);
00848 o = oper_new("cursor_visibility", 1, arg_def, V_VOID, 0, resp_def);
00849 proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
00850
00851 proto_console = p;
00852 proto_register(SERVICE_CONSOLE, p);
00853 }
00854
00855 static void print_syntax()
00856 {
00857 printf("Syntax:\n");
00858 printf("\ttrace [+<events>] <executable> [<arg1> [...]]\n");
00859 printf("or\ttrace [+<events>] -t <task_id>\n");
00860 printf("Events: (default is +tp)\n");
00861 printf("\n");
00862 printf("\tt ... Thread creation and termination\n");
00863 printf("\ts ... System calls\n");
00864 printf("\ti ... Low-level IPC\n");
00865 printf("\tp ... Protocol level\n");
00866 printf("\n");
00867 printf("Examples:\n");
00868 printf("\ttrace +s /app/tetris\n");
00869 printf("\ttrace +tsip -t 12\n");
00870 }
00871
00872 static display_mask_t parse_display_mask(const char *text)
00873 {
00874 display_mask_t dm = 0;
00875 const char *c = text;
00876
00877 while (*c) {
00878 switch (*c) {
00879 case 't':
00880 dm = dm | DM_THREAD;
00881 break;
00882 case 's':
00883 dm = dm | DM_SYSCALL;
00884 break;
00885 case 'i':
00886 dm = dm | DM_IPC;
00887 break;
00888 case 'p':
00889 dm = dm | DM_SYSTEM | DM_USER;
00890 break;
00891 default:
00892 printf("Unexpected event type '%c'.\n", *c);
00893 exit(1);
00894 }
00895
00896 ++c;
00897 }
00898
00899 return dm;
00900 }
00901
00902 static int parse_args(int argc, char *argv[])
00903 {
00904 char *err_p;
00905
00906 task_id = 0;
00907
00908 --argc;
00909 ++argv;
00910
00911 while (argc > 0) {
00912 char *arg = *argv;
00913 if (arg[0] == '+') {
00914 display_mask = parse_display_mask(&arg[1]);
00915 } else if (arg[0] == '-') {
00916 if (arg[1] == 't') {
00917
00918 --argc;
00919 ++argv;
00920 task_id = strtol(*argv, &err_p, 10);
00921 task_ldr = NULL;
00922 task_wait_for = false;
00923 if (*err_p) {
00924 printf("Task ID syntax error\n");
00925 print_syntax();
00926 return -1;
00927 }
00928 } else {
00929 printf("Uknown option '%c'\n", arg[0]);
00930 print_syntax();
00931 return -1;
00932 }
00933 } else {
00934 break;
00935 }
00936
00937 --argc;
00938 ++argv;
00939 }
00940
00941 if (task_id != 0) {
00942 if (argc == 0)
00943 return 0;
00944 printf("Extra arguments\n");
00945 print_syntax();
00946 return -1;
00947 }
00948
00949 if (argc < 1) {
00950 printf("Missing argument\n");
00951 print_syntax();
00952 return -1;
00953 }
00954
00955
00956 printf("Spawning '%s' with arguments:\n", *argv);
00957
00958 char **cp = argv;
00959 while (*cp)
00960 printf("'%s'\n", *cp++);
00961
00962 task_ldr = preload_task(*argv, argv, &task_id);
00963 task_wait_for = true;
00964
00965 return 0;
00966 }
00967
00968 int main(int argc, char *argv[])
00969 {
00970 int rc;
00971 task_exit_t texit;
00972 int retval;
00973
00974 printf("System Call / IPC Tracer\n");
00975 printf("Controls: Q - Quit, P - Pause, R - Resume\n");
00976
00977 display_mask = DM_THREAD | DM_SYSTEM | DM_USER;
00978
00979 if (parse_args(argc, argv) < 0)
00980 return 1;
00981
00982 main_init();
00983
00984 rc = connect_task(task_id);
00985 if (rc < 0) {
00986 printf("Failed connecting to task %" PRIu64 ".\n", task_id);
00987 return 1;
00988 }
00989
00990 printf("Connected to task %" PRIu64 ".\n", task_id);
00991
00992 if (task_ldr != NULL)
00993 program_run();
00994
00995 cev_fibril_start();
00996 trace_task(task_id);
00997
00998 if (task_wait_for) {
00999 printf("Waiting for task to exit.\n");
01000
01001 rc = task_wait(task_id, &texit, &retval);
01002 if (rc != EOK) {
01003 printf("Failed waiting for task.\n");
01004 return -1;
01005 }
01006
01007 if (texit == TASK_EXIT_NORMAL) {
01008 printf("Task exited normally, return value %d.\n",
01009 retval);
01010 } else {
01011 printf("Task exited unexpectedly.\n");
01012 }
01013 }
01014
01015 return 0;
01016 }
01017