2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013,2014 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
35 #include "backend.h" // for arch_library_symbol_init, arch_library_init
38 library_exported_names_init(struct library_exported_names *names);
40 #ifndef OS_HAVE_LIBRARY_DATA
42 os_library_init(struct library *lib)
48 os_library_destroy(struct library *lib)
53 os_library_clone(struct library *retp, struct library *lib)
59 #ifndef ARCH_HAVE_LIBRARY_DATA
61 arch_library_init(struct library *lib)
67 arch_library_destroy(struct library *lib)
72 arch_library_clone(struct library *retp, struct library *lib)
78 #ifndef OS_HAVE_LIBRARY_SYMBOL_DATA
80 os_library_symbol_init(struct library_symbol *libsym)
86 os_library_symbol_destroy(struct library_symbol *libsym)
91 os_library_symbol_clone(struct library_symbol *retp,
92 struct library_symbol *libsym)
98 #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
100 arch_library_symbol_init(struct library_symbol *libsym)
106 arch_library_symbol_destroy(struct library_symbol *libsym)
111 arch_library_symbol_clone(struct library_symbol *retp,
112 struct library_symbol *libsym)
119 arch_addr_hash(const arch_addr_t *addr)
123 int ints[sizeof(arch_addr_t)
124 / sizeof(unsigned int)];
125 } u = { .addr = *addr };
129 for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
130 h ^= dict_hash_int(&u.ints[i]);
135 arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
137 return *addr1 == *addr2;
141 strdup_if(const char **retp, const char *str, int whether)
143 if (whether && str != NULL) {
154 private_library_symbol_init(struct library_symbol *libsym,
156 const char *name, int own_name,
157 enum toplt type_of_plt,
158 int latent, int delayed)
162 libsym->plt_type = type_of_plt;
164 libsym->own_name = own_name;
165 libsym->latent = latent;
166 libsym->delayed = delayed;
167 libsym->enter_addr = (void *)(uintptr_t)addr;
168 libsym->proto = NULL;
172 private_library_symbol_destroy(struct library_symbol *libsym)
174 library_symbol_set_name(libsym, NULL, 0);
178 library_symbol_init(struct library_symbol *libsym,
179 arch_addr_t addr, const char *name, int own_name,
180 enum toplt type_of_plt)
182 private_library_symbol_init(libsym, addr, name, own_name,
185 if (os_library_symbol_init(libsym) < 0)
186 /* We've already set libsym->name and own_name. But
187 * we return failure, and the client code isn't
188 * supposed to call library_symbol_destroy in such
192 if (arch_library_symbol_init(libsym) < 0) {
193 os_library_symbol_destroy(libsym);
201 library_symbol_destroy(struct library_symbol *libsym)
203 if (libsym != NULL) {
204 arch_library_symbol_destroy(libsym);
205 os_library_symbol_destroy(libsym);
206 private_library_symbol_destroy(libsym);
211 library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
213 /* Make lifetimes of name stored at original independent of
214 * the one at the clone. */
216 if (strdup_if(&name, libsym->name, libsym->own_name) < 0)
219 private_library_symbol_init(retp, libsym->enter_addr,
220 name, libsym->own_name, libsym->plt_type,
221 libsym->latent, libsym->delayed);
223 if (os_library_symbol_clone(retp, libsym) < 0) {
225 private_library_symbol_destroy(retp);
229 if (arch_library_symbol_clone(retp, libsym) < 0) {
230 os_library_symbol_destroy(retp);
238 library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
240 if (a->enter_addr < b->enter_addr)
242 if (a->enter_addr > b->enter_addr)
244 if (a->name != NULL && b->name != NULL)
245 return strcmp(a->name, b->name);
246 if (a->name == NULL) {
255 library_symbol_set_name(struct library_symbol *libsym,
256 const char *name, int own_name)
258 if (libsym->own_name)
259 free((char *)libsym->name);
261 libsym->own_name = own_name;
265 library_symbol_equal_cb(struct library_symbol *libsym, void *u)
267 struct library_symbol *standard = u;
268 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
272 library_symbol_named_cb(struct library_symbol *libsym, void *name)
274 return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
278 library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
280 return libsym->delayed ? CBS_STOP : CBS_CONT;
284 private_library_init(struct library *lib, enum library_type type)
292 lib->protolib = NULL;
297 lib->pathname = NULL;
298 lib->own_pathname = 0;
301 library_exported_names_init(&lib->exported_names);
302 lib->should_activate_latent = false;
305 #if defined(HAVE_LIBDW)
306 lib->dwfl_module = NULL;
311 library_init(struct library *lib, enum library_type type)
313 private_library_init(lib, type);
315 if (os_library_init(lib) < 0)
318 if (arch_library_init(lib) < 0) {
319 os_library_destroy(lib);
330 static void dtor_string(const char **tgt, void *data)
334 static int clone_vect(struct vect **to, const struct vect **from, void *data)
336 *to = malloc(sizeof(struct vect));
341 VECT_CLONE(*to, *from, const char*,
346 static void dtor_vect(struct vect **tgt, void *data)
348 VECT_DESTROY(*tgt, const char*, dtor_string, NULL);
353 library_exported_names_init(struct library_exported_names *names)
355 DICT_INIT(&names->names,
356 const char*, uint64_t,
357 dict_hash_string, dict_eq_string, NULL);
358 DICT_INIT(&names->addrs,
359 uint64_t, struct vect*,
360 dict_hash_uint64, dict_eq_uint64, NULL);
364 library_exported_names_destroy(struct library_exported_names *names)
366 DICT_DESTROY(&names->names,
367 const char*, uint64_t,
368 dtor_string, NULL, NULL);
369 DICT_DESTROY(&names->addrs,
370 uint64_t, struct vect*,
371 NULL, dtor_vect, NULL);
375 library_exported_names_clone(struct library_exported_names *retp,
376 const struct library_exported_names *names)
378 return (DICT_CLONE(&retp->names, &names->names,
379 const char*, uint64_t,
380 dict_clone_string, dtor_string,
383 DICT_CLONE(&retp->addrs, &names->addrs,
384 uint64_t, struct vect*,
386 clone_vect, dtor_vect,
390 int library_exported_names_push(struct library_exported_names *names,
391 uint64_t addr, char *name,
394 // first, take ownership of the name, if it's not yet ours
400 // push to the name->addr map
401 int result = DICT_INSERT(&names->names, &name, &addr);
403 // This symbol is already present in the table. This library has
404 // multiple copies of this symbol (probably corresponding to
405 // different symbol versions). I should handle this gracefully
406 // at some point, but for now I simply ignore later instances of
407 // any particular symbol
415 // push to the addr->names map
416 // I get the alias vector. If it doesn't yet exist, I make it
417 struct vect *aliases;
418 struct vect **paliases = DICT_FIND_REF(&names->addrs,
419 &addr, struct vect*);
421 if (paliases == NULL) {
422 aliases = malloc(sizeof(struct vect));
425 VECT_INIT(aliases, const char*);
426 result = DICT_INSERT(&names->addrs, &addr, &aliases);
434 char *namedup = strdup(name);
438 result = vect_pushback(aliases, &namedup);
447 struct library_exported_names_each_alias_context
449 enum callback_status (*inner_cb)(const char *, void *);
450 const char *origname;
453 static enum callback_status
454 library_exported_names_each_alias_cb(const char **name, void *data)
456 struct library_exported_names_each_alias_context *context =
457 (struct library_exported_names_each_alias_context*)data;
459 // I do not report the original name we were asked about. Otherwise, any
460 // time the caller asks for aliases of symbol "sym", I'll always report
461 // "sym" along with any actual aliases
462 if (strcmp(*name, context->origname) == 0)
465 return context->inner_cb(*name, context->data);
468 const char** library_exported_names_each_alias(
469 struct library_exported_names *names,
470 const char *aliasname,
471 const char **name_start_after,
472 enum callback_status (*cb)(const char *,
476 // I have a symbol name. I look up its address, then get the list of
478 uint64_t *addr = DICT_FIND_REF(&names->names,
479 &aliasname, uint64_t);
483 // OK. I have an address. Get the list of symbols at this address
484 struct vect **aliases = DICT_FIND_REF(&names->addrs,
486 assert(aliases != NULL);
488 struct library_exported_names_each_alias_context context =
490 .origname = aliasname,
492 return VECT_EACH(*aliases, const char*, name_start_after,
493 library_exported_names_each_alias_cb, &context);
496 int library_exported_names_contains(struct library_exported_names *names,
497 const char *queryname)
499 uint64_t *addr = DICT_FIND_REF(&names->names,
500 &queryname, uint64_t);
501 return (addr == NULL) ? 0 : 1;
509 library_clone(struct library *retp, struct library *lib)
511 const char *soname = NULL;
512 const char *pathname;
514 /* Make lifetimes of strings stored at original independent of
515 * those at the clone. */
516 if (strdup_if(&soname, lib->soname, lib->own_soname) < 0
517 || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) {
519 free((char *)soname);
523 private_library_init(retp, lib->type);
524 library_set_soname(retp, soname, lib->own_soname);
525 library_set_pathname(retp, pathname, lib->own_pathname);
527 retp->key = lib->key;
528 retp->should_activate_latent = lib->should_activate_latent;
532 struct library_symbol *it;
533 struct library_symbol **nsymp = &retp->symbols;
534 for (it = lib->symbols; it != NULL; it = it->next) {
535 *nsymp = malloc(sizeof(**nsymp));
537 || library_symbol_clone(*nsymp, it) < 0) {
541 /* Release what we managed to allocate. */
542 library_destroy(retp);
546 (*nsymp)->lib = retp;
547 nsymp = &(*nsymp)->next;
552 /* Clone exported names. */
553 if (library_exported_names_clone(&retp->exported_names,
554 &lib->exported_names) != 0)
557 if (os_library_clone(retp, lib) < 0)
560 if (arch_library_clone(retp, lib) < 0) {
561 os_library_destroy(retp);
565 #if defined(HAVE_LIBDW)
566 /* Wipe DWFL_MODULE, leave it to proc_add_library to
568 lib->dwfl_module = NULL;
575 library_destroy(struct library *lib)
580 arch_library_destroy(lib);
581 os_library_destroy(lib);
583 library_set_soname(lib, NULL, 0);
584 library_set_pathname(lib, NULL, 0);
586 struct library_symbol *sym;
587 for (sym = lib->symbols; sym != NULL; ) {
588 struct library_symbol *next = sym->next;
589 library_symbol_destroy(sym);
594 /* Release exported names. */
595 library_exported_names_destroy(&lib->exported_names);
599 library_set_soname(struct library *lib, const char *new_name, int own_name)
602 free((char *)lib->soname);
603 lib->soname = new_name;
604 lib->own_soname = own_name;
608 library_set_pathname(struct library *lib, const char *new_name, int own_name)
610 if (lib->own_pathname)
611 free((char *)lib->pathname);
612 lib->pathname = new_name;
613 lib->own_pathname = own_name;
616 struct library_symbol *
617 library_each_symbol(struct library *lib, struct library_symbol *start_after,
618 enum callback_status (*cb)(struct library_symbol *, void *),
621 struct library_symbol *it = start_after == NULL ? lib->symbols
625 struct library_symbol *next = it->next;
627 switch ((*cb)(it, data)) {
643 library_add_symbol(struct library *lib, struct library_symbol *first)
645 struct library_symbol *last;
646 for (last = first; last != NULL; ) {
648 if (last->next != NULL)
654 assert(last->next == NULL);
655 last->next = lib->symbols;
656 lib->symbols = first;
660 library_named_cb(struct process *proc, struct library *lib, void *name)
662 if (name == lib->soname
663 || strcmp(lib->soname, (char *)name) == 0)
670 library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
672 return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;