library.c revision a24021c5abfa8c2482e3224f14ac191cd0826a8f
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{ 118 libsym->next = NULL; 119 libsym->lib = NULL; 120 libsym->plt_type = type_of_plt; 121 libsym->name = name; 122 libsym->own_name = own_name; 123 libsym->enter_addr = (void *)(uintptr_t)addr; 124} 125 126static void 127private_library_symbol_destroy(struct library_symbol *libsym) 128{ 129 library_symbol_set_name(libsym, NULL, 0); 130} 131 132int 133library_symbol_init(struct library_symbol *libsym, 134 arch_addr_t addr, const char *name, int own_name, 135 enum toplt type_of_plt) 136{ 137 private_library_symbol_init(libsym, addr, name, own_name, type_of_plt); 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 164 if (arch_library_symbol_clone(retp, libsym) < 0) { 165 private_library_symbol_destroy(retp); 166 return -1; 167 } 168 169 return 0; 170} 171 172int 173library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 174{ 175 if (a->enter_addr < b->enter_addr) 176 return -1; 177 if (a->enter_addr > b->enter_addr) 178 return 1; 179 if (a->name != NULL && b->name != NULL) 180 return strcmp(a->name, b->name); 181 if (a->name == NULL) { 182 if (b->name == NULL) 183 return 0; 184 return -1; 185 } 186 return 1; 187} 188 189void 190library_symbol_set_name(struct library_symbol *libsym, 191 const char *name, int own_name) 192{ 193 if (libsym->own_name) 194 free((char *)libsym->name); 195 libsym->name = name; 196 libsym->own_name = own_name; 197} 198 199enum callback_status 200library_symbol_equal_cb(struct library_symbol *libsym, void *u) 201{ 202 struct library_symbol *standard = u; 203 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 204} 205 206 207static void 208private_library_init(struct library *lib, enum library_type type) 209{ 210 lib->next = NULL; 211 212 lib->key = 0; 213 lib->base = 0; 214 lib->entry = 0; 215 lib->dyn_addr = 0; 216 217 lib->soname = NULL; 218 lib->own_soname = 0; 219 220 lib->pathname = NULL; 221 lib->own_pathname = 0; 222 223 lib->symbols = NULL; 224 lib->type = type; 225} 226 227void 228library_init(struct library *lib, enum library_type type) 229{ 230 private_library_init(lib, type); 231 arch_library_init(lib); 232} 233 234int 235library_clone(struct library *retp, struct library *lib) 236{ 237 const char *soname = NULL; 238 const char *pathname; 239 if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0 240 || strdup_if_owned(&pathname, 241 lib->pathname, lib->own_pathname) < 0) { 242 if (lib->own_soname) 243 free((char *)soname); 244 return -1; 245 } 246 247 private_library_init(retp, lib->type); 248 library_set_soname(retp, soname, lib->own_soname); 249 library_set_soname(retp, pathname, lib->own_pathname); 250 arch_library_clone(retp, lib); 251 252 struct library_symbol *it; 253 struct library_symbol **nsymp = &retp->symbols; 254 for (it = lib->symbols; it != NULL; it = it->next) { 255 *nsymp = malloc(sizeof(**nsymp)); 256 if (*nsymp == NULL 257 || library_symbol_clone(*nsymp, it) < 0) { 258 /* Release what we managed to allocate. */ 259 library_destroy(retp); 260 return -1; 261 } 262 263 (*nsymp)->lib = retp; 264 nsymp = &(*nsymp)->next; 265 } 266 return 0; 267} 268 269void 270library_destroy(struct library *lib) 271{ 272 if (lib == NULL) 273 return; 274 275 arch_library_destroy(lib); 276 library_set_soname(lib, NULL, 0); 277 library_set_pathname(lib, NULL, 0); 278 279 struct library_symbol *sym; 280 for (sym = lib->symbols; sym != NULL; ) { 281 struct library_symbol *next = sym->next; 282 library_symbol_destroy(sym); 283 free(sym); 284 sym = next; 285 } 286} 287 288void 289library_set_soname(struct library *lib, const char *new_name, int own_name) 290{ 291 if (lib->own_soname) 292 free((char *)lib->soname); 293 lib->soname = new_name; 294 lib->own_soname = own_name; 295} 296 297void 298library_set_pathname(struct library *lib, const char *new_name, int own_name) 299{ 300 if (lib->own_pathname) 301 free((char *)lib->pathname); 302 lib->pathname = new_name; 303 lib->own_pathname = own_name; 304} 305 306struct library_symbol * 307library_each_symbol(struct library *lib, struct library_symbol *start_after, 308 enum callback_status (*cb)(struct library_symbol *, void *), 309 void *data) 310{ 311 struct library_symbol *it = start_after == NULL ? lib->symbols 312 : start_after->next; 313 314 while (it != NULL) { 315 struct library_symbol *next = it->next; 316 317 switch ((*cb)(it, data)) { 318 case CBS_FAIL: 319 /* XXX handle me */ 320 case CBS_STOP: 321 return it; 322 case CBS_CONT: 323 break; 324 } 325 326 it = next; 327 } 328 329 return NULL; 330} 331 332void 333library_add_symbol(struct library *lib, struct library_symbol *first) 334{ 335 struct library_symbol *last; 336 for (last = first; last != NULL; ) { 337 last->lib = lib; 338 if (last->next != NULL) 339 last = last->next; 340 else 341 break; 342 } 343 344 assert(last->next == NULL); 345 last->next = lib->symbols; 346 lib->symbols = first; 347} 348 349enum callback_status 350library_named_cb(struct Process *proc, struct library *lib, void *name) 351{ 352 if (name == lib->soname 353 || strcmp(lib->soname, (char *)name) == 0) 354 return CBS_STOP; 355 else 356 return CBS_CONT; 357} 358 359enum callback_status 360library_with_key_cb(struct Process *proc, struct library *lib, void *keyp) 361{ 362 return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT; 363} 364