library.c revision 4b4dff4c810ebaccb1e36e1b3e9d69cd793ebde1
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 "callback.h" 29#include "debug.h" 30#include "dict.h" 31#include "backend.h" // for arch_library_symbol_init, arch_library_init 32 33#ifndef ARCH_HAVE_LIBRARY_DATA 34void 35arch_library_init(struct library *lib) 36{ 37} 38 39void 40arch_library_destroy(struct library *lib) 41{ 42} 43 44void 45arch_library_clone(struct library *retp, struct library *lib) 46{ 47} 48#endif 49 50#ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA 51int 52arch_library_symbol_init(struct library_symbol *libsym) 53{ 54 return 0; 55} 56 57void 58arch_library_symbol_destroy(struct library_symbol *libsym) 59{ 60} 61 62int 63arch_library_symbol_clone(struct library_symbol *retp, 64 struct library_symbol *libsym) 65{ 66 return 0; 67} 68#endif 69 70unsigned int 71target_address_hash(const void *key) 72{ 73 /* XXX this assumes that key is passed by value. */ 74 union { 75 arch_addr_t addr; 76 unsigned int ints[sizeof(arch_addr_t) 77 / sizeof(unsigned int)]; 78 } u = { .addr = (arch_addr_t)key }; 79 80 size_t i; 81 unsigned int h = 0; 82 for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i) 83 h ^= dict_key2hash_int((void *)(uintptr_t)u.ints[i]); 84 return h; 85} 86 87int 88target_address_cmp(const void *key1, const void *key2) 89{ 90 /* XXX this assumes that key is passed by value. */ 91 arch_addr_t addr1 = (arch_addr_t)key1; 92 arch_addr_t addr2 = (arch_addr_t)key2; 93 return addr1 < addr2 ? 1 94 : addr1 > addr2 ? -1 : 0; 95} 96 97/* If the other symbol owns the name, we need to make the copy, so 98 * that the life-times of the two symbols are not dependent on each 99 * other. */ 100static int 101strdup_if_owned(const char **retp, const char *str, int owned) 102{ 103 if (!owned || str == NULL) { 104 *retp = str; 105 return 0; 106 } else { 107 *retp = strdup(str); 108 return *retp != NULL ? 0 : -1; 109 } 110} 111 112static void 113private_library_symbol_init(struct library_symbol *libsym, 114 arch_addr_t addr, 115 const char *name, int own_name, 116 enum toplt type_of_plt, 117 int latent, int delayed) 118{ 119 libsym->next = NULL; 120 libsym->lib = NULL; 121 libsym->plt_type = type_of_plt; 122 libsym->name = name; 123 libsym->own_name = own_name; 124 libsym->latent = latent; 125 libsym->delayed = delayed; 126 libsym->enter_addr = (void *)(uintptr_t)addr; 127} 128 129static void 130private_library_symbol_destroy(struct library_symbol *libsym) 131{ 132 library_symbol_set_name(libsym, NULL, 0); 133} 134 135int 136library_symbol_init(struct library_symbol *libsym, 137 arch_addr_t addr, const char *name, int own_name, 138 enum toplt type_of_plt) 139{ 140 private_library_symbol_init(libsym, addr, name, own_name, 141 type_of_plt, 0, 0); 142 143 /* If arch init fails, we've already set libsym->name and 144 * own_name. But we return failure, and the client code isn't 145 * supposed to call library_symbol_destroy in such a case. */ 146 return arch_library_symbol_init(libsym); 147} 148 149void 150library_symbol_destroy(struct library_symbol *libsym) 151{ 152 if (libsym != NULL) { 153 private_library_symbol_destroy(libsym); 154 arch_library_symbol_destroy(libsym); 155 } 156} 157 158int 159library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym) 160{ 161 const char *name; 162 if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0) 163 return -1; 164 165 private_library_symbol_init(retp, libsym->enter_addr, 166 name, libsym->own_name, libsym->plt_type, 167 libsym->latent, libsym->delayed); 168 169 if (arch_library_symbol_clone(retp, libsym) < 0) { 170 private_library_symbol_destroy(retp); 171 return -1; 172 } 173 174 return 0; 175} 176 177int 178library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 179{ 180 if (a->enter_addr < b->enter_addr) 181 return -1; 182 if (a->enter_addr > b->enter_addr) 183 return 1; 184 if (a->name != NULL && b->name != NULL) 185 return strcmp(a->name, b->name); 186 if (a->name == NULL) { 187 if (b->name == NULL) 188 return 0; 189 return -1; 190 } 191 return 1; 192} 193 194void 195library_symbol_set_name(struct library_symbol *libsym, 196 const char *name, int own_name) 197{ 198 if (libsym->own_name) 199 free((char *)libsym->name); 200 libsym->name = name; 201 libsym->own_name = own_name; 202} 203 204enum callback_status 205library_symbol_equal_cb(struct library_symbol *libsym, void *u) 206{ 207 struct library_symbol *standard = u; 208 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 209} 210 211enum callback_status 212library_symbol_named_cb(struct library_symbol *libsym, void *name) 213{ 214 return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT; 215} 216 217static void 218private_library_init(struct library *lib, enum library_type type) 219{ 220 lib->next = NULL; 221 222 lib->key = 0; 223 lib->base = 0; 224 lib->entry = 0; 225 lib->dyn_addr = 0; 226 227 lib->soname = NULL; 228 lib->own_soname = 0; 229 230 lib->pathname = NULL; 231 lib->own_pathname = 0; 232 233 lib->symbols = NULL; 234 lib->exported_names = NULL; 235 lib->type = type; 236} 237 238void 239library_init(struct library *lib, enum library_type type) 240{ 241 private_library_init(lib, type); 242 arch_library_init(lib); 243} 244 245static int 246library_exported_name_clone(struct library_exported_name *retp, 247 struct library_exported_name *exnm) 248{ 249 char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name; 250 if (name == NULL) 251 return -1; 252 retp->name = name; 253 retp->own_name = exnm->own_name; 254 return 0; 255} 256 257int 258library_clone(struct library *retp, struct library *lib) 259{ 260 const char *soname = NULL; 261 const char *pathname; 262 if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0 263 || strdup_if_owned(&pathname, 264 lib->pathname, lib->own_pathname) < 0) { 265 if (lib->own_soname) 266 free((char *)soname); 267 return -1; 268 } 269 270 private_library_init(retp, lib->type); 271 library_set_soname(retp, soname, lib->own_soname); 272 library_set_soname(retp, pathname, lib->own_pathname); 273 arch_library_clone(retp, lib); 274 275 /* Clone symbols. */ 276 { 277 struct library_symbol *it; 278 struct library_symbol **nsymp = &retp->symbols; 279 for (it = lib->symbols; it != NULL; it = it->next) { 280 *nsymp = malloc(sizeof(**nsymp)); 281 if (*nsymp == NULL 282 || library_symbol_clone(*nsymp, it) < 0) { 283 free(*nsymp); 284 fail: 285 /* Release what we managed to allocate. */ 286 library_destroy(retp); 287 return -1; 288 } 289 290 (*nsymp)->lib = retp; 291 nsymp = &(*nsymp)->next; 292 } 293 } 294 295 /* Clone exported names. */ 296 { 297 struct library_exported_name *it; 298 struct library_exported_name **nnamep = &retp->exported_names; 299 for (it = lib->exported_names; it != NULL; it = it->next) { 300 *nnamep = malloc(sizeof(**nnamep)); 301 if (*nnamep == NULL 302 || library_exported_name_clone(*nnamep, it) < 0) { 303 free(*nnamep); 304 goto fail; 305 } 306 nnamep = &(*nnamep)->next; 307 } 308 } 309 310 return 0; 311} 312 313void 314library_destroy(struct library *lib) 315{ 316 if (lib == NULL) 317 return; 318 319 arch_library_destroy(lib); 320 library_set_soname(lib, NULL, 0); 321 library_set_pathname(lib, NULL, 0); 322 323 struct library_symbol *sym; 324 for (sym = lib->symbols; sym != NULL; ) { 325 struct library_symbol *next = sym->next; 326 library_symbol_destroy(sym); 327 free(sym); 328 sym = next; 329 } 330} 331 332void 333library_set_soname(struct library *lib, const char *new_name, int own_name) 334{ 335 if (lib->own_soname) 336 free((char *)lib->soname); 337 lib->soname = new_name; 338 lib->own_soname = own_name; 339} 340 341void 342library_set_pathname(struct library *lib, const char *new_name, int own_name) 343{ 344 if (lib->own_pathname) 345 free((char *)lib->pathname); 346 lib->pathname = new_name; 347 lib->own_pathname = own_name; 348} 349 350struct library_symbol * 351library_each_symbol(struct library *lib, struct library_symbol *start_after, 352 enum callback_status (*cb)(struct library_symbol *, void *), 353 void *data) 354{ 355 struct library_symbol *it = start_after == NULL ? lib->symbols 356 : start_after->next; 357 358 while (it != NULL) { 359 struct library_symbol *next = it->next; 360 361 switch ((*cb)(it, data)) { 362 case CBS_FAIL: 363 /* XXX handle me */ 364 case CBS_STOP: 365 return it; 366 case CBS_CONT: 367 break; 368 } 369 370 it = next; 371 } 372 373 return NULL; 374} 375 376void 377library_add_symbol(struct library *lib, struct library_symbol *first) 378{ 379 struct library_symbol *last; 380 for (last = first; last != NULL; ) { 381 last->lib = lib; 382 if (last->next != NULL) 383 last = last->next; 384 else 385 break; 386 } 387 388 assert(last->next == NULL); 389 last->next = lib->symbols; 390 lib->symbols = first; 391} 392 393enum callback_status 394library_named_cb(struct Process *proc, struct library *lib, void *name) 395{ 396 if (name == lib->soname 397 || strcmp(lib->soname, (char *)name) == 0) 398 return CBS_STOP; 399 else 400 return CBS_CONT; 401} 402 403enum callback_status 404library_with_key_cb(struct Process *proc, struct library *lib, void *keyp) 405{ 406 return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT; 407} 408