source: mainline/uspace/app/trace/trace.c@ 0108984a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0108984a was fb9b0b0, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

Let trace display advice when udebug is not compiled in.

  • Property mode set to 100644
File size: 11.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 <syscall.h>
39#include <ipc/ipc.h>
40#include <fibril.h>
41#include <errno.h>
42#include <udebug.h>
43#include <async.h>
44
45// Temporary: service and method names
46#include "proto.h"
47#include <ipc/services.h>
48#include "../../srv/vfs/vfs.h"
49#include "../../srv/console/console.h"
50
51#include "syscalls.h"
52#include "ipcp.h"
53#include "errors.h"
54
55#define THBUF_SIZE 64
56unsigned thread_hash_buf[THBUF_SIZE];
57unsigned n_threads;
58
59int next_thread_id;
60
61int phoneid;
62int abort_trace;
63
64unsigned thash;
65volatile int paused;
66
67void thread_trace_start(unsigned thread_hash);
68
69static proto_t *proto_console;
70
71static int task_connect(task_id_t task_id)
72{
73 int rc;
74
75 printf("ipc_connect_task(%lld)... ", task_id);
76 rc = ipc_connect_kbox(task_id);
77 printf("-> %d\n", rc);
[fb9b0b0]78
79 if (rc == ENOTSUP) {
80 printf("You do not have userspace debugging support "
81 "compiled in the kernel.\n");
82 printf("Compile kernel with 'Support for userspace debuggers' "
83 "(CONFIG_UDEBUG) enabled.\n");
84 }
85
[9a1b20c]86 phoneid = rc;
87 if (rc < 0) return rc;
88
89 printf("udebug_begin()... ");
90 rc = udebug_begin(phoneid);
91 printf("-> %d\n", rc);
92 if (rc < 0) return rc;
93
94 printf("udebug_set_evmask(0x%x)... ", UDEBUG_EM_ALL);
95 rc = udebug_set_evmask(phoneid, UDEBUG_EM_ALL);
96 printf("-> %d\n", rc);
97 if (rc < 0) return rc;
98
99 return 0;
100}
101
102static int get_thread_list(void)
103{
104 int rc;
105 size_t tb_copied;
106 size_t tb_needed;
107 int i;
108
109 printf("send IPC_M_DEBUG_THREAD_READ message\n");
110 rc = udebug_thread_read(phoneid, thread_hash_buf,
111 THBUF_SIZE*sizeof(unsigned), &tb_copied, &tb_needed);
112 printf("-> %d\n", rc);
113 if (rc < 0) return rc;
114
115 n_threads = tb_copied / sizeof(unsigned);
116
117 printf("thread IDs:");
118 for (i=0; i<n_threads; i++) {
119 printf(" %u", thread_hash_buf[i]);
120 }
121 printf("\ntotal of %u threads\n", tb_needed/sizeof(unsigned));
122
123 return 0;
124}
125
126static void print_sc_retval(int retval, rv_type_t rv_type)
127{
128 printf (" -> ");
129 if (rv_type == RV_INTEGER) {
130 printf("%d", retval);
131 } else if (rv_type == RV_HASH) {
132 printf("0x%08x", retval);
133 } else if (rv_type == RV_ERRNO) {
134 if (retval >= -15 && retval <= 0) {
135 printf("%d %s (%s)", retval,
136 err_desc[retval].name,
137 err_desc[retval].desc);
138 } else {
139 printf("%d", retval);
140 }
141 } else if (rv_type == RV_INT_ERRNO) {
142 if (retval >= -15 && retval < 0) {
143 printf("%d %s (%s)", retval,
144 err_desc[retval].name,
145 err_desc[retval].desc);
146 } else {
147 printf("%d", retval);
148 }
149 }
150 putchar('\n');
151}
152
153static void print_sc_args(unsigned *sc_args, int n)
154{
155 int i;
156
157 putchar('(');
158 if (n > 0) printf("%d", sc_args[0]);
159 for (i=1; i<n; i++) {
160 printf(", %d", sc_args[i]);
161 }
162 putchar(')');
163}
164
165static void sc_ipc_call_async_fast(unsigned *sc_args, int sc_rc)
166{
167 ipc_call_t call;
168 int phoneid;
169
170 if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
171 return;
172
173 phoneid = sc_args[0];
174
175 IPC_SET_METHOD(call, sc_args[1]);
176 IPC_SET_ARG1(call, sc_args[2]);
177 IPC_SET_ARG2(call, sc_args[3]);
178 IPC_SET_ARG3(call, sc_args[4]);
179 IPC_SET_ARG4(call, sc_args[5]);
180 IPC_SET_ARG5(call, 0);
181
182 ipcp_call_out(phoneid, &call, sc_rc);
183}
184
185static void sc_ipc_call_async_slow(unsigned *sc_args, int sc_rc)
186{
187 ipc_call_t call;
188 int rc;
189
190 if (sc_rc == IPC_CALLRET_FATAL || sc_rc == IPC_CALLRET_TEMPORARY)
191 return;
192
193 memset(&call, 0, sizeof(call));
194 rc = udebug_mem_read(phoneid, &call.args, sc_args[1], sizeof(call.args));
195
196 if (rc >= 0) {
197 ipcp_call_out(sc_args[0], &call, sc_rc);
198 }
199}
200
201static void sc_ipc_call_sync_fast(unsigned *sc_args)
202{
203 ipc_call_t question, reply;
204 int rc;
205 int phoneidx;
206
207// printf("sc_ipc_call_sync_fast()\n");
208 phoneidx = sc_args[0];
209
210 IPC_SET_METHOD(question, sc_args[1]);
211 IPC_SET_ARG1(question, sc_args[2]);
212 IPC_SET_ARG2(question, sc_args[3]);
213 IPC_SET_ARG3(question, sc_args[4]);
214 IPC_SET_ARG4(question, 0);
215 IPC_SET_ARG5(question, 0);
216
217// printf("memset\n");
218 memset(&reply, 0, sizeof(reply));
219// printf("udebug_mem_read(phone=%d, buffer_ptr=%u, src_addr=%d, n=%d\n",
220// phoneid, &reply.args, sc_args[5], sizeof(reply.args));
221 rc = udebug_mem_read(phoneid, &reply.args, sc_args[5], sizeof(reply.args));
222// printf("dmr->%d\n", rc);
223 if (rc < 0) return;
224
225// printf("call ipc_call_sync\n");
226 ipcp_call_sync(phoneidx, &question, &reply);
227}
228
229static void sc_ipc_call_sync_slow(unsigned *sc_args)
230{
231 ipc_call_t question, reply;
232 int rc;
233
234 memset(&question, 0, sizeof(question));
235 rc = udebug_mem_read(phoneid, &question.args, sc_args[1], sizeof(question.args));
236 printf("dmr->%d\n", rc);
237 if (rc < 0) return;
238
239 memset(&reply, 0, sizeof(reply));
240 rc = udebug_mem_read(phoneid, &reply.args, sc_args[2], sizeof(reply.args));
241 printf("dmr->%d\n", rc);
242 if (rc < 0) return;
243
244 ipcp_call_sync(sc_args[0], &question, &reply);
245}
246
247static void sc_ipc_wait(unsigned *sc_args, int sc_rc)
248{
249 ipc_call_t call;
250 int rc;
251
252 if (sc_rc == 0) return;
253
254 memset(&call, 0, sizeof(call));
255 rc = udebug_mem_read(phoneid, &call, sc_args[0], sizeof(call));
256// printf("udebug_mem_read(phone %d, dest %d, app-mem src %d, size %d -> %d\n",
257// phoneid, (int)&call, sc_args[0], sizeof(call), rc);
258
259 if (rc >= 0) {
260 ipcp_call_in(&call, sc_rc);
261 }
262}
263
264static void event_syscall_b(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc)
265{
266 unsigned sc_args[6];
267 int rc;
268
269 /* Read syscall arguments */
270 rc = udebug_args_read(phoneid, thread_hash, sc_args);
271
272 async_serialize_start();
273
274// printf("[%d] ", thread_id);
275
276 if (rc < 0) {
277 printf("error\n");
278 async_serialize_end();
279 return;
280 }
281
282 /* Print syscall name, id and arguments */
283 printf("%s", syscall_desc[sc_id].name);
284 print_sc_args(sc_args, syscall_desc[sc_id].n_args);
285
286 async_serialize_end();
287}
288
289static void event_syscall_e(unsigned thread_id, unsigned thread_hash, unsigned sc_id, int sc_rc)
290{
291 unsigned sc_args[6];
292 int rv_type;
293 int rc;
294
295 /* Read syscall arguments */
296 rc = udebug_args_read(phoneid, thread_hash, sc_args);
297
298 async_serialize_start();
299
300// printf("[%d] ", thread_id);
301
302 if (rc < 0) {
303 printf("error\n");
304 async_serialize_end();
305 return;
306 }
307
308 rv_type = syscall_desc[sc_id].rv_type;
309 print_sc_retval(sc_rc, rv_type);
310
311 switch (sc_id) {
312 case SYS_IPC_CALL_ASYNC_FAST:
313 sc_ipc_call_async_fast(sc_args, sc_rc);
314 break;
315 case SYS_IPC_CALL_ASYNC_SLOW:
316 sc_ipc_call_async_slow(sc_args, sc_rc);
317 break;
318 case SYS_IPC_CALL_SYNC_FAST:
319 sc_ipc_call_sync_fast(sc_args);
320 break;
321 case SYS_IPC_CALL_SYNC_SLOW:
322 sc_ipc_call_sync_slow(sc_args);
323 break;
324 case SYS_IPC_WAIT:
325 sc_ipc_wait(sc_args, sc_rc);
326 break;
327 default:
328 break;
329 }
330
331 async_serialize_end();
332}
333
334static void event_thread_b(unsigned hash)
335{
336 async_serialize_start();
337 printf("new thread, hash 0x%x\n", hash);
338 async_serialize_end();
339
340 thread_trace_start(hash);
341}
342
343static int trace_loop(void *thread_hash_arg)
344{
345 int rc;
346 unsigned ev_type;
347 unsigned thread_hash;
348 unsigned thread_id;
349 unsigned val0, val1;
350
351 thread_hash = (unsigned)thread_hash_arg;
352 thread_id = next_thread_id++;
353
354 printf("trace_loop(%d)\n", thread_id);
355
356 while (!abort_trace) {
357
358 /* Run thread until an event occurs */
359 rc = udebug_go(phoneid, thread_hash,
360 &ev_type, &val0, &val1);
361
362// printf("rc = %d, ev_type=%d\n", rc, ev_type);
363 if (ev_type == UDEBUG_EVENT_FINISHED) {
364 printf("thread %u debugging finished\n", thread_id);
365 break;
366 }
367
368 if (rc >= 0) {
369 switch (ev_type) {
370 case UDEBUG_EVENT_SYSCALL_B:
371 event_syscall_b(thread_id, thread_hash, val0, (int)val1);
372 break;
373 case UDEBUG_EVENT_SYSCALL_E:
374 event_syscall_e(thread_id, thread_hash, val0, (int)val1);
375 break;
376 case UDEBUG_EVENT_STOP:
377 printf("stop event\n");
378 printf("waiting for resume\n");
379 while (paused) {
380 usleep(1000000);
381 fibril_yield();
382 printf(".");
383 }
384 printf("resumed\n");
385 break;
386 case UDEBUG_EVENT_THREAD_B:
387 event_thread_b(val0);
388 break;
389 case UDEBUG_EVENT_THREAD_E:
390 printf("thread 0x%x exited\n", val0);
391 abort_trace = 1;
392 break;
393 default:
394 printf("unknown event type %d\n", ev_type);
395 break;
396 }
397 }
398
399 }
400
401 printf("trace_loop(%d) exiting\n", thread_id);
402 return 0;
403}
404
405void thread_trace_start(unsigned thread_hash)
406{
407 fid_t fid;
408
409 thash = thread_hash;
410
411 fid = fibril_create(trace_loop, (void *)thread_hash);
412 if (fid == 0) {
413 printf("Warning: Failed creating fibril\n");
414 }
415 fibril_add_ready(fid);
416}
417
418static void trace_active_task(task_id_t task_id)
419{
420 int i;
421 int rc;
422 int c;
423
424 printf("Syscall Tracer\n");
425
426 rc = task_connect(task_id);
427 if (rc < 0) {
428 printf("Failed to connect to task %lld\n", task_id);
429 return;
430 }
431
432 printf("Connected to task %lld\n", task_id);
433
434 ipcp_init();
435 ipcp_connection_set(1, 0, proto_console);
436
437 rc = get_thread_list();
438 if (rc < 0) {
439 printf("Failed to get thread list (error %d)\n", rc);
440 return;
441 }
442
443 abort_trace = 0;
444
445 for (i = 0; i < n_threads; i++) {
446 thread_trace_start(thread_hash_buf[i]);
447 }
448
449 while(1) {
450 c = getchar();
451 if (c == 'q') break;
452 if (c == 'p') {
453 paused = 1;
454 rc = udebug_stop(phoneid, thash);
455 printf("stop -> %d\n", rc);
456 }
457 if (c == 'r') {
458 paused = 0;
459 }
460 }
461
462 printf("terminate debugging session...\n");
463 abort_trace = 1;
464 udebug_end(phoneid);
465 ipc_hangup(phoneid);
466
467 ipcp_cleanup();
468
469 printf("done\n");
470 return;
471}
472
473static void main_init(void)
474{
475 proto_t *p;
476 oper_t *o;
477
478 next_thread_id = 1;
479 paused = 0;
480
481 proto_init();
482
483 p = proto_new("vfs");
484 o = oper_new("read");
485 proto_add_oper(p, VFS_READ, o);
486 o = oper_new("write");
487 proto_add_oper(p, VFS_WRITE, o);
488 o = oper_new("truncate");
489 proto_add_oper(p, VFS_TRUNCATE, o);
490 o = oper_new("mount");
491 proto_add_oper(p, VFS_MOUNT, o);
492 o = oper_new("unmount");
493 proto_add_oper(p, VFS_UNMOUNT, o);
494
495 proto_register(SERVICE_VFS, p);
496
497 p = proto_new("console");
498 o = oper_new("getchar");
499 proto_add_oper(p, CONSOLE_GETCHAR, o);
500 o = oper_new("putchar");
501 proto_add_oper(p, CONSOLE_PUTCHAR, o);
502 o = oper_new("clear");
503 proto_add_oper(p, CONSOLE_CLEAR, o);
504 o = oper_new("goto");
505 proto_add_oper(p, CONSOLE_GOTO, o);
506 o = oper_new("getsize");
507 proto_add_oper(p, CONSOLE_GETSIZE, o);
508 o = oper_new("flush");
509 proto_add_oper(p, CONSOLE_FLUSH, o);
510 o = oper_new("set_style");
511 proto_add_oper(p, CONSOLE_SET_STYLE, o);
512 o = oper_new("cursor_visibility");
513 proto_add_oper(p, CONSOLE_CURSOR_VISIBILITY, o);
514 o = oper_new("flush");
515 proto_add_oper(p, CONSOLE_FLUSH, o);
516
517 proto_console = p;
518 proto_register(SERVICE_CONSOLE, p);
519}
520
521static void print_syntax()
522{
523 printf("syntax: trace <task_id>\n");
524}
525
526int main(int argc, char *argv[])
527{
528 task_id_t task_id;
529 char *err_p;
530
531 if (argc != 2) {
532 printf("Mising argument\n");
533 print_syntax();
534 return 1;
535 }
536
537 task_id = strtol(argv[1], &err_p, 10);
538
539 if (*err_p) {
540 printf("Task ID syntax error\n");
541 print_syntax();
542 return 1;
543 }
544
545 main_init();
546 trace_active_task(task_id);
547}
548
549/** @}
550 */
Note: See TracBrowser for help on using the repository browser.