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