2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 2001,2009 Juan Cespedes
5 * Copyright (C) 2006 Ian Wienand
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
33 #include "backend.h" // for arch_library_symbol_init, arch_library_init
36 library_exported_names_init(struct library_exported_names *names);
38 #ifndef OS_HAVE_LIBRARY_DATA
40 os_library_init(struct library *lib)
46 os_library_destroy(struct library *lib)
51 os_library_clone(struct library *retp, struct library *lib)
57 #ifndef ARCH_HAVE_LIBRARY_DATA
59 arch_library_init(struct library *lib)
65 arch_library_destroy(struct library *lib)
70 arch_library_clone(struct library *retp, struct library *lib)
76 #ifndef OS_HAVE_LIBRARY_SYMBOL_DATA
78 os_library_symbol_init(struct library_symbol *libsym)
84 os_library_symbol_destroy(struct library_symbol *libsym)
89 os_library_symbol_clone(struct library_symbol *retp,
90 struct library_symbol *libsym)
96 #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
98 arch_library_symbol_init(struct library_symbol *libsym)
104 arch_library_symbol_destroy(struct library_symbol *libsym)
109 arch_library_symbol_clone(struct library_symbol *retp,
110 struct library_symbol *libsym)
117 arch_addr_hash(const arch_addr_t *addr)
121 int ints[sizeof(arch_addr_t)
122 / sizeof(unsigned int)];
123 } u = { .addr = *addr };
127 for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
128 h ^= dict_hash_int(&u.ints[i]);
133 arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
135 return *addr1 == *addr2;
139 strdup_if(const char **retp, const char *str, int whether)
141 if (whether && str != NULL) {
152 private_library_symbol_init(struct library_symbol *libsym,
154 const char *name, int own_name,
155 enum toplt type_of_plt,
156 int latent, int delayed)
160 libsym->plt_type = type_of_plt;
162 libsym->own_name = own_name;
163 libsym->latent = latent;
164 libsym->delayed = delayed;
165 libsym->enter_addr = (void *)(uintptr_t)addr;
166 libsym->proto = NULL;
170 private_library_symbol_destroy(struct library_symbol *libsym)
172 library_symbol_set_name(libsym, NULL, 0);
176 library_symbol_init(struct library_symbol *libsym,
177 arch_addr_t addr, const char *name, int own_name,
178 enum toplt type_of_plt)
180 private_library_symbol_init(libsym, addr, name, own_name,
183 if (os_library_symbol_init(libsym) < 0)
184 /* We've already set libsym->name and own_name. But
185 * we return failure, and the client code isn't
186 * supposed to call library_symbol_destroy in such
190 if (arch_library_symbol_init(libsym) < 0) {
191 os_library_symbol_destroy(libsym);
199 library_symbol_destroy(struct library_symbol *libsym)
201 if (libsym != NULL) {
202 arch_library_symbol_destroy(libsym);
203 os_library_symbol_destroy(libsym);
204 private_library_symbol_destroy(libsym);
209 library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
211 /* Make lifetimes of name stored at original independent of
212 * the one at the clone. */
214 if (strdup_if(&name, libsym->name, libsym->own_name) < 0)
217 private_library_symbol_init(retp, libsym->enter_addr,
218 name, libsym->own_name, libsym->plt_type,
219 libsym->latent, libsym->delayed);
221 if (os_library_symbol_clone(retp, libsym) < 0) {
223 private_library_symbol_destroy(retp);
227 if (arch_library_symbol_clone(retp, libsym) < 0) {
228 os_library_symbol_destroy(retp);
236 library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
238 if (a->enter_addr < b->enter_addr)
240 if (a->enter_addr > b->enter_addr)
242 if (a->name != NULL && b->name != NULL)
243 return strcmp(a->name, b->name);
244 if (a->name == NULL) {
253 library_symbol_set_name(struct library_symbol *libsym,
254 const char *name, int own_name)
256 if (libsym->own_name)
257 free((char *)libsym->name);
259 libsym->own_name = own_name;
263 library_symbol_equal_cb(struct library_symbol *libsym, void *u)
265 struct library_symbol *standard = u;
266 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
270 library_symbol_named_cb(struct library_symbol *libsym, void *name)
272 return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
276 library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
278 return libsym->delayed ? CBS_STOP : CBS_CONT;
282 private_library_init(struct library *lib, enum library_type type)
290 lib->protolib = NULL;
295 lib->pathname = NULL;
296 lib->own_pathname = 0;
299 library_exported_names_init(&lib->exported_names);
302 #if defined(HAVE_LIBDW)
303 lib->dwfl_module = NULL;
308 library_init(struct library *lib, enum library_type type)
310 private_library_init(lib, type);
312 if (os_library_init(lib) < 0)
315 if (arch_library_init(lib) < 0) {
316 os_library_destroy(lib);
327 static void dtor_string(const char **tgt, void *data)
331 static int clone_vect(struct vect **to, const struct vect **from, void *data)
333 *to = malloc(sizeof(struct vect));
338 VECT_CLONE(*to, *from, const char*,
343 static void dtor_vect(const struct vect **tgt, void *data)
345 VECT_DESTROY(*tgt, const char*, dtor_string, NULL);
350 library_exported_names_init(struct library_exported_names *names)
352 DICT_INIT(&names->names,
353 const char*, uint64_t,
354 dict_hash_string, dict_eq_string, NULL);
355 DICT_INIT(&names->addrs,
356 uint64_t, struct vect*,
357 dict_hash_uint64, dict_eq_uint64, NULL);
361 library_exported_names_destroy(struct library_exported_names *names)
363 DICT_DESTROY(&names->names,
364 const char*, uint64_t,
365 dtor_string, NULL, NULL);
366 DICT_DESTROY(&names->addrs,
367 uint64_t, struct vect*,
368 NULL, dtor_vect, NULL);
372 library_exported_names_clone(struct library_exported_names *retp,
373 const struct library_exported_names *names)
376 DICT_CLONE(&retp->names, &names->names,
377 const char*, uint64_t,
378 dict_clone_string, dtor_string,
381 DICT_CLONE(&retp->addrs, &names->addrs,
382 uint64_t, struct vect*,
384 clone_vect, dtor_vect,
388 int library_exported_names_push(struct library_exported_names *names,
389 uint64_t addr, const char *name,
392 // first, take ownership of the name, if it's not yet ours
398 // push to the name->addr map
399 int result = DICT_INSERT(&names->names, &name, &addr);
401 // This symbol is already present in the table. This library has
402 // multiple copies of this symbol (probably corresponding to
403 // different symbol versions). I should handle this gracefully
404 // at some point, but for now I simply ignore later instances of
405 // any particular symbol
413 // push to the addr->names map
414 // I get the alias vector. If it doesn't yet exist, I make it
415 struct vect *aliases;
416 struct vect **paliases = DICT_FIND_REF(&names->addrs,
417 &addr, struct vect*);
419 if (paliases == NULL) {
420 aliases = malloc(sizeof(struct vect));
423 VECT_INIT(aliases, const char*);
424 result = DICT_INSERT(&names->addrs, &addr, &aliases);
431 const char *namedup = strdup(name);
435 result = vect_pushback(aliases, &namedup);
442 struct library_exported_names_each_context
444 enum callback_status (*inner_cb)(const char *, void *);
448 static enum callback_status
449 library_exported_names_each_cb(const char **key, uint64_t *value, void *data)
451 struct library_exported_names_each_context *context =
452 (struct library_exported_names_each_context*)data;
453 enum callback_status status = context->inner_cb(*key, context->data);
454 if (status == CBS_FAIL)
455 context->failure = true;
458 bool library_exported_names_each(const struct library_exported_names *names,
459 enum callback_status (*cb)(const char *,
463 struct library_exported_names_each_context context =
467 DICT_EACH(&names->names,
468 const char*, uint64_t,
469 NULL, library_exported_names_each_cb, &context);
470 return !context.failure;
473 struct library_exported_names_each_alias_context
475 enum callback_status (*inner_cb)(const char *, void *);
476 const char *origname;
480 static enum callback_status
481 library_exported_names_each_alias_cb(const char **name, void *data)
483 struct library_exported_names_each_alias_context *context =
484 (struct library_exported_names_each_alias_context*)data;
486 // I do not report the original name we were asked about. Otherwise, any
487 // time the caller asks for aliases of symbol "sym", I'll always report
488 // "sym" along with any actual aliases
489 if (strcmp(*name, context->origname) == 0)
492 enum callback_status status = context->inner_cb(*name, context->data);
493 if (status == CBS_FAIL)
494 context->failure = true;
498 bool library_exported_names_each_alias(
499 const struct library_exported_names *names,
500 const char *aliasname,
501 enum callback_status (*cb)(const char *,
505 // I have a symbol name. I look up its address, then get the list of
507 uint64_t *addr = DICT_FIND_REF(&names->names,
508 &aliasname, uint64_t);
512 // OK. I have an address. Get the list of symbols at this address
513 struct vect **aliases = DICT_FIND_REF(&names->addrs,
518 struct library_exported_names_each_alias_context context =
520 .origname = aliasname,
523 VECT_EACH(*aliases, const char*, NULL,
524 library_exported_names_each_alias_cb, &context);
531 library_clone(struct library *retp, struct library *lib)
533 const char *soname = NULL;
534 const char *pathname;
536 /* Make lifetimes of strings stored at original independent of
537 * those at the clone. */
538 if (strdup_if(&soname, lib->soname, lib->own_soname) < 0
539 || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) {
541 free((char *)soname);
545 private_library_init(retp, lib->type);
546 library_set_soname(retp, soname, lib->own_soname);
547 library_set_pathname(retp, pathname, lib->own_pathname);
549 retp->key = lib->key;
553 struct library_symbol *it;
554 struct library_symbol **nsymp = &retp->symbols;
555 for (it = lib->symbols; it != NULL; it = it->next) {
556 *nsymp = malloc(sizeof(**nsymp));
558 || library_symbol_clone(*nsymp, it) < 0) {
562 /* Release what we managed to allocate. */
563 library_destroy(retp);
567 (*nsymp)->lib = retp;
568 nsymp = &(*nsymp)->next;
573 /* Clone exported names. */
574 if (library_exported_names_clone(&retp->exported_names,
575 &lib->exported_names) != 0)
578 if (os_library_clone(retp, lib) < 0)
581 if (arch_library_clone(retp, lib) < 0) {
582 os_library_destroy(retp);
590 library_destroy(struct library *lib)
595 arch_library_destroy(lib);
596 os_library_destroy(lib);
598 library_set_soname(lib, NULL, 0);
599 library_set_pathname(lib, NULL, 0);
601 struct library_symbol *sym;
602 for (sym = lib->symbols; sym != NULL; ) {
603 struct library_symbol *next = sym->next;
604 library_symbol_destroy(sym);
609 /* Release exported names. */
610 library_exported_names_destroy(&lib->exported_names);
614 library_set_soname(struct library *lib, const char *new_name, int own_name)
617 free((char *)lib->soname);
618 lib->soname = new_name;
619 lib->own_soname = own_name;
623 library_set_pathname(struct library *lib, const char *new_name, int own_name)
625 if (lib->own_pathname)
626 free((char *)lib->pathname);
627 lib->pathname = new_name;
628 lib->own_pathname = own_name;
631 struct library_symbol *
632 library_each_symbol(struct library *lib, struct library_symbol *start_after,
633 enum callback_status (*cb)(struct library_symbol *, void *),
636 struct library_symbol *it = start_after == NULL ? lib->symbols
640 struct library_symbol *next = it->next;
642 switch ((*cb)(it, data)) {
658 library_add_symbol(struct library *lib, struct library_symbol *first)
660 struct library_symbol *last;
661 for (last = first; last != NULL; ) {
663 if (last->next != NULL)
669 assert(last->next == NULL);
670 last->next = lib->symbols;
671 lib->symbols = first;
675 library_named_cb(struct process *proc, struct library *lib, void *name)
677 if (name == lib->soname
678 || strcmp(lib->soname, (char *)name) == 0)
685 library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
687 return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;