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