Drop uses of #pragma once
[platform/upstream/ltrace.git] / library.c
1 /*
2  * This file is part of ltrace.
3  * Copyright (C) 2011,2012,2013,2014 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 "config.h"
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <stdio.h>
29
30 #include "library.h"
31 #include "callback.h"
32 #include "debug.h"
33 #include "dict.h"
34 #include "vect.h"
35 #include "backend.h" // for arch_library_symbol_init, arch_library_init
36
37 static void
38 library_exported_names_init(struct library_exported_names *names);
39
40 #ifndef OS_HAVE_LIBRARY_DATA
41 int
42 os_library_init(struct library *lib)
43 {
44         return 0;
45 }
46
47 void
48 os_library_destroy(struct library *lib)
49 {
50 }
51
52 int
53 os_library_clone(struct library *retp, struct library *lib)
54 {
55         return 0;
56 }
57 #endif
58
59 #ifndef ARCH_HAVE_LIBRARY_DATA
60 int
61 arch_library_init(struct library *lib)
62 {
63         return 0;
64 }
65
66 void
67 arch_library_destroy(struct library *lib)
68 {
69 }
70
71 int
72 arch_library_clone(struct library *retp, struct library *lib)
73 {
74         return 0;
75 }
76 #endif
77
78 #ifndef OS_HAVE_LIBRARY_SYMBOL_DATA
79 int
80 os_library_symbol_init(struct library_symbol *libsym)
81 {
82         return 0;
83 }
84
85 void
86 os_library_symbol_destroy(struct library_symbol *libsym)
87 {
88 }
89
90 int
91 os_library_symbol_clone(struct library_symbol *retp,
92                         struct library_symbol *libsym)
93 {
94         return 0;
95 }
96 #endif
97
98 #ifndef ARCH_HAVE_LIBRARY_SYMBOL_DATA
99 int
100 arch_library_symbol_init(struct library_symbol *libsym)
101 {
102         return 0;
103 }
104
105 void
106 arch_library_symbol_destroy(struct library_symbol *libsym)
107 {
108 }
109
110 int
111 arch_library_symbol_clone(struct library_symbol *retp,
112                           struct library_symbol *libsym)
113 {
114         return 0;
115 }
116 #endif
117
118 size_t
119 arch_addr_hash(const arch_addr_t *addr)
120 {
121         union {
122                 arch_addr_t addr;
123                 int ints[sizeof(arch_addr_t)
124                          / sizeof(unsigned int)];
125         } u = { .addr = *addr };
126
127         size_t i;
128         size_t h = 0;
129         for (i = 0; i < sizeof(u.ints) / sizeof(*u.ints); ++i)
130                 h ^= dict_hash_int(&u.ints[i]);
131         return h;
132 }
133
134 int
135 arch_addr_eq(const arch_addr_t *addr1, const arch_addr_t *addr2)
136 {
137         return *addr1 == *addr2;
138 }
139
140 int
141 strdup_if(const char **retp, const char *str, int whether)
142 {
143         if (whether && str != NULL) {
144                 str = strdup(str);
145                 if (str == NULL)
146                         return -1;
147         }
148
149         *retp = str;
150         return 0;
151 }
152
153 static void
154 private_library_symbol_init(struct library_symbol *libsym,
155                             arch_addr_t addr,
156                             const char *name, int own_name,
157                             enum toplt type_of_plt,
158                             int latent, int delayed)
159 {
160         libsym->next = NULL;
161         libsym->lib = NULL;
162         libsym->plt_type = type_of_plt;
163         libsym->name = name;
164         libsym->own_name = own_name;
165         libsym->latent = latent;
166         libsym->delayed = delayed;
167         libsym->enter_addr = (void *)(uintptr_t)addr;
168         libsym->proto = NULL;
169 }
170
171 static void
172 private_library_symbol_destroy(struct library_symbol *libsym)
173 {
174         library_symbol_set_name(libsym, NULL, 0);
175 }
176
177 int
178 library_symbol_init(struct library_symbol *libsym,
179                     arch_addr_t addr, const char *name, int own_name,
180                     enum toplt type_of_plt)
181 {
182         private_library_symbol_init(libsym, addr, name, own_name,
183                                     type_of_plt, 0, 0);
184
185         if (os_library_symbol_init(libsym) < 0)
186                 /* We've already set libsym->name and own_name.  But
187                  * we return failure, and the client code isn't
188                  * supposed to call library_symbol_destroy in such
189                  * case.  */
190                 return -1;
191
192         if (arch_library_symbol_init(libsym) < 0) {
193                 os_library_symbol_destroy(libsym);
194                 return -1;
195         }
196
197         return 0;
198 }
199
200 void
201 library_symbol_destroy(struct library_symbol *libsym)
202 {
203         if (libsym != NULL) {
204                 arch_library_symbol_destroy(libsym);
205                 os_library_symbol_destroy(libsym);
206                 private_library_symbol_destroy(libsym);
207         }
208 }
209
210 int
211 library_symbol_clone(struct library_symbol *retp, struct library_symbol *libsym)
212 {
213         /* Make lifetimes of name stored at original independent of
214          * the one at the clone.  */
215         const char *name;
216         if (strdup_if(&name, libsym->name, libsym->own_name) < 0)
217                 return -1;
218
219         private_library_symbol_init(retp, libsym->enter_addr,
220                                     name, libsym->own_name, libsym->plt_type,
221                                     libsym->latent, libsym->delayed);
222
223         if (os_library_symbol_clone(retp, libsym) < 0) {
224         fail:
225                 private_library_symbol_destroy(retp);
226                 return -1;
227         }
228
229         if (arch_library_symbol_clone(retp, libsym) < 0) {
230                 os_library_symbol_destroy(retp);
231                 goto fail;
232         }
233
234         return 0;
235 }
236
237 int
238 library_symbol_cmp(struct library_symbol *a, struct library_symbol *b)
239 {
240         if (a->enter_addr < b->enter_addr)
241                 return -1;
242         if (a->enter_addr > b->enter_addr)
243                 return 1;
244         if (a->name != NULL && b->name != NULL)
245                 return strcmp(a->name, b->name);
246         if (a->name == NULL) {
247                 if (b->name == NULL)
248                         return 0;
249                 return -1;
250         }
251         return 1;
252 }
253
254 void
255 library_symbol_set_name(struct library_symbol *libsym,
256                         const char *name, int own_name)
257 {
258         if (libsym->own_name)
259                 free((char *)libsym->name);
260         libsym->name = name;
261         libsym->own_name = own_name;
262 }
263
264 enum callback_status
265 library_symbol_equal_cb(struct library_symbol *libsym, void *u)
266 {
267         struct library_symbol *standard = u;
268         return library_symbol_cmp(libsym, standard) == 0 ? CBS_STOP : CBS_CONT;
269 }
270
271 enum callback_status
272 library_symbol_named_cb(struct library_symbol *libsym, void *name)
273 {
274         return strcmp(libsym->name, name) == 0 ? CBS_STOP : CBS_CONT;
275 }
276
277 enum callback_status
278 library_symbol_delayed_cb(struct library_symbol *libsym, void *unused)
279 {
280         return libsym->delayed ? CBS_STOP : CBS_CONT;
281 }
282
283 static void
284 private_library_init(struct library *lib, enum library_type type)
285 {
286         lib->next = NULL;
287
288         lib->key = 0;
289         lib->base = 0;
290         lib->entry = 0;
291         lib->dyn_addr = 0;
292         lib->protolib = NULL;
293
294         lib->soname = NULL;
295         lib->own_soname = 0;
296
297         lib->pathname = NULL;
298         lib->own_pathname = 0;
299
300         lib->symbols = NULL;
301         library_exported_names_init(&lib->exported_names);
302         lib->should_activate_latent = false;
303         lib->type = type;
304
305 #if defined(HAVE_LIBDW)
306         lib->dwfl_module = NULL;
307 #endif
308 }
309
310 int
311 library_init(struct library *lib, enum library_type type)
312 {
313         private_library_init(lib, type);
314
315         if (os_library_init(lib) < 0)
316                 return -1;
317
318         if (arch_library_init(lib) < 0) {
319                 os_library_destroy(lib);
320                 return -1;
321         }
322
323         return 0;
324 }
325
326
327
328
329
330 static void dtor_string(const char **tgt, void *data)
331 {
332         free((char*)*tgt);
333 }
334 static int clone_vect(struct vect **to, const struct vect **from, void *data)
335 {
336         *to = malloc(sizeof(struct vect));
337         if (*to == NULL)
338                 return -1;
339
340         return
341                 VECT_CLONE(*to, *from, const char*,
342                            dict_clone_string,
343                            dtor_string,
344                            NULL);
345 }
346 static void dtor_vect(struct vect **tgt, void *data)
347 {
348         VECT_DESTROY(*tgt, const char*, dtor_string, NULL);
349         free(*tgt);
350 }
351
352 static void
353 library_exported_names_init(struct library_exported_names *names)
354 {
355         DICT_INIT(&names->names,
356                   const char*, uint64_t,
357                   dict_hash_string, dict_eq_string, NULL);
358         DICT_INIT(&names->addrs,
359                   uint64_t, struct vect*,
360                   dict_hash_uint64, dict_eq_uint64, NULL);
361 }
362
363 static void
364 library_exported_names_destroy(struct library_exported_names *names)
365 {
366         DICT_DESTROY(&names->names,
367                      const char*, uint64_t,
368                      dtor_string, NULL, NULL);
369         DICT_DESTROY(&names->addrs,
370                      uint64_t, struct vect*,
371                      NULL, dtor_vect, NULL);
372 }
373
374 static int
375 library_exported_names_clone(struct library_exported_names *retp,
376                              const struct library_exported_names *names)
377 {
378         return (DICT_CLONE(&retp->names, &names->names,
379                            const char*, uint64_t,
380                            dict_clone_string, dtor_string,
381                            NULL, NULL,
382                            NULL) < 0  ||
383                 DICT_CLONE(&retp->addrs, &names->addrs,
384                            uint64_t, struct vect*,
385                            NULL, NULL,
386                            clone_vect, dtor_vect,
387                            NULL) < 0) ? -1 : 0;
388 }
389
390 int library_exported_names_push(struct library_exported_names *names,
391                                 uint64_t addr, char *name,
392                                 int own_name )
393 {
394         // first, take ownership of the name, if it's not yet ours
395         if (!own_name)
396                 name = strdup(name);
397         if (name == NULL)
398                 return -1;
399
400         // push to the name->addr map
401         int result = DICT_INSERT(&names->names, &name, &addr);
402         if (result > 0) {
403                 // This symbol is already present in the table. This library has
404                 // multiple copies of this symbol (probably corresponding to
405                 // different symbol versions). I should handle this gracefully
406                 // at some point, but for now I simply ignore later instances of
407                 // any particular symbol
408                 free(name);
409                 return 0;
410         }
411
412         if (result != 0)
413                 return result;
414
415         // push to the addr->names map
416         // I get the alias vector. If it doesn't yet exist, I make it
417         struct vect *aliases;
418         struct vect **paliases = DICT_FIND_REF(&names->addrs,
419                                                &addr, struct vect*);
420
421         if (paliases == NULL) {
422                 aliases = malloc(sizeof(struct vect));
423                 if (aliases == NULL)
424                         return -1;
425                 VECT_INIT(aliases, const char*);
426                 result = DICT_INSERT(&names->addrs, &addr, &aliases);
427                 assert(result <= 0);
428                 if (result < 0)
429                         return result;
430         }
431         else
432                 aliases = *paliases;
433
434         char *namedup = strdup(name);
435         if (namedup == NULL)
436                 return -1;
437
438         result = vect_pushback(aliases, &namedup);
439         if (result != 0) {
440                 free(namedup);
441                 return result;
442         }
443
444         return 0;
445 }
446
447 struct library_exported_names_each_alias_context
448 {
449         enum callback_status (*inner_cb)(const char *, void *);
450         const char *origname;
451         void *data;
452 };
453 static enum callback_status
454 library_exported_names_each_alias_cb(const char **name, void *data)
455 {
456         struct library_exported_names_each_alias_context *context =
457                 (struct library_exported_names_each_alias_context*)data;
458
459         // I do not report the original name we were asked about. Otherwise, any
460         // time the caller asks for aliases of symbol "sym", I'll always report
461         // "sym" along with any actual aliases
462         if (strcmp(*name, context->origname) == 0)
463                 return CBS_CONT;
464
465         return context->inner_cb(*name, context->data);
466 }
467
468 const char** library_exported_names_each_alias(
469         struct library_exported_names *names,
470         const char *aliasname,
471         const char **name_start_after,
472         enum callback_status (*cb)(const char *,
473                                    void *),
474         void *data)
475 {
476         // I have a symbol name. I look up its address, then get the list of
477         // aliased names
478         uint64_t *addr = DICT_FIND_REF(&names->names,
479                                        &aliasname, uint64_t);
480         if (addr == NULL)
481                 return NULL;
482
483         // OK. I have an address. Get the list of symbols at this address
484         struct vect **aliases = DICT_FIND_REF(&names->addrs,
485                                               addr, struct vect*);
486         assert(aliases != NULL);
487
488         struct library_exported_names_each_alias_context context =
489                 {.inner_cb = cb,
490                  .origname = aliasname,
491                  .data = data};
492         return VECT_EACH(*aliases, const char*, name_start_after,
493                          library_exported_names_each_alias_cb, &context);
494 }
495
496 int library_exported_names_contains(struct library_exported_names* names,
497                                     const char* queryname)
498 {
499         uint64_t *addr = DICT_FIND_REF(&names->names,
500                                        &queryname, uint64_t);
501         return (addr == NULL) ? 0 : 1;
502 }
503
504
505
506
507
508 int
509 library_clone(struct library *retp, struct library *lib)
510 {
511         const char *soname = NULL;
512         const char *pathname;
513
514         /* Make lifetimes of strings stored at original independent of
515          * those at the clone.  */
516         if (strdup_if(&soname, lib->soname, lib->own_soname) < 0
517             || strdup_if(&pathname, lib->pathname, lib->own_pathname) < 0) {
518                 if (lib->own_soname)
519                         free((char *)soname);
520                 return -1;
521         }
522
523         private_library_init(retp, lib->type);
524         library_set_soname(retp, soname, lib->own_soname);
525         library_set_pathname(retp, pathname, lib->own_pathname);
526
527         retp->key = lib->key;
528         retp->should_activate_latent = lib->should_activate_latent;
529
530         /* Clone symbols.  */
531         {
532                 struct library_symbol *it;
533                 struct library_symbol **nsymp = &retp->symbols;
534                 for (it = lib->symbols; it != NULL; it = it->next) {
535                         *nsymp = malloc(sizeof(**nsymp));
536                         if (*nsymp == NULL
537                             || library_symbol_clone(*nsymp, it) < 0) {
538                                 free(*nsymp);
539                                 *nsymp = NULL;
540                         fail:
541                                 /* Release what we managed to allocate.  */
542                                 library_destroy(retp);
543                                 return -1;
544                         }
545
546                         (*nsymp)->lib = retp;
547                         nsymp = &(*nsymp)->next;
548                 }
549                 *nsymp = NULL;
550         }
551
552         /* Clone exported names.  */
553         if (library_exported_names_clone(&retp->exported_names,
554                                          &lib->exported_names) != 0)
555                 goto fail;
556
557         if (os_library_clone(retp, lib) < 0)
558                 goto fail;
559
560         if (arch_library_clone(retp, lib) < 0) {
561                 os_library_destroy(retp);
562                 goto fail;
563         }
564
565 #if defined(HAVE_LIBDW)
566         /* Wipe DWFL_MODULE, leave it to proc_add_library to
567          * initialize.  */
568         lib->dwfl_module = NULL;
569 #endif
570
571         return 0;
572 }
573
574 void
575 library_destroy(struct library *lib)
576 {
577         if (lib == NULL)
578                 return;
579
580         arch_library_destroy(lib);
581         os_library_destroy(lib);
582
583         library_set_soname(lib, NULL, 0);
584         library_set_pathname(lib, NULL, 0);
585
586         struct library_symbol *sym;
587         for (sym = lib->symbols; sym != NULL; ) {
588                 struct library_symbol *next = sym->next;
589                 library_symbol_destroy(sym);
590                 free(sym);
591                 sym = next;
592         }
593
594         /* Release exported names.  */
595         library_exported_names_destroy(&lib->exported_names);
596 }
597
598 void
599 library_set_soname(struct library *lib, const char *new_name, int own_name)
600 {
601         if (lib->own_soname)
602                 free((char *)lib->soname);
603         lib->soname = new_name;
604         lib->own_soname = own_name;
605 }
606
607 void
608 library_set_pathname(struct library *lib, const char *new_name, int own_name)
609 {
610         if (lib->own_pathname)
611                 free((char *)lib->pathname);
612         lib->pathname = new_name;
613         lib->own_pathname = own_name;
614 }
615
616 struct library_symbol *
617 library_each_symbol(struct library *lib, struct library_symbol *start_after,
618                     enum callback_status (*cb)(struct library_symbol *, void *),
619                     void *data)
620 {
621         struct library_symbol *it = start_after == NULL ? lib->symbols
622                 : start_after->next;
623
624         while (it != NULL) {
625                 struct library_symbol *next = it->next;
626
627                 switch ((*cb)(it, data)) {
628                 case CBS_FAIL:
629                         /* XXX handle me  */
630                 case CBS_STOP:
631                         return it;
632                 case CBS_CONT:
633                         break;
634                 }
635
636                 it = next;
637         }
638
639         return NULL;
640 }
641
642 void
643 library_add_symbol(struct library *lib, struct library_symbol *first)
644 {
645         struct library_symbol *last;
646         for (last = first; last != NULL; ) {
647                 last->lib = lib;
648                 if (last->next != NULL)
649                         last = last->next;
650                 else
651                         break;
652         }
653
654         assert(last->next == NULL);
655         last->next = lib->symbols;
656         lib->symbols = first;
657 }
658
659 enum callback_status
660 library_named_cb(struct process *proc, struct library *lib, void *name)
661 {
662         if (name == lib->soname
663             || strcmp(lib->soname, (char *)name) == 0)
664                 return CBS_STOP;
665         else
666                 return CBS_CONT;
667 }
668
669 enum callback_status
670 library_with_key_cb(struct process *proc, struct library *lib, void *keyp)
671 {
672         return lib->key == *(arch_addr_t *)keyp ? CBS_STOP : CBS_CONT;
673 }