trace.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jiri Svoboda
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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 /* Temporary: service and method names */
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          * This must be done in background as it will block until
00130          * we let the task reply to this call.
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 //      printf("sc_ipc_call_sync_fast()\n");
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 //      printf("memset\n");
00340         memset(&reply, 0, sizeof(reply));
00341 //      printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
00342 //              phoneid, &reply.args, sc_args[5], sizeof(reply.args));
00343         rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
00344 //      printf("dmr->%d\n", rc);
00345         if (rc < 0) return;
00346 
00347 //      printf("call ipc_call_sync\n");
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 //      printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
00395 //              phoneid, (int)&call, sc_args[0], sizeof(call), rc);
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         /* Read syscall arguments */
00409         rc = udebug_args_read(phoneid, thread_hash, sc_args);
00410 
00411         async_serialize_start();
00412 
00413 //      printf("[%d] ", thread_id);
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                 /* Print syscall name and arguments */
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         /* Read syscall arguments */
00446         rc = udebug_args_read(phoneid, thread_hash, sc_args);
00447 
00448         async_serialize_start();
00449 
00450 //      printf("[%d] ", thread_id);
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                 /* Print syscall return value */
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                 /* Run thread until an event occurs */
00529                 rc = udebug_go(phoneid, thread_hash,
00530                     &ev_type, &val0, &val1);
00531 
00532 //              printf("rc = %d, ev_type=%d\n", rc, ev_type);
00533                 if (ev_type == UDEBUG_EVENT_FINISHED) {
00534                         /* Done tracing this thread */
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         /* Spawn a program loader */
00594         ldr = loader_connect();
00595         if (ldr == NULL)
00596                 return 0;
00597 
00598         /* Get task ID. */
00599         rc = loader_get_task_id(ldr, task_id);
00600         if (rc != EOK)
00601                 goto error;
00602 
00603         /* Send program pathname */
00604         rc = loader_set_pathname(ldr, path);
00605         if (rc != EOK)
00606                 goto error;
00607 
00608         /* Send arguments */
00609         rc = loader_set_args(ldr, (const char **) argv);
00610         if (rc != EOK)
00611                 goto error;
00612 
00613         /* Send default files */
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         /* Load the program. */
00641         rc = loader_load_program(ldr);
00642         if (rc != EOK)
00643                 goto error;
00644 
00645         /* Success */
00646         return ldr;
00647 
00648         /* Error exit */
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          * User apps now typically have console on phone 3.
00686          * (Phones 1 and 2 are used by the loader).
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 /*      o = oper_new("unmount", 0, arg_def);
00804         proto_add_oper(p, VFS_IN_UNMOUNT, o);*/
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                                 /* Trace an already running task */
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         /* Preload the specified program file. */
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 

Generated on Thu Jun 2 07:45:43 2011 for HelenOS/USB by  doxygen 1.4.7