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
62struct locus
63{
64	const char *filename;
65	int line_no;
66};
67
68static 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);
74static 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);
79static 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);
84static int parse_enum(struct protolib *plib, struct locus *loc,
85		      char **str, struct arg_type_info **retp, int *ownp);
86
87struct prototype *list_of_functions = NULL;
88
89static int
90parse_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
126ok:
127	if (isalnum(CTYPE_CONV(*rest)) || *rest == '_')
128		return -1;
129
130	*name = rest;
131	*ret = candidate;
132	return 0;
133}
134
135static void
136eat_spaces(char **str) {
137	while (**str == ' ') {
138		(*str)++;
139	}
140}
141
142static char *
143xstrndup(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
154static char *
155parse_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*/
175static char *
176start_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
203static int
204parse_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
219static int
220check_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
230static int
231check_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
242static int
243parse_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
255static struct expr_node *parse_argnum(struct locus *loc,
256				      char **str, int *ownp, int zero);
257
258static struct expr_node *
259parse_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
287static int
288wrap_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 */
304static struct expr_node *
305parse_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
389fail:
390	free(expr);
391	return NULL;
392}
393
394static struct arg_type_info *
395parse_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
415static int
416parse_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,... ) */
484static int
485parse_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.  */
537static int
538unshare_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
555static int
556parse_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
660static int
661build_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.  */
694static int
695try_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.  */
711static int
712parse_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 ) */
747static int
748parse_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 */
787static int
788parse_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
885static struct arg_type_info *
886parse_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
956static 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
969static struct lens *
970name2lens(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
982static struct arg_type_info *
983parse_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
1016static struct arg_type_info *
1017parse_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
1071static int
1072param_is_void(struct param *param)
1073{
1074	return param->flavor == PARAM_FLAVOR_TYPE
1075		&& param->u.type.type->type == ARGTYPE_VOID;
1076}
1077
1078static struct arg_type_info *
1079get_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
1092static enum callback_status
1093void_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
1109static int
1110process_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(&param);
1180				if (prototype_push_param(&fun, &param) < 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(&param, type, own);
1200		if (prototype_push_param(&fun, &param) < 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
1259int
1260read_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