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, ¶m_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 ¶m_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