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");
This page took 0.045474 seconds and 4 git commands to generate.