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