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