Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of ltrace. |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 3 | * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 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> |
Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 25 | #include <assert.h> |
Petr Machata | fb8502c | 2012-10-27 19:24:35 +0200 | [diff] [blame] | 26 | #include <stdio.h> |
Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 27 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 28 | #include "library.h" |
Petr Machata | a24021c | 2012-09-25 14:46:44 +0200 | [diff] [blame] | 29 | #include "callback.h" |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 30 | #include "debug.h" |
Petr Machata | a24021c | 2012-09-25 14:46:44 +0200 | [diff] [blame] | 31 | #include "dict.h" |
Petr Machata | 98d319e | 2012-05-04 02:22:47 +0200 | [diff] [blame] | 32 | #include "backend.h" // for arch_library_symbol_init, arch_library_init |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 33 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 34 | #ifndef OS_HAVE_LIBRARY_DATA |
| 35 | int |
| 36 | os_library_init(struct library *lib) |
| 37 | { |
| 38 | return 0; |
| 39 | } |
| 40 | |
| 41 | void |
| 42 | os_library_destroy(struct library *lib) |
| 43 | { |
| 44 | } |
| 45 | |
| 46 | int |
| 47 | os_library_clone(struct library *retp, struct library *lib) |
| 48 | { |
| 49 | return 0; |
| 50 | } |
| 51 | #endif |
| 52 | |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 53 | #ifndef ARCH_HAVE_LIBRARY_DATA |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 54 | int |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 55 | arch_library_init(struct library *lib) |
| 56 | { |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 57 | return 0; |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 58 | } |
| 59 | |
| 60 | void |
| 61 | arch_library_destroy(struct library *lib) |
| 62 | { |
| 63 | } |
| 64 | |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 65 | int |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 66 | arch_library_clone(struct library *retp, struct library *lib) |
| 67 | { |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 68 | return 0; |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 69 | } |
| 70 | #endif |
| 71 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 72 | #ifndef OS_HAVE_LIBRARY_SYMBOL_DATA |
| 73 | int |
| 74 | os_library_symbol_init(struct library_symbol *libsym) |
| 75 | { |
| 76 | return 0; |
| 77 | } |
| 78 | |
| 79 | void |
| 80 | os_library_symbol_destroy(struct library_symbol *libsym) |
| 81 | { |
| 82 | } |
| 83 | |
| 84 | int |
| 85 | os_library_symbol_clone(struct library_symbol *retp, |
| 86 | struct library_symbol *libsym) |
| 87 | { |
| 88 | return 0; |
| 89 | } |
| 90 | #endif |
| 91 | |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 92 | #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA |
| 93 | int |
| 94 | arch_library_symbol_init(struct library_symbol *libsym) |
| 95 | { |
| 96 | return 0; |
| 97 | } |
| 98 | |
| 99 | void |
| 100 | arch_library_symbol_destroy(struct library_symbol *libsym) |
| 101 | { |
| 102 | } |
| 103 | |
| 104 | int |
| 105 | arch_library_symbol_clone(struct library_symbol *retp, |
| 106 | struct library_symbol *libsym) |
| 107 | { |
| 108 | return 0; |
| 109 | } |
| 110 | #endif |
| 111 | |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 112 | size_t |
| 113 | arch_addr_hash(const arch_addr_t *addr) |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 114 | { |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 115 | union { |
Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 116 | arch_addr_t addr; |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 117 | int ints[sizeof(arch_addr_t) |
| 118 | / sizeof(unsigned int)]; |
| 119 | } u = { .addr = *addr }; |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 120 | |
| 121 | size_t i; |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 122 | size_t h = 0; |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 123 | for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i) |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 124 | h ^= dict_hash_int(&u.ints[i]); |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 125 | return h; |
| 126 | } |
| 127 | |
| 128 | int |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 129 | arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2) |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 130 | { |
Petr Machata | d7e4ca8 | 2012-11-28 03:38:47 +0100 | [diff] [blame] | 131 | return *addr1 == *addr2; |
Petr Machata | ecb082f | 2012-04-05 02:10:10 +0200 | [diff] [blame] | 132 | } |
| 133 | |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 134 | int |
| 135 | strdup_if(const char **retp, const char *str, int whether) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 136 | { |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 137 | if (whether && str != NULL) { |
| 138 | str = strdup(str); |
| 139 | if (str == NULL) |
| 140 | return -1; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 141 | } |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 142 | |
| 143 | *retp = str; |
| 144 | return 0; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 145 | } |
| 146 | |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 147 | static void |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 148 | private_library_symbol_init(struct library_symbol *libsym, |
Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 149 | arch_addr_t addr, |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 150 | const char *name, int own_name, |
Petr Machata | ef2fd27 | 2012-09-28 00:43:01 +0200 | [diff] [blame] | 151 | enum toplt type_of_plt, |
| 152 | int latent, int delayed) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 153 | { |
Petr Machata | 29add4f | 2012-02-18 16:38:05 +0100 | [diff] [blame] | 154 | libsym->next = NULL; |
Petr Machata | e6523e6 | 2012-03-24 04:54:06 +0100 | [diff] [blame] | 155 | libsym->lib = NULL; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 156 | libsym->plt_type = type_of_plt; |
| 157 | libsym->name = name; |
| 158 | libsym->own_name = own_name; |
Petr Machata | ef2fd27 | 2012-09-28 00:43:01 +0200 | [diff] [blame] | 159 | libsym->latent = latent; |
| 160 | libsym->delayed = delayed; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 161 | libsym->enter_addr = (void *)(uintptr_t)addr; |
Petr Machata | b8f0d8b | 2013-10-16 14:25:45 +0200 | [diff] [blame] | 162 | libsym->proto = NULL; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 163 | } |
| 164 | |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 165 | static void |
| 166 | private_library_symbol_destroy(struct library_symbol *libsym) |
| 167 | { |
| 168 | library_symbol_set_name(libsym, NULL, 0); |
| 169 | } |
| 170 | |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 171 | int |
| 172 | library_symbol_init(struct library_symbol *libsym, |
Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 173 | arch_addr_t addr, const char *name, int own_name, |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 174 | enum toplt type_of_plt) |
| 175 | { |
Petr Machata | ef2fd27 | 2012-09-28 00:43:01 +0200 | [diff] [blame] | 176 | private_library_symbol_init(libsym, addr, name, own_name, |
| 177 | type_of_plt, 0, 0); |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 178 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 179 | if (os_library_symbol_init(libsym) < 0) |
| 180 | /* We've already set libsym->name and own_name. But |
| 181 | * we return failure, and the client code isn't |
| 182 | * supposed to call library_symbol_destroy in such |
| 183 | * case. */ |
| 184 | return -1; |
| 185 | |
| 186 | if (arch_library_symbol_init(libsym) < 0) { |
| 187 | os_library_symbol_destroy(libsym); |
| 188 | return -1; |
| 189 | } |
| 190 | |
| 191 | return 0; |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 192 | } |
| 193 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 194 | void |
| 195 | library_symbol_destroy(struct library_symbol *libsym) |
| 196 | { |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 197 | if (libsym != NULL) { |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 198 | arch_library_symbol_destroy(libsym); |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 199 | os_library_symbol_destroy(libsym); |
| 200 | private_library_symbol_destroy(libsym); |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 201 | } |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | int |
| 205 | library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym) |
| 206 | { |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 207 | /* Make lifetimes of name stored at original independent of |
| 208 | * the one at the clone. */ |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 209 | const char *name; |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 210 | if (strdup_if(&name, libsym->name, libsym->own_name) < 0) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 211 | return -1; |
| 212 | |
Petr Machata | e8d9076 | 2012-04-15 04:28:31 +0200 | [diff] [blame] | 213 | private_library_symbol_init(retp, libsym->enter_addr, |
Petr Machata | ef2fd27 | 2012-09-28 00:43:01 +0200 | [diff] [blame] | 214 | name, libsym->own_name, libsym->plt_type, |
| 215 | libsym->latent, libsym->delayed); |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 216 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 217 | if (os_library_symbol_clone(retp, libsym) < 0) { |
| 218 | fail: |
Petr Machata | 24c6e9d | 2012-04-15 04:31:34 +0200 | [diff] [blame] | 219 | private_library_symbol_destroy(retp); |
| 220 | return -1; |
| 221 | } |
| 222 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 223 | if (arch_library_symbol_clone(retp, libsym) < 0) { |
| 224 | os_library_symbol_destroy(retp); |
| 225 | goto fail; |
| 226 | } |
| 227 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 228 | return 0; |
| 229 | } |
| 230 | |
| 231 | int |
| 232 | library_symbol_cmp(struct library_symbol *a, struct library_symbol *b) |
| 233 | { |
| 234 | if (a->enter_addr < b->enter_addr) |
| 235 | return -1; |
| 236 | if (a->enter_addr > b->enter_addr) |
| 237 | return 1; |
| 238 | if (a->name != NULL && b->name != NULL) |
| 239 | return strcmp(a->name, b->name); |
| 240 | if (a->name == NULL) { |
| 241 | if (b->name == NULL) |
| 242 | return 0; |
| 243 | return -1; |
| 244 | } |
| 245 | return 1; |
| 246 | } |
| 247 | |
Petr Machata | 157cc4d | 2012-04-04 19:00:34 +0200 | [diff] [blame] | 248 | void |
| 249 | library_symbol_set_name(struct library_symbol *libsym, |
| 250 | const char *name, int own_name) |
| 251 | { |
| 252 | if (libsym->own_name) |
| 253 | free((char *)libsym->name); |
| 254 | libsym->name = name; |
| 255 | libsym->own_name = own_name; |
| 256 | } |
| 257 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 258 | enum callback_status |
| 259 | library_symbol_equal_cb(struct library_symbol *libsym, void *u) |
| 260 | { |
| 261 | struct library_symbol *standard = u; |
| 262 | return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT; |
| 263 | } |
| 264 | |
Petr Machata | 016811f | 2012-09-27 23:29:22 +0200 | [diff] [blame] | 265 | enum callback_status |
| 266 | library_symbol_named_cb(struct library_symbol *libsym, void *name) |
| 267 | { |
| 268 | return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT; |
| 269 | } |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 270 | |
Petr Machata | ab2dab5 | 2012-11-07 16:06:33 +0100 | [diff] [blame] | 271 | enum callback_status |
| 272 | library_symbol_delayed_cb(struct library_symbol *libsym, void *unused) |
| 273 | { |
| 274 | return libsym->delayed ? CBS_STOP : CBS_CONT; |
| 275 | } |
| 276 | |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 277 | static void |
| 278 | private_library_init(struct library *lib, enum library_type type) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 279 | { |
| 280 | lib->next = NULL; |
Petr Machata | 8ae3673 | 2012-04-30 01:19:09 +0200 | [diff] [blame] | 281 | |
| 282 | lib->key = 0; |
| 283 | lib->base = 0; |
| 284 | lib->entry = 0; |
| 285 | lib->dyn_addr = 0; |
Petr Machata | f70074c | 2012-12-05 01:40:51 +0100 | [diff] [blame] | 286 | lib->protolib = NULL; |
Petr Machata | 8ae3673 | 2012-04-30 01:19:09 +0200 | [diff] [blame] | 287 | |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 288 | lib->soname = NULL; |
| 289 | lib->own_soname = 0; |
Petr Machata | 8ae3673 | 2012-04-30 01:19:09 +0200 | [diff] [blame] | 290 | |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 291 | lib->pathname = NULL; |
| 292 | lib->own_pathname = 0; |
Petr Machata | 8ae3673 | 2012-04-30 01:19:09 +0200 | [diff] [blame] | 293 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 294 | lib->symbols = NULL; |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 295 | lib->exported_names = NULL; |
Petr Machata | b5f80ac | 2012-04-04 01:46:18 +0200 | [diff] [blame] | 296 | lib->type = type; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 297 | } |
| 298 | |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 299 | int |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 300 | library_init(struct library *lib, enum library_type type) |
| 301 | { |
| 302 | private_library_init(lib, type); |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 303 | |
| 304 | if (os_library_init(lib) < 0) |
| 305 | return -1; |
| 306 | |
| 307 | if (arch_library_init(lib) < 0) { |
| 308 | os_library_destroy(lib); |
| 309 | return -1; |
| 310 | } |
| 311 | |
| 312 | return 0; |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 313 | } |
| 314 | |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 315 | static int |
| 316 | library_exported_name_clone(struct library_exported_name *retp, |
| 317 | struct library_exported_name *exnm) |
| 318 | { |
| 319 | char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name; |
| 320 | if (name == NULL) |
| 321 | return -1; |
| 322 | retp->name = name; |
| 323 | retp->own_name = exnm->own_name; |
| 324 | return 0; |
| 325 | } |
| 326 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 327 | int |
| 328 | library_clone(struct library *retp, struct library *lib) |
| 329 | { |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 330 | const char *soname = NULL; |
| 331 | const char *pathname; |
Petr Machata | b1ab2ae | 2013-01-07 18:09:32 +0100 | [diff] [blame] | 332 | |
| 333 | /* Make lifetimes of strings stored at original independent of |
| 334 | * those at the clone. */ |
| 335 | if (strdup_if(&soname, lib->soname, lib->own_soname) < 0 |
| 336 | || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) { |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 337 | if (lib->own_soname) |
| 338 | free((char *)soname); |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 339 | return -1; |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 340 | } |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 341 | |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 342 | private_library_init(retp, lib->type); |
Petr Machata | b5f80ac | 2012-04-04 01:46:18 +0200 | [diff] [blame] | 343 | library_set_soname(retp, soname, lib->own_soname); |
Petr Machata | fb8502c | 2012-10-27 19:24:35 +0200 | [diff] [blame] | 344 | library_set_pathname(retp, pathname, lib->own_pathname); |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 345 | |
Petr Machata | fb8502c | 2012-10-27 19:24:35 +0200 | [diff] [blame] | 346 | retp->key = lib->key; |
| 347 | |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 348 | /* Clone symbols. */ |
| 349 | { |
| 350 | struct library_symbol *it; |
| 351 | struct library_symbol **nsymp = &retp->symbols; |
| 352 | for (it = lib->symbols; it != NULL; it = it->next) { |
| 353 | *nsymp = malloc(sizeof(**nsymp)); |
| 354 | if (*nsymp == NULL |
| 355 | || library_symbol_clone(*nsymp, it) < 0) { |
| 356 | free(*nsymp); |
Petr Machata | d19b916 | 2013-01-07 20:16:57 +0100 | [diff] [blame] | 357 | *nsymp = NULL; |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 358 | fail: |
| 359 | /* Release what we managed to allocate. */ |
| 360 | library_destroy(retp); |
| 361 | return -1; |
| 362 | } |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 363 | |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 364 | (*nsymp)->lib = retp; |
| 365 | nsymp = &(*nsymp)->next; |
| 366 | } |
Petr Machata | fb8502c | 2012-10-27 19:24:35 +0200 | [diff] [blame] | 367 | *nsymp = NULL; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 368 | } |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 369 | |
| 370 | /* Clone exported names. */ |
| 371 | { |
| 372 | struct library_exported_name *it; |
| 373 | struct library_exported_name **nnamep = &retp->exported_names; |
| 374 | for (it = lib->exported_names; it != NULL; it = it->next) { |
| 375 | *nnamep = malloc(sizeof(**nnamep)); |
| 376 | if (*nnamep == NULL |
| 377 | || library_exported_name_clone(*nnamep, it) < 0) { |
| 378 | free(*nnamep); |
| 379 | goto fail; |
| 380 | } |
| 381 | nnamep = &(*nnamep)->next; |
| 382 | } |
Petr Machata | 23e2b59 | 2012-10-27 16:03:09 +0200 | [diff] [blame] | 383 | *nnamep = NULL; |
Petr Machata | 4b4dff4 | 2012-09-27 23:49:49 +0200 | [diff] [blame] | 384 | } |
| 385 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 386 | if (os_library_clone(retp, lib) < 0) |
Petr Machata | 7287166 | 2013-10-11 14:29:09 +0200 | [diff] [blame] | 387 | goto fail; |
| 388 | |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 389 | if (arch_library_clone(retp, lib) < 0) { |
| 390 | os_library_destroy(retp); |
| 391 | goto fail; |
| 392 | } |
| 393 | |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 394 | return 0; |
| 395 | } |
| 396 | |
| 397 | void |
| 398 | library_destroy(struct library *lib) |
| 399 | { |
| 400 | if (lib == NULL) |
| 401 | return; |
Petr Machata | 994ad6d | 2012-04-17 03:07:04 +0200 | [diff] [blame] | 402 | |
| 403 | arch_library_destroy(lib); |
Petr Machata | 8fdd09b | 2013-10-11 15:08:30 +0200 | [diff] [blame] | 404 | os_library_destroy(lib); |
| 405 | |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 406 | library_set_soname(lib, NULL, 0); |
| 407 | library_set_pathname(lib, NULL, 0); |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 408 | |
| 409 | struct library_symbol *sym; |
| 410 | for (sym = lib->symbols; sym != NULL; ) { |
| 411 | struct library_symbol *next = sym->next; |
| 412 | library_symbol_destroy(sym); |
| 413 | free(sym); |
| 414 | sym = next; |
| 415 | } |
Petr Machata | 819fdb7 | 2012-10-27 02:36:50 +0200 | [diff] [blame] | 416 | |
| 417 | /* Release exported names. */ |
| 418 | struct library_exported_name *it; |
| 419 | for (it = lib->exported_names; it != NULL; ) { |
| 420 | struct library_exported_name *next = it->next; |
| 421 | if (it->own_name) |
| 422 | free((char *)it->name); |
| 423 | free(it); |
| 424 | it = next; |
| 425 | } |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 426 | } |
| 427 | |
| 428 | void |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 429 | library_set_soname(struct library *lib, const char *new_name, int own_name) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 430 | { |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 431 | if (lib->own_soname) |
| 432 | free((char *)lib->soname); |
| 433 | lib->soname = new_name; |
| 434 | lib->own_soname = own_name; |
| 435 | } |
| 436 | |
| 437 | void |
| 438 | library_set_pathname(struct library *lib, const char *new_name, int own_name) |
| 439 | { |
| 440 | if (lib->own_pathname) |
| 441 | free((char *)lib->pathname); |
| 442 | lib->pathname = new_name; |
| 443 | lib->own_pathname = own_name; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 444 | } |
| 445 | |
| 446 | struct library_symbol * |
Petr Machata | 74132a4 | 2012-03-16 02:46:18 +0100 | [diff] [blame] | 447 | library_each_symbol(struct library *lib, struct library_symbol *start_after, |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 448 | enum callback_status (*cb)(struct library_symbol *, void *), |
| 449 | void *data) |
| 450 | { |
Petr Machata | 74132a4 | 2012-03-16 02:46:18 +0100 | [diff] [blame] | 451 | struct library_symbol *it = start_after == NULL ? lib->symbols |
| 452 | : start_after->next; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 453 | |
| 454 | while (it != NULL) { |
| 455 | struct library_symbol *next = it->next; |
| 456 | |
| 457 | switch ((*cb)(it, data)) { |
Petr Machata | ef7fa37 | 2012-03-28 02:05:36 +0200 | [diff] [blame] | 458 | case CBS_FAIL: |
| 459 | /* XXX handle me */ |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 460 | case CBS_STOP: |
| 461 | return it; |
| 462 | case CBS_CONT: |
| 463 | break; |
| 464 | } |
| 465 | |
| 466 | it = next; |
| 467 | } |
| 468 | |
| 469 | return NULL; |
| 470 | } |
| 471 | |
| 472 | void |
Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 473 | library_add_symbol(struct library *lib, struct library_symbol *first) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 474 | { |
Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 475 | struct library_symbol *last; |
| 476 | for (last = first; last != NULL; ) { |
| 477 | last->lib = lib; |
| 478 | if (last->next != NULL) |
| 479 | last = last->next; |
| 480 | else |
| 481 | break; |
| 482 | } |
Petr Machata | e6523e6 | 2012-03-24 04:54:06 +0100 | [diff] [blame] | 483 | |
Petr Machata | 8cce119 | 2012-03-25 01:37:19 +0100 | [diff] [blame] | 484 | assert(last->next == NULL); |
| 485 | last->next = lib->symbols; |
| 486 | lib->symbols = first; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 487 | } |
| 488 | |
| 489 | enum callback_status |
Petr Machata | 929bd57 | 2012-12-17 03:20:34 +0100 | [diff] [blame] | 490 | library_named_cb(struct process *proc, struct library *lib, void *name) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 491 | { |
Petr Machata | 0b55b58 | 2012-04-02 00:38:46 +0200 | [diff] [blame] | 492 | if (name == lib->soname |
| 493 | || strcmp(lib->soname, (char *)name) == 0) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 494 | return CBS_STOP; |
| 495 | else |
| 496 | return CBS_CONT; |
| 497 | } |
| 498 | |
| 499 | enum callback_status |
Petr Machata | 929bd57 | 2012-12-17 03:20:34 +0100 | [diff] [blame] | 500 | library_with_key_cb(struct process *proc, struct library *lib, void *keyp) |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 501 | { |
Petr Machata | bac2da5 | 2012-05-29 00:42:59 +0200 | [diff] [blame] | 502 | return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT; |
Petr Machata | 2b46cfc | 2012-02-18 11:17:29 +0100 | [diff] [blame] | 503 | } |