1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 1998,1999,2003,2007,2008,2009 Juan Cespedes
5 * Copyright (C) 2006 Ian Wienand
6 * Copyright (C) 2006 Steve Fink
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 */
23
24 /* getline is POSIX.1-2008. It was originally a GNU extension, and
25 * chances are uClibc still needs _GNU_SOURCE, but for now try it this
26 * way. */
27 #define _POSIX_C_SOURCE 200809L
28
29 #include "config.h"
30
31 #include <string.h>
32 #include <stdlib.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <assert.h>
36
37 #include "common.h"
38 #include "output.h"
39 #include "expr.h"
40 #include "param.h"
41 #include "printf.h"
42 #include "prototype.h"
43 #include "zero.h"
44 #include "type.h"
45 #include "lens.h"
46 #include "lens_default.h"
47 #include "lens_enum.h"
48
49 /* Lifted from GCC: The ctype functions are often implemented as
50 * macros which do lookups in arrays using the parameter as the
51 * offset. If the ctype function parameter is a char, then gcc will
52 * (appropriately) warn that a "subscript has type char". Using a
53 * (signed) char as a subscript is bad because you may get negative
54 * offsets and thus it is not 8-bit safe. The CTYPE_CONV macro
55 * ensures that the parameter is cast to an unsigned char when a char
56 * is passed in. When an int is passed in, the parameter is left
57 * alone so we don't lose EOF. */
58
59 #define CTYPE_CONV(CH) \
60 (sizeof(CH) == sizeof(unsigned char) ? (int)(unsigned char)(CH) : (int)(CH))
61
62 struct locus
63 {
64 const char *filename;
65 int line_no;
66 };
67
68 static struct arg_type_info *parse_nonpointer_type(struct protolib *plib,
69 struct locus *loc,
70 char **str,
71 struct param **extra_param,
72 size_t param_num,
73 int *ownp, int *forwardp);
74 static struct arg_type_info *parse_type(struct protolib *plib,
75 struct locus *loc,
76 char **str, struct param **extra_param,
77 size_t param_num, int *ownp,
78 int *forwardp);
79 static struct arg_type_info *parse_lens(struct protolib *plib,
80 struct locus *loc,
81 char **str, struct param **extra_param,
82 size_t param_num, int *ownp,
83 int *forwardp);
84 static int parse_enum(struct protolib *plib, struct locus *loc,
85 char **str, struct arg_type_info **retp, int *ownp);
86
87 struct prototype *list_of_functions = NULL;
88
89 static int
parse_arg_type(char ** name,enum arg_type * ret)90 parse_arg_type(char **name, enum arg_type *ret)
91 {
92 char *rest = NULL;
93 enum arg_type candidate;
94
95 #define KEYWORD(KWD, TYPE) \
96 do { \
97 if (strncmp(*name, KWD, sizeof(KWD) - 1) == 0) { \
98 rest = *name + sizeof(KWD) - 1; \
99 candidate = TYPE; \
100 goto ok; \
101 } \
102 } while (0)
103
104 KEYWORD("void", ARGTYPE_VOID);
105 KEYWORD("int", ARGTYPE_INT);
106 KEYWORD("uint", ARGTYPE_UINT);
107 KEYWORD("long", ARGTYPE_LONG);
108 KEYWORD("ulong", ARGTYPE_ULONG);
109 KEYWORD("char", ARGTYPE_CHAR);
110 KEYWORD("short", ARGTYPE_SHORT);
111 KEYWORD("ushort", ARGTYPE_USHORT);
112 KEYWORD("float", ARGTYPE_FLOAT);
113 KEYWORD("double", ARGTYPE_DOUBLE);
114 KEYWORD("array", ARGTYPE_ARRAY);
115 KEYWORD("struct", ARGTYPE_STRUCT);
116
117 /* Misspelling of int used in ltrace.conf that we used to
118 * ship. */
119 KEYWORD("itn", ARGTYPE_INT);
120
121 assert(rest == NULL);
122 return -1;
123
124 #undef KEYWORD
125
126 ok:
127 if (isalnum(CTYPE_CONV(*rest)) || *rest == '_')
128 return -1;
129
130 *name = rest;
131 *ret = candidate;
132 return 0;
133 }
134
135 static void
eat_spaces(char ** str)136 eat_spaces(char **str) {
137 while (**str == ' ') {
138 (*str)++;
139 }
140 }
141
142 static char *
xstrndup(char * str,size_t len)143 xstrndup(char *str, size_t len) {
144 char *ret = (char *) malloc(len + 1);
145 if (ret == NULL) {
146 report_global_error("malloc: %s", strerror(errno));
147 return NULL;
148 }
149 strncpy(ret, str, len);
150 ret[len] = 0;
151 return ret;
152 }
153
154 static char *
parse_ident(struct locus * loc,char ** str)155 parse_ident(struct locus *loc, char **str)
156 {
157 char *ident = *str;
158
159 if (!isalpha(CTYPE_CONV(**str)) && **str != '_') {
160 report_error(loc->filename, loc->line_no, "bad identifier");
161 return NULL;
162 }
163
164 while (**str && (isalnum(CTYPE_CONV(**str)) || **str == '_')) {
165 ++(*str);
166 }
167
168 return xstrndup(ident, *str - ident);
169 }
170
171 /*
172 Returns position in string at the left parenthesis which starts the
173 function's argument signature. Returns NULL on error.
174 */
175 static char *
start_of_arg_sig(char * str)176 start_of_arg_sig(char *str) {
177 char *pos;
178 int stacked = 0;
179
180 if (!strlen(str))
181 return NULL;
182
183 pos = &str[strlen(str)];
184 do {
185 pos--;
186 if (pos < str)
187 return NULL;
188 while ((pos > str) && (*pos != ')') && (*pos != '('))
189 pos--;
190
191 if (*pos == ')')
192 stacked++;
193 else if (*pos == '(')
194 stacked--;
195 else
196 return NULL;
197
198 } while (stacked > 0);
199
200 return (stacked == 0) ? pos : NULL;
201 }
202
203 static int
parse_int(struct locus * loc,char ** str,long * ret)204 parse_int(struct locus *loc, char **str, long *ret)
205 {
206 char *end;
207 long n = strtol(*str, &end, 0);
208 if (end == *str) {
209 report_error(loc->filename, loc->line_no, "bad number");
210 return -1;
211 }
212
213 *str = end;
214 if (ret != NULL)
215 *ret = n;
216 return 0;
217 }
218
219 static int
check_nonnegative(struct locus * loc,long l)220 check_nonnegative(struct locus *loc, long l)
221 {
222 if (l < 0) {
223 report_error(loc->filename, loc->line_no,
224 "expected non-negative value, got %ld", l);
225 return -1;
226 }
227 return 0;
228 }
229
230 static int
check_int(struct locus * loc,long l)231 check_int(struct locus *loc, long l)
232 {
233 int i = l;
234 if ((long)i != l) {
235 report_error(loc->filename, loc->line_no,
236 "Number too large: %ld", l);
237 return -1;
238 }
239 return 0;
240 }
241
242 static int
parse_char(struct locus * loc,char ** str,char expected)243 parse_char(struct locus *loc, char **str, char expected)
244 {
245 if (**str != expected) {
246 report_error(loc->filename, loc->line_no,
247 "expected '%c', got '%c'", expected, **str);
248 return -1;
249 }
250
251 ++*str;
252 return 0;
253 }
254
255 static struct expr_node *parse_argnum(struct locus *loc,
256 char **str, int *ownp, int zero);
257
258 static struct expr_node *
parse_zero(struct locus * loc,char ** str,int * ownp)259 parse_zero(struct locus *loc, char **str, int *ownp)
260 {
261 eat_spaces(str);
262 if (**str == '(') {
263 ++*str;
264 int own;
265 struct expr_node *arg = parse_argnum(loc, str, &own, 0);
266 if (arg == NULL)
267 return NULL;
268 if (parse_char(loc, str, ')') < 0) {
269 fail:
270 expr_destroy(arg);
271 free(arg);
272 return NULL;
273 }
274
275 struct expr_node *ret = build_zero_w_arg(arg, own);
276 if (ret == NULL)
277 goto fail;
278 *ownp = 1;
279 return ret;
280
281 } else {
282 *ownp = 0;
283 return expr_node_zero();
284 }
285 }
286
287 static int
wrap_in_zero(struct expr_node ** nodep)288 wrap_in_zero(struct expr_node **nodep)
289 {
290 struct expr_node *n = build_zero_w_arg(*nodep, 1);
291 if (n == NULL)
292 return -1;
293 *nodep = n;
294 return 0;
295 }
296
297 /*
298 * Input:
299 * argN : The value of argument #N, counting from 1
300 * eltN : The value of element #N of the containing structure
301 * retval : The return value
302 * N : The numeric value N
303 */
304 static struct expr_node *
parse_argnum(struct locus * loc,char ** str,int * ownp,int zero)305 parse_argnum(struct locus *loc, char **str, int *ownp, int zero)
306 {
307 struct expr_node *expr = malloc(sizeof(*expr));
308 if (expr == NULL)
309 return NULL;
310
311 if (isdigit(CTYPE_CONV(**str))) {
312 long l;
313 if (parse_int(loc, str, &l) < 0
314 || check_nonnegative(loc, l) < 0
315 || check_int(loc, l) < 0)
316 goto fail;
317
318 expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0);
319
320 if (zero && wrap_in_zero(&expr) < 0)
321 goto fail;
322
323 *ownp = 1;
324 return expr;
325
326 } else {
327 char *const name = parse_ident(loc, str);
328 if (name == NULL) {
329 fail_ident:
330 free(name);
331 goto fail;
332 }
333
334 int is_arg = strncmp(name, "arg", 3) == 0;
335 if (is_arg || strncmp(name, "elt", 3) == 0) {
336 long l;
337 char *num = name + 3;
338 if (parse_int(loc, &num, &l) < 0
339 || check_int(loc, l) < 0)
340 goto fail_ident;
341
342 if (is_arg) {
343 if (l == 0)
344 expr_init_named(expr, "retval", 0);
345 else
346 expr_init_argno(expr, l - 1);
347 } else {
348 struct expr_node *e_up = malloc(sizeof(*e_up));
349 struct expr_node *e_ix = malloc(sizeof(*e_ix));
350 if (e_up == NULL || e_ix == NULL) {
351 free(e_up);
352 free(e_ix);
353 goto fail_ident;
354 }
355
356 expr_init_up(e_up, expr_self(), 0);
357 struct arg_type_info *ti
358 = type_get_simple(ARGTYPE_LONG);
359 expr_init_const_word(e_ix, l - 1, ti, 0);
360 expr_init_index(expr, e_up, 1, e_ix, 1);
361 }
362
363 } else if (strcmp(name, "retval") == 0) {
364 expr_init_named(expr, "retval", 0);
365
366 } else if (strcmp(name, "zero") == 0) {
367 struct expr_node *ret
368 = parse_zero(loc, str, ownp);
369 if (ret == NULL)
370 goto fail_ident;
371 free(expr);
372 free(name);
373 return ret;
374
375 } else {
376 report_error(loc->filename, loc->line_no,
377 "Unknown length specifier: '%s'", name);
378 goto fail_ident;
379 }
380
381 if (zero && wrap_in_zero(&expr) < 0)
382 goto fail_ident;
383
384 free(name);
385 *ownp = 1;
386 return expr;
387 }
388
389 fail:
390 free(expr);
391 return NULL;
392 }
393
394 static struct arg_type_info *
parse_typedef_name(struct protolib * plib,char ** str)395 parse_typedef_name(struct protolib *plib, char **str)
396 {
397 char *end = *str;
398 while (*end && (isalnum(CTYPE_CONV(*end)) || *end == '_'))
399 ++end;
400 if (end == *str)
401 return NULL;
402
403 size_t len = end - *str;
404 char buf[len + 1];
405 memcpy(buf, *str, len);
406 *str += len;
407 buf[len] = 0;
408
409 struct named_type *nt = protolib_lookup_type(plib, buf, true);
410 if (nt == NULL)
411 return NULL;
412 return nt->info;
413 }
414
415 static int
parse_typedef(struct protolib * plib,struct locus * loc,char ** str)416 parse_typedef(struct protolib *plib, struct locus *loc, char **str)
417 {
418 (*str) += strlen("typedef");
419 eat_spaces(str);
420 char *name = parse_ident(loc, str);
421
422 /* Look through the typedef list whether we already have a
423 * forward of this type. If we do, it must be forward
424 * structure. */
425 struct named_type *forward = protolib_lookup_type(plib, name, true);
426 if (forward != NULL
427 && (forward->info->type != ARGTYPE_STRUCT
428 || !forward->forward)) {
429 report_error(loc->filename, loc->line_no,
430 "Redefinition of typedef '%s'", name);
431 err:
432 free(name);
433 return -1;
434 }
435
436 // Skip = sign
437 eat_spaces(str);
438 if (parse_char(loc, str, '=') < 0)
439 goto err;
440 eat_spaces(str);
441
442 int fwd = 0;
443 int own = 0;
444 struct arg_type_info *info
445 = parse_lens(plib, loc, str, NULL, 0, &own, &fwd);
446 if (info == NULL)
447 goto err;
448
449 struct named_type this_nt;
450 named_type_init(&this_nt, info, own);
451 this_nt.forward = fwd;
452
453 if (forward == NULL) {
454 if (protolib_add_named_type(plib, name, 1, &this_nt) < 0) {
455 named_type_destroy(&this_nt);
456 goto err;
457 }
458 return 0;
459 }
460
461 /* If we are defining a forward, make sure the definition is a
462 * structure as well. */
463 if (this_nt.info->type != ARGTYPE_STRUCT) {
464 report_error(loc->filename, loc->line_no,
465 "Definition of forward '%s' must be a structure.",
466 name);
467 named_type_destroy(&this_nt);
468 goto err;
469 }
470
471 /* Now move guts of the actual type over to the forward type.
472 * We can't just move pointers around, because references to
473 * forward must stay intact. */
474 assert(this_nt.own_type);
475 type_destroy(forward->info);
476 *forward->info = *this_nt.info;
477 forward->forward = 0;
478 free(this_nt.info);
479 free(name);
480 return 0;
481 }
482
483 /* Syntax: struct ( type,type,type,... ) */
484 static int
parse_struct(struct protolib * plib,struct locus * loc,char ** str,struct arg_type_info * info,int * forwardp)485 parse_struct(struct protolib *plib, struct locus *loc,
486 char **str, struct arg_type_info *info,
487 int *forwardp)
488 {
489 eat_spaces(str);
490
491 if (**str == ';') {
492 if (forwardp == NULL) {
493 report_error(loc->filename, loc->line_no,
494 "Forward struct can be declared only "
495 "directly after a typedef.");
496 return -1;
497 }
498
499 /* Forward declaration is currently handled as an
500 * empty struct. */
501 type_init_struct(info);
502 *forwardp = 1;
503 return 0;
504 }
505
506 if (parse_char(loc, str, '(') < 0)
507 return -1;
508
509 eat_spaces(str); // Empty arg list with whitespace inside
510
511 type_init_struct(info);
512
513 while (1) {
514 eat_spaces(str);
515 if (**str == 0 || **str == ')') {
516 parse_char(loc, str, ')');
517 return 0;
518 }
519
520 /* Field delimiter. */
521 if (type_struct_size(info) > 0)
522 parse_char(loc, str, ',');
523
524 eat_spaces(str);
525 int own;
526 struct arg_type_info *field
527 = parse_lens(plib, loc, str, NULL, 0, &own, NULL);
528 if (field == NULL || type_struct_add(info, field, own)) {
529 type_destroy(info);
530 return -1;
531 }
532 }
533 }
534
535 /* Make a copy of INFO and set the *OWN bit if it's not already
536 * owned. */
537 static int
unshare_type_info(struct locus * loc,struct arg_type_info ** infop,int * ownp)538 unshare_type_info(struct locus *loc, struct arg_type_info **infop, int *ownp)
539 {
540 if (*ownp)
541 return 0;
542
543 struct arg_type_info *ninfo = malloc(sizeof(*ninfo));
544 if (ninfo == NULL || type_clone(ninfo, *infop) < 0) {
545 report_error(loc->filename, loc->line_no,
546 "malloc: %s", strerror(errno));
547 free(ninfo);
548 return -1;
549 }
550 *infop = ninfo;
551 *ownp = 1;
552 return 0;
553 }
554
555 static int
parse_string(struct protolib * plib,struct locus * loc,char ** str,struct arg_type_info ** retp,int * ownp)556 parse_string(struct protolib *plib, struct locus *loc,
557 char **str, struct arg_type_info **retp, int *ownp)
558 {
559 struct arg_type_info *info = NULL;
560 struct expr_node *length;
561 int own_length;
562
563 if (isdigit(CTYPE_CONV(**str))) {
564 /* string0 is string[retval], length is zero(retval)
565 * stringN is string[argN], length is zero(argN) */
566 long l;
567 if (parse_int(loc, str, &l) < 0
568 || check_int(loc, l) < 0)
569 return -1;
570
571 struct expr_node *length_arg = malloc(sizeof(*length_arg));
572 if (length_arg == NULL)
573 return -1;
574
575 if (l == 0)
576 expr_init_named(length_arg, "retval", 0);
577 else
578 expr_init_argno(length_arg, l - 1);
579
580 length = build_zero_w_arg(length_arg, 1);
581 if (length == NULL) {
582 expr_destroy(length_arg);
583 free(length_arg);
584 return -1;
585 }
586 own_length = 1;
587
588 } else {
589 eat_spaces(str);
590 if (**str == '[') {
591 (*str)++;
592 eat_spaces(str);
593
594 length = parse_argnum(loc, str, &own_length, 1);
595 if (length == NULL)
596 return -1;
597
598 eat_spaces(str);
599 parse_char(loc, str, ']');
600
601 } else if (**str == '(') {
602 /* Usage of "string" as lens. */
603 ++*str;
604
605 eat_spaces(str);
606 info = parse_type(plib, loc, str, NULL, 0, ownp, NULL);
607 if (info == NULL)
608 return -1;
609
610 length = NULL;
611 own_length = 0;
612
613 eat_spaces(str);
614 parse_char(loc, str, ')');
615
616 } else {
617 /* It was just a simple string after all. */
618 length = expr_node_zero();
619 own_length = 0;
620 }
621 }
622
623 /* String is a pointer to array of chars. */
624 if (info == NULL) {
625 struct arg_type_info *info1 = malloc(sizeof(*info1));
626 struct arg_type_info *info2 = malloc(sizeof(*info2));
627 if (info1 == NULL || info2 == NULL) {
628 free(info1);
629 free(info2);
630 fail:
631 if (own_length) {
632 assert(length != NULL);
633 expr_destroy(length);
634 free(length);
635 }
636 return -1;
637 }
638 type_init_array(info2, type_get_simple(ARGTYPE_CHAR), 0,
639 length, own_length);
640 type_init_pointer(info1, info2, 1);
641
642 info = info1;
643 *ownp = 1;
644 }
645
646 /* We'll need to set the lens, so unshare. */
647 if (unshare_type_info(loc, &info, ownp) < 0)
648 /* If unshare_type_info failed, it must have been as a
649 * result of cloning attempt because *OWNP was 0.
650 * Thus we don't need to destroy INFO. */
651 goto fail;
652
653 info->lens = &string_lens;
654 info->own_lens = 0;
655
656 *retp = info;
657 return 0;
658 }
659
660 static int
build_printf_pack(struct locus * loc,struct param ** packp,size_t param_num)661 build_printf_pack(struct locus *loc, struct param **packp, size_t param_num)
662 {
663 if (packp == NULL) {
664 report_error(loc->filename, loc->line_no,
665 "'format' type in unexpected context");
666 return -1;
667 }
668 if (*packp != NULL) {
669 report_error(loc->filename, loc->line_no,
670 "only one 'format' type per function supported");
671 return -1;
672 }
673
674 *packp = malloc(sizeof(**packp));
675 if (*packp == NULL)
676 return -1;
677
678 struct expr_node *node = malloc(sizeof(*node));
679 if (node == NULL) {
680 free(*packp);
681 *packp = NULL;
682 return -1;
683 }
684
685 expr_init_argno(node, param_num);
686
687 param_pack_init_printf(*packp, node, 1);
688
689 return 0;
690 }
691
692 /* Match and consume KWD if it's next in stream, and return 0.
693 * Otherwise return negative number. */
694 static int
try_parse_kwd(char ** str,const char * kwd)695 try_parse_kwd(char **str, const char *kwd)
696 {
697 size_t len = strlen(kwd);
698 if (strncmp(*str, kwd, len) == 0
699 && !isalnum(CTYPE_CONV((*str)[len]))
700 && (*str)[len] != '_') {
701 (*str) += len;
702 return 0;
703 }
704 return -1;
705 }
706
707 /* XXX EXTRA_PARAM and PARAM_NUM are a kludge to get in
708 * backward-compatible support for "format" parameter type. The
709 * latter is only valid if the former is non-NULL, which is only in
710 * top-level context. */
711 static int
parse_alias(struct protolib * plib,struct locus * loc,char ** str,struct arg_type_info ** retp,int * ownp,struct param ** extra_param,size_t param_num)712 parse_alias(struct protolib *plib, struct locus *loc,
713 char **str, struct arg_type_info **retp, int *ownp,
714 struct param **extra_param, size_t param_num)
715 {
716 /* For backward compatibility, we need to support things like
717 * stringN (which is like string[argN], string[N], and also
718 * bare string. We might, in theory, replace this by
719 * preprocessing configure file sources with M4, but for now,
720 * "string" is syntax. */
721 if (strncmp(*str, "string", 6) == 0) {
722 (*str) += 6;
723 return parse_string(plib, loc, str, retp, ownp);
724
725 } else if (try_parse_kwd(str, "format") >= 0
726 && extra_param != NULL) {
727 /* For backward compatibility, format is parsed as
728 * "string", but it smuggles to the parameter list of
729 * a function a "printf" argument pack with this
730 * parameter as argument. */
731 if (parse_string(plib, loc, str, retp, ownp) < 0)
732 return -1;
733
734 return build_printf_pack(loc, extra_param, param_num);
735
736 } else if (try_parse_kwd(str, "enum") >=0) {
737
738 return parse_enum(plib, loc, str, retp, ownp);
739
740 } else {
741 *retp = NULL;
742 return 0;
743 }
744 }
745
746 /* Syntax: array ( type, N|argN ) */
747 static int
parse_array(struct protolib * plib,struct locus * loc,char ** str,struct arg_type_info * info)748 parse_array(struct protolib *plib, struct locus *loc,
749 char **str, struct arg_type_info *info)
750 {
751 eat_spaces(str);
752 if (parse_char(loc, str, '(') < 0)
753 return -1;
754
755 eat_spaces(str);
756 int own;
757 struct arg_type_info *elt_info
758 = parse_lens(plib, loc, str, NULL, 0, &own, NULL);
759 if (elt_info == NULL)
760 return -1;
761
762 eat_spaces(str);
763 parse_char(loc, str, ',');
764
765 eat_spaces(str);
766 int own_length;
767 struct expr_node *length = parse_argnum(loc, str, &own_length, 0);
768 if (length == NULL) {
769 if (own) {
770 type_destroy(elt_info);
771 free(elt_info);
772 }
773 return -1;
774 }
775
776 type_init_array(info, elt_info, own, length, own_length);
777
778 eat_spaces(str);
779 parse_char(loc, str, ')');
780 return 0;
781 }
782
783 /* Syntax:
784 * enum (keyname[=value],keyname[=value],... )
785 * enum<type> (keyname[=value],keyname[=value],... )
786 */
787 static int
parse_enum(struct protolib * plib,struct locus * loc,char ** str,struct arg_type_info ** retp,int * ownp)788 parse_enum(struct protolib *plib, struct locus *loc, char **str,
789 struct arg_type_info **retp, int *ownp)
790 {
791 /* Optional type argument. */
792 eat_spaces(str);
793 if (**str == '[') {
794 parse_char(loc, str, '[');
795 eat_spaces(str);
796 *retp = parse_nonpointer_type(plib, loc, str, NULL, 0, ownp, 0);
797 if (*retp == NULL)
798 return -1;
799
800 if (!type_is_integral((*retp)->type)) {
801 report_error(loc->filename, loc->line_no,
802 "integral type required as enum argument");
803 fail:
804 if (*ownp) {
805 /* This also releases associated lens
806 * if any was set so far. */
807 type_destroy(*retp);
808 free(*retp);
809 }
810 return -1;
811 }
812
813 eat_spaces(str);
814 if (parse_char(loc, str, ']') < 0)
815 goto fail;
816
817 } else {
818 *retp = type_get_simple(ARGTYPE_INT);
819 *ownp = 0;
820 }
821
822 /* We'll need to set the lens, so unshare. */
823 if (unshare_type_info(loc, retp, ownp) < 0)
824 goto fail;
825
826 eat_spaces(str);
827 if (parse_char(loc, str, '(') < 0)
828 goto fail;
829
830 struct enum_lens *lens = malloc(sizeof(*lens));
831 if (lens == NULL) {
832 report_error(loc->filename, loc->line_no,
833 "malloc enum lens: %s", strerror(errno));
834 return -1;
835 }
836
837 lens_init_enum(lens);
838 (*retp)->lens = &lens->super;
839 (*retp)->own_lens = 1;
840
841 long last_val = 0;
842 while (1) {
843 eat_spaces(str);
844 if (**str == 0 || **str == ')') {
845 parse_char(loc, str, ')');
846 return 0;
847 }
848
849 /* Field delimiter. XXX should we support the C
850 * syntax, where the enumeration can end in pending
851 * comma? */
852 if (lens_enum_size(lens) > 0)
853 parse_char(loc, str, ',');
854
855 eat_spaces(str);
856 char *key = parse_ident(loc, str);
857 if (key == NULL) {
858 err:
859 free(key);
860 goto fail;
861 }
862
863 if (**str == '=') {
864 ++*str;
865 eat_spaces(str);
866 if (parse_int(loc, str, &last_val) < 0)
867 goto err;
868 }
869
870 struct value *value = malloc(sizeof(*value));
871 if (value == NULL)
872 goto err;
873 value_init_detached(value, NULL, *retp, 0);
874 value_set_word(value, last_val);
875
876 if (lens_enum_add(lens, key, 1, value, 1) < 0)
877 goto err;
878
879 last_val++;
880 }
881
882 return 0;
883 }
884
885 static struct arg_type_info *
parse_nonpointer_type(struct protolib * plib,struct locus * loc,char ** str,struct param ** extra_param,size_t param_num,int * ownp,int * forwardp)886 parse_nonpointer_type(struct protolib *plib, struct locus *loc,
887 char **str, struct param **extra_param, size_t param_num,
888 int *ownp, int *forwardp)
889 {
890 const char *orig_str = *str;
891 enum arg_type type;
892 if (parse_arg_type(str, &type) < 0) {
893 struct arg_type_info *type;
894 if (parse_alias(plib, loc, str, &type,
895 ownp, extra_param, param_num) < 0)
896 return NULL;
897 else if (type != NULL)
898 return type;
899
900 *ownp = 0;
901 if ((type = parse_typedef_name(plib, str)) == NULL)
902 report_error(loc->filename, loc->line_no,
903 "unknown type around '%s'", orig_str);
904 return type;
905 }
906
907 /* For some types that's all we need. */
908 switch (type) {
909 case ARGTYPE_VOID:
910 case ARGTYPE_INT:
911 case ARGTYPE_UINT:
912 case ARGTYPE_LONG:
913 case ARGTYPE_ULONG:
914 case ARGTYPE_CHAR:
915 case ARGTYPE_SHORT:
916 case ARGTYPE_USHORT:
917 case ARGTYPE_FLOAT:
918 case ARGTYPE_DOUBLE:
919 *ownp = 0;
920 return type_get_simple(type);
921
922 case ARGTYPE_ARRAY:
923 case ARGTYPE_STRUCT:
924 break;
925
926 case ARGTYPE_POINTER:
927 /* Pointer syntax is not based on keyword, so we
928 * should never get this type. */
929 assert(type != ARGTYPE_POINTER);
930 abort();
931 }
932
933 struct arg_type_info *info = malloc(sizeof(*info));
934 if (info == NULL) {
935 report_error(loc->filename, loc->line_no,
936 "malloc: %s", strerror(errno));
937 return NULL;
938 }
939 *ownp = 1;
940
941 if (type == ARGTYPE_ARRAY) {
942 if (parse_array(plib, loc, str, info) < 0) {
943 fail:
944 free(info);
945 return NULL;
946 }
947 } else {
948 assert(type == ARGTYPE_STRUCT);
949 if (parse_struct(plib, loc, str, info, forwardp) < 0)
950 goto fail;
951 }
952
953 return info;
954 }
955
956 static struct named_lens {
957 const char *name;
958 struct lens *lens;
959 } lenses[] = {
960 { "hide", &blind_lens },
961 { "octal", &octal_lens },
962 { "oct", &octal_lens },
963 { "bitvec", &bitvect_lens },
964 { "hex", &hex_lens },
965 { "bool", &bool_lens },
966 { "guess", &guess_lens },
967 };
968
969 static struct lens *
name2lens(char ** str,int * own_lensp)970 name2lens(char **str, int *own_lensp)
971 {
972 size_t i;
973 for (i = 0; i < sizeof(lenses)/sizeof(*lenses); ++i)
974 if (try_parse_kwd(str, lenses[i].name) == 0) {
975 *own_lensp = 0;
976 return lenses[i].lens;
977 }
978
979 return NULL;
980 }
981
982 static struct arg_type_info *
parse_type(struct protolib * plib,struct locus * loc,char ** str,struct param ** extra_param,size_t param_num,int * ownp,int * forwardp)983 parse_type(struct protolib *plib, struct locus *loc, char **str,
984 struct param **extra_param, size_t param_num,
985 int *ownp, int *forwardp)
986 {
987 struct arg_type_info *info
988 = parse_nonpointer_type(plib, loc, str, extra_param,
989 param_num, ownp, forwardp);
990 if (info == NULL)
991 return NULL;
992
993 while (1) {
994 eat_spaces(str);
995 if (**str == '*') {
996 struct arg_type_info *outer = malloc(sizeof(*outer));
997 if (outer == NULL) {
998 if (*ownp) {
999 type_destroy(info);
1000 free(info);
1001 }
1002 report_error(loc->filename, loc->line_no,
1003 "malloc: %s", strerror(errno));
1004 return NULL;
1005 }
1006 type_init_pointer(outer, info, *ownp);
1007 *ownp = 1;
1008 (*str)++;
1009 info = outer;
1010 } else
1011 break;
1012 }
1013 return info;
1014 }
1015
1016 static struct arg_type_info *
parse_lens(struct protolib * plib,struct locus * loc,char ** str,struct param ** extra_param,size_t param_num,int * ownp,int * forwardp)1017 parse_lens(struct protolib *plib, struct locus *loc,
1018 char **str, struct param **extra_param,
1019 size_t param_num, int *ownp, int *forwardp)
1020 {
1021 int own_lens;
1022 struct lens *lens = name2lens(str, &own_lens);
1023 int has_args = 1;
1024 struct arg_type_info *info;
1025 if (lens != NULL) {
1026 eat_spaces(str);
1027
1028 /* Octal lens gets special treatment, because of
1029 * backward compatibility. */
1030 if (lens == &octal_lens && **str != '(') {
1031 has_args = 0;
1032 info = type_get_simple(ARGTYPE_INT);
1033 *ownp = 0;
1034 } else if (parse_char(loc, str, '(') < 0) {
1035 report_error(loc->filename, loc->line_no,
1036 "expected type argument after the lens");
1037 return NULL;
1038 }
1039 }
1040
1041 if (has_args) {
1042 eat_spaces(str);
1043 info = parse_type(plib, loc, str, extra_param, param_num,
1044 ownp, forwardp);
1045 if (info == NULL) {
1046 fail:
1047 if (own_lens && lens != NULL)
1048 lens_destroy(lens);
1049 return NULL;
1050 }
1051 }
1052
1053 if (lens != NULL && has_args) {
1054 eat_spaces(str);
1055 parse_char(loc, str, ')');
1056 }
1057
1058 /* We can't modify shared types. Make a copy if we have a
1059 * lens. */
1060 if (lens != NULL && unshare_type_info(loc, &info, ownp) < 0)
1061 goto fail;
1062
1063 if (lens != NULL) {
1064 info->lens = lens;
1065 info->own_lens = own_lens;
1066 }
1067
1068 return info;
1069 }
1070
1071 static int
param_is_void(struct param * param)1072 param_is_void(struct param *param)
1073 {
1074 return param->flavor == PARAM_FLAVOR_TYPE
1075 && param->u.type.type->type == ARGTYPE_VOID;
1076 }
1077
1078 static struct arg_type_info *
get_hidden_int(void)1079 get_hidden_int(void)
1080 {
1081 static struct arg_type_info info, *pinfo = NULL;
1082 if (pinfo != NULL)
1083 return pinfo;
1084
1085 info = *type_get_simple(ARGTYPE_INT);
1086 info.lens = &blind_lens;
1087 pinfo = &info;
1088
1089 return pinfo;
1090 }
1091
1092 static enum callback_status
void_to_hidden_int(struct prototype * proto,struct param * param,void * data)1093 void_to_hidden_int(struct prototype *proto, struct param *param, void *data)
1094 {
1095 struct locus *loc = data;
1096 if (param_is_void(param)) {
1097 report_warning(loc->filename, loc->line_no,
1098 "void parameter assumed to be 'hide(int)'");
1099
1100 static struct arg_type_info *type = NULL;
1101 if (type == NULL)
1102 type = get_hidden_int();
1103 param_destroy(param);
1104 param_init_type(param, type, 0);
1105 }
1106 return CBS_CONT;
1107 }
1108
1109 static int
process_line(struct protolib * plib,struct locus * loc,char * buf)1110 process_line(struct protolib *plib, struct locus *loc, char *buf)
1111 {
1112 char *str = buf;
1113 char *tmp;
1114
1115 debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename);
1116 eat_spaces(&str);
1117
1118 /* A comment or empty line. */
1119 if (*str == ';' || *str == 0 || *str == '\n' || *str == '#')
1120 return 0;
1121
1122 if (strncmp(str, "typedef", 7) == 0) {
1123 parse_typedef(plib, loc, &str);
1124 return 0;
1125 }
1126
1127 struct prototype fun;
1128 prototype_init(&fun);
1129
1130 struct param *extra_param = NULL;
1131 char *proto_name = NULL;
1132 int own;
1133 fun.return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL);
1134 if (fun.return_info == NULL) {
1135 err:
1136 debug(3, " Skipping line %d", loc->line_no);
1137
1138 if (extra_param != NULL) {
1139 param_destroy(extra_param);
1140 free(extra_param);
1141 }
1142
1143 prototype_destroy(&fun);
1144 free(proto_name);
1145 return -1;
1146 }
1147 fun.own_return_info = own;
1148 debug(4, " return_type = %d", fun.return_info->type);
1149
1150 eat_spaces(&str);
1151 tmp = start_of_arg_sig(str);
1152 if (tmp == NULL) {
1153 report_error(loc->filename, loc->line_no, "syntax error");
1154 goto err;
1155 }
1156 *tmp = '\0';
1157
1158 proto_name = strdup(str);
1159 if (proto_name == NULL) {
1160 oom:
1161 report_error(loc->filename, loc->line_no,
1162 "%s", strerror(errno));
1163 goto err;
1164 }
1165
1166 str = tmp + 1;
1167 debug(3, " name = %s", proto_name);
1168
1169 int have_stop = 0;
1170
1171 while (1) {
1172 eat_spaces(&str);
1173 if (*str == ')')
1174 break;
1175
1176 if (str[0] == '+') {
1177 if (have_stop == 0) {
1178 struct param param;
1179 param_init_stop(¶m);
1180 if (prototype_push_param(&fun, ¶m) < 0)
1181 goto oom;
1182 have_stop = 1;
1183 }
1184 str++;
1185 }
1186
1187 int own;
1188 size_t param_num = prototype_num_params(&fun) - have_stop;
1189 struct arg_type_info *type
1190 = parse_lens(plib, loc, &str, &extra_param,
1191 param_num, &own, NULL);
1192 if (type == NULL) {
1193 report_error(loc->filename, loc->line_no,
1194 "unknown argument type");
1195 goto err;
1196 }
1197
1198 struct param param;
1199 param_init_type(¶m, type, own);
1200 if (prototype_push_param(&fun, ¶m) < 0)
1201 goto oom;
1202
1203 eat_spaces(&str);
1204 if (*str == ',') {
1205 str++;
1206 continue;
1207 } else if (*str == ')') {
1208 continue;
1209 } else {
1210 if (str[strlen(str) - 1] == '\n')
1211 str[strlen(str) - 1] = '\0';
1212 report_error(loc->filename, loc->line_no,
1213 "syntax error around \"%s\"", str);
1214 goto err;
1215 }
1216 }
1217
1218 /* We used to allow void parameter as a synonym to an argument
1219 * that shouldn't be displayed. But backends really need to
1220 * know the exact type that they are dealing with. The proper
1221 * way to do this these days is to use the hide lens.
1222 *
1223 * So if there are any voids in the parameter list, show a
1224 * warning and assume that they are ints. If there's a sole
1225 * void, assume the function doesn't take any arguments. The
1226 * latter is conservative, we can drop the argument
1227 * altogether, instead of fetching and then not showing it,
1228 * without breaking any observable behavior. */
1229 if (prototype_num_params(&fun) == 1
1230 && param_is_void(prototype_get_nth_param(&fun, 0))) {
1231 if (0)
1232 /* Don't show this warning. Pre-0.7.0
1233 * ltrace.conf often used this idiom. This
1234 * should be postponed until much later, when
1235 * extant uses are likely gone. */
1236 report_warning(loc->filename, loc->line_no,
1237 "sole void parameter ignored");
1238 prototype_destroy_nth_param(&fun, 0);
1239 } else {
1240 prototype_each_param(&fun, NULL, void_to_hidden_int, loc);
1241 }
1242
1243 if (extra_param != NULL) {
1244 prototype_push_param(&fun, extra_param);
1245 free(extra_param);
1246 extra_param = NULL;
1247 }
1248
1249 if (protolib_add_prototype(plib, proto_name, 1, &fun) < 0) {
1250 report_error(loc->filename, loc->line_no,
1251 "couldn't add prototype: %s",
1252 strerror(errno));
1253 goto err;
1254 }
1255
1256 return 0;
1257 }
1258
1259 int
read_config_file(FILE * stream,const char * path,struct protolib * plib)1260 read_config_file(FILE *stream, const char *path, struct protolib *plib)
1261 {
1262 debug(DEBUG_FUNCTION, "Reading config file `%s'...", path);
1263
1264 struct locus loc = { path, 0 };
1265 char *line = NULL;
1266 size_t len = 0;
1267 while (getline(&line, &len, stream) >= 0) {
1268 loc.line_no++;
1269 process_line(plib, &loc, line);
1270 }
1271
1272 free(line);
1273 return 0;
1274 }
1275