aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--display_args.c66
-rw-r--r--ltrace.h22
-rw-r--r--output.c25
-rw-r--r--process_event.c13
-rw-r--r--read_config_file.c167
-rw-r--r--sysdeps/README2
-rw-r--r--sysdeps/linux-gnu/alpha/trace.c4
-rw-r--r--sysdeps/linux-gnu/arm/trace.c4
-rw-r--r--sysdeps/linux-gnu/i386/trace.c4
-rw-r--r--sysdeps/linux-gnu/ia64/trace.c140
-rw-r--r--sysdeps/linux-gnu/m68k/trace.c4
-rw-r--r--sysdeps/linux-gnu/ppc/trace.c4
-rw-r--r--sysdeps/linux-gnu/s390/trace.c3
-rw-r--r--sysdeps/linux-gnu/sparc/trace.c4
-rw-r--r--sysdeps/linux-gnu/x86_64/trace.c4
16 files changed, 354 insertions, 131 deletions
diff --git a/ChangeLog b/ChangeLog
index 8b672f4..151b0c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2006-09-18 Steve Fink <sphink@gmail.com>
+
+ * display_args.c: store arg_num in arg_type_info
+ * display_args.c: support 'double' parameters
+ * display_args.c: fix implementation of float,double params for ia64
+ * output.c, process_event.c: store arg_num in arg_type_info
+ * read_config_file.c: support 'double' parameters
+ * read_config_file.c: store arg_num in arg_type_info, and as a result,
+ stop using singleton objects for any of the arg_type_info's.
+ * read_config_file.c: improve support for struct field alignments
+ * read_config_file.c: count floating-point parameters to support ia64
+ float parameter passing
+ * sysdeps/README, sysdeps/linux-gnu/*/trace.c: pass in the full
+ arg_type_info to gimme_arg rather than just the arg_num (necessary
+ for float params on some architectures)
+ * sysdeps/linux-gnu/ia64/trace.c: accommodate register renaming when
+ fetching the parameters of a function after it has returned
+ * sysdeps/linux-gnu/ia64/trace.c: support floating point parameters
+
2006-09-15 Olaf Hering <olh@suse.de>
* Makefile.in : allow installation as non-root user, print out
diff --git a/display_args.c b/display_args.c
index e8b20e1..08c735a 100644
--- a/display_args.c
+++ b/display_args.c
@@ -27,13 +27,18 @@ static long get_length(enum tof type, struct 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);
return len;
}
- return gimme_arg(type, proc, -len_spec - 1);
+
+ info.arg_num = -len_spec - 1;
+ info.type = ARGTYPE_INT;
+ return gimme_arg(type, proc, &info);
}
static int display_ptrto(enum tof type, struct process *proc, long item,
@@ -199,10 +204,15 @@ int display_value(enum tof type, struct process *proc,
case ARGTYPE_USHORT:
return fprintf(output, "%hu", (unsigned short) value);
case ARGTYPE_FLOAT: {
- union { long l; float f; } cvt;
+ union { long l; float f; double d; } cvt;
cvt.l = value;
return fprintf(output, "%f", cvt.f);
}
+ case ARGTYPE_DOUBLE: {
+ union { long l; float f; double d; } cvt;
+ cvt.l = value;
+ return fprintf(output, "%lf", cvt.d);
+ }
case ARGTYPE_ADDR:
if (!value)
return fprintf(output, "NULL");
@@ -233,17 +243,16 @@ int display_value(enum tof type, struct process *proc,
}
}
-int display_arg(enum tof type, struct process *proc, int arg_num,
- arg_type_info * info)
+int display_arg(enum tof type, struct process *proc, 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);
+ return display_format(type, proc, info->arg_num);
} else {
- arg = gimme_arg(type, proc, arg_num);
+ arg = gimme_arg(type, proc, info);
return display_value(type, proc, arg, info, NULL, NULL);
}
}
@@ -326,8 +335,11 @@ static int display_format(enum tof type, struct process *proc, int arg_num)
unsigned char *str1;
int i;
int len = 0;
+ arg_type_info info;
- addr = (void *)gimme_arg(type, proc, arg_num);
+ info.arg_num = arg_num;
+ info.type = ARGTYPE_POINTER;
+ addr = (void *)gimme_arg(type, proc, &info);
if (!addr) {
return fprintf(output, "NULL");
}
@@ -370,60 +382,68 @@ static int display_format(enum tof type, struct process *proc, int arg_num)
break;
}
} else if (c == 'd' || c == 'i') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
if (!is_long || proc->mask_32bit)
len +=
fprintf(output, ", %d",
(int)gimme_arg(type,
proc,
- ++arg_num));
+ &info));
else
len +=
fprintf(output, ", %ld",
gimme_arg(type,
proc,
- ++arg_num));
+ &info));
break;
} else if (c == 'u') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
if (!is_long || proc->mask_32bit)
len +=
fprintf(output, ", %u",
(int)gimme_arg(type,
proc,
- ++arg_num));
+ &info));
else
len +=
fprintf(output, ", %lu",
gimme_arg(type,
proc,
- ++arg_num));
+ &info));
break;
} else if (c == 'o') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
if (!is_long || proc->mask_32bit)
len +=
fprintf(output, ", 0%o",
(int)gimme_arg(type,
proc,
- ++arg_num));
+ &info));
else
len +=
fprintf(output, ", 0%lo",
gimme_arg(type,
proc,
- ++arg_num));
+ &info));
break;
} else if (c == 'x' || c == 'X') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
if (!is_long || proc->mask_32bit)
len +=
fprintf(output, ", %#x",
(int)gimme_arg(type,
proc,
- ++arg_num));
+ &info));
else
len +=
fprintf(output, ", %#lx",
gimme_arg(type,
proc,
- ++arg_num));
+ &info));
break;
} else if (strchr("eEfFgGaACS", c)
|| (is_long
@@ -432,34 +452,42 @@ static int display_format(enum tof type, struct process *proc, int arg_num)
str1[i + 1] = '\0';
break;
} else if (c == 'c') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
len += fprintf(output, ", '");
len +=
display_char((int)
gimme_arg(type, proc,
- ++arg_num));
+ &info));
len += fprintf(output, "'");
break;
} else if (c == 's') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_POINTER;
len += fprintf(output, ", ");
len +=
display_string(type, proc,
(void *)gimme_arg(type,
proc,
- ++arg_num),
+ &info),
string_maxlength);
break;
} else if (c == 'p' || c == 'n') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_POINTER;
len +=
fprintf(output, ", %p",
(void *)gimme_arg(type,
proc,
- ++arg_num));
+ &info));
break;
} else if (c == '*') {
+ info.arg_num = ++arg_num;
+ info.type = ARGTYPE_LONG;
len +=
fprintf(output, ", %d",
(int)gimme_arg(type, proc,
- ++arg_num));
+ &info));
}
}
}
diff --git a/ltrace.h b/ltrace.h
index 2e0d01e..76aa4dc 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -39,7 +39,8 @@ enum arg_type {
ARGTYPE_CHAR,
ARGTYPE_SHORT,
ARGTYPE_USHORT,
- ARGTYPE_FLOAT,
+ ARGTYPE_FLOAT, /* float value, may require index */
+ ARGTYPE_DOUBLE, /* double value, may require index */
ARGTYPE_ADDR,
ARGTYPE_FILE,
ARGTYPE_FORMAT, /* printf-like format */
@@ -55,6 +56,7 @@ enum arg_type {
typedef struct arg_type_info_t {
enum arg_type type;
+ int arg_num;
union {
// ARGTYPE_ENUM
struct {
@@ -78,7 +80,6 @@ typedef struct arg_type_info_t {
// ARGTYPE_STRUCT
struct {
struct arg_type_info_t **fields; // NULL-terminated
- size_t *gap;
size_t *offset;
size_t size;
} struct_info;
@@ -87,6 +88,16 @@ typedef struct arg_type_info_t {
struct {
struct arg_type_info_t *info;
} ptr_info;
+
+ // ARGTYPE_FLOAT
+ struct {
+ size_t float_index;
+ } float_info;
+
+ // ARGTYPE_DOUBLE
+ struct {
+ size_t float_index;
+ } double_info;
} u;
} arg_type_info;
@@ -201,8 +212,7 @@ extern void *instruction_pointer;
extern struct event *wait_for_something(void);
extern void process_event(struct event *event);
extern void execute_program(struct process *, char **);
-extern int display_arg(enum tof type, struct process *proc, int arg_num,
- arg_type_info *info);
+extern int display_arg(enum tof type, struct process *proc, arg_type_info *info);
extern struct breakpoint *address2bpstruct(struct process *proc, void *addr);
extern void breakpoints_init(struct process *proc);
extern void insert_breakpoint(struct process *proc, void *addr,
@@ -215,7 +225,7 @@ extern void reinitialize_breakpoints(struct process *);
extern struct process *open_program(char *filename, pid_t pid);
extern void open_pid(pid_t pid, int verbose);
extern void show_summary(void);
-extern arg_type_info *lookup_singleton(enum arg_type at);
+extern arg_type_info *lookup_prototype(enum arg_type at);
/* Arch-dependent stuff: */
extern char *pid2name(pid_t pid);
@@ -238,7 +248,7 @@ extern void continue_after_signal(pid_t pid, int signum);
extern void continue_after_breakpoint(struct process *proc,
struct breakpoint *sbp);
extern void continue_enabling_breakpoint(pid_t pid, struct breakpoint *sbp);
-extern long gimme_arg(enum tof type, struct process *proc, int arg_num);
+extern long gimme_arg(enum tof type, struct process *proc, arg_type_info *);
extern void save_register_args(enum tof type, struct process *proc);
extern int umovestr(struct process *proc, void *addr, int len, void *laddr);
extern int umovelong(struct process *proc, void *addr, long *result);
diff --git a/output.c b/output.c
index 59c0807..f30c9fe 100644
--- a/output.c
+++ b/output.c
@@ -166,7 +166,7 @@ void output_left(enum tof type, struct process *proc, char *function_name)
struct function *func;
static arg_type_info *arg_unknown = NULL;
if (arg_unknown == NULL)
- arg_unknown = lookup_singleton(ARGTYPE_UNKNOWN);
+ arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
if (opt_c) {
return;
@@ -191,23 +191,26 @@ void output_left(enum tof type, struct process *proc, char *function_name)
func = name2func(function_name);
if (!func) {
int i;
+ arg_type_info info = *arg_unknown;
for (i = 0; i < 4; i++) {
+ info.arg_num = i;
current_column +=
- display_arg(type, proc, i, arg_unknown);
+ display_arg(type, proc, &info);
current_column += fprintf(output, ", ");
}
- current_column += display_arg(type, proc, 4, arg_unknown);
+ info.arg_num = 4;
+ current_column += display_arg(type, proc, &info);
return;
} else {
int i;
for (i = 0; i < func->num_params - func->params_right - 1; i++) {
current_column +=
- display_arg(type, proc, i, func->arg_info[i]);
+ display_arg(type, proc, func->arg_info[i]);
current_column += fprintf(output, ", ");
}
if (func->num_params > func->params_right) {
current_column +=
- display_arg(type, proc, i, func->arg_info[i]);
+ display_arg(type, proc, func->arg_info[i]);
if (func->params_right) {
current_column += fprintf(output, ", ");
}
@@ -223,7 +226,7 @@ void output_right(enum tof type, struct process *proc, char *function_name)
struct function *func = name2func(function_name);
static arg_type_info *arg_unknown = NULL;
if (arg_unknown == NULL)
- arg_unknown = lookup_singleton(ARGTYPE_UNKNOWN);
+ arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
if (opt_c) {
struct opt_c_struct *st;
@@ -276,21 +279,23 @@ void output_right(enum tof type, struct process *proc, char *function_name)
}
if (!func) {
+ arg_type_info info = *arg_unknown;
current_column += fprintf(output, ") ");
tabto(opt_a - 1);
fprintf(output, "= ");
- display_arg(type, proc, -1, arg_unknown);
+ info.arg_num = -1;
+ display_arg(type, proc, &info);
} else {
int i;
for (i = func->num_params - func->params_right;
i < func->num_params - 1; i++) {
current_column +=
- display_arg(type, proc, i, func->arg_info[i]);
+ display_arg(type, proc, func->arg_info[i]);
current_column += fprintf(output, ", ");
}
if (func->params_right) {
current_column +=
- display_arg(type, proc, i, func->arg_info[i]);
+ display_arg(type, proc, func->arg_info[i]);
}
current_column += fprintf(output, ") ");
tabto(opt_a - 1);
@@ -298,7 +303,7 @@ void output_right(enum tof type, struct process *proc, char *function_name)
if (func->return_info->type == ARGTYPE_VOID) {
fprintf(output, "<void>");
} else {
- display_arg(type, proc, -1, func->return_info);
+ display_arg(type, proc, func->return_info);
}
}
if (opt_T) {
diff --git a/process_event.c b/process_event.c
index 9241135..f01f27e 100644
--- a/process_event.c
+++ b/process_event.c
@@ -225,8 +225,11 @@ static void process_sysret(struct event *event)
}
if (fork_p(event->proc, event->e_un.sysnum)) {
if (opt_f) {
+ arg_type_info info;
+ info.arg_num = -1; /* Return value */
+ info.type = ARGTYPE_LONG;
pid_t child =
- gimme_arg(LT_TOF_SYSCALLR, event->proc, -1);
+ gimme_arg(LT_TOF_SYSCALLR, event->proc, &info);
if (child > 0) {
open_pid(child, 0);
}
@@ -239,7 +242,10 @@ static void process_sysret(struct event *event)
sysname(event->proc, event->e_un.sysnum));
}
if (exec_p(event->proc, event->e_un.sysnum)) {
- if (gimme_arg(LT_TOF_SYSCALLR, event->proc, -1) == 0) {
+ arg_type_info info;
+ info.arg_num = -1; /* Return value */
+ info.type = ARGTYPE_LONG;
+ if (gimme_arg(LT_TOF_SYSCALLR, event->proc, &info) == 0) {
pid_t saved_pid;
event->proc->mask_32bit = 0;
event->proc->personality = 0;
@@ -260,11 +266,12 @@ static void process_sysret(struct event *event)
static void process_breakpoint(struct event *event)
{
int i, j;
- struct breakpoint *sbp, *nxtbp;
+ struct breakpoint *sbp;
debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
if ((sbp = event->proc->breakpoint_being_enabled) != 0) {
#ifdef __powerpc__
+ struct breakpoint *nxtbp;
char nop_inst[] = PPC_NOP;
if (memcmp(sbp->orig_value, nop_inst, PPC_NOP_LENGTH) == 0) {
nxtbp = address2bpstruct(event->proc,
diff --git a/read_config_file.c b/read_config_file.c
index ec1a4a8..3c7c971 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -36,6 +36,7 @@ static struct list_of_pt_t {
"short", ARGTYPE_SHORT}, {
"ushort", ARGTYPE_USHORT}, {
"float", ARGTYPE_FLOAT}, {
+ "double", ARGTYPE_DOUBLE}, {
"addr", ARGTYPE_ADDR}, {
"file", ARGTYPE_FILE}, {
"format", ARGTYPE_FORMAT}, {
@@ -47,10 +48,10 @@ static struct list_of_pt_t {
NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */
};
-/* Array of singleton objects for each of the types. The order in this
+/* Array of prototype objects for each of the types. The order in this
* array must exactly match the list of enumerated values in
* ltrace.h */
-static arg_type_info arg_type_singletons[] = {
+static arg_type_info arg_type_prototypes[] = {
{ ARGTYPE_VOID },
{ ARGTYPE_INT },
{ ARGTYPE_UINT },
@@ -61,6 +62,7 @@ static arg_type_info arg_type_singletons[] = {
{ ARGTYPE_SHORT },
{ ARGTYPE_USHORT },
{ ARGTYPE_FLOAT },
+ { ARGTYPE_DOUBLE },
{ ARGTYPE_ADDR },
{ ARGTYPE_FILE },
{ ARGTYPE_FORMAT },
@@ -74,12 +76,12 @@ static arg_type_info arg_type_singletons[] = {
{ ARGTYPE_UNKNOWN }
};
-arg_type_info *lookup_singleton(enum arg_type at)
+arg_type_info *lookup_prototype(enum arg_type at)
{
if (at >= 0 && at <= ARGTYPE_COUNT)
- return &arg_type_singletons[at];
+ return &arg_type_prototypes[at];
else
- return &arg_type_singletons[ARGTYPE_COUNT]; /* UNKNOWN */
+ return &arg_type_prototypes[ARGTYPE_COUNT]; /* UNKNOWN */
}
static arg_type_info *str2type(char **str)
@@ -90,11 +92,11 @@ static arg_type_info *str2type(char **str)
if (!strncmp(*str, tmp->name, strlen(tmp->name))
&& index(" ,()#*;012345[", *(*str + strlen(tmp->name)))) {
*str += strlen(tmp->name);
- return lookup_singleton(tmp->pt);
+ return lookup_prototype(tmp->pt);
}
tmp++;
}
- return lookup_singleton(ARGTYPE_UNKNOWN);
+ return lookup_prototype(ARGTYPE_UNKNOWN);
}
static void eat_spaces(char **str)
@@ -162,25 +164,6 @@ static char *start_of_arg_sig(char *str)
return (stacked == 0) ? pos : NULL;
}
-/*
- Decide whether a type needs any additional parameters.
- For now, we do not parse any nontrivial argument types.
-*/
-static int simple_type(enum arg_type at)
-{
- switch (at) {
- case ARGTYPE_STRING:
- case ARGTYPE_STRING_N:
- case ARGTYPE_ARRAY:
- case ARGTYPE_ENUM:
- case ARGTYPE_STRUCT:
- return 0;
-
- default:
- return 1;
- }
-}
-
static int parse_int(char **str)
{
char *end;
@@ -298,10 +281,14 @@ static size_t arg_sizeof(arg_type_info * arg)
return sizeof(short);
} else if (arg->type == ARGTYPE_FLOAT) {
return sizeof(float);
+ } else if (arg->type == ARGTYPE_DOUBLE) {
+ return sizeof(double);
} else if (arg->type == ARGTYPE_ENUM) {
return sizeof(int);
} else if (arg->type == ARGTYPE_STRUCT) {
return arg->u.struct_info.size;
+ } else if (arg->type == ARGTYPE_POINTER) {
+ return sizeof(void*);
} else if (arg->type == ARGTYPE_ARRAY) {
if (arg->u.array_info.len_spec > 0)
return arg->u.array_info.len_spec * arg->u.array_info.elt_size;
@@ -312,58 +299,84 @@ static size_t arg_sizeof(arg_type_info * arg)
}
}
-/* I'm sure this isn't completely correct, but just try to get most of
- * them right for now. */
#undef alignof
#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
-static void align_struct(arg_type_info* info)
+static size_t arg_align(arg_type_info * arg)
{
- struct {
- char c;
- int i;
- } ci;
- struct {
- struct {
- char c;
- } s;
- int i;
- } cis;
+ struct { char c; char C; } cC;
+ struct { char c; short s; } cs;
+ struct { char c; int i; } ci;
+ struct { char c; long l; } cl;
+ struct { char c; void* p; } cp;
+ struct { char c; float f; } cf;
+ struct { char c; double d; } cd;
+
+ static size_t char_alignment = alignof(C, cC);
+ static size_t short_alignment = alignof(s, cs);
+ static size_t int_alignment = alignof(i, ci);
+ static size_t long_alignment = alignof(l, cl);
+ static size_t ptr_alignment = alignof(p, cp);
+ static size_t float_alignment = alignof(f, cf);
+ static size_t double_alignment = alignof(d, cd);
+
+ switch (arg->type) {
+ case ARGTYPE_LONG:
+ case ARGTYPE_ULONG:
+ return long_alignment;
+ case ARGTYPE_CHAR:
+ return char_alignment;
+ case ARGTYPE_SHORT:
+ case ARGTYPE_USHORT:
+ return short_alignment;
+ case ARGTYPE_FLOAT:
+ return float_alignment;
+ case ARGTYPE_DOUBLE:
+ return double_alignment;
+ case ARGTYPE_ADDR:
+ case ARGTYPE_FILE:
+ case ARGTYPE_FORMAT:
+ case ARGTYPE_STRING:
+ case ARGTYPE_STRING_N:
+ case ARGTYPE_POINTER:
+ return ptr_alignment;
- size_t int_alignment = alignof(i, ci);
- size_t whole_struct_alignment = alignof(i, cis);
+ case ARGTYPE_ARRAY:
+ return arg_align(&arg->u.array_info.elt_type[0]);
+
+ case ARGTYPE_STRUCT:
+ return arg_align(arg->u.struct_info.fields[0]);
+
+ default:
+ return int_alignment;
+ }
+}
+static size_t align_skip(size_t alignment, size_t offset)
+{
+ if (offset % alignment)
+ return alignment - (offset % alignment);
+ else
+ return 0;
+}
+
+/* I'm sure this isn't completely correct, but just try to get most of
+ * them right for now. */
+static void align_struct(arg_type_info* info)
+{
size_t offset;
- size_t gap;
int i;
if (info->u.struct_info.size != 0)
return; // Already done
- // The gap array isn't actually needed anymore, because the
- // offset can be used for everything.
-
- // 1. Add internal padding
+ // Compute internal padding due to alignment constraints for
+ // various types.
offset = 0;
for (i = 0; info->u.struct_info.fields[i] != NULL; i++) {
arg_type_info *field = info->u.struct_info.fields[i];
+ offset += align_skip(arg_align(field), offset);
info->u.struct_info.offset[i] = offset;
offset += arg_sizeof(field);
-
- if (offset % int_alignment != 0) {
- gap = int_alignment - offset % int_alignment;
- info->u.struct_info.gap[i] = gap;
- offset += gap;
- }
- }
-
- // 2. Add padding at end of entire struct
- for (i = 0; info->u.struct_info.fields[i] != NULL; i++);
- if (i == 0)
- return;
- if (offset % whole_struct_alignment != 0) {
- gap = whole_struct_alignment - offset % whole_struct_alignment;
- info->u.struct_info.gap[i - 1] = gap;
- offset += gap;
}
info->u.struct_info.size = offset;
@@ -376,7 +389,7 @@ static arg_type_info *parse_nonpointer_type(char **str)
if (strncmp(*str, "typedef", 7) == 0) {
parse_typedef(str);
- return lookup_singleton(ARGTYPE_UNKNOWN);
+ return lookup_prototype(ARGTYPE_UNKNOWN);
}
simple = str2type(str);
@@ -388,9 +401,6 @@ static arg_type_info *parse_nonpointer_type(char **str)
return simple; // UNKNOWN
}
- if (simple_type(simple->type) && simple->type != ARGTYPE_STRING)
- return simple;
-
info = malloc(sizeof(*info));
info->type = simple->type;
@@ -508,8 +518,6 @@ static arg_type_info *parse_nonpointer_type(char **str)
(*str)++; // Get past open paren
info->u.struct_info.fields =
malloc((MAX_ARGS + 1) * sizeof(void *));
- info->u.struct_info.gap =
- malloc((MAX_ARGS + 1) * sizeof(size_t));
info->u.struct_info.offset =
malloc((MAX_ARGS + 1) * sizeof(size_t));
info->u.struct_info.size = 0;
@@ -527,7 +535,6 @@ static arg_type_info *parse_nonpointer_type(char **str)
(*str)++; // Get past comma
eat_spaces(str);
}
- info->u.struct_info.gap[field_num] = 0;
if ((info->u.struct_info.fields[field_num++] =
parse_type(str)) == NULL)
return NULL;
@@ -543,11 +550,16 @@ static arg_type_info *parse_nonpointer_type(char **str)
}
default:
- output_line(0, "Syntax error in `%s', line %d: Unknown type encountered",
- filename, line_no);
- free(info);
- error_count++;
- return NULL;
+ if (info->type == ARGTYPE_UNKNOWN) {
+ output_line(0, "Syntax error in `%s', line %d: "
+ "Unknown type encountered",
+ filename, line_no);
+ free(info);
+ error_count++;
+ return NULL;
+ } else {
+ return info;
+ }
}
}
@@ -571,6 +583,7 @@ static struct function *process_line(char *buf)
char *str = buf;
char *tmp;
int i;
+ int float_num = 0;
line_no++;
debug(3, "Reading line %d of `%s'", line_no, filename);
@@ -582,6 +595,7 @@ static struct function *process_line(char *buf)
debug(3, " Skipping line %d", line_no);
return NULL;
}
+ fun.return_info->arg_num = -1;
debug(4, " return_type = %d", fun.return_info->type);
eat_spaces(&str);
tmp = start_of_arg_sig(str);
@@ -615,6 +629,11 @@ static struct function *process_line(char *buf)
error_count++;
return NULL;
}
+ if (fun.arg_info[i]->type == ARGTYPE_FLOAT)
+ fun.arg_info[i]->u.float_info.float_index = float_num++;
+ else if (fun.arg_info[i]->type == ARGTYPE_DOUBLE)
+ fun.arg_info[i]->u.double_info.float_index = float_num++;
+ fun.arg_info[i]->arg_num = i;
eat_spaces(&str);
if (*str == ',') {
str++;
diff --git a/sysdeps/README b/sysdeps/README
index 1ec4935..9876548 100644
--- a/sysdeps/README
+++ b/sysdeps/README
@@ -22,7 +22,7 @@ int syscall_p(struct process * proc, int status, int * sysnum);
void * get_instruction_pointer(pid_t pid);
void * get_stack_pointer(pid_t pid);
void * get_return_addr(pid_t pid, void * stack_pointer);
-long gimme_arg(enum tof type, struct process * proc, int arg_num);
+long gimme_arg(enum tof type, struct process * proc, arg_type_info*);
int umovestr(struct process * proc, void * addr, int len, void * laddr);
int umovelong(struct process * proc, void * addr, long * result);
char * pid2name(pid_t pid);
diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
index 36a9938..459efa6 100644
--- a/sysdeps/linux-gnu/alpha/trace.c
+++ b/sysdeps/linux-gnu/alpha/trace.c
@@ -47,8 +47,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (arg_num == -1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0);
}
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
index ac5d5d2..efa625e 100644
--- a/sysdeps/linux-gnu/arm/trace.c
+++ b/sysdeps/linux-gnu/arm/trace.c
@@ -51,8 +51,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (arg_num == -1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0);
}
diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c
index 36197d1..6406272 100644
--- a/sysdeps/linux-gnu/i386/trace.c
+++ b/sysdeps/linux-gnu/i386/trace.c
@@ -43,8 +43,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (arg_num == -1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EAX, 0);
}
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
index dd7ceb2..ce07d86 100644
--- a/sysdeps/linux-gnu/ia64/trace.c
+++ b/sysdeps/linux-gnu/ia64/trace.c
@@ -34,6 +34,18 @@ union bundle_t {
unsigned long code[2];
};
+union cfm_t {
+ struct {
+ unsigned long sof:7;
+ unsigned long sol:7;
+ unsigned long sor:4;
+ unsigned long rrb_gr:7;
+ unsigned long rrb_fr:7;
+ unsigned long rrb_pr:6;
+ } cfm;
+ unsigned long value;
+};
+
int syscall_p(struct process *proc, int status, int *sysnum)
{
@@ -105,13 +117,25 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+/* Stolen from David Mosberger's utrace tool, which he released under
+ the GPL
+ (http://www.gelato.unsw.edu.au/archives/linux-ia64/0104/1405.html) */
+static inline double
+fpreg_to_double (struct ia64_fpreg *fp)
{
+ double result;
+
+ asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp));
+ return result;
+}
- unsigned long bsp, cfm;
+static long gimme_long_arg(enum tof type, struct process *proc, int arg_num)
+{
+ union cfm_t cfm;
+ unsigned long bsp;
bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0);
- cfm = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0);
+ cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0);
if (arg_num == -1) /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, PT_R8, 0);
@@ -119,14 +143,25 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
/* First 8 arguments are passed in registers on the register
* stack, the following arguments are passed on the stack
* after a 16 byte scratch area
- */
- if (type == LT_TOF_FUNCTION || LT_TOF_FUNCTIONR) {
- if (arg_num < 8)
+ *
+ * If the function has returned, the ia64 register window has
+ * been reverted to the caller's configuration. So although in
+ * the callee, the first parameter is in R32, in the caller
+ * the first parameter comes in the registers after the local
+ * registers (really, input parameters plus locals, but the
+ * hardware doesn't track the distinction.) So we have to add
+ * in the size of the local area (sol) to find the first
+ * parameter passed to the callee. */
+ if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
+ if (arg_num < 8) {
+ if (type == LT_TOF_FUNCTIONR)
+ arg_num += cfm.cfm.sol;
+
return ptrace(PTRACE_PEEKDATA, proc->pid,
- (long)ia64_rse_skip_regs((long *)bsp,
- -cfm + arg_num),
+ (long)ia64_rse_skip_regs((unsigned long *)bsp,
+ -cfm.cfm.sof + arg_num),
0);
- else {
+ } else {
unsigned long sp =
ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16;
return ptrace(PTRACE_PEEKDATA, proc->pid,
@@ -136,7 +171,7 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR)
return ptrace(PTRACE_PEEKDATA, proc->pid,
- (long)ia64_rse_skip_regs((long *)bsp, arg_num),
+ (long)ia64_rse_skip_regs((unsigned long *)bsp, arg_num),
0);
/* error if we get here */
@@ -144,6 +179,91 @@ long gimme_arg(enum tof type, struct process *proc, int arg_num)
exit(1);
}
+static long float_regs[8] = { PT_F8, PT_F9, PT_F10, PT_F11,
+ PT_F12, PT_F13, PT_F14, PT_F15 };
+static double gimme_float_arg(enum tof type, struct process *proc, int arg_num)
+{
+ union cfm_t cfm;
+ unsigned long bsp;
+ struct ia64_fpreg reg;
+
+ if (arg_num == -1) { /* return value */
+ reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid,
+ PT_F8, 0);
+ reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid,
+ PT_F8 + 0x8, 0);
+ return fpreg_to_double(&reg);
+ }
+
+ bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0);
+ cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0);
+
+ /* The first 8 arguments are passed in regular registers
+ * (counting from R32), unless they are floating point values
+ * (the case in question here). In that case, up to the first
+ * 8 regular registers are still "allocated" for each of the
+ * first 8 parameters, but if a parameter is floating point,
+ * then the register is left unset and the parameter is passed
+ * in the first available floating-point register, counting
+ * from F8.
+ *
+ * Take func(int a, float f, int b, double d), for example.
+ * a - passed in R32
+ * f - R33 left unset, value passed in F8
+ * b - passed in R34
+ * d - R35 left unset, value passed in F9
+ *
+ * ltrace handles this by counting floating point arguments
+ * while parsing declarations. The "arg_num" in this routine
+ * (which is only called for floating point values) really
+ * means which floating point parameter we're looking for,
+ * ignoring everything else.
+ *
+ * Following the first 8 arguments, the remaining arguments
+ * are passed on the stack after a 16 byte scratch area
+ */
+ if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) {
+ if (arg_num < 8) {
+ reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid,
+ float_regs[arg_num], 0);
+ reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid,
+ float_regs[arg_num] + 0x8, 0);
+ return fpreg_to_double(&reg);
+ } else {
+ unsigned long sp =
+ ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16;
+ reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid,
+ sp + (8 * (arg_num - 8)));
+ reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid,
+ sp + (8 * (arg_num - 8)) + 0x8);
+ return fpreg_to_double(&reg);
+ }
+ }
+
+ /* error if we get here */
+ fprintf(stderr, "gimme_arg called with wrong arguments\n");
+ exit(1);
+}
+
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
+{
+ int arg_num = info->arg_num;
+ union {
+ long l;
+ float f;
+ double d;
+ } cvt;
+
+ if (info->type == ARGTYPE_FLOAT)
+ cvt.f = gimme_float_arg(type, proc, info->u.float_info.float_index);
+ else if (info->type == ARGTYPE_DOUBLE)
+ cvt.d = gimme_float_arg(type, proc, info->u.double_info.float_index);
+ else
+ cvt.l = gimme_long_arg(type, proc, arg_num);
+
+ return cvt.l;
+}
+
void save_register_args(enum tof type, struct process *proc)
{
}
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
index 0329b0a..c05959c 100644
--- a/sysdeps/linux-gnu/m68k/trace.c
+++ b/sysdeps/linux-gnu/m68k/trace.c
@@ -48,8 +48,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (arg_num == -1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D0, 0);
}
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
index c726889..888c38f 100644
--- a/sysdeps/linux-gnu/ppc/trace.c
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -56,8 +56,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (arg_num == -1) { /* return value */
return ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long) * PT_R3,
0);
diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
index 7da28f1..0e93f39 100644
--- a/sysdeps/linux-gnu/s390/trace.c
+++ b/sysdeps/linux-gnu/s390/trace.c
@@ -161,8 +161,9 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
long ret;
switch (arg_num) {
diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
index 5f0b629..0533998 100644
--- a/sysdeps/linux-gnu/sparc/trace.c
+++ b/sysdeps/linux-gnu/sparc/trace.c
@@ -48,8 +48,10 @@ int syscall_p(struct process *proc, int status, int *sysnum)
return 0;
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
proc_archdep *a = (proc_archdep *) proc->arch_ptr;
if (!a->valid) {
fprintf(stderr, "Could not get child registers\n");
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
index c03043b..56622c9 100644
--- a/sysdeps/linux-gnu/x86_64/trace.c
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -86,8 +86,10 @@ gimme_arg32(enum tof type, struct process *proc, int arg_num)
exit(1);
}
-long gimme_arg(enum tof type, struct process *proc, int arg_num)
+long gimme_arg(enum tof type, struct process *proc, arg_type_info *info)
{
+ int arg_num = info->arg_num;
+
if (proc->mask_32bit)
return (unsigned int)gimme_arg32(type, proc, arg_num);