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