Update TODO
[platform/upstream/ltrace.git] / prototype.c
1 /*
2  * This file is part of ltrace.
3  * Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  */
20
21 #include <alloca.h>
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26
27 #include "common.h"
28 #include "callback.h"
29 #include "param.h"
30 #include "prototype.h"
31 #include "type.h"
32 #include "options.h"
33 #include "read_config_file.h"
34 #include "backend.h"
35
36 struct protolib_cache g_protocache;
37 static struct protolib legacy_typedefs;
38
39 void
40 prototype_init(struct prototype *proto)
41 {
42         VECT_INIT(&proto->params, struct param);
43
44         proto->return_info = NULL;
45         proto->own_return_info = 0;
46 }
47
48 static void
49 param_destroy_cb(struct param *param, void *data)
50 {
51         param_destroy(param);
52 }
53
54 void
55 prototype_destroy(struct prototype *proto)
56 {
57         if (proto == NULL)
58                 return;
59         if (proto->own_return_info) {
60                 type_destroy(proto->return_info);
61                 free(proto->return_info);
62         }
63
64         VECT_DESTROY(&proto->params, struct param, &param_destroy_cb, NULL);
65 }
66
67 int
68 prototype_push_param(struct prototype *proto, struct param *param)
69 {
70         return VECT_PUSHBACK(&proto->params, param);
71 }
72
73 size_t
74 prototype_num_params(struct prototype *proto)
75 {
76         return vect_size(&proto->params);
77 }
78
79 void
80 prototype_destroy_nth_param(struct prototype *proto, size_t n)
81 {
82         assert(n < prototype_num_params(proto));
83         VECT_ERASE(&proto->params, struct param, n, n+1,
84                    &param_destroy_cb, NULL);
85 }
86
87 struct param *
88 prototype_get_nth_param(struct prototype *proto, size_t n)
89 {
90         assert(n < prototype_num_params(proto));
91         return VECT_ELEMENT(&proto->params, struct param, n);
92 }
93
94 struct each_param_data {
95         struct prototype *proto;
96         enum callback_status (*cb)(struct prototype *, struct param *, void *);
97         void *data;
98 };
99
100 static enum callback_status
101 each_param_cb(struct param *param, void *data)
102 {
103         struct each_param_data *cb_data = data;
104         return (cb_data->cb)(cb_data->proto, param, cb_data->data);
105 }
106
107 struct param *
108 prototype_each_param(struct prototype *proto, struct param *start_after,
109                      enum callback_status (*cb)(struct prototype *,
110                                                 struct param *, void *),
111                      void *data)
112 {
113         struct each_param_data cb_data = { proto, cb, data };
114         return VECT_EACH(&proto->params, struct param, start_after,
115                          &each_param_cb, &cb_data);
116 }
117
118 void
119 named_type_init(struct named_type *named,
120                 struct arg_type_info *info, int own_type)
121 {
122         named->info = info;
123         named->own_type = own_type;
124         named->forward = 0;
125 }
126
127 void
128 named_type_destroy(struct named_type *named)
129 {
130         if (named->own_type) {
131                 type_destroy(named->info);
132                 free(named->info);
133         }
134 }
135
136 void
137 protolib_init(struct protolib *plib)
138 {
139         DICT_INIT(&plib->prototypes, char *, struct prototype,
140                   dict_hash_string, dict_eq_string, NULL);
141
142         DICT_INIT(&plib->named_types, char *, struct named_type,
143                   dict_hash_string, dict_eq_string, NULL);
144
145         VECT_INIT(&plib->imports, struct protolib *);
146
147         plib->refs = 0;
148 }
149
150 static void
151 destroy_prototype_cb(struct prototype *proto, void *data)
152 {
153         prototype_destroy(proto);
154 }
155
156 static void
157 destroy_named_type_cb(struct named_type *named, void *data)
158 {
159         named_type_destroy(named);
160 }
161
162 void
163 protolib_destroy(struct protolib *plib)
164 {
165         assert(plib->refs == 0);
166
167         VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
168
169         DICT_DESTROY(&plib->prototypes, const char *, struct prototype,
170                      dict_dtor_string, destroy_prototype_cb, NULL);
171
172         DICT_DESTROY(&plib->named_types, const char *, struct named_type,
173                      dict_dtor_string, destroy_named_type_cb, NULL);
174 }
175
176 static struct protolib **
177 each_import(struct protolib *plib, struct protolib **start_after,
178             enum callback_status (*cb)(struct protolib **, void *), void *data)
179 {
180         assert(plib != NULL);
181         return VECT_EACH(&plib->imports, struct protolib *,
182                          start_after, cb, data);
183 }
184
185 static enum callback_status
186 is_or_imports(struct protolib **plibp, void *data)
187 {
188         assert(plibp != NULL);
189         assert(*plibp != NULL);
190         struct protolib *import = data;
191         if (*plibp == import
192             || each_import(*plibp, NULL, &is_or_imports, import) != NULL)
193                 return CBS_STOP;
194         else
195                 return CBS_CONT;
196 }
197
198 int
199 protolib_add_import(struct protolib *plib, struct protolib *import)
200 {
201         assert(plib != NULL);
202         assert(import != NULL);
203         if (is_or_imports(&import, plib) == CBS_STOP) {
204                 fprintf(stderr, "Recursive import rejected.\n");
205                 return -2;
206         }
207
208         return VECT_PUSHBACK(&plib->imports, &import) < 0 ? -1 : 0;
209 }
210
211 static int
212 bailout(const char *name, int own)
213 {
214         int save_errno = errno;
215         if (own)
216                 free((char *)name);
217         errno = save_errno;
218         return -1;
219 }
220
221 int
222 protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
223                        struct prototype *proto)
224 {
225         assert(plib != NULL);
226         if (strdup_if(&name, name, !own_name) < 0)
227                 return -1;
228         if (DICT_INSERT(&plib->prototypes, &name, proto) < 0)
229                 return bailout(name, own_name);
230         return 0;
231 }
232
233 int
234 protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
235                         struct named_type *named)
236 {
237         assert(plib != NULL);
238         if (strdup_if(&name, name, !own_name) < 0)
239                 return -1;
240         if (DICT_INSERT(&plib->named_types, &name, named) < 0)
241                 return bailout(name, own_name);
242         return 0;
243 }
244
245 struct lookup {
246         const char *name;
247         struct dict *(*getter)(struct protolib *plib);
248         bool imports;
249         void *result;
250 };
251
252 static struct dict *
253 get_prototypes(struct protolib *plib)
254 {
255         assert(plib != NULL);
256         return &plib->prototypes;
257 }
258
259 static struct dict *
260 get_named_types(struct protolib *plib)
261 {
262         assert(plib != NULL);
263         return &plib->named_types;
264 }
265
266 static enum callback_status
267 protolib_lookup_rec(struct protolib **plibp, void *data)
268 {
269         assert(plibp != NULL);
270         assert(*plibp != NULL);
271         struct lookup *lookup = data;
272         struct dict *dict = (*lookup->getter)(*plibp);
273
274         lookup->result = dict_find(dict, &lookup->name);
275         if (lookup->result != NULL)
276                 return CBS_STOP;
277
278         if (lookup->imports && each_import(*plibp, NULL, &protolib_lookup_rec,
279                                            lookup) != NULL) {
280                 assert(lookup->result != NULL);
281                 return CBS_STOP;
282         }
283
284         return CBS_CONT;
285 }
286
287 static void *
288 protolib_lookup(struct protolib *plib, const char *name,
289                 struct dict *(*getter)(struct protolib *),
290                 bool imports)
291 {
292         assert(plib != NULL);
293         struct lookup lookup = { name, getter, imports, NULL };
294         if (protolib_lookup_rec(&plib, &lookup) == CBS_STOP)
295                 assert(lookup.result != NULL);
296         else
297                 assert(lookup.result == NULL);
298         return lookup.result;
299 }
300
301 struct prototype *
302 protolib_lookup_prototype(struct protolib *plib, const char *name, bool imports)
303 {
304         assert(plib != NULL);
305         return protolib_lookup(plib, name, &get_prototypes, imports);
306 }
307
308 struct named_type *
309 protolib_lookup_type(struct protolib *plib, const char *name, bool imports)
310 {
311         assert(plib != NULL);
312         return protolib_lookup(plib, name, &get_named_types, imports);
313 }
314
315 static void
316 destroy_protolib_cb(struct protolib **plibp, void *data)
317 {
318         assert(plibp != NULL);
319
320         if (*plibp != NULL
321             && --(*plibp)->refs == 0) {
322                 protolib_destroy(*plibp);
323                 free(*plibp);
324         }
325 }
326
327 void
328 protolib_cache_destroy(struct protolib_cache *cache)
329 {
330         DICT_DESTROY(&cache->protolibs, const char *, struct protolib *,
331                      dict_dtor_string, destroy_protolib_cb, NULL);
332 }
333
334 struct load_config_data {
335         struct protolib_cache *self;
336         const char *key;
337         struct protolib *result;
338 };
339
340 static struct protolib *
341 consider_config_dir(struct protolib_cache *cache,
342                     const char *path, const char *key)
343 {
344         size_t len = sizeof ".conf";
345         char slash[2] = {'/'};
346         char *buf = alloca(strlen(path) + 1 + strlen(key) + len);
347         strcpy(stpcpy(stpcpy(stpcpy(buf, path), slash), key), ".conf");
348
349         return protolib_cache_file(cache, buf, 0);
350 }
351
352 static enum callback_status
353 consider_confdir_cb(struct opt_F_t *entry, void *d)
354 {
355         if (opt_F_get_kind(entry) != OPT_F_DIR)
356                 return CBS_CONT;
357         struct load_config_data *data = d;
358
359         data->result = consider_config_dir(data->self,
360                                            entry->pathname, data->key);
361         return data->result != NULL ? CBS_STOP : CBS_CONT;
362 }
363
364 static int
365 load_dash_F_dirs(struct protolib_cache *cache,
366                  const char *key, struct protolib **retp)
367 {
368         struct load_config_data data = {cache, key};
369
370         if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
371                       consider_confdir_cb, &data) == NULL)
372                 /* Not found.  That's fine.  */
373                 return 0;
374
375         if (data.result == NULL)
376                 /* There were errors.  */
377                 return -1;
378
379         *retp = data.result;
380         return 0;
381 }
382
383 static int
384 load_config(struct protolib_cache *cache,
385             const char *key, int private, struct protolib **retp)
386 {
387         const char **dirs = NULL;
388         if (os_get_config_dirs(private, &dirs) < 0
389             || dirs == NULL)
390                 return -1;
391
392         for (; *dirs != NULL; ++dirs) {
393                 struct protolib *plib = consider_config_dir(cache, *dirs, key);
394                 if (plib != NULL) {
395                         *retp = plib;
396                         break;
397                 }
398         }
399
400         return 0;
401 }
402
403 static enum callback_status
404 import_legacy_file(char **fnp, void *data)
405 {
406         struct protolib_cache *cache = data;
407         struct protolib *plib = protolib_cache_file(cache, *fnp, 1);
408         if (plib != NULL) {
409                 /* The cache now owns the file name.  */
410                 *fnp = NULL;
411                 if (protolib_add_import(&cache->imports, plib) < 0)
412                         return CBS_STOP;
413         }
414
415         return CBS_CONT;
416 }
417
418 static int
419 add_ltrace_conf(struct protolib_cache *cache)
420 {
421         /* Look into private config directories for .ltrace.conf and
422          * into system config directories for ltrace.conf.  If it's
423          * found, add it to implicit import module.  */
424         struct vect legacy_files;
425         VECT_INIT(&legacy_files, char *);
426         if (os_get_ltrace_conf_filenames(&legacy_files) < 0) {
427                 vect_destroy(&legacy_files, NULL, NULL);
428                 return -1;
429         }
430
431         int ret = VECT_EACH(&legacy_files, char *, NULL,
432                             import_legacy_file, cache) == NULL ? 0 : -1;
433         VECT_DESTROY(&legacy_files, char *, vect_dtor_string, NULL);
434         return ret;
435 }
436
437 static enum callback_status
438 add_imports_cb(struct opt_F_t *entry, void *data)
439 {
440         struct protolib_cache *self = data;
441         if (opt_F_get_kind(entry) != OPT_F_FILE)
442                 return CBS_CONT;
443
444         struct protolib *new_import
445                 = protolib_cache_file(self, entry->pathname, 0);
446
447         if (new_import == NULL
448             || protolib_add_import(&self->imports, new_import) < 0)
449                 /* N.B. If new_import is non-NULL, it has been already
450                  * cached.  We don't therefore destroy it on
451                  * failures.  */
452                 return CBS_STOP;
453
454         return CBS_CONT;
455 }
456
457 int
458 protolib_cache_init(struct protolib_cache *cache, struct protolib *import)
459 {
460         DICT_INIT(&cache->protolibs, char *, struct protolib *,
461                   dict_hash_string, dict_eq_string, NULL);
462         protolib_init(&cache->imports);
463
464         /* At this point the cache is consistent.  This is important,
465          * because next we will use it to cache files that we load
466          * due to -F.
467          *
468          * But we are about to construct the implicit import module,
469          * which means this module can't be itself imported to the
470          * files that we load now.  So remember that we are still
471          * bootstrapping.  */
472         cache->bootstrap = 1;
473
474         if (protolib_add_import(&cache->imports, &legacy_typedefs) < 0
475             || (import != NULL
476                 && protolib_add_import(&cache->imports, import) < 0)
477             || add_ltrace_conf(cache) < 0
478             || VECT_EACH(&opt_F, struct opt_F_t, NULL,
479                          add_imports_cb, cache) != NULL) {
480                 protolib_cache_destroy(cache);
481                 return -1;
482         }
483
484         cache->bootstrap = 0;
485         return 0;
486 }
487
488 static enum callback_status
489 add_import_cb(struct protolib **importp, void *data)
490 {
491         struct protolib *plib = data;
492         if (protolib_add_import(plib, *importp) < 0)
493                 return CBS_STOP;
494         else
495                 return CBS_CONT;
496 }
497
498 static struct protolib *
499 build_default_config(struct protolib_cache *cache, const char *key)
500 {
501         struct protolib *new_plib = malloc(sizeof(*new_plib));
502         if (new_plib == NULL) {
503                 fprintf(stderr, "Couldn't create config module %s: %s\n",
504                         key, strerror(errno));
505                 return NULL;
506         }
507
508         protolib_init(new_plib);
509
510         /* If bootstrapping, copy over imports from implicit import
511          * module to new_plib.  We can't reference the implicit
512          * import module itself, because new_plib will become part of
513          * this same implicit import module itself.  */
514         if ((cache->bootstrap && each_import(&cache->imports, NULL,
515                                              add_import_cb, new_plib) != NULL)
516             || (!cache->bootstrap
517                 && protolib_add_import(new_plib, &cache->imports) < 0)) {
518
519                 fprintf(stderr,
520                         "Couldn't add imports to config module %s: %s\n",
521                         key, strerror(errno));
522                 protolib_destroy(new_plib);
523                 free(new_plib);
524                 return NULL;
525         }
526
527         return new_plib;
528 }
529
530 static void
531 attempt_to_cache(struct protolib_cache *cache,
532                  const char *key, struct protolib *plib)
533 {
534         if (protolib_cache_protolib(cache, key, 1, plib) == 0
535             || plib == NULL)
536                 /* Never mind failing to store a NULL.  */
537                 return;
538
539         /* Returning a protolib that hasn't been cached would leak
540          * that protolib, but perhaps it's less bad then giving up
541          * outright.  At least print an error message.  */
542         fprintf(stderr, "Couldn't cache prototype library for %s\n", key);
543         free((void *) key);
544 }
545
546 int
547 protolib_cache_maybe_load(struct protolib_cache *cache,
548                           const char *key, int own_key, bool allow_private,
549                           struct protolib **retp)
550 {
551         if (DICT_FIND_VAL(&cache->protolibs, &key, retp) == 0)
552                 return 0;
553
554         if (strdup_if(&key, key, !own_key) < 0) {
555                 fprintf(stderr, "Couldn't cache %s: %s\n",
556                         key, strerror(errno));
557                 return -1;
558         }
559
560         *retp = NULL;
561         if (load_dash_F_dirs(cache, key, retp) < 0
562             || (*retp == NULL && allow_private
563                 && load_config(cache, key, 1, retp) < 0)
564             || (*retp == NULL
565                 && load_config(cache, key, 0, retp) < 0))
566         {
567                 if (!own_key)
568                         free((void *) key);
569                 fprintf(stderr,
570                         "Error occurred when attempting to load a prototype "
571                         "library for %s.\n", key);
572                 return -1;
573         }
574
575         if (*retp != NULL)
576                 attempt_to_cache(cache, key, *retp);
577         else if (!own_key)
578                 free((void *) key);
579
580         return 0;
581 }
582
583 struct protolib *
584 protolib_cache_load(struct protolib_cache *cache,
585                     const char *key, int own_key, bool allow_private)
586 {
587         struct protolib *plib;
588         if (protolib_cache_maybe_load(cache, key, own_key,
589                                       allow_private, &plib) < 0)
590                 return NULL;
591
592         if (plib == NULL)
593                 plib = protolib_cache_default(cache, key, own_key);
594
595         return plib;
596 }
597
598 struct protolib *
599 protolib_cache_default(struct protolib_cache *cache,
600                        const char *key, int own_key)
601 {
602         if (strdup_if(&key, key, !own_key) < 0) {
603                 fprintf(stderr, "Couldn't cache default %s: %s\n",
604                         key, strerror(errno));
605                 return NULL;
606         }
607
608         struct protolib *plib = build_default_config(cache, key);
609
610         /* Whatever came out of this (even NULL), store it in
611          * the cache.  */
612         attempt_to_cache(cache, key, plib);
613
614         return plib;
615 }
616
617 struct protolib *
618 protolib_cache_file(struct protolib_cache *cache,
619                     const char *filename, int own_filename)
620 {
621         {
622                 struct protolib *plib;
623                 if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
624                         return plib;
625         }
626
627         FILE *stream = fopen(filename, "r");
628         if (stream == NULL)
629                 return NULL;
630
631         if (strdup_if(&filename, filename, !own_filename) < 0) {
632                 fprintf(stderr, "Couldn't cache %s: %s\n",
633                         filename, strerror(errno));
634                 fclose(stream);
635                 return NULL;
636         }
637
638         struct protolib *new_plib = build_default_config(cache, filename);
639         if (new_plib == NULL
640             || read_config_file(stream, filename, new_plib) < 0) {
641                 fclose(stream);
642                 if (own_filename)
643                         free((char *) filename);
644                 if (new_plib != NULL) {
645                         protolib_destroy(new_plib);
646                         free(new_plib);
647                 }
648                 return NULL;
649         }
650
651         attempt_to_cache(cache, filename, new_plib);
652         fclose(stream);
653         return new_plib;
654 }
655
656 int
657 protolib_cache_protolib(struct protolib_cache *cache,
658                         const char *filename, int own_filename,
659                         struct protolib *plib)
660 {
661         if (strdup_if(&filename, filename, !own_filename) < 0) {
662                 fprintf(stderr, "Couldn't cache %s: %s\n",
663                         filename, strerror(errno));
664                 return -1;
665         }
666
667         int rc = DICT_INSERT(&cache->protolibs, &filename, &plib);
668         if (rc < 0 && own_filename)
669                 free((char *) filename);
670         if (rc == 0 && plib != NULL)
671                 plib->refs++;
672         return rc;
673 }
674
675 static void
676 destroy_global_config(void)
677 {
678         protolib_cache_destroy(&g_protocache);
679         protolib_destroy(&legacy_typedefs);
680 }
681
682 void
683 init_global_config(void)
684 {
685         protolib_init(&legacy_typedefs);
686
687         struct arg_type_info *ptr_info = type_get_voidptr();
688         static struct named_type voidptr_type;
689         named_type_init(&voidptr_type, ptr_info, 0);
690
691         /* Build legacy typedefs first.  This is used by
692          * protolib_cache_init call below.  */
693         if (protolib_add_named_type(&legacy_typedefs, "addr", 0,
694                                     &voidptr_type) < 0
695             || protolib_add_named_type(&legacy_typedefs, "file", 0,
696                                        &voidptr_type) < 0) {
697                 fprintf(stderr,
698                         "Couldn't initialize aliases `addr' and `file'.\n");
699
700                 exit(1);
701         }
702
703         if (protolib_cache_init(&g_protocache, NULL) < 0) {
704                 fprintf(stderr, "Couldn't init prototype cache\n");
705                 exit(1);
706         }
707
708         atexit(destroy_global_config);
709 }