Home | History | Annotate | Download | only in ltrace
      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
     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
     49 param_destroy_cb(struct param *param, void *data)
     50 {
     51 	param_destroy(param);
     52 }
     53 
     54 void
     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
     68 prototype_push_param(struct prototype *proto, struct param *param)
     69 {
     70 	return VECT_PUSHBACK(&proto->params, param);
     71 }
     72 
     73 size_t
     74 prototype_num_params(struct prototype *proto)
     75 {
     76 	return vect_size(&proto->params);
     77 }
     78 
     79 void
     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 *
     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
    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 *
    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
    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
    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
    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
    151 destroy_prototype_cb(struct prototype *proto, void *data)
    152 {
    153 	prototype_destroy(proto);
    154 }
    155 
    156 static void
    157 destroy_named_type_cb(struct named_type *named, void *data)
    158 {
    159 	named_type_destroy(named);
    160 }
    161 
    162 void
    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 **
    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
    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
    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
    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
    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
    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 *
    253 get_prototypes(struct protolib *plib)
    254 {
    255 	assert(plib != NULL);
    256 	return &plib->prototypes;
    257 }
    258 
    259 static struct dict *
    260 get_named_types(struct protolib *plib)
    261 {
    262 	assert(plib != NULL);
    263 	return &plib->named_types;
    264 }
    265 
    266 static enum callback_status
    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 *
    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 *
    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 *
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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 *
    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 *
    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 *
    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
    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
    675 destroy_global_config(void)
    676 {
    677 	protolib_cache_destroy(&g_protocache);
    678 	protolib_destroy(&legacy_typedefs);
    679 }
    680 
    681 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