2 * This file is part of ltrace.
3 * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
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.
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.
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
30 #include "prototype.h"
33 #include "read_config_file.h"
36 struct protolib_cache g_protocache;
37 static struct protolib legacy_typedefs;
40 prototype_init(struct prototype *proto)
42 VECT_INIT(&proto->params, struct param);
44 proto->return_info = NULL;
45 proto->own_return_info = 0;
49 param_destroy_cb(struct param *param, void *data)
55 prototype_destroy(struct prototype *proto)
59 if (proto->own_return_info) {
60 type_destroy(proto->return_info);
61 free(proto->return_info);
64 VECT_DESTROY(&proto->params, struct param, ¶m_destroy_cb, NULL);
68 prototype_push_param(struct prototype *proto, struct param *param)
70 return VECT_PUSHBACK(&proto->params, param);
74 prototype_num_params(struct prototype *proto)
76 return vect_size(&proto->params);
80 prototype_destroy_nth_param(struct prototype *proto, size_t n)
82 assert(n < prototype_num_params(proto));
83 VECT_ERASE(&proto->params, struct param, n, n+1,
84 ¶m_destroy_cb, NULL);
88 prototype_get_nth_param(struct prototype *proto, size_t n)
90 assert(n < prototype_num_params(proto));
91 return VECT_ELEMENT(&proto->params, struct param, n);
94 struct each_param_data {
95 struct prototype *proto;
96 enum callback_status (*cb)(struct prototype *, struct param *, void *);
100 static enum callback_status
101 each_param_cb(struct param *param, void *data)
103 struct each_param_data *cb_data = data;
104 return (cb_data->cb)(cb_data->proto, param, cb_data->data);
108 prototype_each_param(struct prototype *proto, struct param *start_after,
109 enum callback_status (*cb)(struct prototype *,
110 struct param *, void *),
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);
119 named_type_init(struct named_type *named,
120 struct arg_type_info *info, int own_type)
123 named->own_type = own_type;
128 named_type_destroy(struct named_type *named)
130 if (named->own_type) {
131 type_destroy(named->info);
137 protolib_init(struct protolib *plib)
139 DICT_INIT(&plib->prototypes, char *, struct prototype,
140 dict_hash_string, dict_eq_string, NULL);
142 DICT_INIT(&plib->named_types, char *, struct named_type,
143 dict_hash_string, dict_eq_string, NULL);
145 VECT_INIT(&plib->imports, struct protolib *);
151 destroy_prototype_cb(struct prototype *proto, void *data)
153 prototype_destroy(proto);
157 destroy_named_type_cb(struct named_type *named, void *data)
159 named_type_destroy(named);
163 protolib_destroy(struct protolib *plib)
165 assert(plib->refs == 0);
167 VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
169 DICT_DESTROY(&plib->prototypes, const char *, struct prototype,
170 dict_dtor_string, destroy_prototype_cb, NULL);
172 DICT_DESTROY(&plib->named_types, const char *, struct named_type,
173 dict_dtor_string, destroy_named_type_cb, NULL);
176 static struct protolib **
177 each_import(struct protolib *plib, struct protolib **start_after,
178 enum callback_status (*cb)(struct protolib **, void *), void *data)
180 assert(plib != NULL);
181 return VECT_EACH(&plib->imports, struct protolib *,
182 start_after, cb, data);
185 static enum callback_status
186 is_or_imports(struct protolib **plibp, void *data)
188 assert(plibp != NULL);
189 assert(*plibp != NULL);
190 struct protolib *import = data;
192 || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
199 protolib_add_import(struct protolib *plib, struct protolib *import)
201 assert(plib != NULL);
202 assert(import != NULL);
203 if (is_or_imports(&import, plib) == CBS_STOP) {
204 fprintf(stderr, "Recursive import rejected.\n");
208 return VECT_PUSHBACK(&plib->imports, &import) < 0 ? -1 : 0;
212 bailout(const char *name, int own)
214 int save_errno = errno;
222 protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
223 struct prototype *proto)
225 assert(plib != NULL);
226 if (strdup_if(&name, name, !own_name) < 0)
228 if (DICT_INSERT(&plib->prototypes, &name, proto) < 0)
229 return bailout(name, own_name);
234 protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
235 struct named_type *named)
237 assert(plib != NULL);
238 if (strdup_if(&name, name, !own_name) < 0)
240 if (DICT_INSERT(&plib->named_types, &name, named) < 0)
241 return bailout(name, own_name);
247 struct dict *(*getter)(struct protolib *plib);
253 get_prototypes(struct protolib *plib)
255 assert(plib != NULL);
256 return &plib->prototypes;
260 get_named_types(struct protolib *plib)
262 assert(plib != NULL);
263 return &plib->named_types;
266 static enum callback_status
267 protolib_lookup_rec(struct protolib **plibp, void *data)
269 assert(plibp != NULL);
270 assert(*plibp != NULL);
271 struct lookup *lookup = data;
272 struct dict *dict = (*lookup->getter)(*plibp);
274 lookup->result = dict_find(dict, &lookup->name);
275 if (lookup->result != NULL)
278 if (lookup->imports && each_import(*plibp, NULL, &protolib_lookup_rec,
280 assert(lookup->result != NULL);
288 protolib_lookup(struct protolib *plib, const char *name,
289 struct dict *(*getter)(struct protolib *),
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);
297 assert(lookup.result == NULL);
298 return lookup.result;
302 protolib_lookup_prototype(struct protolib *plib, const char *name, bool imports)
304 assert(plib != NULL);
305 return protolib_lookup(plib, name, &get_prototypes, imports);
309 protolib_lookup_type(struct protolib *plib, const char *name, bool imports)
311 assert(plib != NULL);
312 return protolib_lookup(plib, name, &get_named_types, imports);
316 destroy_protolib_cb(struct protolib **plibp, void *data)
318 assert(plibp != NULL);
321 && --(*plibp)->refs == 0) {
322 protolib_destroy(*plibp);
328 protolib_cache_destroy(struct protolib_cache *cache)
330 DICT_DESTROY(&cache->protolibs, const char *, struct protolib *,
331 dict_dtor_string, destroy_protolib_cb, NULL);
334 struct load_config_data {
335 struct protolib_cache *self;
337 struct protolib *result;
340 static struct protolib *
341 consider_config_dir(struct protolib_cache *cache,
342 const char *path, const char *key)
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");
349 return protolib_cache_file(cache, buf, 0);
352 static enum callback_status
353 consider_confdir_cb(struct opt_F_t *entry, void *d)
355 if (opt_F_get_kind(entry) != OPT_F_DIR)
357 struct load_config_data *data = d;
359 data->result = consider_config_dir(data->self,
360 entry->pathname, data->key);
361 return data->result != NULL ? CBS_STOP : CBS_CONT;
365 load_dash_F_dirs(struct protolib_cache *cache,
366 const char *key, struct protolib **retp)
368 struct load_config_data data = {cache, key};
370 if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
371 consider_confdir_cb, &data) == NULL)
372 /* Not found. That's fine. */
375 if (data.result == NULL)
376 /* There were errors. */
384 load_config(struct protolib_cache *cache,
385 const char *key, int private, struct protolib **retp)
387 const char **dirs = NULL;
388 if (os_get_config_dirs(private, &dirs) < 0
392 for (; *dirs != NULL; ++dirs) {
393 struct protolib *plib = consider_config_dir(cache, *dirs, key);
403 static enum callback_status
404 import_legacy_file(char **fnp, void *data)
406 struct protolib_cache *cache = data;
407 struct protolib *plib = protolib_cache_file(cache, *fnp, 1);
409 /* The cache now owns the file name. */
411 if (protolib_add_import(&cache->imports, plib) < 0)
419 add_ltrace_conf(struct protolib_cache *cache)
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);
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);
437 static enum callback_status
438 add_imports_cb(struct opt_F_t *entry, void *data)
440 struct protolib_cache *self = data;
441 if (opt_F_get_kind(entry) != OPT_F_FILE)
444 struct protolib *new_import
445 = protolib_cache_file(self, entry->pathname, 0);
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
458 protolib_cache_init(struct protolib_cache *cache, struct protolib *import)
460 DICT_INIT(&cache->protolibs, char *, struct protolib *,
461 dict_hash_string, dict_eq_string, NULL);
462 protolib_init(&cache->imports);
464 /* At this point the cache is consistent. This is important,
465 * because next we will use it to cache files that we load
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
472 cache->bootstrap = 1;
474 if (protolib_add_import(&cache->imports, &legacy_typedefs) < 0
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);
484 cache->bootstrap = 0;
488 static enum callback_status
489 add_import_cb(struct protolib **importp, void *data)
491 struct protolib *plib = data;
492 if (protolib_add_import(plib, *importp) < 0)
498 static struct protolib *
499 build_default_config(struct protolib_cache *cache, const char *key)
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));
508 protolib_init(new_plib);
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)) {
520 "Couldn't add imports to config module %s: %s\n",
521 key, strerror(errno));
522 protolib_destroy(new_plib);
531 attempt_to_cache(struct protolib_cache *cache,
532 const char *key, struct protolib *plib)
534 if (protolib_cache_protolib(cache, key, 1, plib) == 0
536 /* Never mind failing to store a NULL. */
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);
547 protolib_cache_maybe_load(struct protolib_cache *cache,
548 const char *key, int own_key, bool allow_private,
549 struct protolib **retp)
551 if (DICT_FIND_VAL(&cache->protolibs, &key, retp) == 0)
554 if (strdup_if(&key, key, !own_key) < 0) {
555 fprintf(stderr, "Couldn't cache %s: %s\n",
556 key, strerror(errno));
561 if (load_dash_F_dirs(cache, key, retp) < 0
562 || (*retp == NULL && allow_private
563 && load_config(cache, key, 1, retp) < 0)
565 && load_config(cache, key, 0, retp) < 0))
570 "Error occurred when attempting to load a prototype "
571 "library for %s.\n", key);
576 attempt_to_cache(cache, key, *retp);
584 protolib_cache_load(struct protolib_cache *cache,
585 const char *key, int own_key, bool allow_private)
587 struct protolib *plib;
588 if (protolib_cache_maybe_load(cache, key, own_key,
589 allow_private, &plib) < 0)
593 plib = protolib_cache_default(cache, key, own_key);
599 protolib_cache_default(struct protolib_cache *cache,
600 const char *key, int own_key)
602 if (strdup_if(&key, key, !own_key) < 0) {
603 fprintf(stderr, "Couldn't cache default %s: %s\n",
604 key, strerror(errno));
608 struct protolib *plib = build_default_config(cache, key);
610 /* Whatever came out of this (even NULL), store it in
612 attempt_to_cache(cache, key, plib);
618 protolib_cache_file(struct protolib_cache *cache,
619 const char *filename, int own_filename)
622 struct protolib *plib;
623 if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
627 FILE *stream = fopen(filename, "r");
631 if (strdup_if(&filename, filename, !own_filename) < 0) {
632 fprintf(stderr, "Couldn't cache %s: %s\n",
633 filename, strerror(errno));
638 struct protolib *new_plib = build_default_config(cache, filename);
640 || read_config_file(stream, filename, new_plib) < 0) {
643 free((char *) filename);
644 if (new_plib != NULL) {
645 protolib_destroy(new_plib);
651 attempt_to_cache(cache, filename, new_plib);
657 protolib_cache_protolib(struct protolib_cache *cache,
658 const char *filename, int own_filename,
659 struct protolib *plib)
661 if (strdup_if(&filename, filename, !own_filename) < 0) {
662 fprintf(stderr, "Couldn't cache %s: %s\n",
663 filename, strerror(errno));
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)
676 destroy_global_config(void)
678 protolib_cache_destroy(&g_protocache);
679 protolib_destroy(&legacy_typedefs);
683 init_global_config(void)
685 protolib_init(&legacy_typedefs);
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);
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,
695 || protolib_add_named_type(&legacy_typedefs, "file", 0,
696 &voidptr_type) < 0) {
698 "Couldn't initialize aliases `addr' and `file'.\n");
703 if (protolib_cache_init(&g_protocache, NULL) < 0) {
704 fprintf(stderr, "Couldn't init prototype cache\n");
708 atexit(destroy_global_config);