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 
36 struct protolib_cache g_protocache;
37 static struct protolib legacy_typedefs;
38 
39 void
prototype_init(struct prototype * proto)40 prototype_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 
48 static void
param_destroy_cb(struct param * param,void * data)49 param_destroy_cb(struct param *param, void *data)
50 {
51 	param_destroy(param);
52 }
53 
54 void
prototype_destroy(struct prototype * proto)55 prototype_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 
67 int
prototype_push_param(struct prototype * proto,struct param * param)68 prototype_push_param(struct prototype *proto, struct param *param)
69 {
70 	return VECT_PUSHBACK(&proto->params, param);
71 }
72 
73 size_t
prototype_num_params(struct prototype * proto)74 prototype_num_params(struct prototype *proto)
75 {
76 	return vect_size(&proto->params);
77 }
78 
79 void
prototype_destroy_nth_param(struct prototype * proto,size_t n)80 prototype_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 
87 struct param *
prototype_get_nth_param(struct prototype * proto,size_t n)88 prototype_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 
94 struct each_param_data {
95 	struct prototype *proto;
96 	enum callback_status (*cb)(struct prototype *, struct param *, void *);
97 	void *data;
98 };
99 
100 static enum callback_status
each_param_cb(struct param * param,void * data)101 each_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 
107 struct param *
prototype_each_param(struct prototype * proto,struct param * start_after,enum callback_status (* cb)(struct prototype *,struct param *,void *),void * data)108 prototype_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 
118 void
named_type_init(struct named_type * named,struct arg_type_info * info,int own_type)119 named_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 
127 void
named_type_destroy(struct named_type * named)128 named_type_destroy(struct named_type *named)
129 {
130 	if (named->own_type) {
131 		type_destroy(named->info);
132 		free(named->info);
133 	}
134 }
135 
136 void
protolib_init(struct protolib * plib)137 protolib_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 
150 static void
destroy_prototype_cb(struct prototype * proto,void * data)151 destroy_prototype_cb(struct prototype *proto, void *data)
152 {
153 	prototype_destroy(proto);
154 }
155 
156 static void
destroy_named_type_cb(struct named_type * named,void * data)157 destroy_named_type_cb(struct named_type *named, void *data)
158 {
159 	named_type_destroy(named);
160 }
161 
162 void
protolib_destroy(struct protolib * plib)163 protolib_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 
176 static struct protolib **
each_import(struct protolib * plib,struct protolib ** start_after,enum callback_status (* cb)(struct protolib **,void *),void * data)177 each_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 
185 static enum callback_status
is_or_imports(struct protolib ** plibp,void * data)186 is_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 
198 int
protolib_add_import(struct protolib * plib,struct protolib * import)199 protolib_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 
211 static int
bailout(const char * name,int own)212 bailout(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 
221 int
protolib_add_prototype(struct protolib * plib,const char * name,int own_name,struct prototype * proto)222 protolib_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 
233 int
protolib_add_named_type(struct protolib * plib,const char * name,int own_name,struct named_type * named)234 protolib_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 
245 struct lookup {
246 	const char *name;
247 	struct dict *(*getter)(struct protolib *plib);
248 	bool imports;
249 	void *result;
250 };
251 
252 static struct dict *
get_prototypes(struct protolib * plib)253 get_prototypes(struct protolib *plib)
254 {
255 	assert(plib != NULL);
256 	return &plib->prototypes;
257 }
258 
259 static struct dict *
get_named_types(struct protolib * plib)260 get_named_types(struct protolib *plib)
261 {
262 	assert(plib != NULL);
263 	return &plib->named_types;
264 }
265 
266 static enum callback_status
protolib_lookup_rec(struct protolib ** plibp,void * data)267 protolib_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 
287 static void *
protolib_lookup(struct protolib * plib,const char * name,struct dict * (* getter)(struct protolib *),bool imports)288 protolib_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 
301 struct prototype *
protolib_lookup_prototype(struct protolib * plib,const char * name,bool imports)302 protolib_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 
308 struct named_type *
protolib_lookup_type(struct protolib * plib,const char * name,bool imports)309 protolib_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 
315 static void
destroy_protolib_cb(struct protolib ** plibp,void * data)316 destroy_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 
327 void
protolib_cache_destroy(struct protolib_cache * cache)328 protolib_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 
334 struct load_config_data {
335 	struct protolib_cache *self;
336 	const char *key;
337 	struct protolib *result;
338 };
339 
340 static struct protolib *
consider_config_dir(struct protolib_cache * cache,const char * path,const char * key)341 consider_config_dir(struct protolib_cache *cache,
342 		    const char *path, const char *key)
343 {
344 	size_t len = sizeof ".conf";
345 	char *buf = alloca(strlen(path) + 1 + strlen(key) + len);
346 	sprintf(buf, "%s/%s.conf", path, key);
347 
348 	return protolib_cache_file(cache, buf, 0);
349 }
350 
351 static enum callback_status
consider_confdir_cb(struct opt_F_t * entry,void * d)352 consider_confdir_cb(struct opt_F_t *entry, void *d)
353 {
354 	if (opt_F_get_kind(entry) != OPT_F_DIR)
355 		return CBS_CONT;
356 	struct load_config_data *data = d;
357 
358 	data->result = consider_config_dir(data->self,
359 					   entry->pathname, data->key);
360 	return data->result != NULL ? CBS_STOP : CBS_CONT;
361 }
362 
363 static int
load_dash_F_dirs(struct protolib_cache * cache,const char * key,struct protolib ** retp)364 load_dash_F_dirs(struct protolib_cache *cache,
365 		 const char *key, struct protolib **retp)
366 {
367 	struct load_config_data data = {cache, key};
368 
369 	if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
370 		      consider_confdir_cb, &data) == NULL)
371 		/* Not found.  That's fine.  */
372 		return 0;
373 
374 	if (data.result == NULL)
375 		/* There were errors.  */
376 		return -1;
377 
378 	*retp = data.result;
379 	return 0;
380 }
381 
382 static int
load_config(struct protolib_cache * cache,const char * key,int private,struct protolib ** retp)383 load_config(struct protolib_cache *cache,
384 	    const char *key, int private, struct protolib **retp)
385 {
386 	const char **dirs = NULL;
387 	if (os_get_config_dirs(private, &dirs) < 0
388 	    || dirs == NULL)
389 		return -1;
390 
391 	for (; *dirs != NULL; ++dirs) {
392 		struct protolib *plib = consider_config_dir(cache, *dirs, key);
393 		if (plib != NULL) {
394 			*retp = plib;
395 			break;
396 		}
397 	}
398 
399 	return 0;
400 }
401 
402 static enum callback_status
import_legacy_file(char ** fnp,void * data)403 import_legacy_file(char **fnp, void *data)
404 {
405 	struct protolib_cache *cache = data;
406 	struct protolib *plib = protolib_cache_file(cache, *fnp, 1);
407 	if (plib != NULL) {
408 		/* The cache now owns the file name.  */
409 		*fnp = NULL;
410 		if (protolib_add_import(&cache->imports, plib) < 0)
411 			return CBS_STOP;
412 	}
413 
414 	return CBS_CONT;
415 }
416 
417 static int
add_ltrace_conf(struct protolib_cache * cache)418 add_ltrace_conf(struct protolib_cache *cache)
419 {
420 	/* Look into private config directories for .ltrace.conf and
421 	 * into system config directories for ltrace.conf.  If it's
422 	 * found, add it to implicit import module.  */
423 	struct vect legacy_files;
424 	VECT_INIT(&legacy_files, char *);
425 	if (os_get_ltrace_conf_filenames(&legacy_files) < 0) {
426 		vect_destroy(&legacy_files, NULL, NULL);
427 		return -1;
428 	}
429 
430 	int ret = VECT_EACH(&legacy_files, char *, NULL,
431 			    import_legacy_file, cache) == NULL ? 0 : -1;
432 	VECT_DESTROY(&legacy_files, char *, vect_dtor_string, NULL);
433 	return ret;
434 }
435 
436 static enum callback_status
add_imports_cb(struct opt_F_t * entry,void * data)437 add_imports_cb(struct opt_F_t *entry, void *data)
438 {
439 	struct protolib_cache *self = data;
440 	if (opt_F_get_kind(entry) != OPT_F_FILE)
441 		return CBS_CONT;
442 
443 	struct protolib *new_import
444 		= protolib_cache_file(self, entry->pathname, 0);
445 
446 	if (new_import == NULL
447 	    || protolib_add_import(&self->imports, new_import) < 0)
448 		/* N.B. If new_import is non-NULL, it has been already
449 		 * cached.  We don't therefore destroy it on
450 		 * failures.  */
451 		return CBS_STOP;
452 
453 	return CBS_CONT;
454 }
455 
456 int
protolib_cache_init(struct protolib_cache * cache,struct protolib * import)457 protolib_cache_init(struct protolib_cache *cache, struct protolib *import)
458 {
459 	DICT_INIT(&cache->protolibs, char *, struct protolib *,
460 		  dict_hash_string, dict_eq_string, NULL);
461 	protolib_init(&cache->imports);
462 
463 	/* At this point the cache is consistent.  This is important,
464 	 * because next we will use it to cache files that we load
465 	 * due to -F.
466 	 *
467 	 * But we are about to construct the implicit import module,
468 	 * which means this module can't be itself imported to the
469 	 * files that we load now.  So remember that we are still
470 	 * bootstrapping.  */
471 	cache->bootstrap = 1;
472 
473 	if (protolib_add_import(&cache->imports, &legacy_typedefs) < 0
474 	    || (import != NULL
475 		&& protolib_add_import(&cache->imports, import) < 0)
476 	    || add_ltrace_conf(cache) < 0
477 	    || VECT_EACH(&opt_F, struct opt_F_t, NULL,
478 			 add_imports_cb, cache) != NULL) {
479 		protolib_cache_destroy(cache);
480 		return -1;
481 	}
482 
483 	cache->bootstrap = 0;
484 	return 0;
485 }
486 
487 static enum callback_status
add_import_cb(struct protolib ** importp,void * data)488 add_import_cb(struct protolib **importp, void *data)
489 {
490 	struct protolib *plib = data;
491 	if (protolib_add_import(plib, *importp) < 0)
492 		return CBS_STOP;
493 	else
494 		return CBS_CONT;
495 }
496 
497 static struct protolib *
build_default_config(struct protolib_cache * cache,const char * key)498 build_default_config(struct protolib_cache *cache, const char *key)
499 {
500 	struct protolib *new_plib = malloc(sizeof(*new_plib));
501 	if (new_plib == NULL) {
502 		fprintf(stderr, "Couldn't create config module %s: %s\n",
503 			key, strerror(errno));
504 		return NULL;
505 	}
506 
507 	protolib_init(new_plib);
508 
509 	/* If bootstrapping, copy over imports from implicit import
510 	 * module to new_plib.  We can't reference the implicit
511 	 * import module itself, because new_plib will become part of
512 	 * this same implicit import module itself.  */
513 	if ((cache->bootstrap && each_import(&cache->imports, NULL,
514 					     add_import_cb, new_plib) != NULL)
515 	    || (!cache->bootstrap
516 		&& protolib_add_import(new_plib, &cache->imports) < 0)) {
517 
518 		fprintf(stderr,
519 			"Couldn't add imports to config module %s: %s\n",
520 			key, strerror(errno));
521 		protolib_destroy(new_plib);
522 		free(new_plib);
523 		return NULL;
524 	}
525 
526 	return new_plib;
527 }
528 
529 static void
attempt_to_cache(struct protolib_cache * cache,const char * key,struct protolib * plib)530 attempt_to_cache(struct protolib_cache *cache,
531 		 const char *key, struct protolib *plib)
532 {
533 	if (protolib_cache_protolib(cache, key, 1, plib) == 0
534 	    || plib == NULL)
535 		/* Never mind failing to store a NULL.  */
536 		return;
537 
538 	/* Returning a protolib that hasn't been cached would leak
539 	 * that protolib, but perhaps it's less bad then giving up
540 	 * outright.  At least print an error message.  */
541 	fprintf(stderr, "Couldn't cache prototype library for %s\n", key);
542 	free((void *) key);
543 }
544 
545 int
protolib_cache_maybe_load(struct protolib_cache * cache,const char * key,int own_key,bool allow_private,struct protolib ** retp)546 protolib_cache_maybe_load(struct protolib_cache *cache,
547 			  const char *key, int own_key, bool allow_private,
548 			  struct protolib **retp)
549 {
550 	if (DICT_FIND_VAL(&cache->protolibs, &key, retp) == 0)
551 		return 0;
552 
553 	if (strdup_if(&key, key, !own_key) < 0) {
554 		fprintf(stderr, "Couldn't cache %s: %s\n",
555 			key, strerror(errno));
556 		return -1;
557 	}
558 
559 	*retp = NULL;
560 	if (load_dash_F_dirs(cache, key, retp) < 0
561 	    || (*retp == NULL && allow_private
562 		&& load_config(cache, key, 1, retp) < 0)
563 	    || (*retp == NULL
564 		&& load_config(cache, key, 0, retp) < 0))
565 	{
566 		fprintf(stderr,
567 			"Error occurred when attempting to load a prototype "
568 			"library for %s.\n", key);
569 		if (!own_key)
570 			free((void *) key);
571 		return -1;
572 	}
573 
574 	if (*retp != NULL)
575 		attempt_to_cache(cache, key, *retp);
576 	else if (!own_key)
577 		free((void *) key);
578 
579 	return 0;
580 }
581 
582 struct protolib *
protolib_cache_load(struct protolib_cache * cache,const char * key,int own_key,bool allow_private)583 protolib_cache_load(struct protolib_cache *cache,
584 		    const char *key, int own_key, bool allow_private)
585 {
586 	struct protolib *plib;
587 	if (protolib_cache_maybe_load(cache, key, own_key,
588 				      allow_private, &plib) < 0)
589 		return NULL;
590 
591 	if (plib == NULL)
592 		plib = protolib_cache_default(cache, key, own_key);
593 
594 	return plib;
595 }
596 
597 struct protolib *
protolib_cache_default(struct protolib_cache * cache,const char * key,int own_key)598 protolib_cache_default(struct protolib_cache *cache,
599 		       const char *key, int own_key)
600 {
601 	if (strdup_if(&key, key, !own_key) < 0) {
602 		fprintf(stderr, "Couldn't cache default %s: %s\n",
603 			key, strerror(errno));
604 		return NULL;
605 	}
606 
607 	struct protolib *plib = build_default_config(cache, key);
608 
609 	/* Whatever came out of this (even NULL), store it in
610 	 * the cache.  */
611 	attempt_to_cache(cache, key, plib);
612 
613 	return plib;
614 }
615 
616 struct protolib *
protolib_cache_file(struct protolib_cache * cache,const char * filename,int own_filename)617 protolib_cache_file(struct protolib_cache *cache,
618 		    const char *filename, int own_filename)
619 {
620 	{
621 		struct protolib *plib;
622 		if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
623 			return plib;
624 	}
625 
626 	FILE *stream = fopen(filename, "r");
627 	if (stream == NULL)
628 		return NULL;
629 
630 	if (strdup_if(&filename, filename, !own_filename) < 0) {
631 		fprintf(stderr, "Couldn't cache %s: %s\n",
632 			filename, strerror(errno));
633 		fclose(stream);
634 		return NULL;
635 	}
636 
637 	struct protolib *new_plib = build_default_config(cache, filename);
638 	if (new_plib == NULL
639 	    || read_config_file(stream, filename, new_plib) < 0) {
640 		fclose(stream);
641 		if (own_filename)
642 			free((char *) filename);
643 		if (new_plib != NULL) {
644 			protolib_destroy(new_plib);
645 			free(new_plib);
646 		}
647 		return NULL;
648 	}
649 
650 	attempt_to_cache(cache, filename, new_plib);
651 	fclose(stream);
652 	return new_plib;
653 }
654 
655 int
protolib_cache_protolib(struct protolib_cache * cache,const char * filename,int own_filename,struct protolib * plib)656 protolib_cache_protolib(struct protolib_cache *cache,
657 			const char *filename, int own_filename,
658 			struct protolib *plib)
659 {
660 	if (strdup_if(&filename, filename, !own_filename) < 0) {
661 		fprintf(stderr, "Couldn't cache %s: %s\n",
662 			filename, strerror(errno));
663 		return -1;
664 	}
665 
666 	int rc = DICT_INSERT(&cache->protolibs, &filename, &plib);
667 	if (rc < 0 && own_filename)
668 		free((char *) filename);
669 	if (rc == 0 && plib != NULL)
670 		plib->refs++;
671 	return rc;
672 }
673 
674 static void
destroy_global_config(void)675 destroy_global_config(void)
676 {
677 	protolib_cache_destroy(&g_protocache);
678 	protolib_destroy(&legacy_typedefs);
679 }
680 
681 void
init_global_config(void)682 init_global_config(void)
683 {
684 	protolib_init(&legacy_typedefs);
685 
686 	struct arg_type_info *ptr_info = type_get_voidptr();
687 	static struct named_type voidptr_type;
688 	named_type_init(&voidptr_type, ptr_info, 0);
689 
690 	/* Build legacy typedefs first.  This is used by
691 	 * protolib_cache_init call below.  */
692 	if (protolib_add_named_type(&legacy_typedefs, "addr", 0,
693 				    &voidptr_type) < 0
694 	    || protolib_add_named_type(&legacy_typedefs, "file", 0,
695 				       &voidptr_type) < 0) {
696 		fprintf(stderr,
697 			"Couldn't initialize aliases `addr' and `file'.\n");
698 
699 		exit(1);
700 	}
701 
702 	if (protolib_cache_init(&g_protocache, NULL) < 0) {
703 		fprintf(stderr, "Couldn't init prototype cache\n");
704 		exit(1);
705 	}
706 
707 	atexit(destroy_global_config);
708 }
709