prototype.c revision f9f3df4c9e232dc06b769daa5edf489675c5cdfc
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012 Petr Machata, Red Hat Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21#include <alloca.h>
22#include <errno.h>
23#include <stdlib.h>
24#include <string.h>
25#include <stdio.h>
26
27#include "callback.h"
28#include "param.h"
29#include "prototype.h"
30#include "type.h"
31#include "options.h"
32#include "read_config_file.h"
33#include "backend.h"
34
35struct protolib_cache g_protocache;
36static struct protolib legacy_typedefs;
37
38void
39prototype_init(struct prototype *proto)
40{
41	VECT_INIT(&proto->params, struct param);
42
43	proto->return_info = NULL;
44	proto->own_return_info = 0;
45}
46
47static void
48param_destroy_cb(struct param *param, void *data)
49{
50	param_destroy(param);
51}
52
53void
54prototype_destroy(struct prototype *proto)
55{
56	if (proto == NULL)
57		return;
58	if (proto->own_return_info) {
59		type_destroy(proto->return_info);
60		free(proto->return_info);
61	}
62
63	VECT_DESTROY(&proto->params, struct param, &param_destroy_cb, NULL);
64}
65
66int
67prototype_push_param(struct prototype *proto, struct param *param)
68{
69	return VECT_PUSHBACK(&proto->params, param);
70}
71
72size_t
73prototype_num_params(struct prototype *proto)
74{
75	return vect_size(&proto->params);
76}
77
78void
79prototype_destroy_nth_param(struct prototype *proto, size_t n)
80{
81	assert(n < prototype_num_params(proto));
82	VECT_ERASE(&proto->params, struct param, n, n+1,
83		   &param_destroy_cb, NULL);
84}
85
86struct param *
87prototype_get_nth_param(struct prototype *proto, size_t n)
88{
89	assert(n < prototype_num_params(proto));
90	return VECT_ELEMENT(&proto->params, struct param, n);
91}
92
93struct each_param_data {
94	struct prototype *proto;
95	enum callback_status (*cb)(struct prototype *, struct param *, void *);
96	void *data;
97};
98
99static enum callback_status
100each_param_cb(struct param *param, void *data)
101{
102	struct each_param_data *cb_data = data;
103	return (cb_data->cb)(cb_data->proto, param, cb_data->data);
104}
105
106struct param *
107prototype_each_param(struct prototype *proto, struct param *start_after,
108		     enum callback_status (*cb)(struct prototype *,
109						struct param *, void *),
110		     void *data)
111{
112	struct each_param_data cb_data = { proto, cb, data };
113	return VECT_EACH(&proto->params, struct param, start_after,
114			 &each_param_cb, &cb_data);
115}
116
117void
118named_type_init(struct named_type *named,
119		struct arg_type_info *info, int own_type)
120{
121	named->info = info;
122	named->own_type = own_type;
123	named->forward = 0;
124}
125
126void
127named_type_destroy(struct named_type *named)
128{
129	if (named->own_type) {
130		type_destroy(named->info);
131		free(named->info);
132	}
133}
134
135void
136protolib_init(struct protolib *plib)
137{
138	DICT_INIT(&plib->prototypes, const char *, struct prototype,
139		  dict_hash_string, dict_eq_string, NULL);
140
141	DICT_INIT(&plib->named_types, const char *, struct named_type,
142		  dict_hash_string, dict_eq_string, NULL);
143
144	VECT_INIT(&plib->imports, struct protolib *);
145
146	plib->refs = 0;
147}
148
149static void
150destroy_prototype_cb(struct prototype *proto, void *data)
151{
152	prototype_destroy(proto);
153}
154
155static void
156destroy_named_type_cb(struct named_type *named, void *data)
157{
158	named_type_destroy(named);
159}
160
161void
162protolib_destroy(struct protolib *plib)
163{
164	assert(plib->refs == 0);
165
166	VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
167
168	DICT_DESTROY(&plib->prototypes, const char *, struct prototype,
169		     dict_dtor_string, destroy_prototype_cb, NULL);
170
171	DICT_DESTROY(&plib->named_types, const char *, struct named_type,
172		     dict_dtor_string, destroy_named_type_cb, NULL);
173}
174
175static struct protolib **
176each_import(struct protolib *plib, struct protolib **start_after,
177	    enum callback_status (*cb)(struct protolib **, void *), void *data)
178{
179	assert(plib != NULL);
180	return VECT_EACH(&plib->imports, struct protolib *,
181			 start_after, cb, data);
182}
183
184static enum callback_status
185is_or_imports(struct protolib **plibp, void *data)
186{
187	assert(plibp != NULL);
188	assert(*plibp != NULL);
189	struct protolib *import = data;
190	if (*plibp == import
191	    || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
192		return CBS_STOP;
193	else
194		return CBS_CONT;
195}
196
197int
198protolib_add_import(struct protolib *plib, struct protolib *import)
199{
200	assert(plib != NULL);
201	assert(import != NULL);
202	if (is_or_imports(&import, plib) == CBS_STOP) {
203		fprintf(stderr, "Recursive import rejected.\n");
204		return -2;
205	}
206
207	return VECT_PUSHBACK(&plib->imports, &import) < 0 ? -1 : 0;
208}
209
210static int
211clone_if_not_own(const char **strp, int own)
212{
213	assert(*strp != NULL);
214
215	if (!own) {
216		*strp = strdup(*strp);
217		if (*strp == NULL)
218			return -1;
219	}
220
221	return 0;
222}
223
224static int
225bailout(const char *name, int own)
226{
227	int save_errno = errno;
228	if (own)
229		free((char *)name);
230	errno = save_errno;
231	return -1;
232}
233
234int
235protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
236		       struct prototype *proto)
237{
238	assert(plib != NULL);
239	if (clone_if_not_own(&name, own_name) < 0)
240		return -1;
241	if (DICT_INSERT(&plib->prototypes, &name, proto) < 0)
242		return bailout(name, own_name);
243	return 0;
244}
245
246int
247protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
248			struct named_type *named)
249{
250	assert(plib != NULL);
251	if (clone_if_not_own(&name, own_name) < 0)
252		return -1;
253	if (DICT_INSERT(&plib->named_types, &name, named) < 0)
254		return bailout(name, own_name);
255	return 0;
256}
257
258struct lookup {
259	const char *name;
260	void *result;
261	struct dict *(*getter)(struct protolib *plib);
262};
263
264static struct dict *
265get_prototypes(struct protolib *plib)
266{
267	assert(plib != NULL);
268	return &plib->prototypes;
269}
270
271static struct dict *
272get_named_types(struct protolib *plib)
273{
274	assert(plib != NULL);
275	return &plib->named_types;
276}
277
278static enum callback_status
279protolib_lookup_rec(struct protolib **plibp, void *data)
280{
281	assert(plibp != NULL);
282	assert(*plibp != NULL);
283	struct lookup *lookup = data;
284	struct dict *dict = (*lookup->getter)(*plibp);
285
286	lookup->result = dict_find(dict, &lookup->name);
287	if (lookup->result != NULL)
288		return CBS_STOP;
289
290	if (each_import(*plibp, NULL, &protolib_lookup_rec, lookup) != NULL) {
291		assert(lookup->result != NULL);
292		return CBS_STOP;
293	}
294
295	return CBS_CONT;
296}
297
298static void *
299protolib_lookup(struct protolib *plib, const char *name,
300		struct dict *(*getter)(struct protolib *))
301{
302	assert(plib != NULL);
303	struct lookup lookup = { name, NULL, getter };
304	if (protolib_lookup_rec(&plib, &lookup) == CBS_STOP)
305		assert(lookup.result != NULL);
306	else
307		assert(lookup.result == NULL);
308	return lookup.result;
309}
310
311struct prototype *
312protolib_lookup_prototype(struct protolib *plib, const char *name)
313{
314	assert(plib != NULL);
315	return protolib_lookup(plib, name, &get_prototypes);
316}
317
318struct named_type *
319protolib_lookup_type(struct protolib *plib, const char *name)
320{
321	assert(plib != NULL);
322	return protolib_lookup(plib, name, &get_named_types);
323}
324
325static void
326destroy_protolib_cb(struct protolib **plibp, void *data)
327{
328	assert(plibp != NULL);
329	assert(*plibp != NULL);
330
331	if (--(*plibp)->refs == 0) {
332		protolib_destroy(*plibp);
333		free(*plibp);
334	}
335}
336
337void
338protolib_cache_destroy(struct protolib_cache *cache)
339{
340	DICT_DESTROY(&cache->protolibs, const char *, struct protolib *,
341		     dict_dtor_string, destroy_protolib_cb, NULL);
342}
343
344struct load_config_data {
345	struct protolib_cache *self;
346	const char *key;
347	struct protolib *result;
348};
349
350static struct protolib *
351consider_config_dir(struct protolib_cache *cache,
352		    const char *path, const char *key)
353{
354	size_t len = sizeof ".conf";
355	char slash[2] = {'/'};
356	char *buf = alloca(strlen(path) + 1 + strlen(key) + len);
357	strcpy(stpcpy(stpcpy(stpcpy(buf, path), slash), key), ".conf");
358
359	return protolib_cache_file(cache, buf, 0);
360}
361
362static enum callback_status
363consider_confdir_cb(struct opt_F_t *entry, void *d)
364{
365	if (opt_F_get_kind(entry) != OPT_F_DIR)
366		return CBS_CONT;
367	struct load_config_data *data = d;
368
369	data->result = consider_config_dir(data->self,
370					   entry->pathname, data->key);
371	return data->result != NULL ? CBS_STOP : CBS_CONT;
372}
373
374static int
375load_dash_F_dirs(struct protolib_cache *cache,
376		 const char *key, struct protolib **retp)
377{
378	struct load_config_data data = {cache, key};
379
380	if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
381		      consider_confdir_cb, &data) == NULL)
382		/* Not found.  That's fine.  */
383		return 0;
384
385	if (data.result == NULL)
386		/* There were errors.  */
387		return -1;
388
389	*retp = data.result;
390	return 0;
391}
392
393static int
394load_config(struct protolib_cache *cache,
395	    const char *key, int private, struct protolib **retp)
396{
397	const char **dirs = NULL;
398	if (os_get_config_dirs(private, &dirs) < 0
399	    || dirs == NULL)
400		return -1;
401
402	for (; *dirs != NULL; ++dirs) {
403		struct protolib *plib = consider_config_dir(cache, *dirs, key);
404		if (plib != NULL) {
405			*retp = plib;
406			break;
407		}
408	}
409
410	return 0;
411}
412
413static int
414add_ltrace_conf(struct protolib_cache *cache)
415{
416	/* Look into private config directories for .ltrace.conf and
417	 * into system config directories for ltrace.conf.  If it's
418	 * found, add it to implicit import module.  */
419	struct protolib *plib = NULL;
420	const char *home = NULL;
421	if (os_get_ltrace_conf_filename(&home) < 0
422	    || (home != NULL
423		&& (plib = consider_config_dir(cache, home, ".ltrace")) != NULL
424		&& protolib_add_import(&cache->imports, plib) < 0)
425	    || (plib == NULL && load_config(cache, "ltrace", 0, &plib) < 0)
426	    || (plib != NULL && protolib_add_import(&cache->imports, plib) < 0))
427		/* N.B. If plib is non-NULL, it has been already
428		 * cached.  We don't therefore destroy it on
429		 * failures.  */
430		return -1;
431
432	/* Never mind whether we've found anything.  It's fine if the
433	 * config is absent.  */
434	return 0;
435}
436
437static enum callback_status
438add_imports_cb(struct opt_F_t *entry, void *data)
439{
440	struct protolib_cache *self = data;
441	if (opt_F_get_kind(entry) != OPT_F_FILE)
442		return CBS_CONT;
443
444	struct protolib *new_import
445		= protolib_cache_file(self, entry->pathname, 0);
446
447	if (new_import == NULL
448	    || protolib_add_import(&self->imports, new_import) < 0)
449		/* N.B. If new_import is non-NULL, it has been already
450		 * cached.  We don't therefore destroy it on
451		 * failures.  */
452		return CBS_STOP;
453
454	return CBS_CONT;
455}
456
457int
458protolib_cache_init(struct protolib_cache *cache, struct protolib *import)
459{
460	DICT_INIT(&cache->protolibs, const char *, struct protolib *,
461		  dict_hash_string, dict_eq_string, NULL);
462	protolib_init(&cache->imports);
463
464	/* At this point the cache is consistent.  This is important,
465	 * because next we will use it to cache files that we load
466	 * due to -F.
467	 *
468	 * But we are about to construct the implicit import module,
469	 * which means this module can't be itself imported to the
470	 * files that we load now.  So remember that we are still
471	 * bootstrapping.  */
472	cache->bootstrap = 1;
473
474	if (protolib_add_import(&cache->imports, &legacy_typedefs) < 0
475	    || (import != NULL
476		&& protolib_add_import(&cache->imports, import) < 0)
477	    || add_ltrace_conf(cache) < 0
478	    || VECT_EACH(&opt_F, struct opt_F_t, NULL,
479			 add_imports_cb, cache) != NULL) {
480		protolib_cache_destroy(cache);
481		return -1;
482	}
483
484	cache->bootstrap = 0;
485	return 0;
486}
487
488static enum callback_status
489add_import_cb(struct protolib **importp, void *data)
490{
491	struct protolib *plib = data;
492	if (protolib_add_import(plib, *importp) < 0)
493		return CBS_STOP;
494	else
495		return CBS_CONT;
496}
497
498static struct protolib *
499build_default_config(struct protolib_cache *cache, const char *key)
500{
501	struct protolib *new_plib = malloc(sizeof(*new_plib));
502	if (new_plib == NULL) {
503		fprintf(stderr, "Couldn't create config module %s: %s\n",
504			key, strerror(errno));
505		return NULL;
506	}
507
508	protolib_init(new_plib);
509
510	/* If bootstrapping, copy over imports from implicit import
511	 * module to new_plib.  We can't reference the implicit
512	 * import module itself, because new_plib will become part of
513	 * this same implicit import module itself.  */
514	if ((cache->bootstrap && each_import(&cache->imports, NULL,
515					     add_import_cb, new_plib) != NULL)
516	    || (!cache->bootstrap
517		&& protolib_add_import(new_plib, &cache->imports) < 0)) {
518
519		fprintf(stderr,
520			"Couldn't add imports to config module %s: %s\n",
521			key, strerror(errno));
522		protolib_destroy(new_plib);
523		free(new_plib);
524		return NULL;
525	}
526
527	return new_plib;
528}
529
530static void
531attempt_to_cache(struct protolib_cache *cache,
532		 const char *key, struct protolib *plib)
533{
534	if (protolib_cache_protolib(cache, key, 1, plib) == 0
535	    || plib == NULL)
536		/* Never mind failing to store a NULL.  */
537		return;
538
539	/* Returning a protolib that hasn't been cached would leak
540	 * that protolib, but perhaps it's less bad then giving up
541	 * outright.  At least print an error message.  */
542	fprintf(stderr, "Couldn't cache prototype library for %s\n", key);
543}
544
545struct protolib *
546protolib_cache_search(struct protolib_cache *cache,
547		      const char *key, int own_key, int allow_private)
548{
549	struct protolib *plib = NULL;
550	if (DICT_FIND_VAL(&cache->protolibs, &key, &plib) == 0)
551		return plib;
552
553	if (clone_if_not_own(&key, own_key) < 0) {
554		fprintf(stderr, "Couldn't cache %s: %s\n",
555			key, strerror(errno));
556		return NULL;
557	}
558
559	/* The order is: -F directories, private directories, system
560	 * directories.  If the config file is not found anywhere,
561	 * build a default one.  */
562	if (load_dash_F_dirs(cache, key, &plib) < 0
563	    || (plib == NULL && allow_private
564		&& load_config(cache, key, 1, &plib) < 0)
565	    || (plib == NULL
566		&& load_config(cache, key, 0, &plib) < 0)
567	    || (plib == NULL
568		&& (plib = build_default_config(cache, key)) == NULL))
569		fprintf(stderr,
570			"Error occurred when attempting to load a prototype "
571			"library for %s.\n", key);
572
573	/* Whatever came out of this (even NULL), store it in the
574	 * cache.  */
575	attempt_to_cache(cache, key, plib);
576	return plib;
577}
578
579struct protolib *
580protolib_cache_file(struct protolib_cache *cache,
581		    const char *filename, int own_filename)
582{
583	{
584		struct protolib *plib;
585		if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
586			return plib;
587	}
588
589	FILE *stream = fopen(filename, "r");
590	if (stream == NULL)
591		return NULL;
592
593	if (clone_if_not_own(&filename, own_filename) < 0) {
594		fprintf(stderr, "Couldn't cache %s: %s\n",
595			filename, strerror(errno));
596		fclose(stream);
597		return NULL;
598	}
599
600	struct protolib *new_plib = build_default_config(cache, filename);
601	if (new_plib == NULL
602	    || read_config_file(stream, filename, new_plib) < 0) {
603		fclose(stream);
604		if (own_filename)
605			free((char *)filename);
606		if (new_plib != NULL) {
607			protolib_destroy(new_plib);
608			free(new_plib);
609		}
610		return NULL;
611	}
612
613	attempt_to_cache(cache, filename, new_plib);
614	fclose(stream);
615	return new_plib;
616}
617
618int
619protolib_cache_protolib(struct protolib_cache *cache,
620			const char *filename, int own_filename,
621			struct protolib *plib)
622{
623	if (clone_if_not_own(&filename, own_filename) < 0) {
624		fprintf(stderr, "Couldn't cache %s: %s\n",
625			filename, strerror(errno));
626		return -1;
627	}
628
629	int rc = DICT_INSERT(&cache->protolibs, &filename, &plib);
630	if (rc < 0 && own_filename)
631		free((char *)filename);
632	if (rc == 0)
633		plib->refs++;
634	return rc;
635}
636
637void
638init_global_config(void)
639{
640	protolib_init(&legacy_typedefs);
641	struct arg_type_info *void_info = type_get_simple(ARGTYPE_VOID);
642	static struct arg_type_info ptr_info;
643	type_init_pointer(&ptr_info, void_info, 0);
644
645	static struct named_type voidptr_type;
646	named_type_init(&voidptr_type, &ptr_info, 0);
647
648	/* Build legacy typedefs first.  This is used by
649	 * protolib_cache_init call below.  */
650	if (protolib_add_named_type(&legacy_typedefs, "addr", 0,
651				    &voidptr_type) < 0
652	    || protolib_add_named_type(&legacy_typedefs, "file", 0,
653				       &voidptr_type) < 0) {
654		fprintf(stderr,
655			"Couldn't initialize aliases `addr' and `file'.\n");
656
657		/* Since global config was not yet initialized, do an
658		 * early exit.  */
659		fflush(stderr);
660		_Exit(1);
661	}
662
663	if (protolib_cache_init(&g_protocache, NULL) < 0) {
664		fprintf(stderr, "Couldn't init prototype cache\n");
665		fflush(stderr);
666		_Exit(1);
667	}
668}
669
670void
671destroy_global_config(void)
672{
673	protolib_cache_destroy(&g_protocache);
674	protolib_destroy(&legacy_typedefs);
675}
676