New changes from Andrew
[deliverable/binutils-gdb.git] / sim / ppc / spa-reporter.c
CommitLineData
5b4d72dd
MM
1/*
2 * Copyright (C) 1991 Gordon Irlam. All rights reserved.
3 */
4
5/*
6 * Sparc trace generator.
7 *
8 * Generate a Sparc address trace.
9 *
10 * Report system calls.
11 *
12 * We want to display the system call and the return value at the same time
13 * (so that other output does not appear between the two) but also want to
14 * identify system calls that block without having to wait for them to
15 * return. Whenever a system call is performed we store the name of the
16 * call and the parameters. If we don't see a return within a certain time
17 * period we display the call regardless, and assume it has blocked.
18 */
19
20
21/*
22 * Imported declarations.
23 */
24
25#include <unistd.h>
26#include <stdlib.h>
27#include <fcntl.h>
28#include <stdio.h>
29#include <malloc.h>
30#include <ctype.h>
31#include <string.h>
32#include <signal.h>
33#include <sys/types.h>
34#include <sys/ptrace.h>
35#include <sys/syscall.h>
36#include <machine/trap.h>
37
38/*
39 * sigcleanup is not defined in a system header file.
40 */
41#define SYS_sigcleanup 139
42
43#include "prototype.h"
44#include "error.h"
45#include "spy.h"
46#include "system_calls.h"
47
48
49/*
50 * Forward declarations.
51 */
52
53PROTOTYPE(void report_trap,
54 (int pid, void *addr, int trap, int g1, syscall_params *params));
55PROTOTYPE(void report_trap_result, (int pid, int error, int o0, int o1));
56PROTOTYPE(void display_trap_msg, (void));
57PROTOTYPE(void delayed_trap_msg, (void));
58PROTOTYPE(void discard_trap_msg, (void));
59PROTOTYPE(int copy_memory, (int pid, void *addr, int size, char *data));
60PROTOTYPE(char *snarf_string, (int pid, void *addr));
61PROTOTYPE(char *snarf_data, (int pid, void *addr, int size));
62PROTOTYPE(char *format_value,
63 (int pid, fmt_type format, unsigned long value, int opt));
64PROTOTYPE(int printable_data, (char *data, int size));
65PROTOTYPE(char *print_string, (char *data, int size));
66
67
68/*
69 * Global definitions.
70 */
71
72static char *trap_msg = NULL;
73static fmt_type result_format;
74static int no_return;
75static fmt_type post_fmt;
76static unsigned long post_value;
77static int post_size;
78
79
80/*
81 * Report the occurence of the specified trap.
82 */
83
84void report_trap(pid, addr, trap, g1, params_addr)
85 int pid;
86 void *addr;
87 int trap;
88 int g1;
89 syscall_params *params_addr;
90{
91 syscall_params params;
92 call_desc *call;
93 int i;
94 fmt_type arg_format;
95 char *arg_str;
96
97 /*
98 * Display any previous trap message that is still pending (it might have
99 * been a trap that did not return a value, and so has not yet been
100 * displayed).
101 */
102
103 display_trap_msg();
104
105 /*
106 * Read the parameters, and construct a string describing the system call.
107 */
108
109 ensure(ptrace(PTRACE_READDATA, pid,
110 (char *) params_addr, sizeof(syscall_params),
111 (char *) params) != -1);
112
113 no_return = 0;
114
115 if (trap != T_SOFTWARE_TRAP) {
116
117 /*
118 * Not a system call trap.
119 */
120
121 no_return = 1;
122
123 ensure((trap_msg = malloc(17 + 20 + 1)) != NULL);
124 sprintf(trap_msg, "0x%08lx: trap %d", (unsigned long) addr, trap);
125
126 result_format = fmt_unknown;
127 } if ((g1 < 0) || (g1 >= no_system_calls)) {
128
129 /*
130 * An unknown system call.
131 */
132
133 ensure((trap_msg = malloc(21 + 20 + 1)) != NULL);
134 sprintf(trap_msg, "0x%08lx: _unknown_%d(",
135 (unsigned long) addr, g1);
136
137 arg_str = format_value(pid, fmt_unknown, params[0], 0);
138 ensure((trap_msg = realloc(trap_msg, strlen(trap_msg)
139 + strlen(arg_str) + 1 + 1))
140 != NULL);
141 sprintf(trap_msg + sizeof(trap_msg), "%s)", arg_str);
142 free(arg_str);
143
144 result_format = fmt_unknown;
145 } else {
146
147 /*
148 * A known system call.
149 */
150
151 call = &system_calls[g1];
152 switch (g1) {
153 case SYS_open :
154 if (!(params[1] & O_CREAT)) {
155 call = &system_call_open_simple;
156 }
157 break;
158 case SYS_exit :
159 case SYS_execve :
160 case SYS_sigcleanup :
161 no_return = 1;
162 break;
163 default :
164 break;
165 }
166
167 ensure((trap_msg = malloc(13 + strlen(call->name) + 1 + 1))
168 != NULL);
169 sprintf(trap_msg, "0x%08lx: %s(",
170 (unsigned long) addr, call->name);
171
172 /*
173 * Display each of the arguments.
174 */
175
176 for (i = 0; i < NO_PARAMS; i++) {
177 if ((arg_format = call->arg[i]) == fmt_none) {
178 break;
179 }
180 if (i > 0) {
181 strcat(trap_msg, ", ");
182 }
183 if (arg_format == fmt_data) {
184 assert(((i + 1) < NO_PARAMS) &&
185 (call->arg[i + 1] == fmt_data_size));
186 arg_str = format_value(pid, arg_format,
187 params[i], (int) params[i + 1]);
188 } else {
189 arg_str = format_value(pid, arg_format, params[i], 0);
190 }
191 ensure((trap_msg = realloc(trap_msg, strlen(trap_msg) +
192 strlen(arg_str) + 2 + 1))
193 != NULL);
194 strcat(trap_msg, arg_str);
195 free(arg_str);
196 }
197
198 strcat(trap_msg, ")");
199
200 result_format = call->result;
201 }
202
203 /*
204 * Set alarm so that name of call will be displayed even if it blocks.
205 */
206
207 alarm((unsigned int) 1);
208}
209
210
211/*
212 * Report the value returned as a result of the most recent trap.
213 */
214
215void report_trap_result(pid, error, o0, o1)
216 int pid;
217 int error;
218 int o0;
219 int o1;
220{
221 char *result, *eno, *emsg, *addr;
222
223 /*
224 * Turn off alarm used to ensure we print the call promptly - we are about
225 * to print it now.
226 */
227
228 alarm((unsigned int) 0);
229
230 /*
231 * See if previous call blocked.
232 */
233
234 if (trap_msg == NULL) {
235 ensure((trap_msg = strdup(" [previous call]")) != NULL);
236 }
237
238 /*
239 * Work out error message (if any) to be printed following return value.
240 */
241
242 if (error) {
243 eno = format_value(pid, fmt_error, o0, 0);
244 ensure((emsg = malloc(9 + strlen(eno) + 1)) != NULL);
245 sprintf(emsg, " [error %s]", eno);
246 free(eno);
247 o0 = -1;
248 post_fmt = fmt_none;
249 } else {
250 ensure((emsg = strdup("")) != NULL);
251 }
252
253 /*
254 * Print out all the details of the system call.
255 */
256
257 if (result_format == fmt_none) {
258 ensure(fprintf(msgfile, "%s: %s%s\n", trace_progname, trap_msg, emsg)
259 != EOF);
260 } else {
261 result = format_value(pid, result_format, o0, 0);
262 ensure(fprintf(msgfile, "%s: %s -> %s%s\n",
263 trace_progname, trap_msg, result, emsg) != EOF);
264 free(result);
265 }
266
267 free(emsg);
268
269 /*
270 * Display any string or buffer modified by the system call if required.
271 * And providing it can be displayed as a (non-null) string.
272 */
273
274 if (post_fmt != fmt_none) {
275 result = format_value(pid, post_fmt, post_value, post_size);
276 if ((result[0] == '"') && (strlen(result) > 2)) {
277 addr = format_value(pid, fmt_ptr, post_value, 0);
278 ensure(fprintf(msgfile, "%s: %s: %s\n",
279 trace_progname, addr, result) != EOF);
280 free(addr);
281 }
282 free(result);
283 post_fmt = fmt_none;
284 }
285
286 free(trap_msg);
287 trap_msg = NULL;
288}
289
290
291/*
292 * Report any trap messages that haven't been reported yet.
293 */
294
295void display_trap_msg() {
296
297 /*
298 * Clear the alarm - we are about to print the message.
299 */
300
301 alarm((unsigned int) 0);
302
303 if (trap_msg != NULL) {
304 ensure(fprintf(msgfile, "%s: %s\n", trace_progname, trap_msg) != EOF);
305 free(trap_msg);
306 trap_msg = NULL;
307 }
308}
309
310
311/*
312 * Report the completion of a trap message as being delayed.
313 *
314 * This routine is invoked when a SIGALRM is received.
315 */
316
317void delayed_trap_msg() {
318
319 assert(trap_msg != NULL);
320
321 /*
322 * If the call was not expected to return a value, think nothing of it,
323 * otherwise assume the call has blocked.
324 */
325
326 ensure(fprintf(msgfile, "%s: %s%s\n",
327 trace_progname, trap_msg, (no_return ? "" : " [pending]"))
328 != EOF);
329 free(trap_msg);
330 trap_msg = NULL;
331}
332
333
334/*
335 * Discard any pending trap messages.
336 *
337 * This routine is used by the child of a fork to discard the fork system call
338 * record.
339 */
340
341void discard_trap_msg() {
342
343 trap_msg = NULL;
344}
345
346
347/*
348 * Attempt to copy size bytes from the target process to data. The number of
349 * bytes successfully copied is returned.
350 */
351
352int copy_memory(pid, addr, size, data)
353 int pid;
354 void *addr;
355 int size;
356 char *data;
357{
358 int lo, hi, try;
359
360 assert(size >= 0);
361
362 /*
363 * Common cases first.
364 */
365
366 if (ptrace(PTRACE_READDATA, pid, (char *) addr, size, data) != -1) {
367 return size;
368 } else if (ptrace(PTRACE_READDATA, pid, (char *) addr, 1, data) == -1) {
369 return 0;
370 }
371
372 /*
373 * Binary search.
374 */
375
376 lo = 1;
377 hi = size - 1;
378
379 while (lo < hi) {
380 try = (lo + hi + 1) / 2;
381 if (ptrace(PTRACE_READDATA, pid, (char *) addr, try, data) != -1) {
382 lo = try;
383 } else {
384 hi = try - 1;
385 }
386 }
387
388 ensure(ptrace(PTRACE_READDATA, pid, (char *) addr, lo, data) != -1);
389
390 return lo;
391}
392
393
394/*
395 * Create a string representing the contents of the indicated null termintated
396 * region of memory.
397 */
398
399char *snarf_string(pid, addr)
400 int pid;
401 void *addr;
402{
403 char data[STRING_SIZE_LIMIT + 1];
404 int size, len;
405 char *result = NULL;
406 int too_long = 0;
407
408 size = copy_memory(pid, addr, STRING_SIZE_LIMIT, data);
409 data[size] = '\0';
410 len = strlen(data);
411 too_long = (len == STRING_SIZE_LIMIT);
412 if ((len < size) || too_long) {
413 if (printable_data(data, len)) {
414 result = print_string(data, len);
415 if (too_long) {
416 ensure((result = realloc(result, strlen(result) + 2 + 1))
417 != NULL);
418 strcat(result, "..");
419 }
420 }
421 }
422
423 return result;
424}
425
426
427/*
428 * Create a string representing the contents of the indicated length delimited
429 * region of memory.
430 */
431
432char *snarf_data(pid, addr, size)
433 int pid;
434 void *addr;
435 int size;
436{
437 char data[DATA_SIZE_LIMIT];
438 char *result = NULL;
439 int too_long = 0;
440
441 if (size > DATA_SIZE_LIMIT) {
442 size = DATA_SIZE_LIMIT;
443 too_long = 1;
444 }
445 if ((size >= 0) && (copy_memory(pid, addr, size, data) == size)) {
446 if (printable_data(data, size)) {
447 result = print_string(data, size);
448 if (too_long) {
449 ensure((result = realloc(result, strlen(result) + 2 + 1))
450 != NULL);
451 strcat(result, "..");
452 }
453 }
454 }
455
456 return result;
457}
458
459
460/*
461 * Create a string representing the contents of the indicated null termintated
462 * array of pointers to null terminated regions of memory.
463 */
464
465char *snarf_string_array(pid, addr)
466 int pid;
467 void *addr;
468{
469 char *data[ARRAY_SIZE_LIMIT + 1];
470 int size, len, i;
471 char *result = NULL;
472 char *s;
473 int too_long = 0;
474
475 size = copy_memory(pid, addr, ARRAY_SIZE_LIMIT * sizeof(char *),
476 (char *) data) / sizeof(char *);
477 data[size] = NULL;
478 for (len = 0; data[len] != NULL; len++) {
479 }
480 too_long = (len == ARRAY_SIZE_LIMIT);
481 if ((len < size) || too_long) {
482 ensure((result = strdup("{")) != NULL);
483 for (i = 0; i < len; i++) {
484 if (i > 0) {
485 strcat(result, ", ");
486 }
487 s = format_value(pid, fmt_string, (unsigned long) data[i], 0);
488 ensure((result = realloc(result,
489 strlen(result) + strlen(s) + 2 + 5 + 1))
490 != NULL);
491 strcat(result, s);
492 }
493 if (too_long) {
494 strcat(result, ", ..");
495 }
496 strcat(result, "}");
497 }
498
499 return result;
500}
501
502
503/*
504 * Return a string containing a value printed in a specific format. Opt is a
505 * second optional parameter currently only used to contain the size to be used
506 * with fmt_data.
507 */
508
509char *format_value(pid, format, value, opt)
510 int pid;
511 fmt_type format;
512 unsigned long value;
513 int opt;
514{
515 char *str;
516 int sig, error;
517
518 /*
519 * See if we are meant to hang on to the value for later use.
520 */
521
522 switch (format) {
523
524 case fmt_post_string :
525 post_fmt = fmt_string ;
526 post_value = value;
527 format = fmt_ptr;
528 break;
529
530 case fmt_post_data :
531 post_fmt = fmt_data;
532 post_value = value;
533 format = fmt_ptr;
534 break;
535
536 case fmt_data_size :
537 format = FMT_SIZE;
538 break;
539
540 case fmt_post_data_size :
541 post_size = (int) value;
542 format = FMT_SIZE;
543 break;
544
545 default :
546 break;
547 }
548
549 /*
550 * Display the value.
551 */
552
553 switch (format) {
554
555 case fmt_dec :
556
557 ensure((str = malloc(20 + 1)) != NULL);
558 sprintf(str, "%d", (int) value);
559 break;
560
561 case fmt_hex :
562
563 ensure((str = malloc(2 + 20 + 1)) != NULL);
564 sprintf(str, "0x%lx", value);
565 break;
566
567 case fmt_ptr :
568
569 if (value == 0) {
570 ensure((str = strdup("NULL")) != NULL);
571 } else {
572 ensure((str = malloc(10 + 1)) != NULL);
573 sprintf(str, "0x%08lx", value);
574 }
575 break;
576
577 case fmt_fd :
578
579 ensure((str = malloc(2 + 20 + 1)) != NULL);
580 sprintf(str, "fd%d", (int) value);
581 break;
582
583 case fmt_signal :
584
585 sig = (int) value;
586 if ((sig < 0) || (sig >= no_signal_names)) {
587 ensure((str = malloc(20 + 1)) != NULL);
588 sprintf(str, "%d", sig);
589 } else {
590 ensure((str = strdup(signal_names[sig])) != NULL);
591 }
592 break;
593
594 case fmt_error :
595
596 error = (int) value;
597 if ((error < 0) || (error >= no_error_names)) {
598 ensure((str = malloc(20 + 1)) != NULL);
599 sprintf(str, "%d", error);
600 } else {
601 ensure((str = strdup(error_names[error])) != NULL);
602 }
603 break;
604
605 case fmt_open_flags :
606
607 ensure((str = malloc(8 + 3 + 20 + 1)) != NULL);
608 switch (value & 3) {
609 case O_RDONLY :
610 sprintf(str, "O_RDONLY");
611 value -= O_RDONLY;
612 break;
613 case O_WRONLY :
614 sprintf(str, "O_WRONLY");
615 value -= O_WRONLY;
616 break;
617 case O_RDWR :
618 sprintf(str, "O_RDWR");
619 value -= O_RDWR;
620 break;
621 default :
622 sprintf(str, "0x%lx", value);
623 value = 0;
624 break;
625 }
626 if (value != 0) {
627 sprintf(str + strlen(str), "|0x%lx", value);
628 }
629 break;
630
631 case fmt_unknown :
632
633 ensure((str = strdup("..")) != NULL);
634 break;
635
636 case fmt_string :
637
638 if ((str = snarf_string(pid, (void *) value)) == NULL) {
639 str = format_value(pid, fmt_ptr, value, 0);
640 }
641 break;
642
643 case fmt_data :
644
645 if ((str = snarf_data(pid, (void *) value, opt)) == NULL) {
646 str = format_value(pid, fmt_ptr, value, 0);
647 }
648 break;
649
650 case fmt_string_array :
651
652 if ((str = snarf_string_array(pid, (void *) value)) == NULL) {
653 str = format_value(pid, fmt_ptr, value, 0);
654 }
655 break;
656
657 default :
658
659 diagnose("Unexpected display format");
660 break;
661 }
662
663 return str;
664}
665
666
667/*
668 * Determine whether size bytes of data are printable.
669 */
670
671int printable_data(data, size)
672 char *data;
673 int size;
674{
675 int i;
676
677 for (i = 0; i < size; i++) {
678
679 if (!(isprint(data[i]))) {
680
681 switch (data[i]) {
682
683 case '\0' :
684 case '\t' :
685 case '\n' :
686 case '\f' :
687 case '\r' :
688 break;
689
690 default :
691 return 0;
692 break;
693 }
694 }
695 }
696
697 return 1;
698}
699
700
701/*
702 * Create a string representing size bytes of data.
703 */
704
705char *print_string(data, size)
706 char *data;
707 int size;
708{
709 char *str, *s;
710 int i;
711
712 assert(size >= 0);
713
714 ensure((str = malloc(1 + size * 2 + 1 + 1)) != NULL);
715 s = str;
716
717 *(s++) = '"';
718
719 for (i = 0; i < size; i++) {
720
721 if ((!(isprint(data[i]))) || (data[i] == '"') || (data[i] == '\\')) {
722
723 *(s++) = '\\';
724
725 switch (data[i]) {
726 case '\0' :
727 *(s++) = '0';
728 break;
729 case '\t' :
730 *(s++) = 't';
731 break;
732 case '\n' :
733 *(s++) = 'n';
734 break;
735 case '\f' :
736 *(s++) = 'f';
737 break;
738 case '\r' :
739 *(s++) = 'r';
740 break;
741 case '"' :
742 case '\\' :
743 *(s++) = data[i];
744 break;
745 default :
746 diagnose("Attempted to display illegal character");
747 }
748 } else {
749
750 *(s++) = data[i];
751 }
752 }
753
754 *(s++) = '"';
755 *s = '\0';
756
757 return str;
758}
This page took 0.100235 seconds and 4 git commands to generate.