library.c revision e8d9076a97f6617868466a99bd18e11e3f6389ac
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2001,2009 Juan Cespedes 5 * Copyright (C) 2006 Ian Wienand 6 * 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. 11 * 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. 16 * 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 20 * 02110-1301 USA 21 */ 22 23#include <stdlib.h> 24#include <string.h> 25#include <assert.h> 26 27#include "library.h" 28#include "proc.h" // for enum callback_status 29#include "debug.h" 30 31unsigned int 32target_address_hash(const void *key) 33{ 34 /* XXX this assumes that key is passed by value. */ 35 union { 36 target_address_t addr; 37 unsigned int ints[sizeof(target_address_t) 38 / sizeof(unsigned int)]; 39 } u = { .addr = (target_address_t)key }; 40 41 size_t i; 42 unsigned int h = 0; 43 for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i) 44 h ^= dict_key2hash_int(u.ints + i); 45 return h; 46} 47 48int 49target_address_cmp(const void *key1, const void *key2) 50{ 51 /* XXX this assumes that key is passed by value. */ 52 target_address_t addr1 = (target_address_t)key1; 53 target_address_t addr2 = (target_address_t)key2; 54 return addr1 < addr2 ? 1 55 : addr1 > addr2 ? -1 : 0; 56} 57 58/* If the other symbol owns the name, we need to make the copy, so 59 * that the life-times of the two symbols are not dependent on each 60 * other. */ 61static int 62strdup_if_owned(const char **retp, const char *str, int owned) 63{ 64 if (!owned || str == NULL) { 65 *retp = str; 66 return 0; 67 } else { 68 *retp = strdup(str); 69 return *retp != NULL ? 0 : -1; 70 } 71} 72 73void 74private_library_symbol_init(struct library_symbol *libsym, 75 target_address_t addr, 76 const char *name, int own_name, 77 enum toplt type_of_plt) 78{ 79 libsym->next = NULL; 80 libsym->lib = NULL; 81 libsym->plt_type = type_of_plt; 82 libsym->name = name; 83 libsym->own_name = own_name; 84 libsym->enter_addr = (void *)(uintptr_t)addr; 85} 86 87int 88library_symbol_init(struct library_symbol *libsym, 89 target_address_t addr, const char *name, int own_name, 90 enum toplt type_of_plt) 91{ 92 private_library_symbol_init(libsym, addr, name, own_name, type_of_plt); 93 return 0; 94 95} 96 97void 98library_symbol_destroy(struct library_symbol *libsym) 99{ 100 if (libsym != NULL) 101 library_symbol_set_name(libsym, NULL, 0); 102} 103 104int 105library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym) 106{ 107 const char *name; 108 if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0) 109 return -1; 110 111 private_library_symbol_init(retp, libsym->enter_addr, 112 name, libsym->own_name, libsym->plt_type); 113 return 0; 114} 115 116int 117library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 118{ 119 if (a->enter_addr < b->enter_addr) 120 return -1; 121 if (a->enter_addr > b->enter_addr) 122 return 1; 123 if (a->name != NULL && b->name != NULL) 124 return strcmp(a->name, b->name); 125 if (a->name == NULL) { 126 if (b->name == NULL) 127 return 0; 128 return -1; 129 } 130 return 1; 131} 132 133void 134library_symbol_set_name(struct library_symbol *libsym, 135 const char *name, int own_name) 136{ 137 if (libsym->own_name) 138 free((char *)libsym->name); 139 libsym->name = name; 140 libsym->own_name = own_name; 141} 142 143enum callback_status 144library_symbol_equal_cb(struct library_symbol *libsym, void *u) 145{ 146 struct library_symbol *standard = u; 147 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 148} 149 150void 151library_init(struct library *lib, enum library_type type) 152{ 153 lib->next = NULL; 154 lib->soname = NULL; 155 lib->own_soname = 0; 156 lib->pathname = NULL; 157 lib->own_pathname = 0; 158 lib->symbols = NULL; 159 lib->type = type; 160} 161 162int 163library_clone(struct library *retp, struct library *lib) 164{ 165 const char *soname = NULL; 166 const char *pathname; 167 if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0 168 || strdup_if_owned(&pathname, 169 lib->pathname, lib->own_pathname) < 0) { 170 if (lib->own_soname) 171 free((char *)soname); 172 return -1; 173 } 174 175 library_init(retp, lib->type); 176 library_set_soname(retp, soname, lib->own_soname); 177 library_set_soname(retp, pathname, lib->own_pathname); 178 179 struct library_symbol *it; 180 struct library_symbol **nsymp = &retp->symbols; 181 for (it = lib->symbols; it != NULL; it = it->next) { 182 *nsymp = malloc(sizeof(**nsymp)); 183 if (*nsymp == NULL 184 || library_symbol_clone(*nsymp, it) < 0) { 185 /* Release what we managed to allocate. */ 186 library_destroy(retp); 187 return -1; 188 } 189 190 (*nsymp)->lib = retp; 191 nsymp = &(*nsymp)->next; 192 } 193 return 0; 194} 195 196void 197library_destroy(struct library *lib) 198{ 199 if (lib == NULL) 200 return; 201 library_set_soname(lib, NULL, 0); 202 library_set_pathname(lib, NULL, 0); 203 204 struct library_symbol *sym; 205 for (sym = lib->symbols; sym != NULL; ) { 206 struct library_symbol *next = sym->next; 207 library_symbol_destroy(sym); 208 free(sym); 209 sym = next; 210 } 211} 212 213void 214library_set_soname(struct library *lib, const char *new_name, int own_name) 215{ 216 if (lib->own_soname) 217 free((char *)lib->soname); 218 lib->soname = new_name; 219 lib->own_soname = own_name; 220} 221 222void 223library_set_pathname(struct library *lib, const char *new_name, int own_name) 224{ 225 if (lib->own_pathname) 226 free((char *)lib->pathname); 227 lib->pathname = new_name; 228 lib->own_pathname = own_name; 229} 230 231struct library_symbol * 232library_each_symbol(struct library *lib, struct library_symbol *start_after, 233 enum callback_status (*cb)(struct library_symbol *, void *), 234 void *data) 235{ 236 struct library_symbol *it = start_after == NULL ? lib->symbols 237 : start_after->next; 238 239 while (it != NULL) { 240 struct library_symbol *next = it->next; 241 242 switch ((*cb)(it, data)) { 243 case CBS_FAIL: 244 /* XXX handle me */ 245 case CBS_STOP: 246 return it; 247 case CBS_CONT: 248 break; 249 } 250 251 it = next; 252 } 253 254 return NULL; 255} 256 257void 258library_add_symbol(struct library *lib, struct library_symbol *first) 259{ 260 struct library_symbol *last; 261 for (last = first; last != NULL; ) { 262 last->lib = lib; 263 if (last->next != NULL) 264 last = last->next; 265 else 266 break; 267 } 268 269 assert(last->next == NULL); 270 last->next = lib->symbols; 271 lib->symbols = first; 272} 273 274enum callback_status 275library_named_cb(struct Process *proc, struct library *lib, void *name) 276{ 277 if (name == lib->soname 278 || strcmp(lib->soname, (char *)name) == 0) 279 return CBS_STOP; 280 else 281 return CBS_CONT; 282} 283 284enum callback_status 285library_with_key_cb(struct Process *proc, struct library *lib, void *keyp) 286{ 287 return lib->key == *(target_address_t *)keyp ? CBS_STOP : CBS_CONT; 288} 289