library.c revision 157cc4d6ee93f35e3aa65edcf57f369ae4e4677c
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 31/* If the other symbol owns the name, we need to make the copy, so 32 * that the life-times of the two symbols are not dependent on each 33 * other. */ 34static int 35strdup_if_owned(const char **retp, const char *str, int owned) 36{ 37 if (!owned || str == NULL) { 38 *retp = str; 39 return 0; 40 } else { 41 *retp = strdup(str); 42 return *retp != NULL ? 0 : -1; 43 } 44} 45 46void 47library_symbol_init(struct library_symbol *libsym, 48 target_address_t addr, const char *name, int own_name, 49 enum toplt type_of_plt) 50{ 51 libsym->next = NULL; 52 libsym->lib = NULL; 53 libsym->plt_type = type_of_plt; 54 libsym->name = name; 55 libsym->own_name = own_name; 56 libsym->enter_addr = (void *)(uintptr_t)addr; 57} 58 59void 60library_symbol_destroy(struct library_symbol *libsym) 61{ 62 if (libsym != NULL) 63 library_symbol_set_name(libsym, NULL, 0); 64} 65 66int 67library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym) 68{ 69 const char *name; 70 if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0) 71 return -1; 72 73 library_symbol_init(retp, libsym->enter_addr, 74 name, libsym->own_name, libsym->plt_type); 75 return 0; 76} 77 78int 79library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 80{ 81 if (a->enter_addr < b->enter_addr) 82 return -1; 83 if (a->enter_addr > b->enter_addr) 84 return 1; 85 if (a->name != NULL && b->name != NULL) 86 return strcmp(a->name, b->name); 87 if (a->name == NULL) { 88 if (b->name == NULL) 89 return 0; 90 return -1; 91 } 92 return 1; 93} 94 95void 96library_symbol_set_name(struct library_symbol *libsym, 97 const char *name, int own_name) 98{ 99 if (libsym->own_name) 100 free((char *)libsym->name); 101 libsym->name = name; 102 libsym->own_name = own_name; 103} 104 105enum callback_status 106library_symbol_equal_cb(struct library_symbol *libsym, void *u) 107{ 108 struct library_symbol *standard = u; 109 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 110} 111 112void 113library_init(struct library *lib, enum library_type type) 114{ 115 lib->next = NULL; 116 lib->soname = NULL; 117 lib->own_soname = 0; 118 lib->pathname = NULL; 119 lib->own_pathname = 0; 120 lib->symbols = NULL; 121 lib->type = type; 122} 123 124int 125library_clone(struct library *retp, struct library *lib) 126{ 127 const char *soname = NULL; 128 const char *pathname; 129 if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0 130 || strdup_if_owned(&pathname, 131 lib->pathname, lib->own_pathname) < 0) { 132 if (lib->own_soname) 133 free((char *)soname); 134 return -1; 135 } 136 137 library_init(retp, lib->type); 138 library_set_soname(retp, soname, lib->own_soname); 139 library_set_soname(retp, pathname, lib->own_pathname); 140 141 struct library_symbol *it; 142 struct library_symbol **nsymp = &retp->symbols; 143 for (it = lib->symbols; it != NULL; it = it->next) { 144 *nsymp = malloc(sizeof(**nsymp)); 145 if (*nsymp == NULL 146 || library_symbol_clone(*nsymp, it) < 0) { 147 /* Release what we managed to allocate. */ 148 library_destroy(retp); 149 return -1; 150 } 151 152 (*nsymp)->lib = retp; 153 nsymp = &(*nsymp)->next; 154 } 155 return 0; 156} 157 158void 159library_destroy(struct library *lib) 160{ 161 if (lib == NULL) 162 return; 163 library_set_soname(lib, NULL, 0); 164 library_set_pathname(lib, NULL, 0); 165 166 struct library_symbol *sym; 167 for (sym = lib->symbols; sym != NULL; ) { 168 struct library_symbol *next = sym->next; 169 library_symbol_destroy(sym); 170 free(sym); 171 sym = next; 172 } 173} 174 175void 176library_set_soname(struct library *lib, const char *new_name, int own_name) 177{ 178 if (lib->own_soname) 179 free((char *)lib->soname); 180 lib->soname = new_name; 181 lib->own_soname = own_name; 182} 183 184void 185library_set_pathname(struct library *lib, const char *new_name, int own_name) 186{ 187 if (lib->own_pathname) 188 free((char *)lib->pathname); 189 lib->pathname = new_name; 190 lib->own_pathname = own_name; 191} 192 193struct library_symbol * 194library_each_symbol(struct library *lib, struct library_symbol *start_after, 195 enum callback_status (*cb)(struct library_symbol *, void *), 196 void *data) 197{ 198 struct library_symbol *it = start_after == NULL ? lib->symbols 199 : start_after->next; 200 201 while (it != NULL) { 202 struct library_symbol *next = it->next; 203 204 switch ((*cb)(it, data)) { 205 case CBS_FAIL: 206 /* XXX handle me */ 207 case CBS_STOP: 208 return it; 209 case CBS_CONT: 210 break; 211 } 212 213 it = next; 214 } 215 216 return NULL; 217} 218 219void 220library_add_symbol(struct library *lib, struct library_symbol *first) 221{ 222 struct library_symbol *last; 223 for (last = first; last != NULL; ) { 224 last->lib = lib; 225 if (last->next != NULL) 226 last = last->next; 227 else 228 break; 229 } 230 231 assert(last->next == NULL); 232 last->next = lib->symbols; 233 lib->symbols = first; 234} 235 236enum callback_status 237library_named_cb(struct Process *proc, struct library *lib, void *name) 238{ 239 if (name == lib->soname 240 || strcmp(lib->soname, (char *)name) == 0) 241 return CBS_STOP; 242 else 243 return CBS_CONT; 244} 245 246enum callback_status 247library_with_key_cb(struct Process *proc, struct library *lib, void *keyp) 248{ 249 return lib->key == *(target_address_t *)keyp ? CBS_STOP : CBS_CONT; 250} 251