library.c revision 522a6ca083c8b9e964548b0e79a4bdc8095d6e2e
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->needs_init = 0; 52 libsym->is_weak = is_weak; 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 && libsym->own_name) 63 free((char *)libsym->name); 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->lib, libsym->enter_addr, 74 name, libsym->own_name, libsym->plt_type, 75 libsym->is_weak); 76 retp->needs_init = libsym->needs_init; 77 return 0; 78} 79 80int 81library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) 82{ 83 if (a->enter_addr < b->enter_addr) 84 return -1; 85 if (a->enter_addr > b->enter_addr) 86 return 1; 87 if (a->name != NULL && b->name != NULL) 88 return strcmp(a->name, b->name); 89 if (a->name == NULL) { 90 if (b->name == NULL) 91 return 0; 92 return -1; 93 } 94 return 1; 95} 96 97enum callback_status 98library_symbol_equal_cb(struct library_symbol *libsym, void *u) 99{ 100 struct library_symbol *standard = u; 101 return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; 102} 103 104void 105library_init(struct library *lib, const char *name, int own_name) 106{ 107 lib->next = NULL; 108 lib->name = name; 109 lib->own_name = own_name; 110 lib->symbols = NULL; 111} 112 113int 114library_clone(struct library *retp, struct library *lib) 115{ 116 const char *name; 117 if (strdup_if_owned(&name, lib->name, lib->own_name) < 0) 118 return -1; 119 120 library_init(retp, lib->name, lib->own_name); 121 122 struct library_symbol *it; 123 struct library_symbol **nsymp = &retp->symbols; 124 for (it = lib->symbols; it != NULL; it = it->next) { 125 *nsymp = malloc(sizeof(**nsymp)); 126 if (*nsymp == NULL 127 || library_symbol_clone(*nsymp, it) < 0) { 128 /* Release what we managed to allocate. */ 129 library_destroy(retp); 130 return -1; 131 } 132 133 (*nsymp)->lib = retp; 134 nsymp = &(*nsymp)->next; 135 } 136 return 0; 137} 138 139void 140library_destroy(struct library *lib) 141{ 142 if (lib == NULL) 143 return; 144 library_set_name(lib, NULL, 0); 145 146 struct library_symbol *sym; 147 for (sym = lib->symbols; sym != NULL; ) { 148 struct library_symbol *next = sym->next; 149 library_symbol_destroy(sym); 150 free(sym); 151 sym = next; 152 } 153} 154 155void 156library_set_name(struct library *lib, const char *new_name, int own_name) 157{ 158 if (lib->own_name) 159 free((char *)lib->name); 160 lib->name = new_name; 161 lib->own_name = own_name; 162} 163 164struct library_symbol * 165library_each_symbol(struct library *lib, struct library_symbol *it, 166 enum callback_status (*cb)(struct library_symbol *, void *), 167 void *data) 168{ 169 if (it == NULL) 170 it = lib->symbols; 171 172 while (it != NULL) { 173 struct library_symbol *next = it->next; 174 175 switch ((*cb)(it, data)) { 176 case CBS_STOP: 177 return it; 178 case CBS_CONT: 179 break; 180 } 181 182 it = next; 183 } 184 185 return NULL; 186} 187 188void 189library_add_symbol(struct library *lib, struct library_symbol *sym) 190{ 191 sym->next = lib->symbols; 192 lib->symbols = sym; 193} 194 195enum callback_status 196library_named_cb(struct Process *proc, struct library *lib, void *name) 197{ 198 if (name == lib->name 199 || strcmp(lib->name, (char *)name) == 0) 200 return CBS_STOP; 201 else 202 return CBS_CONT; 203} 204 205enum callback_status 206library_with_base_cb(struct Process *proc, struct library *lib, void *basep) 207{ 208 return lib->base == *(target_address_t *)basep ? CBS_STOP : CBS_CONT; 209} 210