summaryrefslogtreecommitdiff
path: root/display_args.c
diff options
context:
space:
mode:
Diffstat (limited to 'display_args.c')
-rw-r--r--display_args.c460
1 files changed, 460 insertions, 0 deletions
diff --git a/display_args.c b/display_args.c
new file mode 100644
index 0000000..993a808
--- /dev/null
+++ b/display_args.c
@@ -0,0 +1,460 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "common.h"
+
+static int display_char(int what);
+static int display_string(enum tof type, Process *proc,
+ void* addr, size_t maxlen);
+static int display_value(enum tof type, Process *proc,
+ long value, arg_type_info *info,
+ void *st, arg_type_info* st_info);
+static int display_unknown(enum tof type, Process *proc, long value);
+static int display_format(enum tof type, Process *proc, int arg_num);
+
+static int string_maxlength = INT_MAX;
+static int array_maxlength = INT_MAX;
+
+static long
+get_length(enum tof type, Process *proc, int len_spec,
+ void *st, arg_type_info* st_info) {
+ long len;
+ arg_type_info info;
+
+ if (len_spec > 0)
+ return len_spec;
+ if (type == LT_TOF_STRUCT) {
+ umovelong (proc, st + st_info->u.struct_info.offset[-len_spec-1],
+ &len, st_info->u.struct_info.fields[-len_spec-1]);
+ return len;
+ }
+
+ info.type = ARGTYPE_INT;
+ return gimme_arg(type, proc, -len_spec-1, &info);
+}
+
+static int
+display_ptrto(enum tof type, Process *proc, long item,
+ arg_type_info * info,
+ void *st, arg_type_info* st_info) {
+ arg_type_info temp;
+ temp.type = ARGTYPE_POINTER;
+ temp.u.ptr_info.info = info;
+ return display_value(type, proc, item, &temp, st, st_info);
+}
+
+/*
+ * addr - A pointer to the first element of the array
+ *
+ * The function name is used to indicate that we're not actually
+ * looking at an 'array', which is a contiguous region of memory
+ * containing a sequence of elements of some type; instead, we have a
+ * pointer to that region of memory.
+ */
+static int
+display_arrayptr(enum tof type, Process *proc,
+ void *addr, arg_type_info * info,
+ void *st, arg_type_info* st_info) {
+ int len = 0;
+ int i;
+ int array_len;
+
+ if (addr == NULL)
+ return fprintf(options.output, "NULL");
+
+ array_len = get_length(type, proc, info->u.array_info.len_spec,
+ st, st_info);
+ len += fprintf(options.output, "[ ");
+ for (i = 0; i < options.arraylen && i < array_maxlength && i < array_len; i++) {
+ arg_type_info *elt_type = info->u.array_info.elt_type;
+ size_t elt_size = info->u.array_info.elt_size;
+ if (i != 0)
+ len += fprintf(options.output, ", ");
+ if (options.debug)
+ len += fprintf(options.output, "%p=", addr);
+ len +=
+ display_ptrto(type, proc, (long) addr, elt_type, st, st_info);
+ addr += elt_size;
+ }
+ if (i < array_len)
+ len += fprintf(options.output, "...");
+ len += fprintf(options.output, " ]");
+ return len;
+}
+
+/* addr - A pointer to the beginning of the memory region occupied by
+ * the struct (aka a pointer to the struct)
+ */
+static int
+display_structptr(enum tof type, Process *proc,
+ void *addr, arg_type_info * info) {
+ int i;
+ arg_type_info *field;
+ int len = 0;
+
+ if (addr == NULL)
+ return fprintf(options.output, "NULL");
+
+ len += fprintf(options.output, "{ ");
+ for (i = 0; (field = info->u.struct_info.fields[i]) != NULL; i++) {
+ if (i != 0)
+ len += fprintf(options.output, ", ");
+ if (options.debug)
+ len +=
+ fprintf(options.output, "%p=",
+ addr + info->u.struct_info.offset[i]);
+ len +=
+ display_ptrto(LT_TOF_STRUCT, proc,
+ (long) addr + info->u.struct_info.offset[i],
+ field, addr, info);
+ }
+ len += fprintf(options.output, " }");
+
+ return len;
+}
+
+static int
+display_pointer(enum tof type, Process *proc, long value,
+ arg_type_info * info,
+ void *st, arg_type_info* st_info) {
+ long pointed_to;
+ arg_type_info *inner = info->u.ptr_info.info;
+
+ if (inner->type == ARGTYPE_ARRAY) {
+ return display_arrayptr(type, proc, (void*) value, inner,
+ st, st_info);
+ } else if (inner->type == ARGTYPE_STRUCT) {
+ return display_structptr(type, proc, (void *) value, inner);
+ } else {
+ if (value == 0)
+ return fprintf(options.output, "NULL");
+ else if (umovelong (proc, (void *) value, &pointed_to,
+ info->u.ptr_info.info) < 0)
+ return fprintf(options.output, "?");
+ else
+ return display_value(type, proc, pointed_to, inner,
+ st, st_info);
+ }
+}
+
+static int
+display_enum(enum tof type, Process *proc,
+ arg_type_info* info, long value) {
+ int ii;
+ for (ii = 0; ii < info->u.enum_info.entries; ++ii) {
+ if (info->u.enum_info.values[ii] == value)
+ return fprintf(options.output, "%s", info->u.enum_info.keys[ii]);
+ }
+
+ return display_unknown(type, proc, value);
+}
+
+/* Args:
+ type - syscall or shared library function or memory
+ proc - information about the traced process
+ value - the value to display
+ info - the description of the type to display
+ st - if the current value is a struct member, the address of the struct
+ st_info - type of the above struct
+
+ Those last two parameters are used for structs containing arrays or
+ strings whose length is given by another structure element.
+*/
+int
+display_value(enum tof type, Process *proc,
+ long value, arg_type_info *info,
+ void *st, arg_type_info* st_info) {
+ int tmp;
+
+ switch (info->type) {
+ case ARGTYPE_VOID:
+ return 0;
+ case ARGTYPE_INT:
+ return fprintf(options.output, "%d", (int) value);
+ case ARGTYPE_UINT:
+ return fprintf(options.output, "%u", (unsigned) value);
+ case ARGTYPE_LONG:
+ if (proc->mask_32bit)
+ return fprintf(options.output, "%d", (int) value);
+ else
+ return fprintf(options.output, "%ld", value);
+ case ARGTYPE_ULONG:
+ if (proc->mask_32bit)
+ return fprintf(options.output, "%u", (unsigned) value);
+ else
+ return fprintf(options.output, "%lu", (unsigned long) value);
+ case ARGTYPE_OCTAL:
+ return fprintf(options.output, "0%o", (unsigned) value);
+ case ARGTYPE_CHAR:
+ tmp = fprintf(options.output, "'");
+ tmp += display_char(value == -1 ? value : (char) value);
+ tmp += fprintf(options.output, "'");
+ return tmp;
+ case ARGTYPE_SHORT:
+ return fprintf(options.output, "%hd", (short) value);
+ case ARGTYPE_USHORT:
+ return fprintf(options.output, "%hu", (unsigned short) value);
+ case ARGTYPE_FLOAT: {
+ union { long l; float f; double d; } cvt;
+ cvt.l = value;
+ return fprintf(options.output, "%f", cvt.f);
+ }
+ case ARGTYPE_DOUBLE: {
+ union { long l; float f; double d; } cvt;
+ cvt.l = value;
+ return fprintf(options.output, "%lf", cvt.d);
+ }
+ case ARGTYPE_ADDR:
+ if (!value)
+ return fprintf(options.output, "NULL");
+ else
+ return fprintf(options.output, "0x%08lx", value);
+ case ARGTYPE_FORMAT:
+ fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
+ exit(1);
+ case ARGTYPE_STRING:
+ return display_string(type, proc, (void*) value,
+ string_maxlength);
+ case ARGTYPE_STRING_N:
+ return display_string(type, proc, (void*) value,
+ get_length(type, proc,
+ info->u.string_n_info.size_spec, st, st_info));
+ case ARGTYPE_ARRAY:
+ return fprintf(options.output, "<array without address>");
+ case ARGTYPE_ENUM:
+ return display_enum(type, proc, info, value);
+ case ARGTYPE_STRUCT:
+ return fprintf(options.output, "<struct without address>");
+ case ARGTYPE_POINTER:
+ return display_pointer(type, proc, value, info,
+ st, st_info);
+ case ARGTYPE_UNKNOWN:
+ default:
+ return display_unknown(type, proc, value);
+ }
+}
+
+int
+display_arg(enum tof type, Process *proc, int arg_num, arg_type_info * info) {
+ long arg;
+
+ if (info->type == ARGTYPE_VOID) {
+ return 0;
+ } else if (info->type == ARGTYPE_FORMAT) {
+ return display_format(type, proc, arg_num);
+ } else {
+ arg = gimme_arg(type, proc, arg_num, info);
+ return display_value(type, proc, arg, info, NULL, NULL);
+ }
+}
+
+static int
+display_char(int what) {
+ switch (what) {
+ case -1:
+ return fprintf(options.output, "EOF");
+ case '\r':
+ return fprintf(options.output, "\\r");
+ case '\n':
+ return fprintf(options.output, "\\n");
+ case '\t':
+ return fprintf(options.output, "\\t");
+ case '\b':
+ return fprintf(options.output, "\\b");
+ case '\\':
+ return fprintf(options.output, "\\\\");
+ default:
+ if (isprint(what)) {
+ return fprintf(options.output, "%c", what);
+ } else {
+ return fprintf(options.output, "\\%03o", (unsigned char)what);
+ }
+ }
+}
+
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+
+static int
+display_string(enum tof type, Process *proc, void *addr,
+ size_t maxlength) {
+ unsigned char *str1;
+ int i;
+ int len = 0;
+
+ if (!addr) {
+ return fprintf(options.output, "NULL");
+ }
+
+ str1 = malloc(MIN(options.strlen, maxlength) + 3);
+ if (!str1) {
+ return fprintf(options.output, "???");
+ }
+ umovestr(proc, addr, MIN(options.strlen, maxlength) + 1, str1);
+ len = fprintf(options.output, "\"");
+ for (i = 0; i < MIN(options.strlen, maxlength); i++) {
+ if (str1[i]) {
+ len += display_char(str1[i]);
+ } else {
+ break;
+ }
+ }
+ len += fprintf(options.output, "\"");
+ if (str1[i] && (options.strlen <= maxlength)) {
+ len += fprintf(options.output, "...");
+ }
+ free(str1);
+ return len;
+}
+
+static int
+display_unknown(enum tof type, Process *proc, long value) {
+ if (proc->mask_32bit) {
+ if ((int)value < 1000000 && (int)value > -1000000)
+ return fprintf(options.output, "%d", (int)value);
+ else
+ return fprintf(options.output, "%p", (void *)value);
+ } else if (value < 1000000 && value > -1000000) {
+ return fprintf(options.output, "%ld", value);
+ } else {
+ return fprintf(options.output, "%p", (void *)value);
+ }
+}
+
+static int
+display_format(enum tof type, Process *proc, int arg_num) {
+ void *addr;
+ unsigned char *str1;
+ int i;
+ int len = 0;
+ arg_type_info info;
+
+ info.type = ARGTYPE_POINTER;
+ addr = (void *)gimme_arg(type, proc, arg_num, &info);
+ if (!addr) {
+ return fprintf(options.output, "NULL");
+ }
+
+ str1 = malloc(MIN(options.strlen, string_maxlength) + 3);
+ if (!str1) {
+ return fprintf(options.output, "???");
+ }
+ umovestr(proc, addr, MIN(options.strlen, string_maxlength) + 1, str1);
+ len = fprintf(options.output, "\"");
+ for (i = 0; len < MIN(options.strlen, string_maxlength) + 1; i++) {
+ if (str1[i]) {
+ len += display_char(str1[i]);
+ } else {
+ break;
+ }
+ }
+ len += fprintf(options.output, "\"");
+ if (str1[i] && (options.strlen <= string_maxlength)) {
+ len += fprintf(options.output, "...");
+ }
+ for (i = 0; str1[i]; i++) {
+ if (str1[i] == '%') {
+ int is_long = 0;
+ while (1) {
+ unsigned char c = str1[++i];
+ if (c == '%') {
+ break;
+ } else if (!c) {
+ break;
+ } else if (strchr("lzZtj", c)) {
+ is_long++;
+ if (c == 'j')
+ is_long++;
+ if (is_long > 1
+ && (sizeof(long) < sizeof(long long)
+ || proc->mask_32bit)) {
+ len += fprintf(options.output, ", ...");
+ str1[i + 1] = '\0';
+ break;
+ }
+ } else if (c == 'd' || c == 'i') {
+ info.type = ARGTYPE_LONG;
+ if (!is_long || proc->mask_32bit)
+ len +=
+ fprintf(options.output, ", %d",
+ (int)gimme_arg(type, proc, ++arg_num, &info));
+ else
+ len +=
+ fprintf(options.output, ", %ld",
+ gimme_arg(type, proc, ++arg_num, &info));
+ break;
+ } else if (c == 'u') {
+ info.type = ARGTYPE_LONG;
+ if (!is_long || proc->mask_32bit)
+ len +=
+ fprintf(options.output, ", %u",
+ (int)gimme_arg(type, proc, ++arg_num, &info));
+ else
+ len +=
+ fprintf(options.output, ", %lu",
+ gimme_arg(type, proc, ++arg_num, &info));
+ break;
+ } else if (c == 'o') {
+ info.type = ARGTYPE_LONG;
+ if (!is_long || proc->mask_32bit)
+ len +=
+ fprintf(options.output, ", 0%o",
+ (int)gimme_arg(type, proc, ++arg_num, &info));
+ else
+ len +=
+ fprintf(options.output, ", 0%lo",
+ gimme_arg(type, proc, ++arg_num, &info));
+ break;
+ } else if (c == 'x' || c == 'X') {
+ info.type = ARGTYPE_LONG;
+ if (!is_long || proc->mask_32bit)
+ len +=
+ fprintf(options.output, ", %#x",
+ (int)gimme_arg(type, proc, ++arg_num, &info));
+ else
+ len +=
+ fprintf(options.output, ", %#lx",
+ gimme_arg(type, proc, ++arg_num, &info));
+ break;
+ } else if (strchr("eEfFgGaACS", c)
+ || (is_long
+ && (c == 'c' || c == 's'))) {
+ len += fprintf(options.output, ", ...");
+ str1[i + 1] = '\0';
+ break;
+ } else if (c == 'c') {
+ info.type = ARGTYPE_LONG;
+ len += fprintf(options.output, ", '");
+ len +=
+ display_char((int)
+ gimme_arg(type, proc, ++arg_num, &info));
+ len += fprintf(options.output, "'");
+ break;
+ } else if (c == 's') {
+ info.type = ARGTYPE_POINTER;
+ len += fprintf(options.output, ", ");
+ len +=
+ display_string(type, proc,
+ (void *)gimme_arg(type, proc, ++arg_num, &info),
+ string_maxlength);
+ break;
+ } else if (c == 'p' || c == 'n') {
+ info.type = ARGTYPE_POINTER;
+ len +=
+ fprintf(options.output, ", %p",
+ (void *)gimme_arg(type, proc, ++arg_num, &info));
+ break;
+ } else if (c == '*') {
+ info.type = ARGTYPE_LONG;
+ len +=
+ fprintf(options.output, ", %d",
+ (int)gimme_arg(type, proc, ++arg_num, &info));
+ }
+ }
+ }
+ }
+ free(str1);
+ return len;
+}