prototype.c revision d2154eae286064c4114ec924186535961dfaad79
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2012,2013 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 "common.h"
28#include "callback.h"
29#include "param.h"
30#include "prototype.h"
31#include "type.h"
32#include "options.h"
33#include "read_config_file.h"
34#include "backend.h"
35
36struct protolib_cache g_protocache;
37static struct protolib legacy_typedefs;
38
39void
40prototype_init(struct prototype *proto)
41{
42	VECT_INIT(&proto->params, struct param);
43
44	proto->return_info = NULL;
45	proto->own_return_info = 0;
46}
47
48static void
49param_destroy_cb(struct param *param, void *data)
50{
51	param_destroy(param);
52}
53
54void
55prototype_destroy(struct prototype *proto)
56{
57	if (proto == NULL)
58		return;
59	if (proto->own_return_info) {
60		type_destroy(proto->return_info);
61		free(proto->return_info);
62	}
63
64	VECT_DESTROY(&proto->params, struct param, &param_destroy_cb, NULL);
65}
66
67int
68prototype_push_param(struct prototype *proto, struct param *param)
69{
70	return VECT_PUSHBACK(&proto->params, param);
71}
72
73size_t
74prototype_num_params(struct prototype *proto)
75{
76	return vect_size(&proto->params);
77}
78
79void
80prototype_destroy_nth_param(struct prototype *proto, size_t n)
81{
82	assert(n < prototype_num_params(proto));
83	VECT_ERASE(&proto->params, struct param, n, n+1,
84		   &param_destroy_cb, NULL);
85}
86
87struct param *
88prototype_get_nth_param(struct prototype *proto, size_t n)
89{
90	assert(n < prototype_num_params(proto));
91	return VECT_ELEMENT(&proto->params, struct param, n);
92}
93
94struct each_param_data {
95	struct prototype *proto;
96	enum callback_status (*cb)(struct prototype *, struct param *, void *);
97	void *data;
98};
99
100static enum callback_status
101each_param_cb(struct param *param, void *data)
102{
103	struct each_param_data *cb_data = data;
104	return (cb_data->cb)(cb_data->proto, param, cb_data->data);
105}
106
107struct param *
108prototype_each_param(struct prototype *proto, struct param *start_after,
109		     enum callback_status (*cb)(struct prototype *,
110						struct param *, void *),
111		     void *data)
112{
113	struct each_param_data cb_data = { proto, cb, data };
114	return VECT_EACH(&proto->params, struct param, start_after,
115			 &each_param_cb, &cb_data);
116}
117
118void
119named_type_init(struct named_type *named,
120		struct arg_type_info *info, int own_type)
121{
122	named->info = info;
123	named->own_type = own_type;
124	named->forward = 0;
125}
126
127void
128named_type_destroy(struct named_type *named)
129{
130	if (named->own_type) {
131		type_destroy(named->info);
132		free(named->info);
133	}
134}
135
136void
137protolib_init(struct protolib *plib)
138{
139	DICT_INIT(&plib->prototypes, char *, struct prototype,
140		  dict_hash_string, dict_eq_string, NULL);
141
142	DICT_INIT(&plib->named_types, char *, struct named_type,
143		  dict_hash_string, dict_eq_string, NULL);
144
145	VECT_INIT(&plib->imports, struct protolib *);
146
147	plib->refs = 0;
148}
149
150static void
151destroy_prototype_cb(struct prototype *proto, void *data)
152{
153	prototype_destroy(proto);
154}
155
156static void
157destroy_named_type_cb(struct named_type *named, void *data)
158{
159	named_type_destroy(named);
160}
161
162void
163protolib_destroy(struct protolib *plib)
164{
165	assert(plib->refs == 0);
166
167	VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
168
169	DICT_DESTROY(&plib->prototypes, const char *, struct prototype,
170		     dict_dtor_string, destroy_prototype_cb, NULL);
171
172	DICT_DESTROY(&plib->named_types, const char *, struct named_type,
173		     dict_dtor_string, destroy_named_type_cb, NULL);
174}
175
176static struct protolib **
177each_import(struct protolib *plib, struct protolib **start_after,
178	    enum callback_status (*cb)(struct protolib **, void *), void *data)
179{
180	assert(plib != NULL);
181	return VECT_EACH(&plib->imports, struct protolib *,
182			 start_after, cb, data);
183}
184
185static enum callback_status
186is_or_imports(struct protolib **plibp, void *data)
187{
188	assert(plibp != NULL);
189	assert(*plibp != NULL);
190	struct protolib *import = data;
191	if (*plibp == import
192	    || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
193		return CBS_STOP;
194	else
195		return CBS_CONT;
196}
197
198int
199protolib_add_import(struct protolib *plib, struct protolib *import)
200{
201	assert(plib != NULL);
202	assert(import != NULL);
203	if (is_or_imports(&import, plib) == CBS_STOP) {
204		fprintf(stderr, "Recursive import rejected.\n");
205		return -2;
206	}
207
208	return VECT_PUSHBACK(&plib->imports, &import) < 0 ? -1 : 0;
209}
210
211static int
212bailout(const char *name, int own)
213{
214	int save_errno = errno;
215	if (own)
216		free((char *)name);
217	errno = save_errno;
218	return -1;
219}
220
221int
222protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
223		       struct prototype *proto)
224{
225	assert(plib != NULL);
226	if (strdup_if(&name, name, !own_name) < 0)
227		return -1;
228	if (DICT_INSERT(&plib->prototypes, &name, proto) < 0)
229		return bailout(name, own_name);
230	return 0;
231}
232
233int
234protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
235			struct named_type *named)
236{
237	assert(plib != NULL);
238	if (strdup_if(&name, name, !own_name) < 0)
239		return -1;
240	if (DICT_INSERT(&plib->named_types, &name, named) < 0)
241		return bailout(name, own_name);
242	return 0;
243}
244
245struct lookup {
246	const char *name;
247	struct dict *(*getter)(struct protolib *plib);
248	bool imports;
249	void *result;
250};
251
252static struct dict *
253get_prototypes(struct protolib *plib)
254{
255	assert(plib != NULL);
256	return &plib->prototypes;
257}
258
259static struct dict *
260get_named_types(struct protolib *plib)
261{
262	assert(plib != NULL);
263	return &plib->named_types;
264}
265
266static enum callback_status
267protolib_lookup_rec(struct protolib **plibp, void *data)
268{
269	assert(plibp != NULL);
270	assert(*plibp != NULL);
271	struct lookup *lookup = data;
272	struct dict *dict = (*lookup->getter)(*plibp);
273
274	lookup->result = dict_find(dict, &lookup->name);
275	if (lookup->result != NULL)
276		return CBS_STOP;
277
278	if (lookup->imports && each_import(*plibp, NULL, &protolib_lookup_rec,
279					   lookup) != NULL) {
280		assert(lookup->result != NULL);
281		return CBS_STOP;
282	}
283
284	return CBS_CONT;
285}
286
287static void *
288protolib_lookup(struct protolib *plib, const char *name,
289		struct dict *(*getter)(struct protolib *),
290		bool imports)
291{
292	assert(plib != NULL);
293	struct lookup lookup = { name, getter, imports, NULL };
294	if (protolib_lookup_rec(&plib, &lookup) == CBS_STOP)
295		assert(lookup.result != NULL);
296	else
297		assert(lookup.result == NULL);
298	return lookup.result;
299}
300
301struct prototype *
302protolib_lookup_prototype(struct protolib *plib, const char *name, bool imports)
303{
304	assert(plib != NULL);
305	return protolib_lookup(plib, name, &get_prototypes, imports);
306}
307
308struct named_type *
309protolib_lookup_type(struct protolib *plib, const char *name, bool imports)
310{
311	assert(plib != NULL);
312	return protolib_lookup(plib, name, &get_named_types, imports);
313}
314
315static void
316destroy_protolib_cb(struct protolib **plibp, void *data)
317{
318	assert(plibp != NULL);
319
320	if (*plibp != NULL
321	    && --(*plibp)->refs == 0) {
322		protolib_destroy(*plibp);
323		free(*plibp);
324	}
325}
326
327void
328protolib_cache_destroy(struct protolib_cache *cache)
329{
330	DICT_DESTROY(&cache->protolibs, const char *, struct protolib *,
331		     dict_dtor_string, destroy_protolib_cb, NULL);
332}
333
334struct load_config_data {
335	struct protolib_cache *self;
336	const char *key;
337	struct protolib *result;
338};
339
340static struct protolib *
341consider_config_dir(struct protolib_cache *cache,
342		    const char *path, const char *key)
343{
344	size_t len = sizeof ".conf";
345	char slash[2] = {'/'};
346	char *buf = alloca(strlen(path) + 1 + strlen(key) + len);
347	strcpy(stpcpy(stpcpy(stpcpy(buf, path), slash), key), ".conf");
348
349	return protolib_cache_file(cache, buf, 0);
350}
351
352static enum callback_status
353consider_confdir_cb(struct opt_F_t *entry, void *d)
354{
355	if (opt_F_get_kind(entry) != OPT_F_DIR)
356		return CBS_CONT;
357	struct load_config_data *data = d;
358
359	data->result = consider_config_dir(data->self,
360					   entry->pathname, data->key);
361	return data->result != NULL ? CBS_STOP : CBS_CONT;
362}
363
364static int
365load_dash_F_dirs(struct protolib_cache *cache,
366		 const char *key, struct protolib **retp)
367{
368	struct load_config_data data = {cache, key};
369
370	if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
371		      consider_confdir_cb, &data) == NULL)
372		/* Not found.  That's fine.  */
373		return 0;
374
375	if (data.result == NULL)
376		/* There were errors.  */
377		return -1;
378
379	*retp = data.result;
380	return 0;
381}
382
383static int
384load_config(struct protolib_cache *cache,
385	    const char *key, int private, struct protolib **retp)
386{
387	const char **dirs = NULL;
388	if (os_get_config_dirs(private, &dirs) < 0
389	    || dirs == NULL)
390		return -1;
391
392	for (; *dirs != NULL; ++dirs) {
393		struct protolib *plib = consider_config_dir(cache, *dirs, key);
394		if (plib != NULL) {
395			*retp = plib;
396			break;
397		}
398	}
399
400	return 0;
401}
402
403static enum callback_status
404import_legacy_file(char **fnp, void *data)
405{
406	struct protolib_cache *cache = data;
407	struct protolib *plib = protolib_cache_file(cache, *fnp, 1);
408	if (plib != NULL) {
409		/* The cache now owns the file name.  */
410		*fnp = NULL;
411		if (protolib_add_import(&cache->imports, plib) < 0)
412			return CBS_STOP;
413	}
414
415	return CBS_CONT;
416}
417
418static int
419add_ltrace_conf(struct protolib_cache *cache)
420{
421	/* Look into private config directories for .ltrace.conf and
422	 * into system config directories for ltrace.conf.  If it's
423	 * found, add it to implicit import module.  */
424	struct vect legacy_files;
425	VECT_INIT(&legacy_files, char *);
426	if (os_get_ltrace_conf_filenames(&legacy_files) < 0) {
427		vect_destroy(&legacy_files, NULL, NULL);
428		return -1;
429	}
430
431	int ret = VECT_EACH(&legacy_files, char *, NULL,
432			    import_legacy_file, cache) == NULL ? 0 : -1;
433	VECT_DESTROY(&legacy_files, char *, vect_dtor_string, NULL);
434	return ret;
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, 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	free((void *) key);
544}
545
546int
547protolib_cache_maybe_load(struct protolib_cache *cache,
548			  const char *key, int own_key, bool allow_private,
549			  struct protolib **retp)
550{
551	if (DICT_FIND_VAL(&cache->protolibs, &key, retp) == 0)
552		return 0;
553
554	if (strdup_if(&key, key, !own_key) < 0) {
555		fprintf(stderr, "Couldn't cache %s: %s\n",
556			key, strerror(errno));
557		return -1;
558	}
559
560	*retp = NULL;
561	if (load_dash_F_dirs(cache, key, retp) < 0
562	    || (*retp == NULL && allow_private
563		&& load_config(cache, key, 1, retp) < 0)
564	    || (*retp == NULL
565		&& load_config(cache, key, 0, retp) < 0))
566	{
567		fprintf(stderr,
568			"Error occurred when attempting to load a prototype "
569			"library for %s.\n", key);
570		if (!own_key)
571			free((void *) key);
572		return -1;
573	}
574
575	if (*retp != NULL)
576		attempt_to_cache(cache, key, *retp);
577	else if (!own_key)
578		free((void *) key);
579
580	return 0;
581}
582
583struct protolib *
584protolib_cache_load(struct protolib_cache *cache,
585		    const char *key, int own_key, bool allow_private)
586{
587	struct protolib *plib;
588	if (protolib_cache_maybe_load(cache, key, own_key,
589				      allow_private, &plib) < 0)
590		return NULL;
591
592	if (plib == NULL)
593		plib = protolib_cache_default(cache, key, own_key);
594
595	return plib;
596}
597
598struct protolib *
599protolib_cache_default(struct protolib_cache *cache,
600		       const char *key, int own_key)
601{
602	if (strdup_if(&key, key, !own_key) < 0) {
603		fprintf(stderr, "Couldn't cache default %s: %s\n",
604			key, strerror(errno));
605		return NULL;
606	}
607
608	struct protolib *plib = build_default_config(cache, key);
609
610	/* Whatever came out of this (even NULL), store it in
611	 * the cache.  */
612	attempt_to_cache(cache, key, plib);
613
614	return plib;
615}
616
617struct protolib *
618protolib_cache_file(struct protolib_cache *cache,
619		    const char *filename, int own_filename)
620{
621	{
622		struct protolib *plib;
623		if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
624			return plib;
625	}
626
627	FILE *stream = fopen(filename, "r");
628	if (stream == NULL)
629		return NULL;
630
631	if (strdup_if(&filename, filename, !own_filename) < 0) {
632		fprintf(stderr, "Couldn't cache %s: %s\n",
633			filename, strerror(errno));
634		fclose(stream);
635		return NULL;
636	}
637
638	struct protolib *new_plib = build_default_config(cache, filename);
639	if (new_plib == NULL
640	    || read_config_file(stream, filename, new_plib) < 0) {
641		fclose(stream);
642		if (own_filename)
643			free((char *) filename);
644		if (new_plib != NULL) {
645			protolib_destroy(new_plib);
646			free(new_plib);
647		}
648		return NULL;
649	}
650
651	attempt_to_cache(cache, filename, new_plib);
652	fclose(stream);
653	return new_plib;
654}
655
656int
657protolib_cache_protolib(struct protolib_cache *cache,
658			const char *filename, int own_filename,
659			struct protolib *plib)
660{
661	if (strdup_if(&filename, filename, !own_filename) < 0) {
662		fprintf(stderr, "Couldn't cache %s: %s\n",
663			filename, strerror(errno));
664		return -1;
665	}
666
667	int rc = DICT_INSERT(&cache->protolibs, &filename, &plib);
668	if (rc < 0 && own_filename)
669		free((char *) filename);
670	if (rc == 0 && plib != NULL)
671		plib->refs++;
672	return rc;
673}
674
675static void
676destroy_global_config(void)
677{
678	protolib_cache_destroy(&g_protocache);
679	protolib_destroy(&legacy_typedefs);
680}
681
682void
683init_global_config(void)
684{
685	protolib_init(&legacy_typedefs);
686
687	struct arg_type_info *ptr_info = type_get_voidptr();
688	static struct named_type voidptr_type;
689	named_type_init(&voidptr_type, ptr_info, 0);
690
691	/* Build legacy typedefs first.  This is used by
692	 * protolib_cache_init call below.  */
693	if (protolib_add_named_type(&legacy_typedefs, "addr", 0,
694				    &voidptr_type) < 0
695	    || protolib_add_named_type(&legacy_typedefs, "file", 0,
696				       &voidptr_type) < 0) {
697		fprintf(stderr,
698			"Couldn't initialize aliases `addr' and `file'.\n");
699
700		exit(1);
701	}
702
703	if (protolib_cache_init(&g_protocache, NULL) < 0) {
704		fprintf(stderr, "Couldn't init prototype cache\n");
705		exit(1);
706	}
707
708	atexit(destroy_global_config);
709}
710