2 * Copyright (C) 1991 Gordon Irlam. All rights reserved.
6 * Sparc trace generator.
8 * Generate a Sparc address trace.
10 * Report system calls.
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.
22 * Imported declarations.
47 #include <sys/types.h>
48 #include <sys/ptrace.h>
49 #include <sys/syscall.h>
50 #include <machine/trap.h>
53 * sigcleanup is not defined in a system header file.
55 #define SYS_sigcleanup 139
57 #include "prototype.h"
60 #include "system_calls.h"
64 * Forward declarations.
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));
86 static char *trap_msg = NULL;
87 static fmt_type result_format;
89 static fmt_type post_fmt;
90 static unsigned long post_value;
95 * Report the occurence of the specified trap.
98 void report_trap(pid, addr, trap, g1, params_addr)
103 syscall_params *params_addr;
105 syscall_params params;
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
120 * Read the parameters, and construct a string describing the system call.
123 ensure(ptrace(PTRACE_READDATA, pid,
124 (char *) params_addr, sizeof(syscall_params),
125 (char *) params) != -1);
129 if (trap != T_SOFTWARE_TRAP) {
132 * Not a system call trap.
137 ensure((trap_msg = malloc(17 + 20 + 1)) != NULL);
138 sprintf(trap_msg, "0x%08lx: trap %d", (unsigned long) addr, trap);
140 result_format = fmt_unknown;
141 } if ((g1 < 0) || (g1 >= no_system_calls)) {
144 * An unknown system call.
147 ensure((trap_msg = malloc(21 + 20 + 1)) != NULL);
148 sprintf(trap_msg, "0x%08lx: _unknown_%d(",
149 (unsigned long) addr, g1);
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))
155 sprintf(trap_msg + sizeof(trap_msg), "%s)", arg_str);
158 result_format = fmt_unknown;
162 * A known system call.
165 call = &system_calls[g1];
168 if (!(params[1] & O_CREAT)) {
169 call = &system_call_open_simple;
174 case SYS_sigcleanup :
181 ensure((trap_msg = malloc(13 + strlen(call->name) + 1 + 1))
183 sprintf(trap_msg, "0x%08lx: %s(",
184 (unsigned long) addr, call->name);
187 * Display each of the arguments.
190 for (i = 0; i < NO_PARAMS; i++) {
191 if ((arg_format = call->arg[i]) == fmt_none) {
195 strcat(trap_msg, ", ");
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]);
203 arg_str = format_value(pid, arg_format, params[i], 0);
205 ensure((trap_msg = realloc(trap_msg, strlen(trap_msg) +
206 strlen(arg_str) + 2 + 1))
208 strcat(trap_msg, arg_str);
212 strcat(trap_msg, ")");
214 result_format = call->result;
218 * Set alarm so that name of call will be displayed even if it blocks.
221 alarm((unsigned int) 1);
226 * Report the value returned as a result of the most recent trap.
229 void report_trap_result(pid, error, o0, o1)
235 char *result, *eno, *emsg, *addr;
238 * Turn off alarm used to ensure we print the call promptly - we are about
242 alarm((unsigned int) 0);
245 * See if previous call blocked.
248 if (trap_msg == NULL) {
249 ensure((trap_msg = strdup(" [previous call]")) != NULL);
253 * Work out error message (if any) to be printed following return value.
257 eno = format_value(pid, fmt_error, o0, 0);
258 ensure((emsg = malloc(9 + strlen(eno) + 1)) != NULL);
259 sprintf(emsg, " [error %s]", eno);
264 ensure((emsg = strdup("")) != NULL);
268 * Print out all the details of the system call.
271 if (result_format == fmt_none) {
272 ensure(fprintf(msgfile, "%s: %s%s\n", trace_progname, trap_msg, emsg)
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);
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.
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);
306 * Report any trap messages that haven't been reported yet.
309 void display_trap_msg() {
312 * Clear the alarm - we are about to print the message.
315 alarm((unsigned int) 0);
317 if (trap_msg != NULL) {
318 ensure(fprintf(msgfile, "%s: %s\n", trace_progname, trap_msg) != EOF);
326 * Report the completion of a trap message as being delayed.
328 * This routine is invoked when a SIGALRM is received.
331 void delayed_trap_msg() {
333 assert(trap_msg != NULL);
336 * If the call was not expected to return a value, think nothing of it,
337 * otherwise assume the call has blocked.
340 ensure(fprintf(msgfile, "%s: %s%s\n",
341 trace_progname, trap_msg, (no_return ? "" : " [pending]"))
349 * Discard any pending trap messages.
351 * This routine is used by the child of a fork to discard the fork system call
355 void discard_trap_msg() {
362 * Attempt to copy size bytes from the target process to data. The number of
363 * bytes successfully copied is returned.
366 int copy_memory(pid, addr, size, data)
377 * Common cases first.
380 if (ptrace(PTRACE_READDATA, pid, (char *) addr, size, data) != -1) {
382 } else if (ptrace(PTRACE_READDATA, pid, (char *) addr, 1, data) == -1) {
394 try = (lo + hi + 1) / 2;
395 if (ptrace(PTRACE_READDATA, pid, (char *) addr, try, data) != -1) {
402 ensure(ptrace(PTRACE_READDATA, pid, (char *) addr, lo, data) != -1);
409 * Create a string representing the contents of the indicated null termintated
413 char *snarf_string(pid, addr)
417 char data[STRING_SIZE_LIMIT + 1];
422 size = copy_memory(pid, addr, STRING_SIZE_LIMIT, 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);
430 ensure((result = realloc(result, strlen(result) + 2 + 1))
432 strcat(result, "..");
442 * Create a string representing the contents of the indicated length delimited
446 char *snarf_data(pid, addr, size)
451 char data[DATA_SIZE_LIMIT];
455 if (size > DATA_SIZE_LIMIT) {
456 size = DATA_SIZE_LIMIT;
459 if ((size >= 0) && (copy_memory(pid, addr, size, data) == size)) {
460 if (printable_data(data, size)) {
461 result = print_string(data, size);
463 ensure((result = realloc(result, strlen(result) + 2 + 1))
465 strcat(result, "..");
475 * Create a string representing the contents of the indicated null termintated
476 * array of pointers to null terminated regions of memory.
479 char *snarf_string_array(pid, addr)
483 char *data[ARRAY_SIZE_LIMIT + 1];
489 size = copy_memory(pid, addr, ARRAY_SIZE_LIMIT * sizeof(char *),
490 (char *) data) / sizeof(char *);
492 for (len = 0; data[len] != NULL; len++) {
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++) {
499 strcat(result, ", ");
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))
508 strcat(result, ", ..");
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
523 char *format_value(pid, format, value, opt)
533 * See if we are meant to hang on to the value for later use.
538 case fmt_post_string :
539 post_fmt = fmt_string ;
554 case fmt_post_data_size :
555 post_size = (int) value;
571 ensure((str = malloc(20 + 1)) != NULL);
572 sprintf(str, "%d", (int) value);
577 ensure((str = malloc(2 + 20 + 1)) != NULL);
578 sprintf(str, "0x%lx", value);
584 ensure((str = strdup("NULL")) != NULL);
586 ensure((str = malloc(10 + 1)) != NULL);
587 sprintf(str, "0x%08lx", value);
593 ensure((str = malloc(2 + 20 + 1)) != NULL);
594 sprintf(str, "fd%d", (int) value);
600 if ((sig < 0) || (sig >= no_signal_names)) {
601 ensure((str = malloc(20 + 1)) != NULL);
602 sprintf(str, "%d", sig);
604 ensure((str = strdup(signal_names[sig])) != NULL);
611 if ((error < 0) || (error >= no_error_names)) {
612 ensure((str = malloc(20 + 1)) != NULL);
613 sprintf(str, "%d", error);
615 ensure((str = strdup(error_names[error])) != NULL);
619 case fmt_open_flags :
621 ensure((str = malloc(8 + 3 + 20 + 1)) != NULL);
624 sprintf(str, "O_RDONLY");
628 sprintf(str, "O_WRONLY");
632 sprintf(str, "O_RDWR");
636 sprintf(str, "0x%lx", value);
641 sprintf(str + strlen(str), "|0x%lx", value);
647 ensure((str = strdup("..")) != NULL);
652 if ((str = snarf_string(pid, (void *) value)) == NULL) {
653 str = format_value(pid, fmt_ptr, value, 0);
659 if ((str = snarf_data(pid, (void *) value, opt)) == NULL) {
660 str = format_value(pid, fmt_ptr, value, 0);
664 case fmt_string_array :
666 if ((str = snarf_string_array(pid, (void *) value)) == NULL) {
667 str = format_value(pid, fmt_ptr, value, 0);
673 diagnose("Unexpected display format");
682 * Determine whether size bytes of data are printable.
685 int printable_data(data, size)
691 for (i = 0; i < size; i++) {
693 if (!(isprint(data[i]))) {
716 * Create a string representing size bytes of data.
719 char *print_string(data, size)
728 ensure((str = malloc(1 + size * 2 + 1 + 1)) != NULL);
733 for (i = 0; i < size; i++) {
735 if ((!(isprint(data[i]))) || (data[i] == '"') || (data[i] == '\\')) {
760 diagnose("Attempted to display illegal character");