aboutsummaryrefslogtreecommitdiff
path: root/prototype.h
blob: 824bfd92fd81a49f2eca8eeceb5808e7c86005fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/*
 * This file is part of ltrace.
 * Copyright (C) 2012, 2013 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 <stdbool.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 own_type : 1;
};

/* Initialize a named type INFO, which, if OWN_TYPE, is destroyed when
 * named_type_destroy is called.  */
void named_type_init(struct named_type *named,
		     struct arg_type_info *info, int own_type);

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;

	/* Reference count.  */
	unsigned refs;
};

/* Initialize PLIB.  */
void 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.  NAMED _pointer_ is copied to PLIB.  */
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 and IMPORTS
 * is true, 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, bool imports);

/* 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 and IMPORTS is
 * true, 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, bool imports);

/* 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;

	/* Fake module for implicit imports.  This is populated by all
	 * files coming from -F.  When -F is empty, it also contains
	 * either $HOME/.ltrace.conf, or /etc/ltrace.conf (whichever
	 * comes first).  */
	struct protolib imports;

	/* For tracking uses of cache during cache's own
	 * initialization.  */
	int bootstrap : 1;
};

/* Initialize CACHE.  Returns 0 on success or a negative value on
 * failure.  */
int protolib_cache_init(struct protolib_cache *cache,
			struct protolib *import);

/* Destroy CACHE.  */
void protolib_cache_destroy(struct protolib_cache *cache);

/* Get protolib corresponding to KEY from CACHE.  KEY would typically
 * be the soname of a library for which a protolib should be obtained.
 * If none has been loaded yet, load a new protolib, cache and return
 * it.  Returns NULL for failures.
 *
 * Protolibs are loaded from a config directory.  If -F contains
 * directory names, those are checked first.  Next, os_get_config_dirs
 * callback is used to get a list of directories to look into.  In the
 * first round, if ALLOW_PRIVATE, ltrace looks in user's private
 * directories.  If the config file wasn't found, the second round is
 * made through system directories.  In each directory, ltrace looks
 * and reads the file named KEY.conf.
 *
 * If the config file still wasn't found, an empty (but non-NULL)
 * protolib is provided instead.  That is augmented with the following
 * imports:
 *
 * - Legacy typedefs
 * - The IMPORT argument passed to protolib_cache_init, if non-NULL
 * - $HOME/.ltrace.conf if available
 * - @sysconfdir@/ltrace.conf if available
 * - Any configure _files_ passed in -F
 *
 * This function returns either the loaded protolib, or NULL when
 * there was an error.  */
struct protolib *protolib_cache_load(struct protolib_cache *cache,
				     const char *key, int own_key,
				     bool allow_private);

/* This is similar to protolib_cache_load, except that if a protolib
 * is not found NULL is returned instead of a default module.
 *
 * It returns 0 for success and a negative value for failure, and the
 * actual return value is passed via *RET.*/
int protolib_cache_maybe_load(struct protolib_cache *cache,
			      const char *key, int own_key,
			      bool allow_private,
			      struct protolib **ret);

/* This is similar to protolib_cache_load, but instead of looking for
 * the file to load in directories, the filename is given.  */
struct protolib *protolib_cache_file(struct protolib_cache *cache,
				     const char *filename, int own_filename);

/* This caches a default module.  This is what protolib_cache_load
 * calls if it fails to find the actual protolib.  Returns default
 * protolib or NULL if there was an error.  */
struct protolib *protolib_cache_default(struct protolib_cache *cache,
					const char *key, int own_key);

/* This is similar to protolib_cache_file, but the library to cache is
 * given in argument.  Returns 0 on success or a negative value on
 * failure.  PLIB is thereafter owned by CACHE.  */
int protolib_cache_protolib(struct protolib_cache *cache,
			    const char *filename, int own_filename,
			    struct protolib *plib);

/* Single global prototype cache.
 *
 * XXX Eventually each ABI should have its own cache.  The idea is
 * that there's one per-ABI config file that all others use for
 * elementary typedefs (long, char, size_t).  Ltrace then only deals
 * in fixed-width integral types (and pointers etc.).  */
extern struct protolib_cache g_protocache;

void init_global_config(void);

#endif /* _PROTOTYPE_H_ */