aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog13
-rw-r--r--Makefile.am2
-rw-r--r--common.h9
-rw-r--r--display_args.c43
-rw-r--r--fetch.c130
-rw-r--r--fetch.h64
-rw-r--r--handle_event.c2
-rw-r--r--output.c306
-rw-r--r--output.h1
-rw-r--r--proc.c24
-rw-r--r--proc.h7
11 files changed, 452 insertions, 149 deletions
diff --git a/ChangeLog b/ChangeLog
index 4f20aa9..0324341 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,18 @@
2012-01-06 Petr Machata <pmachata@redhat.com>
+ * fetch.c, fetch.h: New module.
+ * common.h (enum tof): Move to fetch.h
+ (struct output_state): New struct
+ (struct callstack_element.fetch_context, .out): New fields
+ * handle_event.c (handle_clone): Clone fetch_context's
+ * output.c (build_default_prototype): New function
+ (fetch_simple_param, fetch_param_stop, fetch_one_param)
+ (fetch_params, output_one, output_params): New functions.
+ (output_left, output_right): Do the parameter output using the
+ above functions.
+
+2012-01-06 Petr Machata <pmachata@redhat.com>
+
* common.h (enum tof.LT_TOF_NONE, .LT_TOF_STRUCT): Drop.
* output.c: Adjust.
diff --git a/Makefile.am b/Makefile.am
index 3c8cb25..90165d0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -34,6 +34,7 @@ libltrace_la_SOURCES = \
value.c \
value_dict.c \
expr.c \
+ fetch.c \
vect.c \
libltrace_la_LIBADD = \
@@ -76,6 +77,7 @@ noinst_HEADERS = \
value.h \
value_dict.h \
expr.h \
+ fetch.h \
vect.h \
dist_man1_MANS = \
diff --git a/common.h b/common.h
index 258ad8b..acff84b 100644
--- a/common.h
+++ b/common.h
@@ -50,13 +50,6 @@ extern char * command;
extern int exiting; /* =1 if we have to exit ASAP */
-enum tof {
- LT_TOF_FUNCTION, /* A real library function */
- LT_TOF_FUNCTIONR, /* Return from a real library function */
- LT_TOF_SYSCALL, /* A syscall */
- LT_TOF_SYSCALLR, /* Return from a syscall */
-};
-
typedef struct Function Function;
struct Function {
const char * name;
@@ -140,8 +133,6 @@ extern void continue_after_signal(pid_t pid, int signum);
extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
extern void continue_after_breakpoint(struct Process *proc, struct breakpoint *sbp);
extern void continue_after_vfork(Process * proc);
-extern long gimme_arg(enum tof type, Process *proc, int arg_num,
- struct arg_type_info *info);
extern size_t umovebytes (Process *proc, void * addr, void * laddr, size_t count);
extern int ffcheck(void * maddr);
extern void * sym2addr(Process *, struct library_symbol *);
diff --git a/display_args.c b/display_args.c
index 8848b35..4a1747d 100644
--- a/display_args.c
+++ b/display_args.c
@@ -35,9 +35,6 @@
#include "type.h"
#include "common.h"
-static int format_argument_2(FILE *stream, struct value *value,
- struct value_dict *arguments);
-
#define READER(NAME, TYPE) \
static int \
NAME(struct value *value, TYPE *ret, struct value_dict *arguments) \
@@ -235,7 +232,7 @@ format_struct(FILE *stream, struct value *value, struct value_dict *arguments)
struct value element;
if (value_init_element(&element, value, i) < 0)
return -1;
- int o = format_argument_2(stream, &element, arguments);
+ int o = format_argument(stream, &element, arguments);
if (o < 0)
return -1;
written += o;
@@ -251,7 +248,7 @@ format_pointer(FILE *stream, struct value *value, struct value_dict *arguments)
struct value element;
if (value_init_deref(&element, value) < 0)
return -1;
- return format_argument_2(stream, &element, arguments);
+ return format_argument(stream, &element, arguments);
}
/*
@@ -300,7 +297,7 @@ format_array(FILE *stream, struct value *value, struct value_dict *arguments,
return -1;
if (value_is_zero(&element, arguments)) /* XXX emulate ZERO */
break;
- int o = format_argument_2(stream, &element, arguments);
+ int o = format_argument(stream, &element, arguments);
if (o < 0)
return -1;
written += o;
@@ -313,9 +310,8 @@ format_array(FILE *stream, struct value *value, struct value_dict *arguments,
return written;
}
-static int
-format_argument_2(FILE *stream, struct value *value,
- struct value_dict *arguments)
+int
+format_argument(FILE *stream, struct value *value, struct value_dict *arguments)
{
struct expr_node *length = NULL;
switch (value->type->type) {
@@ -384,7 +380,7 @@ format_argument_2(FILE *stream, struct value *value,
value_clone(&tmp, value);
value_set_type(&tmp, info, 0);
- int ret = format_argument_2(stream, &tmp, arguments);
+ int ret = format_argument(stream, &tmp, arguments);
value_destroy(&tmp);
type_destroy(&info[0]);
@@ -400,30 +396,3 @@ format_argument_2(FILE *stream, struct value *value,
}
abort();
}
-
-int
-format_argument(FILE *stream, struct value *value, struct value_dict *arguments)
-{
- /* Arrays decay into pointers for purposes of argument
- * passing. Before the proper support for this lands, wrap
- * top-level arrays in pointers here. */
- if (value->type->type == ARGTYPE_ARRAY) {
-
- struct arg_type_info info;
- type_init_pointer(&info, value->type, 0);
-
- struct value tmp;
- value_clone(&tmp, value);
- value_set_type(&tmp, &info, 0);
-
- int ret = format_argument_2(stream, &tmp, arguments);
-
- value_destroy(&tmp);
- type_destroy(&info);
-
- return ret;
-
- } else {
- return format_argument_2(stream, value, arguments);
- }
-}
diff --git a/fetch.c b/fetch.c
new file mode 100644
index 0000000..f68b4e5
--- /dev/null
+++ b/fetch.c
@@ -0,0 +1,130 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fetch.h"
+#include "value.h"
+#include "arch.h"
+
+#ifdef ARCH_HAVE_FETCH_ARG
+struct fetch_context *arch_fetch_arg_init(enum tof type, struct Process *proc,
+ struct arg_type_info *ret_info);
+
+struct fetch_context *arch_fetch_arg_clone(struct Process *proc,
+ struct fetch_context *context);
+
+int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type,
+ struct Process *proc, struct arg_type_info *info,
+ struct value *valuep);
+
+int arch_fetch_retval(struct fetch_context *ctx, enum tof type,
+ struct Process *proc, struct arg_type_info *info,
+ struct value *valuep);
+
+void arch_fetch_arg_done(struct fetch_context *context);
+
+#else
+/* Fall back to gimme_arg. */
+
+long gimme_arg(enum tof type, struct Process *proc, int arg_num,
+ struct arg_type_info *info);
+
+struct fetch_context {
+ int argnum;
+};
+
+struct fetch_context *
+arch_fetch_arg_init(enum tof type, struct Process *proc,
+ struct arg_type_info *ret_info)
+{
+ return calloc(sizeof(struct fetch_context), 1);
+}
+
+struct fetch_context *
+arch_fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+{
+ struct fetch_context *ret = malloc(sizeof(*ret));
+ if (ret == NULL)
+ return NULL;
+ return memcpy(ret, context, sizeof(*ret));
+}
+
+int
+arch_fetch_arg_next(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep)
+{
+ long l = gimme_arg(type, proc, context->argnum++, info);
+ value_set_long(valuep, l);
+ return 0;
+}
+
+int
+arch_fetch_retval(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep)
+{
+ long l = gimme_arg(type, proc, -1, info);
+ value_set_long(valuep, l);
+ return 0;
+}
+
+void
+arch_fetch_arg_done(struct fetch_context *context)
+{
+ free(context);
+}
+#endif
+
+struct fetch_context *
+fetch_arg_init(enum tof type, struct Process *proc,
+ struct arg_type_info *ret_info)
+{
+ return arch_fetch_arg_init(type, proc, ret_info);
+}
+
+struct fetch_context *
+fetch_arg_clone(struct Process *proc, struct fetch_context *context)
+{
+ return arch_fetch_arg_clone(proc, context);
+}
+
+int
+fetch_arg_next(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep)
+{
+ return arch_fetch_arg_next(context, type, proc, info, valuep);
+}
+
+int
+fetch_retval(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep)
+{
+ return arch_fetch_retval(context, type, proc, info, valuep);
+}
+
+void
+fetch_arg_done(struct fetch_context *context)
+{
+ return arch_fetch_arg_done(context);
+}
diff --git a/fetch.h b/fetch.h
new file mode 100644
index 0000000..6a5385c
--- /dev/null
+++ b/fetch.h
@@ -0,0 +1,64 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef FETCH_H
+#define FETCH_H
+
+#include "forward.h"
+
+/* XXX isn't SYSCALL TOF just a different ABI? Maybe we needed to
+ * support variant ABIs all along. */
+enum tof {
+ LT_TOF_FUNCTION, /* A real library function */
+ LT_TOF_FUNCTIONR, /* Return from a real library function */
+ LT_TOF_SYSCALL, /* A syscall */
+ LT_TOF_SYSCALLR, /* Return from a syscall */
+};
+
+/* The contents of the structure is defined by the back end. */
+struct fetch_context;
+
+/* Initialize argument fetching. Returns NULL on failure. RET_INFO
+ * is the return type of the function. */
+struct fetch_context *fetch_arg_init(enum tof type, struct Process *proc,
+ struct arg_type_info *ret_info);
+
+/* Make a clone of context. */
+struct fetch_context *fetch_arg_clone(struct Process *proc,
+ struct fetch_context *context);
+
+/* Load next argument. The function returns 0 on success or a
+ * negative value on failure. The extracted value is stored in
+ * *VALUEP. */
+int fetch_arg_next(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep);
+
+/* Load return value. The function returns 0 on success or a negative
+ * value on failure. The extracted value is stored in *VALUEP. */
+int fetch_retval(struct fetch_context *context, enum tof type,
+ struct Process *proc,
+ struct arg_type_info *info, struct value *valuep);
+
+/* Destroy fetch context. CONTEXT shall be the same memory location
+ * that was passed to fetch_arg_next. */
+void fetch_arg_done(struct fetch_context *context);
+
+#endif /* FETCH_H */
diff --git a/handle_event.c b/handle_event.c
index 7d1eb61..ffce2ff 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -37,9 +37,9 @@
#include "common.h"
#include "value_dict.h"
#include "breakpoint.h"
-#include "common.h"
#include "library.h"
#include "proc.h"
+#include "fetch.h"
static void handle_signal(Event *event);
static void handle_exit(Event *event);
diff --git a/output.c b/output.c
index e1b3a2a..ee444d5 100644
--- a/output.c
+++ b/output.c
@@ -31,6 +31,7 @@
#include <time.h>
#include <sys/time.h>
#include <unistd.h>
+#include <errno.h>
#include "common.h"
#include "proc.h"
@@ -38,6 +39,7 @@
#include "type.h"
#include "value.h"
#include "value_dict.h"
+#include "fetch.h"
/* TODO FIXME XXX: include in common.h: */
extern struct timeval current_time_spent;
@@ -125,27 +127,50 @@ begin_of_line(Process *proc, int is_func, int indent)
}
}
+/* The default prototype is: long X(long, long, long, long). */
+static Function *
+build_default_prototype(void)
+{
+ Function *ret = malloc(sizeof(*ret));
+ size_t i = 0;
+ if (ret == NULL)
+ goto err;
+ memset(ret, 0, sizeof(*ret));
+
+ struct arg_type_info *unknown_type = type_get_simple(ARGTYPE_UNKNOWN);
+
+ ret->return_info = unknown_type;
+
+ ret->num_params = 4;
+ for (i = 0; i < (size_t)ret->num_params; ++i)
+ ret->arg_info[i] = unknown_type;
+
+ return ret;
+
+err:
+ report_global_error("malloc: %s", strerror(errno));
+ free(ret);
+
+ return NULL;
+}
+
static Function *
name2func(char const *name) {
Function *tmp;
const char *str1, *str2;
- tmp = list_of_functions;
- while (tmp) {
-#ifdef USE_DEMANGLE
- str1 = options.demangle ? my_demangle(tmp->name) : tmp->name;
- str2 = options.demangle ? my_demangle(name) : name;
-#else
+ for (tmp = list_of_functions; tmp != NULL; tmp = tmp->next) {
str1 = tmp->name;
str2 = name;
-#endif
- if (!strcmp(str1, str2)) {
-
+ if (!strcmp(str1, str2))
return tmp;
- }
- tmp = tmp->next;
}
- return NULL;
+
+ static Function *def = NULL;
+ if (def == NULL)
+ def = build_default_prototype();
+
+ return def;
}
void
@@ -182,15 +207,128 @@ tabto(int col) {
}
}
+static int
+account_output(int o)
+{
+ if (o < 0)
+ return -1;
+ current_column += o;
+ return 0;
+}
+
+static int
+output_error(void)
+{
+ return account_output(fprintf(options.output, "?"));
+}
+
+static int
+fetch_simple_param(enum tof type, Process *proc, struct fetch_context *context,
+ struct value_dict *arguments, struct arg_type_info *info,
+ struct value *valuep)
+{
+ /* Arrays decay into pointers per C standard. We check for
+ * this here, because here we also capture arrays that come
+ * from parameter packs. */
+ int own = 0;
+ if (info->type == ARGTYPE_ARRAY) {
+ struct arg_type_info *tmp = malloc(sizeof(*tmp));
+ if (tmp != NULL) {
+ type_init_pointer(tmp, info, 0);
+ info = tmp;
+ own = 1;
+ }
+ }
+
+ struct value value;
+ value_init(&value, proc, NULL, info, own);
+ if (fetch_arg_next(context, type, proc, info, &value) < 0)
+ return -1;
+
+ if (val_dict_push_next(arguments, &value) < 0) {
+ value_destroy(&value);
+ return -1;
+ }
+
+ if (valuep != NULL)
+ *valuep = value;
+
+ return 0;
+}
+
+static void
+fetch_param_stop(struct value_dict *arguments, ssize_t *params_leftp)
+{
+ if (*params_leftp == -1)
+ *params_leftp = val_dict_count(arguments);
+}
+
+static int
+fetch_one_param(enum tof type, Process *proc, struct fetch_context *context,
+ struct value_dict *arguments, struct arg_type_info *info,
+ ssize_t *params_leftp)
+{
+ return fetch_simple_param(type, proc, context, arguments,
+ info, NULL);
+}
+
+static int
+fetch_params(enum tof type, Process *proc, struct fetch_context *context,
+ struct value_dict *arguments, Function *func, ssize_t *params_leftp)
+{
+ size_t i;
+ for (i = 0; i < (size_t)func->num_params; ++i) {
+ if (i == (size_t)(func->num_params - func->params_right))
+ fetch_param_stop(arguments, params_leftp);
+ if (fetch_one_param(type, proc, context, arguments,
+ func->arg_info[i], params_leftp) < 0)
+ return -1;
+ }
+
+ /* Implicit stop at the end of parameter list. */
+ fetch_param_stop(arguments, params_leftp);
+ return 0;
+}
+
+static int
+output_one(struct value *val, struct value_dict *arguments)
+{
+ int o = format_argument(options.output, val, arguments);
+ if (account_output(o) < 0) {
+ if (output_error() < 0)
+ return -1;
+ o = 1;
+ }
+ return o;
+}
+
+static int
+output_params(struct value_dict *arguments, size_t start, size_t end,
+ int *need_delimp)
+{
+ size_t i;
+ int need_delim = *need_delimp;
+ for (i = start; i < end; ++i) {
+ if (need_delim
+ && account_output(fprintf(options.output, ", ")) < 0)
+ return -1;
+ struct value *value = val_dict_get_num(arguments, i);
+ if (value == NULL)
+ return -1;
+ need_delim = output_one(value, arguments);
+ if (need_delim < 0)
+ return -1;
+ }
+ *need_delimp = need_delim;
+ return 0;
+}
+
void
output_left(enum tof type, struct Process *proc,
struct library_symbol *libsym)
{
const char *function_name = libsym->name;
Function *func;
- static struct arg_type_info *arg_unknown = NULL;
- if (arg_unknown == NULL)
- arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
if (options.summary) {
return;
@@ -201,74 +339,46 @@ output_left(enum tof type, struct Process *proc,
}
current_proc = proc;
current_depth = proc->callstack_depth;
- begin_of_line(type, type == LT_TOF_FUNCTION, 1);
+ begin_of_line(proc, type == LT_TOF_FUNCTION, 1);
if (!options.hide_caller && libsym->lib != NULL
&& libsym->plt_type != LS_TOPLT_NONE)
current_column += fprintf(options.output, "%s->",
libsym->lib->soname);
+
+ const char *name = function_name;
#ifdef USE_DEMANGLE
- current_column +=
- fprintf(options.output, "%s(",
- (options.demangle
- ? my_demangle(function_name) : function_name));
-#else
- current_column += fprintf(options.output, "%s(", function_name);
+ if (options.demangle)
+ name = my_demangle(function_name);
#endif
+ if (account_output(fprintf(options.output, "%s(", name)) < 0)
+ return;
func = name2func(function_name);
+ if (func == NULL)
+ return;
+ struct fetch_context *context = fetch_arg_init(type, proc,
+ func->return_info);
struct value_dict *arguments = malloc(sizeof(*arguments));
if (arguments == NULL)
return;
val_dict_init(arguments);
- int num, right;
- if (!func) {
- int i;
- for (i = 0; i < 4; i++) {
- long l = gimme_arg(type, proc, i, arg_unknown);
- struct value val;
- value_init(&val, proc, NULL, arg_unknown, 0);
- value_set_long(&val, l);
- val_dict_push_next(arguments, &val);
- }
- right = 0;
- num = 4;
- } else {
- int i;
- for (i = 0; i < func->num_params; i++) {
- long l = gimme_arg(type, proc, i, func->arg_info[i]);
- struct value val;
- value_init(&val, proc, NULL, func->arg_info[i], 0);
- value_set_long(&val, l);
- val_dict_push_next(arguments, &val);
- }
- right = func->params_right;
- num = func->num_params;
- }
-
- int i;
- for (i = 0; i < num - right - 1; i++) {
- current_column +=
- format_argument(options.output,
- val_dict_get_num(arguments, i),
- arguments);
- current_column += fprintf(options.output, ", ");
- }
-
- if (num > right) {
- current_column +=
- format_argument(options.output,
- val_dict_get_num(arguments, i),
- arguments);
- if (right) {
- current_column += fprintf(options.output, ", ");
- }
+ ssize_t params_left = -1;
+ int need_delim = 0;
+ if (fetch_params(type, proc, context, arguments, func, &params_left) < 0
+ || output_params(arguments, 0, params_left, &need_delim) < 0) {
+ val_dict_destroy(arguments);
+ fetch_arg_done(context);
+ return;
}
struct callstack_element *stel
= &proc->callstack[proc->callstack_depth - 1];
+ stel->fetch_context = context;
stel->arguments = arguments;
+ stel->out.params_left = params_left;
+ stel->out.need_delim = need_delim;
}
void
@@ -276,9 +386,8 @@ output_right(enum tof type, struct Process *proc, struct library_symbol *libsym)
{
const char *function_name = libsym->name;
Function *func = name2func(function_name);
- static struct arg_type_info *arg_unknown = NULL;
- if (arg_unknown == NULL)
- arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN);
+ if (func == NULL)
+ return;
if (options.summary) {
struct opt_c_struct *st;
@@ -333,44 +442,41 @@ output_right(enum tof type, struct Process *proc, struct library_symbol *libsym)
struct callstack_element *stel
= &proc->callstack[proc->callstack_depth - 1];
+ struct fetch_context *context = stel->fetch_context;
+
+ /* Fetch & enter into dictionary the retval first, so that
+ * other values can use it in expressions. */
struct value retval;
- struct arg_type_info *return_info = arg_unknown;
- if (func != NULL)
- return_info = func->return_info;
- long l = gimme_arg(type, proc, -1, return_info);
- value_init(&retval, proc, NULL, return_info, 0);
- value_set_long(&retval, l);
- val_dict_push_named(stel->arguments, &retval, "retval", 0);
-
- if (!func) {
- current_column += fprintf(options.output, ") ");
- tabto(options.align - 1);
- fprintf(options.output, "= ");
- } else {
- int i;
- for (i = func->num_params - func->params_right;
- i < func->num_params - 1; i++) {
- current_column +=
- format_argument(options.output,
- val_dict_get_num
- (stel->arguments, i),
- stel->arguments);
- current_column += fprintf(options.output, ", ");
- }
- if (func->params_right) {
- current_column +=
- format_argument(options.output,
- val_dict_get_num
- (stel->arguments, i),
- stel->arguments);
+ int own_retval = 0;
+ if (context != NULL) {
+ value_init(&retval, proc, NULL, func->return_info, 0);
+ own_retval = 1;
+ if (fetch_retval(context, type, proc, func->return_info,
+ &retval) == 0) {
+ if (stel->arguments != NULL
+ && val_dict_push_named(stel->arguments, &retval,
+ "retval", 0) == 0)
+ own_retval = 0;
}
- current_column += fprintf(options.output, ") ");
- tabto(options.align - 1);
- fprintf(options.output, "= ");
}
- format_argument(options.output, &retval, stel->arguments);
+ if (stel->arguments != NULL)
+ output_params(stel->arguments, stel->out.params_left,
+ val_dict_count(stel->arguments),
+ &stel->out.need_delim);
+
+ current_column += fprintf(options.output, ") ");
+ tabto(options.align - 1);
+ fprintf(options.output, "= ");
+
+ output_one(&retval, stel->arguments);
+
+ if (own_retval)
+ value_destroy(&retval);
+
val_dict_destroy(stel->arguments);
+ free(stel->arguments);
+ fetch_arg_done(context);
if (opt_T) {
fprintf(options.output, " <%lu.%06d>",
diff --git a/output.h b/output.h
index 2db9d27..481a385 100644
--- a/output.h
+++ b/output.h
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
+#include "fetch.h"
#include "forward.h"
diff --git a/proc.c b/proc.c
index 7672ae8..cd8f6cd 100644
--- a/proc.c
+++ b/proc.c
@@ -291,11 +291,26 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
size_t i;
for (i = 0; i < retp->callstack_depth; ++i) {
+ struct fetch_context *ctx = retp->callstack[i].fetch_context;
+ if (ctx != NULL) {
+ struct fetch_context *nctx = fetch_arg_clone(p, ctx);
+ if (nctx == NULL) {
+ int j;
+ release1:
+ for (j = 0; j < i; ++j) {
+ nctx = retp->callstack[i].fetch_context;
+ fetch_arg_done(nctx);
+ retp->callstack[i].fetch_context = NULL;
+ }
+ goto fail2;
+ }
+ retp->callstack[i].fetch_context = nctx;
+ }
+
struct value_dict *args = retp->callstack[i].arguments;
if (args != NULL) {
fail3:
struct value_dict *nargs = malloc(sizeof(*nargs));
- fprintf(stderr, "{A:%p->%p}", args, nargs);
if (nargs == NULL
|| val_dict_clone(nargs, args) < 0) {
@@ -306,7 +321,12 @@ process_clone(struct Process *retp, struct Process *proc, pid_t pid)
free(nargs);
p->callstack[i].arguments = NULL;
}
- goto fail2;
+
+ /* Pretend that this round went well,
+ * so that release1 frees I-th
+ * fetch_context. */
+ ++i;
+ goto release1;
}
retp->callstack[i].arguments = nargs;
}
diff --git a/proc.h b/proc.h
index f62f5f9..f530e5d 100644
--- a/proc.h
+++ b/proc.h
@@ -64,6 +64,11 @@ enum process_state {
STATE_IGNORED /* ignore this process (it's a fork and no -f was used) */
};
+struct output_state {
+ size_t params_left;
+ int need_delim;
+};
+
struct callstack_element {
union {
int syscall;
@@ -72,7 +77,9 @@ struct callstack_element {
int is_syscall;
void * return_addr;
struct timeval time_spent;
+ struct fetch_context *fetch_context;
struct value_dict *arguments;
+ struct output_state out;
};
/* XXX We should get rid of this. */