Imported Upstream version 0.7.2
[platform/upstream/ltrace.git] / library.c
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 #include <stdio.h>
27
28 #include "library.h"
29 #include "callback.h"
30 #include "debug.h"
31 #include "dict.h"
32 #include "backend.h" // for arch_library_symbol_init, arch_library_init
33
34 #ifndef ARCH_HAVE_LIBRARY_DATA
35 void
36 arch_library_init(struct library *lib)
37 {
38 }
39
40 void
41 arch_library_destroy(struct library *lib)
42 {
43 }
44
45 void
46 arch_library_clone(struct library *retp, struct library *lib)
47 {
48 }
49 #endif
50
51 #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
52 int
53 arch_library_symbol_init(struct library_symbol *libsym)
54 {
55         return 0;
56 }
57
58 void
59 arch_library_symbol_destroy(struct library_symbol *libsym)
60 {
61 }
62
63 int
64 arch_library_symbol_clone(struct library_symbol *retp,
65                           struct library_symbol *libsym)
66 {
67         return 0;
68 }
69 #endif
70
71 unsigned int
72 target_address_hash(const void *key)
73 {
74         /* XXX this assumes that key is passed by value.  */
75         union {
76                 arch_addr_t addr;
77                 unsigned int ints[sizeof(arch_addr_t)
78                                   / sizeof(unsigned int)];
79         } u = { .addr = (arch_addr_t)key };
80
81         size_t i;
82         unsigned int h = 0;
83         for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
84                 h ^= dict_key2hash_int((void *)(uintptr_t)u.ints[i]);
85         return h;
86 }
87
88 int
89 target_address_cmp(const void *key1, const void *key2)
90 {
91         /* XXX this assumes that key is passed by value.  */
92         arch_addr_t addr1 = (arch_addr_t)key1;
93         arch_addr_t addr2 = (arch_addr_t)key2;
94         return addr1 < addr2 ? 1
95              : addr1 > addr2 ? -1 : 0;
96 }
97
98 /* If the other symbol owns the name, we need to make the copy, so
99  * that the life-times of the two symbols are not dependent on each
100  * other.  */
101 static int
102 strdup_if_owned(const char **retp, const char *str, int owned)
103 {
104         if (!owned || str == NULL) {
105                 *retp = str;
106                 return 0;
107         } else {
108                 *retp = strdup(str);
109                 return *retp != NULL ? 0 : -1;
110         }
111 }
112
113 static void
114 private_library_symbol_init(struct library_symbol *libsym,
115                             arch_addr_t addr,
116                             const char *name, int own_name,
117                             enum toplt type_of_plt,
118                             int latent, int delayed)
119 {
120         libsym->next = NULL;
121         libsym->lib = NULL;
122         libsym->plt_type = type_of_plt;
123         libsym->name = name;
124         libsym->own_name = own_name;
125         libsym->latent = latent;
126         libsym->delayed = delayed;
127         libsym->enter_addr = (void *)(uintptr_t)addr;
128 }
129
130 static void
131 private_library_symbol_destroy(struct library_symbol *libsym)
132 {
133         library_symbol_set_name(libsym, NULL, 0);
134 }
135
136 int
137 library_symbol_init(struct library_symbol *libsym,
138                     arch_addr_t addr, const char *name, int own_name,
139                     enum toplt type_of_plt)
140 {
141         private_library_symbol_init(libsym, addr, name, own_name,
142                                     type_of_plt, 0, 0);
143
144         /* If arch init fails, we've already set libsym->name and
145          * own_name.  But we return failure, and the client code isn't
146          * supposed to call library_symbol_destroy in such a case.  */
147         return arch_library_symbol_init(libsym);
148 }
149
150 void
151 library_symbol_destroy(struct library_symbol *libsym)
152 {
153         if (libsym != NULL) {
154                 private_library_symbol_destroy(libsym);
155                 arch_library_symbol_destroy(libsym);
156         }
157 }
158
159 int
160 library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
161 {
162         const char *name;
163         if (strdup_if_owned(&name, libsym->name, libsym->own_name) < 0)
164                 return -1;
165
166         private_library_symbol_init(retp, libsym->enter_addr,
167                                     name, libsym->own_name, libsym->plt_type,
168                                     libsym->latent, libsym->delayed);
169
170         if (arch_library_symbol_clone(retp, libsym) < 0) {
171                 private_library_symbol_destroy(retp);
172                 return -1;
173         }
174
175         return 0;
176 }
177
178 int
179 library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
180 {
181         if (a->enter_addr < b->enter_addr)
182                 return -1;
183         if (a->enter_addr > b->enter_addr)
184                 return 1;
185         if (a->name != NULL && b->name != NULL)
186                 return strcmp(a->name, b->name);
187         if (a->name == NULL) {
188                 if (b->name == NULL)
189                         return 0;
190                 return -1;
191         }
192         return 1;
193 }
194
195 void
196 library_symbol_set_name(struct library_symbol *libsym,
197                         const char *name, int own_name)
198 {
199         if (libsym->own_name)
200                 free((char *)libsym->name);
201         libsym->name = name;
202         libsym->own_name = own_name;
203 }
204
205 enum callback_status
206 library_symbol_equal_cb(struct library_symbol *libsym, void *u)
207 {
208         struct library_symbol *standard = u;
209         return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
210 }
211
212 enum callback_status
213 library_symbol_named_cb(struct library_symbol *libsym, void *name)
214 {
215         return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
216 }
217
218 enum callback_status
219 library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
220 {
221         return libsym->delayed ? CBS_STOP : CBS_CONT;
222 }
223
224 static void
225 private_library_init(struct library *lib, enum library_type type)
226 {
227         lib->next = NULL;
228
229         lib->key = 0;
230         lib->base = 0;
231         lib->entry = 0;
232         lib->dyn_addr = 0;
233
234         lib->soname = NULL;
235         lib->own_soname = 0;
236
237         lib->pathname = NULL;
238         lib->own_pathname = 0;
239
240         lib->symbols = NULL;
241         lib->exported_names = NULL;
242         lib->type = type;
243 }
244
245 void
246 library_init(struct library *lib, enum library_type type)
247 {
248         private_library_init(lib, type);
249         arch_library_init(lib);
250 }
251
252 static int
253 library_exported_name_clone(struct library_exported_name *retp,
254                             struct library_exported_name *exnm)
255 {
256         char *name = exnm->own_name ? strdup(exnm->name) : (char *)exnm->name;
257         if (name == NULL)
258                 return -1;
259         retp->name = name;
260         retp->own_name = exnm->own_name;
261         return 0;
262 }
263
264 int
265 library_clone(struct library *retp, struct library *lib)
266 {
267         const char *soname = NULL;
268         const char *pathname;
269         if (strdup_if_owned(&soname, lib->soname, lib->own_soname) < 0
270              || strdup_if_owned(&pathname,
271                                 lib->pathname, lib->own_pathname) < 0) {
272                 if (lib->own_soname)
273                         free((char *)soname);
274                 return -1;
275         }
276
277         private_library_init(retp, lib->type);
278         library_set_soname(retp, soname, lib->own_soname);
279         library_set_pathname(retp, pathname, lib->own_pathname);
280         arch_library_clone(retp, lib);
281
282         retp->key = lib->key;
283
284         /* Clone symbols.  */
285         {
286                 struct library_symbol *it;
287                 struct library_symbol **nsymp = &retp->symbols;
288                 for (it = lib->symbols; it != NULL; it = it->next) {
289                         *nsymp = malloc(sizeof(**nsymp));
290                         if (*nsymp == NULL
291                             || library_symbol_clone(*nsymp, it) < 0) {
292                                 free(*nsymp);
293                         fail:
294                                 /* Release what we managed to allocate.  */
295                                 library_destroy(retp);
296                                 return -1;
297                         }
298
299                         (*nsymp)->lib = retp;
300                         nsymp = &(*nsymp)->next;
301                 }
302                 *nsymp = NULL;
303         }
304
305         /* Clone exported names.  */
306         {
307                 struct library_exported_name *it;
308                 struct library_exported_name **nnamep = &retp->exported_names;
309                 for (it = lib->exported_names; it != NULL; it = it->next) {
310                         *nnamep = malloc(sizeof(**nnamep));
311                         if (*nnamep == NULL
312                             || library_exported_name_clone(*nnamep, it) < 0) {
313                                 free(*nnamep);
314                                 goto fail;
315                         }
316                         nnamep = &(*nnamep)->next;
317                 }
318                 *nnamep = NULL;
319         }
320
321         return 0;
322 }
323
324 void
325 library_destroy(struct library *lib)
326 {
327         if (lib == NULL)
328                 return;
329
330         arch_library_destroy(lib);
331         library_set_soname(lib, NULL, 0);
332         library_set_pathname(lib, NULL, 0);
333
334         struct library_symbol *sym;
335         for (sym = lib->symbols; sym != NULL; ) {
336                 struct library_symbol *next = sym->next;
337                 library_symbol_destroy(sym);
338                 free(sym);
339                 sym = next;
340         }
341
342         /* Release exported names.  */
343         struct library_exported_name *it;
344         for (it = lib->exported_names; it != NULL; ) {
345                 struct library_exported_name *next = it->next;
346                 if (it->own_name)
347                         free((char *)it->name);
348                 free(it);
349                 it = next;
350         }
351 }
352
353 void
354 library_set_soname(struct library *lib, const char *new_name, int own_name)
355 {
356         if (lib->own_soname)
357                 free((char *)lib->soname);
358         lib->soname = new_name;
359         lib->own_soname = own_name;
360 }
361
362 void
363 library_set_pathname(struct library *lib, const char *new_name, int own_name)
364 {
365         if (lib->own_pathname)
366                 free((char *)lib->pathname);
367         lib->pathname = new_name;
368         lib->own_pathname = own_name;
369 }
370
371 struct library_symbol *
372 library_each_symbol(struct library *lib, struct library_symbol *start_after,
373                     enum callback_status (*cb)(struct library_symbol *, void *),
374                     void *data)
375 {
376         struct library_symbol *it = start_after == NULL ? lib->symbols
377                 : start_after->next;
378
379         while (it != NULL) {
380                 struct library_symbol *next = it->next;
381
382                 switch ((*cb)(it, data)) {
383                 case CBS_FAIL:
384                         /* XXX handle me  */
385                 case CBS_STOP:
386                         return it;
387                 case CBS_CONT:
388                         break;
389                 }
390
391                 it = next;
392         }
393
394         return NULL;
395 }
396
397 void
398 library_add_symbol(struct library *lib, struct library_symbol *first)
399 {
400         struct library_symbol *last;
401         for (last = first; last != NULL; ) {
402                 last->lib = lib;
403                 if (last->next != NULL)
404                         last = last->next;
405                 else
406                         break;
407         }
408
409         assert(last->next == NULL);
410         last->next = lib->symbols;
411         lib->symbols = first;
412 }
413
414 enum callback_status
415 library_named_cb(struct Process *proc, struct library *lib, void *name)
416 {
417         if (name == lib->soname
418             || strcmp(lib->soname, (char *)name) == 0)
419                 return CBS_STOP;
420         else
421                 return CBS_CONT;
422 }
423
424 enum callback_status
425 library_with_key_cb(struct Process *proc, struct library *lib, void *keyp)
426 {
427         return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
428 }