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