library.c revision b931085e37224dd2932fb637eaba5da29c4c5eb7
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, struct library *lib, 46 target_address_t addr, const char *name, int own_name, 47 enum toplt type_of_plt, int is_weak) 48{ 49 libsym->next = NULL; 50 libsym->lib = lib; 51 libsym->is_weak = is_weak; 52 libsym->plt_type = type_of_plt; 53 libsym->name = name; 54 libsym->own_name = own_name; 55 libsym->enter_addr = (void *)(uintptr_t)addr; 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, libsym->lib, libsym->enter_addr, 73 name, libsym->own_name, libsym->plt_type, 74 libsym->is_weak); 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 95enum callback_status 96library_symbol_equal_cb(struct library_symbol *libsym, void *u) 97{ 98 struct library_symbol *standard = u; 99 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 100} 101 102void 103library_init(struct library *lib, const char *name, int own_name) 104{ 105 lib->next = NULL; 106 lib->name = name; 107 lib->own_name = own_name; 108 lib->symbols = NULL; 109} 110 111int 112library_clone(struct library *retp, struct library *lib) 113{ 114 const char *name; 115 if (strdup_if_owned(&name, lib->name, lib->own_name) < 0) 116 return -1; 117 118 library_init(retp, lib->name, lib->own_name); 119 120 struct library_symbol *it; 121 struct library_symbol **nsymp = &retp->symbols; 122 for (it = lib->symbols; it != NULL; it = it->next) { 123 *nsymp = malloc(sizeof(**nsymp)); 124 if (*nsymp == NULL 125 || library_symbol_clone(*nsymp, it) < 0) { 126 /* Release what we managed to allocate. */ 127 library_destroy(retp); 128 return -1; 129 } 130 131 (*nsymp)->lib = retp; 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 *start_after, 164 enum callback_status (*cb)(struct library_symbol *, void *), 165 void *data) 166{ 167 struct library_symbol *it = start_after == NULL ? lib->symbols 168 : start_after->next; 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