library.c revision 2b46cfc1127d390eddd9593fe5ce5399c1f68130
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 "library.h" 26#include "proc.h" // for enum callback_status 27#include "debug.h" 28 29/* If the other symbol owns the name, we need to make the copy, so 30 * that the life-times of the two symbols are not dependent on each 31 * other. */ 32static int 33strdup_if_owned(const char **retp, const char *str, int owned) 34{ 35 if (!owned || str == NULL) { 36 *retp = str; 37 return 0; 38 } else { 39 *retp = strdup(str); 40 return *retp != NULL ? 0 : -1; 41 } 42} 43 44void 45library_symbol_init(struct library_symbol *libsym, 46 GElf_Addr addr, const char *name, int own_name, 47 enum toplt type_of_plt, int is_weak) 48{ 49 libsym->needs_init = 0; 50 libsym->is_weak = is_weak; 51 libsym->plt_type = type_of_plt; 52 libsym->name = name; 53 libsym->own_name = own_name; 54 libsym->enter_addr = (void *)(uintptr_t)addr; 55 libsym->next = NULL; 56} 57 58void 59library_symbol_destroy(struct library_symbol *libsym) 60{ 61 if (libsym != NULL && libsym->own_name) 62 free((char *)libsym->name); 63} 64 65int 66library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym) 67{ 68 const char *name; 69 if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0) 70 return -1; 71 72 library_symbol_init(retp, (GElf_Addr)libsym->enter_addr, 73 name, libsym->own_name, libsym->plt_type, 74 libsym->is_weak); 75 retp->needs_init = libsym->needs_init; 76 return 0; 77} 78 79int 80library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 81{ 82 if (a->enter_addr < b->enter_addr) 83 return -1; 84 if (a->enter_addr > b->enter_addr) 85 return 1; 86 if (a->name != NULL && b->name != NULL) 87 return strcmp(a->name, b->name); 88 if (a->name == NULL) { 89 if (b->name == NULL) 90 return 0; 91 return -1; 92 } 93 return 1; 94} 95 96enum callback_status 97library_symbol_equal_cb(struct library_symbol *libsym, void *u) 98{ 99 struct library_symbol *standard = u; 100 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 101} 102 103void 104library_init(struct library *lib, const char *name, int own_name) 105{ 106 lib->next = NULL; 107 lib->name = name; 108 lib->own_name = own_name; 109 lib->symbols = NULL; 110} 111 112int 113library_clone(struct library *retp, struct library *lib) 114{ 115 const char *name; 116 if (strdup_if_owned(&name, lib->name, lib->own_name) < 0) 117 return -1; 118 119 library_init(retp, lib->name, lib->own_name); 120 121 struct library_symbol *it; 122 struct library_symbol **nsymp = &retp->symbols; 123 for (it = lib->symbols; it != NULL; it = it->next) { 124 *nsymp = malloc(sizeof(**nsymp)); 125 if (*nsymp == NULL 126 || library_symbol_clone(*nsymp, it) < 0) { 127 /* Release what we managed to allocate. */ 128 library_destroy(retp); 129 return -1; 130 } 131 132 nsymp = &(*nsymp)->next; 133 } 134 return 0; 135} 136 137void 138library_destroy(struct library *lib) 139{ 140 if (lib == NULL) 141 return; 142 library_set_name(lib, NULL, 0); 143 144 struct library_symbol *sym; 145 for (sym = lib->symbols; sym != NULL; ) { 146 struct library_symbol *next = sym->next; 147 library_symbol_destroy(sym); 148 free(sym); 149 sym = next; 150 } 151} 152 153void 154library_set_name(struct library *lib, const char *new_name, int own_name) 155{ 156 if (lib->own_name) 157 free((char *)lib->name); 158 lib->name = new_name; 159 lib->own_name = own_name; 160} 161 162struct library_symbol * 163library_each_symbol(struct library *lib, struct library_symbol *it, 164 enum callback_status (*cb)(struct library_symbol *, void *), 165 void *data) 166{ 167 if (it == NULL) 168 it = lib->symbols; 169 170 while (it != NULL) { 171 struct library_symbol *next = it->next; 172 173 switch ((*cb)(it, data)) { 174 case CBS_STOP: 175 return it; 176 case CBS_CONT: 177 break; 178 } 179 180 it = next; 181 } 182 183 return NULL; 184} 185 186void 187library_add_symbol(struct library *lib, struct library_symbol *sym) 188{ 189 sym->next = lib->symbols; 190 lib->symbols = sym; 191} 192 193enum callback_status 194library_named_cb(struct Process *proc, struct library *lib, void *name) 195{ 196 if (name == lib->name 197 || strcmp(lib->name, (char *)name) == 0) 198 return CBS_STOP; 199 else 200 return CBS_CONT; 201} 202 203enum callback_status 204library_with_base_cb(struct Process *proc, struct library *lib, void *basep) 205{ 206 return lib->base == *(target_address_t *)basep ? CBS_STOP : CBS_CONT; 207} 208