Add determining when we do not have enough writeback slots; Do not do model specific...
[deliverable/binutils-gdb.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.045474 seconds and 4 git commands to generate.