aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2012-12-17 04:37:57 +0100
committerPetr Machata <pmachata@redhat.com>2013-03-08 22:55:25 +0100
commitebc56a70e20ca0b3fc49c0eb5fc83e56c5e1fa5b (patch)
treec88cfaa4857b798b09376d181f045617d42fe81b
parentdaefa4a03e16b56e54c6116cec44153aff9dd3b7 (diff)
downloadltrace-ebc56a70e20ca0b3fc49c0eb5fc83e56c5e1fa5b.tar.gz
Introduce a module for managing prototypes and prototype libraries
This is to be used, eventually, for keeping one prototype library per DSO. Right now we only have one prototype library, like before: g_prototypes. Typedef submodule is not yet used, only prototypes are stored in the protolib as of now. The change in Makefile.am is actually an inclusion of prototype.{c,h} followed by a rewrap of name lists.
-rw-r--r--Makefile.am77
-rw-r--r--common.h10
-rw-r--r--output.c99
-rw-r--r--prototype.c263
-rw-r--r--prototype.h155
-rw-r--r--read_config_file.c137
6 files changed, 540 insertions, 201 deletions
diff --git a/Makefile.am b/Makefile.am
index c3356de..db34382 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,36 +32,12 @@ AM_CPPFLAGS += \
noinst_LTLIBRARIES = \
libltrace.la
-libltrace_la_SOURCES = \
- breakpoints.c \
- debug.c \
- demangle.c \
- dict.c \
- ltrace-elf.c \
- execute_program.c \
- handle_event.c \
- libltrace.c \
- options.c \
- output.c \
- proc.c \
- read_config_file.c \
- summary.c \
- library.c \
- filter.c \
- glob.c \
- type.c \
- value.c \
- value_dict.c \
- expr.c \
- fetch.c \
- vect.c \
- param.c \
- printf.c \
- zero.c \
- lens.c \
- lens_default.c \
- lens_enum.c \
- memstream.c
+libltrace_la_SOURCES = breakpoints.c debug.c demangle.c dict.c \
+ ltrace-elf.c execute_program.c handle_event.c libltrace.c \
+ options.c output.c proc.c read_config_file.c summary.c \
+ library.c filter.c glob.c type.c value.c value_dict.c expr.c \
+ fetch.c vect.c param.c printf.c zero.c lens.c lens_default.c \
+ lens_enum.c memstream.c prototype.c
libltrace_la_LIBADD = \
$(libelf_LIBS) \
@@ -71,7 +47,6 @@ libltrace_la_LIBADD = \
$(libunwind_LIBS) \
sysdeps/libos.la
-
bin_PROGRAMS = \
ltrace
@@ -81,40 +56,12 @@ ltrace_SOURCES = \
ltrace_LDADD = \
libltrace.la
-
-noinst_HEADERS = \
- backend.h \
- breakpoint.h \
- common.h \
- debug.h \
- defs.h \
- demangle.h \
- dict.h \
- forward.h \
- ltrace-elf.h \
- ltrace.h \
- options.h \
- output.h \
- proc.h \
- read_config_file.h \
- library.h \
- filter.h \
- glob.h \
- vect.h \
- type.h \
- value.h \
- value_dict.h \
- callback.h \
- expr.h \
- fetch.h \
- vect.h \
- param.h \
- printf.h \
- zero.h \
- lens.h \
- lens_default.h \
- lens_enum.h \
- memstream.h
+noinst_HEADERS = backend.h breakpoint.h common.h debug.h defs.h \
+ demangle.h dict.h forward.h ltrace-elf.h ltrace.h options.h \
+ output.h proc.h read_config_file.h library.h filter.h glob.h \
+ vect.h type.h value.h value_dict.h callback.h expr.h fetch.h \
+ vect.h param.h printf.h zero.h lens.h lens_default.h \
+ lens_enum.h memstream.h prototype.h
dist_man1_MANS = ltrace.1
dist_man5_MANS = ltrace.conf.5
diff --git a/common.h b/common.h
index 67ee39b..637f041 100644
--- a/common.h
+++ b/common.h
@@ -43,16 +43,6 @@ extern char * command;
extern int exiting; /* =1 if we have to exit ASAP */
-struct prototype {
- const char *name;
- struct param *params;
- struct arg_type_info *return_info;
- int own_return_info;
- size_t num_params;
- struct prototype *next;
-};
-
-extern struct prototype *list_of_functions;
extern char *PLTs_initialized_by_here;
#include "options.h"
diff --git a/output.c b/output.c
index bde93c7..b0ee0ae 100644
--- a/output.c
+++ b/output.c
@@ -34,7 +34,7 @@
#include <errno.h>
#include <assert.h>
-#include "common.h"
+#include "output.h"
#include "demangle.h"
#include "fetch.h"
#include "lens_default.h"
@@ -43,6 +43,7 @@
#include "options.h"
#include "param.h"
#include "proc.h"
+#include "prototype.h"
#include "type.h"
#include "value.h"
#include "value_dict.h"
@@ -152,58 +153,41 @@ get_unknown_type(void)
static struct prototype *
build_default_prototype(void)
{
- struct prototype *ret = malloc(sizeof(*ret));
- size_t i = 0;
- if (ret == NULL)
- goto err;
- memset(ret, 0, sizeof(*ret));
+ static struct prototype *ret = NULL;
+ if (ret != NULL)
+ return ret;
- struct arg_type_info *unknown_type = get_unknown_type();
+ static struct prototype proto;
+ prototype_init(&proto);
- ret->return_info = unknown_type;
- ret->own_return_info = 0;
+ struct arg_type_info *unknown_type = get_unknown_type();
+ assert(unknown_type != NULL);
+ proto.return_info = unknown_type;
+ proto.own_return_info = 0;
- ret->num_params = 4;
- ret->params = malloc(sizeof(*ret->params) * ret->num_params);
- if (ret->params == NULL)
- goto err;
+ struct param unknown_param;
+ param_init_type(&unknown_param, unknown_type, 0);
- for (i = 0; i < ret->num_params; ++i)
- param_init_type(&ret->params[i], unknown_type, 0);
+ size_t i;
+ for (i = 0; i < 4; ++i)
+ if (prototype_push_param(&proto, &unknown_param) < 0) {
+ report_global_error("build_default_prototype: %s",
+ strerror(errno));
+ prototype_destroy(&proto);
+ return NULL;
+ }
+ ret = &proto;
return ret;
-
-err:
- report_global_error("malloc: %s", strerror(errno));
- if (ret->params != NULL) {
- while (i-- > 0)
- param_destroy(&ret->params[i]);
- free(ret->params);
- }
-
- free(ret);
-
- return NULL;
}
static struct prototype *
name2func(char const *name)
{
- struct prototype *tmp;
- const char *str1, *str2;
-
- for (tmp = list_of_functions; tmp != NULL; tmp = tmp->next) {
- str1 = tmp->name;
- str2 = name;
- if (!strcmp(str1, str2))
- return tmp;
- }
-
- static struct prototype *def = NULL;
- if (def == NULL)
- def = build_default_prototype();
-
- return def;
+ struct prototype *p = protolib_lookup_prototype(&g_prototypes, name);
+ if (p != NULL)
+ return p;
+ return build_default_prototype();
}
void
@@ -373,17 +357,38 @@ fetch_one_param(enum tof type, struct process *proc,
abort();
}
+struct fetch_one_param_data
+{
+ struct process *proc;
+ struct fetch_context *context;
+ struct value_dict *arguments;
+ ssize_t *params_leftp;
+ enum tof tof;
+};
+
+static enum callback_status
+fetch_one_param_cb(struct prototype *proto, struct param *param, void *data)
+{
+ struct fetch_one_param_data *cb_data = data;
+ if (fetch_one_param(cb_data->tof, cb_data->proc, cb_data->context,
+ cb_data->arguments, param,
+ cb_data->params_leftp) < 0)
+ return CBS_STOP;
+ else
+ return CBS_CONT;
+}
+
static int
fetch_params(enum tof type, struct process *proc,
struct fetch_context *context,
struct value_dict *arguments, struct prototype *func,
ssize_t *params_leftp)
{
- size_t i;
- for (i = 0; i < func->num_params; ++i)
- if (fetch_one_param(type, proc, context, arguments,
- &func->params[i], params_leftp) < 0)
- return -1;
+ struct fetch_one_param_data cb_data
+ = { proc, context, arguments, params_leftp, type };
+ if (prototype_each_param(func, NULL,
+ &fetch_one_param_cb, &cb_data) != NULL)
+ return -1;
/* Implicit stop at the end of parameter list. */
fetch_param_stop(arguments, params_leftp);
diff --git a/prototype.c b/prototype.c
new file mode 100644
index 0000000..0575dd3
--- /dev/null
+++ b/prototype.c
@@ -0,0 +1,263 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 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 "prototype.h"
+#include "callback.h"
+#include "param.h"
+#include "type.h"
+
+struct protolib g_prototypes;
+
+void
+prototype_init(struct prototype *proto)
+{
+ VECT_INIT(&proto->params, struct param);
+
+ proto->return_info = NULL;
+ proto->own_return_info = 0;
+}
+
+static void
+param_destroy_cb(struct param *param, void *data)
+{
+ param_destroy(param);
+}
+
+void
+prototype_destroy(struct prototype *proto)
+{
+ if (proto == NULL)
+ return;
+ if (proto->own_return_info) {
+ type_destroy(proto->return_info);
+ free(proto->return_info);
+ }
+
+ VECT_DESTROY(&proto->params, struct param, &param_destroy_cb, NULL);
+}
+
+int
+prototype_push_param(struct prototype *proto, struct param *param)
+{
+ return VECT_PUSHBACK(&proto->params, param);
+}
+
+size_t
+prototype_num_params(struct prototype *proto)
+{
+ return vect_size(&proto->params);
+}
+
+void
+prototype_destroy_nth_param(struct prototype *proto, size_t n)
+{
+ assert(n < prototype_num_params(proto));
+ VECT_ERASE(&proto->params, struct param, n, n+1,
+ &param_destroy_cb, NULL);
+}
+
+struct param *
+prototype_get_nth_param(struct prototype *proto, size_t n)
+{
+ assert(n < prototype_num_params(proto));
+ return VECT_ELEMENT(&proto->params, struct param, n);
+}
+
+struct each_param_data {
+ struct prototype *proto;
+ enum callback_status (*cb)(struct prototype *, struct param *, void *);
+ void *data;
+};
+
+static enum callback_status
+each_param_cb(struct param *param, void *data)
+{
+ struct each_param_data *cb_data = data;
+ return (cb_data->cb)(cb_data->proto, param, cb_data->data);
+}
+
+struct param *
+prototype_each_param(struct prototype *proto, struct param *start_after,
+ enum callback_status (*cb)(struct prototype *,
+ struct param *, void *),
+ void *data)
+{
+ struct each_param_data cb_data = { proto, cb, data };
+ return VECT_EACH(&proto->params, struct param, start_after,
+ &each_param_cb, &cb_data);
+}
+
+void
+named_type_destroy(struct named_type *named)
+{
+ if (named->owned) {
+ type_destroy(named->info);
+ free(named->info);
+ }
+}
+
+int
+protolib_init(struct protolib *plib)
+{
+ plib->prototypes = dict_init(&dict_key2hash_string,
+ &dict_key_cmp_string);
+ if (plib->prototypes == NULL)
+ return -1;
+
+ plib->named_types = dict_init(&dict_key2hash_string,
+ &dict_key_cmp_string);
+ if (plib->named_types == NULL) {
+ dict_clear(plib->prototypes);
+ return -1;
+ }
+
+ VECT_INIT(&plib->imports, struct protolib *);
+ return 0;
+}
+
+static void
+prototype_entry_destroy(void *key, void *val, void *data)
+{
+ char *name = key;
+ struct prototype *proto = val;
+ free(name);
+ prototype_destroy(proto);
+}
+
+static void
+named_type_entry_destroy(void *key, void *val, void *data)
+{
+ char *name = key;
+ struct named_type *named = val;
+ free(name);
+ named_type_destroy(named);
+}
+
+void
+protolib_destroy(struct protolib *plib)
+{
+ VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
+
+ dict_apply_to_all(plib->prototypes, prototype_entry_destroy, NULL);
+ dict_clear(plib->prototypes);
+
+ dict_apply_to_all(plib->named_types, named_type_entry_destroy, NULL);
+ dict_clear(plib->named_types);
+}
+
+static struct protolib **
+each_import(struct protolib *plib, struct protolib **start_after,
+ enum callback_status (*cb)(struct protolib **, void *), void *data)
+{
+ return VECT_EACH(&plib->imports, struct protolib *,
+ start_after, cb, data);
+}
+
+static enum callback_status
+is_or_imports(struct protolib **plibp, void *data)
+{
+ struct protolib *import = data;
+ if (*plibp == import
+ || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
+ return CBS_STOP;
+ else
+ return CBS_CONT;
+}
+
+int
+protolib_add_import(struct protolib *plib, struct protolib *import)
+{
+ if (is_or_imports(&plib, import) == CBS_STOP)
+ return -2;
+
+ return VECT_PUSHBACK(&plib->imports, import) < 0 ? -1 : 0;
+}
+
+static int
+enroll(struct dict *dict, const char *name, int own_name, void *value)
+{
+ assert(name != NULL);
+
+ if (!own_name) {
+ name = strdup(name);
+ if (name == NULL)
+ return -1;
+ }
+
+ if (dict_enter(dict, (void *)name, value) < 0) {
+ if (own_name)
+ free((void *)name);
+ return -1;
+ }
+ return 0;
+}
+
+int
+protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
+ struct prototype *proto)
+{
+ return enroll(plib->prototypes, name, own_name, proto);
+}
+
+int
+protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
+ struct named_type *named)
+{
+ return enroll(plib->named_types, name, own_name, named);
+}
+
+struct lookup {
+ const char *name;
+ void *result;
+};
+
+static enum callback_status
+lookup_prototype_rec(struct protolib **plibp, void *data)
+{
+ struct lookup *lookup = data;
+
+ lookup->result = dict_find_entry((*plibp)->prototypes, lookup->name);
+ if (lookup->result != NULL)
+ return CBS_STOP;
+
+ if (each_import(*plibp, NULL, &lookup_prototype_rec, lookup) != NULL) {
+ assert(lookup->result != NULL);
+ return CBS_STOP;
+ }
+
+ return CBS_CONT;
+}
+
+struct prototype *
+protolib_lookup_prototype(struct protolib *plib, const char *name)
+{
+ struct lookup lookup = { name, NULL };
+ if (lookup_prototype_rec(&plib, &lookup) == CBS_STOP)
+ assert(lookup.result != NULL);
+ else
+ assert(lookup.result == NULL);
+ return lookup.result;
+}
+
+struct named_type *
+protolib_lookup_type(struct protolib *plib, const char *name);
diff --git a/prototype.h b/prototype.h
new file mode 100644
index 0000000..7a75e2f
--- /dev/null
+++ b/prototype.h
@@ -0,0 +1,155 @@
+/*
+ * This file is part of ltrace.
+ * Copyright (C) 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 _PROTOTYPE_H_
+#define _PROTOTYPE_H_
+
+#include "forward.h"
+#include "dict.h"
+#include "vect.h"
+
+/* Function prototype. */
+struct prototype {
+ /* Vector of struct param. */
+ struct vect params;
+
+ struct arg_type_info *return_info;
+ int own_return_info : 1;
+};
+
+/* Initialize a prototype PROTO. The name will be NAME, and the
+ * corresponding string will be owned and freed on destroy if
+ * OWN_NAME. */
+void prototype_init(struct prototype *proto);
+
+/* Destroy PROTO (but don't free the memory block pointed-to by
+ * PROTO). */
+void prototype_destroy(struct prototype *proto);
+
+/* Add new parameter PARAM to PROTO. The structure contents are
+ * copied and PARAM pointer itself is not owned by PROTO. */
+int prototype_push_param(struct prototype *proto, struct param *param);
+
+/* Return number of parameters of prototype. */
+size_t prototype_num_params(struct prototype *proto);
+
+/* Destroy N-th parameter from PROTO. N shall be smaller than the
+ * number of parameters. */
+void prototype_destroy_nth_param(struct prototype *proto, size_t n);
+
+/* Get N-th parameter of PROTO. N shall be smaller than the number of
+ * parameters. */
+struct param *prototype_get_nth_param(struct prototype *proto, size_t n);
+
+/* Iterate through the parameters of PROTO. See callback.h for notes
+ * on iteration interfaces. */
+struct param *prototype_each_param
+ (struct prototype *proto, struct param *start_after,
+ enum callback_status (*cb)(struct prototype *, struct param *, void *),
+ void *data);
+
+/* For storing type aliases. */
+struct named_type {
+ struct arg_type_info *info;
+ int forward : 1;
+ int owned : 1;
+};
+
+void named_type_destroy(struct named_type *named);
+
+/* One prototype library. */
+struct protolib {
+ /* Other libraries to look through if the definition is not
+ * found here. Note that due to the way imports are stored,
+ * there is no way to distinguish where exactly (at which
+ * place of the config file) the import was made. */
+ struct vect imports;
+
+ /* Dictionary of name->struct prototype. */
+ struct dict *prototypes;
+
+ /* Dictionary of name->struct named_type. */
+ struct dict *named_types;
+};
+
+/* Initialize PLIB. Returns 0 on success or a negative value on
+ * failure. */
+int protolib_init(struct protolib *plib);
+
+/* Destroy PLIB. */
+void protolib_destroy(struct protolib *plib);
+
+/* Push IMPORT to PLIB. Returns 0 on success or a negative value on
+ * failure. In particular, -2 is returned if mutual import is
+ * detected. */
+int protolib_add_import(struct protolib *plib, struct protolib *import);
+
+/* Add a prototype PROTO to PLIB. Returns 0 on success or a negative
+ * value on failure. NAME is owned and released on PLIB destruction
+ * if OWN_NAME. */
+int protolib_add_prototype(struct protolib *plib,
+ const char *name, int own_name,
+ struct prototype *proto);
+
+/* Add a named type NAMED to PLIB. Returns 0 on success or a negative
+ * value on failure. NAME is owned and released on PLIB destruction
+ * if OWN_NAME. */
+int protolib_add_named_type(struct protolib *plib,
+ const char *name, int own_name,
+ struct named_type *named);
+
+/* Lookup prototype named NAME in PLIB. If none is found, look
+ * recursively in each of the imports. Returns the corresponding
+ * prototype, or NULL if none was found. */
+struct prototype *protolib_lookup_prototype(struct protolib *plib,
+ const char *name);
+
+/* Add a named type NAMED to PLIB. Returns 0 on success or a negative
+ * value on failure. */
+int protolib_add_type(struct protolib *plib, struct named_type *named);
+
+/* Lookup type named NAME in PLIB. If none is found, look recursively
+ * in each of the imports. Returns the corresponding type, or NULL if
+ * none was found. */
+struct named_type *protolib_lookup_type(struct protolib *plib,
+ const char *name);
+
+/* A cache of prototype libraries. Can load prototype libraries on
+ * demand.
+ *
+ * XXX ltrace should open one config per ABI, which maps long, int,
+ * etc. to uint32_t etc. It would also map char to either of
+ * {u,}int8_t. Other protolibs would have this as implicit import.
+ * That would mean that the cache needs ABI tagging--each ABI should
+ * have a separate prototype cache, because the types will potentially
+ * differ between the ABI's. protolib cache would then naturally be
+ * stored in the ABI object, when this is introduced. */
+struct protolib_cache {
+ /* Dictionary of filename->protolib. */
+ struct dict *protolibs;
+};
+
+
+/* Single global prototype library.
+ * XXX Eventually each struct library should have its own prototype
+ * library, so that there is one prototype library per DSO. */
+extern struct protolib g_prototypes;
+
+#endif /* _PROTOTYPE_H_ */
diff --git a/read_config_file.c b/read_config_file.c
index f478656..52d23ea 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -39,6 +39,7 @@
#include "expr.h"
#include "param.h"
#include "printf.h"
+#include "prototype.h"
#include "zero.h"
#include "type.h"
#include "lens.h"
@@ -508,21 +509,6 @@ parse_typedef(char **str)
free(this_td);
}
-static void
-destroy_fun(struct prototype *fun)
-{
- size_t i;
- if (fun == NULL)
- return;
- if (fun->own_return_info) {
- type_destroy(fun->return_info);
- free(fun->return_info);
- }
- for (i = 0; i < fun->num_params; ++i)
- param_destroy(&fun->params[i]);
- free(fun->params);
-}
-
/* Syntax: struct ( type,type,type,... ) */
static int
parse_struct(char **str, struct arg_type_info *info,
@@ -1088,23 +1074,6 @@ parse_lens(char **str, struct param **extra_param, size_t param_num, int *ownp,
}
static int
-add_param(struct prototype *fun, size_t *allocdp)
-{
- size_t allocd = *allocdp;
- /* XXX +1 is for the extra_param handling hack. */
- if ((fun->num_params + 1) >= allocd) {
- allocd = allocd > 0 ? 2 * allocd : 8;
- void *na = realloc(fun->params, sizeof(*fun->params) * allocd);
- if (na == NULL)
- return -1;
-
- fun->params = na;
- *allocdp = allocd;
- }
- return 0;
-}
-
-static int
param_is_void(struct param *param)
{
return param->flavor == PARAM_FLAVOR_TYPE
@@ -1124,8 +1093,24 @@ get_hidden_int(void)
return info;
}
+static enum callback_status
+void_to_hidden_int(struct prototype *proto, struct param *param, void *data)
+{
+ if (param_is_void(param)) {
+ report_warning(filename, line_no,
+ "void parameter assumed to be 'hide(int)'");
+
+ static struct arg_type_info *type = NULL;
+ if (type == NULL)
+ type = get_hidden_int();
+ param_destroy(param);
+ param_init_type(param, type, 0);
+ }
+ return CBS_CONT;
+}
+
static int
-process_line(char *buf)
+process_line(char *buf, struct protolib *plib)
{
char *str = buf;
char *tmp;
@@ -1145,17 +1130,20 @@ process_line(char *buf)
struct prototype *fun = calloc(1, sizeof(*fun));
if (fun == NULL) {
- report_error(filename, line_no,
- "alloc function: %s", strerror(errno));
+ report_error(filename, line_no, "%s", strerror(errno));
return -1;
}
+ prototype_init(fun);
+ char *proto_name = NULL;
int own;
fun->return_info = parse_lens(&str, NULL, 0, &own, NULL);
if (fun->return_info == NULL) {
err:
debug(3, " Skipping line %d", line_no);
- destroy_fun(fun);
+ prototype_destroy(fun);
+ free(fun);
+ free(proto_name);
return -1;
}
fun->own_return_info = own;
@@ -1168,13 +1156,18 @@ process_line(char *buf)
goto err;
}
*tmp = '\0';
- fun->name = strdup(str);
+
+ proto_name = strdup(str);
+ if (proto_name == NULL) {
+ oom:
+ report_error(filename, line_no, "%s", strerror(errno));
+ goto err;
+ }
+
str = tmp + 1;
- debug(3, " name = %s", fun->name);
+ debug(3, " name = %s", proto_name);
- size_t allocd = 0;
struct param *extra_param = NULL;
-
int have_stop = 0;
while (1) {
@@ -1184,33 +1177,29 @@ process_line(char *buf)
if (str[0] == '+') {
if (have_stop == 0) {
- if (add_param(fun, &allocd) < 0)
- goto add_err;
- param_init_stop
- (&fun->params[fun->num_params++]);
+ struct param param;
+ param_init_stop(&param);
+ if (prototype_push_param(fun, &param) < 0)
+ goto oom;
have_stop = 1;
}
str++;
}
- if (add_param(fun, &allocd) < 0) {
- add_err:
- report_error(filename, line_no, "(re)alloc params: %s",
- strerror(errno));
- goto err;
- }
-
int own;
+ size_t param_num = prototype_num_params(fun) - have_stop;
struct arg_type_info *type
- = parse_lens(&str, &extra_param,
- fun->num_params - have_stop, &own, NULL);
+ = parse_lens(&str, &extra_param, param_num, &own, NULL);
if (type == NULL) {
report_error(filename, line_no,
"unknown argument type");
goto err;
}
- param_init_type(&fun->params[fun->num_params++], type, own);
+ struct param param;
+ param_init_type(&param, type, own);
+ if (prototype_push_param(fun, &param) < 0)
+ goto oom;
eat_spaces(&str);
if (*str == ',') {
@@ -1238,7 +1227,8 @@ process_line(char *buf)
* latter is conservative, we can drop the argument
* altogether, instead of fetching and then not showing it,
* without breaking any observable behavior. */
- if (fun->num_params == 1 && param_is_void(&fun->params[0])) {
+ if (prototype_num_params(fun) == 1
+ && param_is_void(prototype_get_nth_param(fun, 0))) {
if (0)
/* Don't show this warning. Pre-0.7.0
* ltrace.conf often used this idiom. This
@@ -1246,35 +1236,21 @@ process_line(char *buf)
* extant uses are likely gone. */
report_warning(filename, line_no,
"sole void parameter ignored");
- param_destroy(&fun->params[0]);
- fun->num_params = 0;
+ prototype_destroy_nth_param(fun, 0);
} else {
- size_t i;
- for (i = 0; i < fun->num_params; ++i) {
- if (param_is_void(&fun->params[i])) {
- report_warning
- (filename, line_no,
- "void parameter assumed to be "
- "'hide(int)'");
-
- static struct arg_type_info *type = NULL;
- if (type == NULL)
- type = get_hidden_int();
- param_destroy(&fun->params[i]);
- param_init_type(&fun->params[i], type, 0);
- }
- }
+ prototype_each_param(fun, NULL, void_to_hidden_int, NULL);
}
if (extra_param != NULL) {
- assert(fun->num_params < allocd);
- memcpy(&fun->params[fun->num_params++], extra_param,
- sizeof(*extra_param));
+ prototype_push_param(fun, extra_param);
free(extra_param);
}
- fun->next = list_of_functions;
- list_of_functions = fun;
+ if (protolib_add_prototype(plib, proto_name, 1, fun) < 0) {
+ report_error(filename, line_no, "couldn't add prototype: %s",
+ strerror(errno));
+ goto err;
+ }
return 0;
}
@@ -1282,9 +1258,11 @@ process_line(char *buf)
void
init_global_config(void)
{
+ protolib_init(&g_prototypes);
+
struct arg_type_info *info = malloc(2 * sizeof(*info));
if (info == NULL) {
- fprintf(stderr, "Couldn't init global config: %s\n",
+ fprintf(stderr, "Couldn't allocate memory for aliases: %s.\n",
strerror(errno));
exit(1);
}
@@ -1301,6 +1279,7 @@ init_global_config(void)
void
destroy_global_config(void)
{
+ protolib_destroy(&g_prototypes);
}
void
@@ -1320,7 +1299,7 @@ read_config_file(char *file)
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, stream) >= 0)
- process_line(line);
+ process_line(line, &g_prototypes);
free(line);
fclose(stream);
}