read_config_file.c revision 31af32cfcd61671cbb5e567870103766b3231521
1/*
2 * This file is part of ltrace.
3 * Copyright (C) 2011,2012 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#include "config.h"
25
26#include <string.h>
27#include <stdlib.h>
28#include <ctype.h>
29#include <errno.h>
30#include <error.h>
31#include <assert.h>
32
33#include "common.h"
34#include "output.h"
35#include "expr.h"
36#include "param.h"
37#include "printf.h"
38#include "zero.h"
39#include "type.h"
40#include "lens.h"
41
42static int line_no;
43static char *filename;
44
45static struct arg_type_info *parse_nonpointer_type(char **str,
46						   struct param **extra_param,
47						   size_t param_num, int *ownp);
48static struct arg_type_info *parse_type(char **str, struct param **extra_param,
49					size_t param_num, int *ownp);
50static struct arg_type_info *parse_lens(char **str, struct param **extra_param,
51					size_t param_num, int *ownp);
52
53Function *list_of_functions = NULL;
54
55static int
56parse_arg_type(char **name, enum arg_type *ret)
57{
58	char *rest = NULL;
59	enum arg_type candidate = ARGTYPE_UNKNOWN;
60
61#define KEYWORD(KWD, TYPE)						\
62	do {								\
63		if (strncmp(*name, KWD, sizeof(KWD) - 1) == 0) {	\
64			rest = *name + sizeof(KWD) - 1;			\
65			candidate = TYPE;				\
66			goto ok;					\
67		}							\
68	} while (0)
69
70	KEYWORD("void", ARGTYPE_VOID);
71	KEYWORD("int", ARGTYPE_INT);
72	KEYWORD("uint", ARGTYPE_UINT);
73	KEYWORD("long", ARGTYPE_LONG);
74	KEYWORD("ulong", ARGTYPE_ULONG);
75	KEYWORD("octal", ARGTYPE_OCTAL);
76	KEYWORD("char", ARGTYPE_CHAR);
77	KEYWORD("short", ARGTYPE_SHORT);
78	KEYWORD("ushort", ARGTYPE_USHORT);
79	KEYWORD("float", ARGTYPE_FLOAT);
80	KEYWORD("double", ARGTYPE_DOUBLE);
81	KEYWORD("array", ARGTYPE_ARRAY);
82	KEYWORD("enum", ARGTYPE_ENUM);
83	KEYWORD("struct", ARGTYPE_STRUCT);
84
85	assert(rest == NULL);
86	return -1;
87
88#undef KEYWORD
89
90ok:
91	if (isalnum(*rest))
92		return -1;
93
94	*name = rest;
95	*ret = candidate;
96	return 0;
97}
98
99static void
100eat_spaces(char **str) {
101	while (**str == ' ') {
102		(*str)++;
103	}
104}
105
106static char *
107xstrndup(char *str, size_t len) {
108	char *ret = (char *) malloc(len + 1);
109	if (ret == NULL) {
110		report_global_error("malloc: %s", strerror(errno));
111		return NULL;
112	}
113	strncpy(ret, str, len);
114	ret[len] = 0;
115	return ret;
116}
117
118static char *
119parse_ident(char **str) {
120	char *ident = *str;
121
122	if (!isalpha(**str) && **str != '_') {
123		report_error(filename, line_no, "bad identifier");
124		return NULL;
125	}
126
127	while (**str && (isalnum(**str) || **str == '_')) {
128		++(*str);
129	}
130
131	return xstrndup(ident, *str - ident);
132}
133
134/*
135  Returns position in string at the left parenthesis which starts the
136  function's argument signature. Returns NULL on error.
137*/
138static char *
139start_of_arg_sig(char *str) {
140	char *pos;
141	int stacked = 0;
142
143	if (!strlen(str))
144		return NULL;
145
146	pos = &str[strlen(str)];
147	do {
148		pos--;
149		if (pos < str)
150			return NULL;
151		while ((pos > str) && (*pos != ')') && (*pos != '('))
152			pos--;
153
154		if (*pos == ')')
155			stacked++;
156		else if (*pos == '(')
157			stacked--;
158		else
159			return NULL;
160
161	} while (stacked > 0);
162
163	return (stacked == 0) ? pos : NULL;
164}
165
166static int
167parse_int(char **str, long *ret)
168{
169	char *end;
170	long n = strtol(*str, &end, 0);
171	if (end == *str) {
172		report_error(filename, line_no, "bad number");
173		return -1;
174	}
175
176	*str = end;
177	if (ret != NULL)
178		*ret = n;
179	return 0;
180}
181
182static int
183check_nonnegative(long l)
184{
185	if (l < 0) {
186		report_error(filename, line_no,
187			     "expected non-negative value, got %ld", l);
188		return -1;
189	}
190	return 0;
191}
192
193static int
194check_int(long l)
195{
196	int i = l;
197	if ((long)i != l) {
198		report_error(filename, line_no,
199			     "Number too large: %ld", l);
200		return -1;
201	}
202	return 0;
203}
204
205static int
206parse_char(char **str, char expected)
207{
208	if (**str != expected) {
209		report_error(filename, line_no,
210			     "expected '%c', got '%c'", expected, **str);
211		return -1;
212	}
213
214	++*str;
215	return 0;
216}
217
218static struct expr_node *parse_argnum(char **str, int zero);
219
220static struct expr_node *
221parse_zero(char **str, struct expr_node *ret)
222{
223	eat_spaces(str);
224	if (**str == '(') {
225		++*str;
226		struct expr_node *arg = parse_argnum(str, 0);
227		if (arg == NULL)
228			return NULL;
229		if (parse_char(str, ')') < 0) {
230		fail:
231			expr_destroy(arg);
232			free(arg);
233			return NULL;
234		}
235
236		struct expr_node *ret = build_zero_w_arg(arg, 1);
237		if (ret == NULL)
238			goto fail;
239		return ret;
240
241	} else {
242		return expr_node_zero();
243	}
244}
245
246static int
247wrap_in_zero(struct expr_node **nodep)
248{
249	struct expr_node *n = build_zero_w_arg(*nodep, 1);
250	if (n == NULL)
251		return -1;
252	*nodep = n;
253	return 0;
254}
255
256/*
257 * Input:
258 *  argN   : The value of argument #N, counting from 1
259 *  eltN   : The value of element #N of the containing structure
260 *  retval : The return value
261 *  N      : The numeric value N
262 */
263static struct expr_node *
264parse_argnum(char **str, int zero)
265{
266	struct expr_node *expr = malloc(sizeof(*expr));
267	if (expr == NULL)
268		return NULL;
269
270	if (isdigit(**str)) {
271		long l;
272		if (parse_int(str, &l) < 0
273		    || check_nonnegative(l) < 0
274		    || check_int(l) < 0)
275			goto fail;
276
277		expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0);
278
279		if (zero && wrap_in_zero(&expr) < 0)
280			goto fail;
281
282		return expr;
283
284	} else {
285		char *name = parse_ident(str);
286		if (name == NULL)
287			goto fail;
288
289		int is_arg = strncmp(name, "arg", 3) == 0;
290		int is_elt = !is_arg && strncmp(name, "elt", 3) == 0;
291		if (is_arg || is_elt) {
292			long l;
293			name += 3;
294			if (parse_int(&name, &l) < 0
295			    || check_int(l) < 0)
296				goto fail;
297
298			if (is_arg) {
299				expr_init_argno(expr, l - 1);
300			} else {
301				struct expr_node *e_up = malloc(sizeof(*e_up));
302				struct expr_node *e_ix = malloc(sizeof(*e_ix));
303				if (e_up == NULL || e_ix == NULL) {
304					free(e_up);
305					free(e_ix);
306					goto fail;
307				}
308
309				expr_init_up(e_up, expr_self(), 0);
310				struct arg_type_info *ti
311					= type_get_simple(ARGTYPE_LONG);
312				expr_init_const_word(e_ix, l - 1, ti, 0);
313				expr_init_index(expr, e_up, 1, e_ix, 1);
314			}
315
316		} else if (strcmp(name, "retval") == 0) {
317			expr_init_named(expr, "retval", 0);
318
319		} else if (strcmp(name, "zero") == 0) {
320			struct expr_node *ret = parse_zero(str, expr);
321			if (ret == NULL)
322				goto fail;
323			return ret;
324
325		} else {
326			report_error(filename, line_no,
327				     "Unknown length specifier: '%s'", name);
328			goto fail;
329		}
330
331		if (zero && wrap_in_zero(&expr) < 0)
332			goto fail;
333
334		return expr;
335	}
336
337fail:
338	free(expr);
339	return NULL;
340}
341
342struct typedef_node_t {
343	char *name;
344	struct arg_type_info *info;
345	int own_type;
346	struct typedef_node_t *next;
347} *typedefs = NULL;
348
349static struct arg_type_info *
350lookup_typedef(char **str) {
351	struct typedef_node_t *node;
352	char *end = *str;
353	while (*end && (isalnum(*end) || *end == '_'))
354		++end;
355	if (end == *str)
356		return NULL;
357
358	for (node = typedefs; node != NULL; node = node->next) {
359		if (strncmp(*str, node->name, end - *str) == 0) {
360			(*str) += strlen(node->name);
361			return node->info;
362		}
363	}
364
365	return NULL;
366}
367
368static struct typedef_node_t *
369insert_typedef(char *name, struct arg_type_info *info, int own_type)
370{
371	struct typedef_node_t *binding = malloc(sizeof(*binding));
372	binding->name = name;
373	binding->info = info;
374	binding->own_type = own_type;
375	binding->next = typedefs;
376	typedefs = binding;
377	return binding;
378}
379
380static void
381parse_typedef(char **str) {
382	char *name;
383	struct arg_type_info *info;
384
385	(*str) += strlen("typedef");
386	eat_spaces(str);
387
388	// Grab out the name of the type
389	name = parse_ident(str);
390
391	// Skip = sign
392	eat_spaces(str);
393	if (parse_char(str, '=') < 0)
394		return;
395	eat_spaces(str);
396
397	// Parse the type
398	int own;
399	info = parse_type(str, NULL, 0, &own);
400
401	insert_typedef(name, info, own);
402}
403
404static void
405destroy_fun(Function *fun)
406{
407	size_t i;
408	if (fun == NULL)
409		return;
410	if (fun->own_return_info) {
411		type_destroy(fun->return_info);
412		free(fun->return_info);
413	}
414	for (i = 0; i < fun->num_params; ++i)
415		param_destroy(&fun->params[i]);
416	free(fun->params);
417}
418
419/* Syntax: struct ( type,type,type,... ) */
420static int
421parse_struct(char **str, struct arg_type_info *info)
422{
423	eat_spaces(str);
424	if (parse_char(str, '(') < 0)
425		return -1;
426
427	eat_spaces(str); // Empty arg list with whitespace inside
428
429	type_init_struct(info);
430
431	while (1) {
432		eat_spaces(str);
433		if (**str == 0 || **str == ')') {
434			parse_char(str, ')');
435			return 0;
436		}
437
438		/* Field delimiter.  */
439		if (type_struct_size(info) > 0)
440			parse_char(str, ',');
441
442		eat_spaces(str);
443		int own;
444		struct arg_type_info *field = parse_lens(str, NULL, 0, &own);
445		if (field == NULL || type_struct_add(info, field, own)) {
446			type_destroy(info);
447			return -1;
448		}
449	}
450}
451
452static int
453parse_string(char **str, struct arg_type_info **retp)
454{
455	struct arg_type_info *info = malloc(sizeof(*info));
456	if (info == NULL) {
457	fail:
458		free(info);
459		return -1;
460	}
461
462	struct expr_node *length;
463	int own_length;
464
465	if (isdigit(**str)) {
466		/* string0 is string[retval], length is zero(retval)
467		 * stringN is string[argN], length is zero(argN) */
468		long l;
469		if (parse_int(str, &l) < 0
470		    || check_int(l) < 0)
471			goto fail;
472
473		struct expr_node *length_arg = malloc(sizeof(*length_arg));
474		if (length_arg == NULL)
475			goto fail;
476
477		if (l == 0)
478			expr_init_named(length_arg, "retval", 0);
479		else
480			expr_init_argno(length_arg, l - 1);
481
482		length = build_zero_w_arg(length_arg, 1);
483		if (length == NULL) {
484			expr_destroy(length_arg);
485			free(length_arg);
486			goto fail;
487		}
488		own_length = 1;
489
490	} else {
491		eat_spaces(str);
492		if (**str == '[') {
493			(*str)++;
494			eat_spaces(str);
495
496			length = parse_argnum(str, 1);
497			if (length == NULL)
498				goto fail;
499			own_length = 1;
500
501			eat_spaces(str);
502			parse_char(str, ']');
503
504		} else {
505			/* It was just a simple string after all.  */
506			length = expr_node_zero();
507			own_length = 0;
508		}
509	}
510
511	/* String is a pointer to array of chars.  */
512	type_init_string(info, length, own_length);
513
514	*retp = info;
515	return 0;
516}
517
518static int
519build_printf_pack(struct param **packp, size_t param_num)
520{
521	if (packp == NULL) {
522		report_error(filename, line_no,
523			     "'format' type in unexpected context");
524		return -1;
525	}
526	if (*packp != NULL) {
527		report_error(filename, line_no,
528			     "only one 'format' type per function supported");
529		return -1;
530	}
531
532	*packp = malloc(sizeof(**packp));
533	if (*packp == NULL)
534		return -1;
535
536	struct expr_node *node = malloc(sizeof(*node));
537	if (node == NULL) {
538		free(*packp);
539		return -1;
540	}
541
542	expr_init_argno(node, param_num);
543
544	param_pack_init_printf(*packp, node, 1);
545
546	return 0;
547}
548
549/* Make a copy of INFO and set the *OWN bit if it's not already
550 * owned.  */
551static int
552unshare_type_info(struct arg_type_info **infop, int *ownp)
553{
554	if (*ownp)
555		return 0;
556
557	struct arg_type_info *ninfo = malloc(sizeof(*ninfo));
558	if (ninfo == NULL) {
559		report_error(filename, line_no,
560			     "malloc: %s", strerror(errno));
561		return -1;
562	}
563	*ninfo = **infop;
564	*infop = ninfo;
565	*ownp = 1;
566	return 0;
567}
568
569/* XXX extra_param and param_num are a kludge to get in
570 * backward-compatible support for "format" parameter type.  The
571 * latter is only valid if the former is non-NULL, which is only in
572 * top-level context.  */
573static int
574parse_alias(char **str, struct arg_type_info **retp, int *ownp,
575	    struct param **extra_param, size_t param_num)
576{
577	/* For backward compatibility, we need to support things like
578	 * stringN (which is like string[argN], string[N], and also
579	 * bare string.  We might, in theory, replace this by
580	 * preprocessing configure file sources with M4, but for now,
581	 * "string" is syntax.  */
582	if (strncmp(*str, "string", 6) == 0) {
583		(*str) += 6;
584		return parse_string(str, retp);
585
586	} else if (strncmp(*str, "format", 6) == 0
587		   && !isalnum((*str)[6])
588		   && extra_param != NULL) {
589		/* For backward compatibility, format is parsed as
590		 * "string", but it smuggles to the parameter list of
591		 * a function a "printf" argument pack with this
592		 * parameter as argument.  */
593		(*str) += 6;
594		if (parse_string(str, retp) < 0)
595			return -1;
596
597		return build_printf_pack(extra_param, param_num);
598
599	} else {
600		*retp = NULL;
601		return 0;
602	}
603}
604
605/* Syntax: array ( type, N|argN ) */
606static int
607parse_array(char **str, struct arg_type_info *info)
608{
609	eat_spaces(str);
610	if (parse_char(str, '(') < 0)
611		return -1;
612
613	eat_spaces(str);
614	int own;
615	struct arg_type_info *elt_info = parse_lens(str, NULL, 0, &own);
616	if (elt_info == NULL)
617		return -1;
618
619	eat_spaces(str);
620	parse_char(str, ',');
621
622	eat_spaces(str);
623	struct expr_node *length = parse_argnum(str, 0);
624	if (length == NULL) {
625		if (own) {
626			type_destroy(elt_info);
627			free(elt_info);
628		}
629		return -1;
630	}
631
632	type_init_array(info, elt_info, own, length, 1);
633
634	eat_spaces(str);
635	parse_char(str, ')');
636	return 0;
637}
638
639/* Syntax: enum ( keyname=value,keyname=value,... ) */
640static int
641parse_enum(char **str, struct arg_type_info *info)
642{
643	eat_spaces(str);
644	if (parse_char(str, '(') < 0)
645		return -1;
646
647	type_init_enum(info);
648
649	int last_val = 0;
650	while (1) {
651		eat_spaces(str);
652		if (**str == 0 || **str == ')') {
653			parse_char(str, ')');
654			return 0;
655		}
656
657		/* Field delimiter.  XXX should we support the C
658		 * syntax, where the enumeration can end in pending
659		 * comma?  */
660		if (type_enum_size(info) > 0)
661			parse_char(str, ',');
662
663		eat_spaces(str);
664		char *key = parse_ident(str);
665		if (key == NULL) {
666		err:
667			free(key);
668			return -1;
669		}
670
671		if (**str == '=') {
672			++*str;
673			eat_spaces(str);
674			long l;
675			if (parse_int(str, &l) < 0 || check_int(l) < 0)
676				goto err;
677			last_val = l;
678
679		} else {
680			last_val++;
681		}
682
683		if (type_enum_add(info, key, 1, last_val) < 0)
684			goto err;
685	}
686
687	return 0;
688}
689
690static struct arg_type_info *
691parse_nonpointer_type(char **str, struct param **extra_param, size_t param_num,
692		      int *ownp)
693{
694	enum arg_type type;
695	if (parse_arg_type(str, &type) < 0) {
696		struct arg_type_info *simple;
697		if (parse_alias(str, &simple, ownp, extra_param, param_num) < 0)
698			return NULL;
699		if (simple == NULL)
700			simple = lookup_typedef(str);
701		if (simple != NULL) {
702			*ownp = 0;
703			return simple;
704		}
705
706		report_error(filename, line_no,
707			     "unknown type around '%s'", *str);
708		return NULL;
709	}
710
711	int (*parser) (char **, struct arg_type_info *) = NULL;
712
713	/* For some types that's all we need.  */
714	switch (type) {
715	case ARGTYPE_UNKNOWN:
716	case ARGTYPE_VOID:
717	case ARGTYPE_INT:
718	case ARGTYPE_UINT:
719	case ARGTYPE_LONG:
720	case ARGTYPE_ULONG:
721	case ARGTYPE_OCTAL:
722	case ARGTYPE_CHAR:
723	case ARGTYPE_SHORT:
724	case ARGTYPE_USHORT:
725	case ARGTYPE_FLOAT:
726	case ARGTYPE_DOUBLE:
727		*ownp = 0;
728		return type_get_simple(type);
729
730	case ARGTYPE_ARRAY:
731		parser = parse_array;
732		break;
733
734	case ARGTYPE_ENUM:
735		parser = parse_enum;
736		break;
737
738	case ARGTYPE_STRUCT:
739		parser = parse_struct;
740		break;
741
742	case ARGTYPE_STRING_N:
743		/* Strings are handled in aliases, to support
744		 * "stringN" syntax cleanly.  */
745		assert(type != ARGTYPE_STRING_N);
746		abort();
747
748	case ARGTYPE_POINTER:
749		/* Pointer syntax is not based on keyword, so we
750		 * should never get this type.  */
751		assert(type != ARGTYPE_POINTER);
752		abort();
753	}
754
755	struct arg_type_info *info = malloc(sizeof(*info));
756	if (info == NULL) {
757		report_error(filename, line_no,
758			     "malloc: %s", strerror(errno));
759		return NULL;
760	}
761	*ownp = 1;
762
763	if (parser(str, info) < 0) {
764		free(info);
765		return NULL;
766	}
767
768	return info;
769}
770
771static struct named_lens {
772	const char *name;
773	struct lens *lens;
774} lenses[] = {
775};
776
777static struct lens *
778name2lens(char **str, int *own_lensp)
779{
780	char *str2 = *str;
781	char *ident = parse_ident(&str2);
782	size_t i;
783	for (i = 0; i < sizeof(lenses)/sizeof(*lenses); ++i)
784		if (strcmp(ident, lenses[i].name) == 0) {
785			*str = str2;
786			*own_lensp = 0;
787			return lenses[i].lens;
788		}
789
790	return NULL;
791}
792
793static struct arg_type_info *
794parse_type(char **str, struct param **extra_param, size_t param_num, int *ownp)
795{
796	struct arg_type_info *info
797		= parse_nonpointer_type(str, extra_param, param_num, ownp);
798	if (info == NULL)
799		return NULL;
800
801	while (1) {
802		eat_spaces(str);
803		if (**str == '*') {
804			struct arg_type_info *outer = malloc(sizeof(*outer));
805			if (outer == NULL) {
806				if (*ownp) {
807					type_destroy(info);
808					free(info);
809				}
810				report_error(filename, line_no,
811					     "malloc: %s", strerror(errno));
812				return NULL;
813			}
814			type_init_pointer(outer, info, *ownp);
815			*ownp = 1;
816			(*str)++;
817			info = outer;
818		} else
819			break;
820	}
821	return info;
822}
823
824static struct arg_type_info *
825parse_lens(char **str, struct param **extra_param, size_t param_num, int *ownp)
826{
827	int own_lens;
828	struct lens *lens = name2lens(str, &own_lens);
829	int has_args = 1;
830	struct arg_type_info *info;
831	if (lens != NULL) {
832		eat_spaces(str);
833
834		if (parse_char(str, '(') < 0) {
835			report_error(filename, line_no,
836				     "expected type argument after the lens");
837			return NULL;
838		}
839	}
840
841	if (has_args) {
842		eat_spaces(str);
843		info = parse_type(str, extra_param, param_num, ownp);
844		if (info == NULL) {
845		fail:
846			if (own_lens && lens != NULL)
847				lens_destroy(lens);
848			return NULL;
849		}
850	}
851
852	if (lens != NULL && has_args) {
853		eat_spaces(str);
854		parse_char(str, ')');
855	}
856
857	/* We can't modify shared types.  Make a copy if we have a
858	 * lens.  */
859	if (lens != NULL && unshare_type_info(&info, ownp) < 0)
860		goto fail;
861
862	if (lens != NULL) {
863		info->lens = lens;
864		info->own_lens = own_lens;
865	}
866
867	return info;
868}
869
870static int
871add_param(Function *fun, size_t *allocdp)
872{
873	size_t allocd = *allocdp;
874	/* XXX +1 is for the extra_param handling hack.  */
875	if ((fun->num_params + 1) >= allocd) {
876		allocd = allocd > 0 ? 2 * allocd : 8;
877		void *na = realloc(fun->params, sizeof(*fun->params) * allocd);
878		if (na == NULL)
879			return -1;
880
881		fun->params = na;
882		*allocdp = allocd;
883	}
884	return 0;
885}
886
887static Function *
888process_line(char *buf) {
889	char *str = buf;
890	char *tmp;
891
892	line_no++;
893	debug(3, "Reading line %d of `%s'", line_no, filename);
894	eat_spaces(&str);
895
896	/* A comment or empty line.  */
897	if (*str == ';' || *str == 0)
898		return NULL;
899
900	if (strncmp(str, "typedef", 7) == 0) {
901		parse_typedef(&str);
902		return NULL;
903	}
904
905	Function *fun = calloc(1, sizeof(*fun));
906	if (fun == NULL) {
907		report_error(filename, line_no,
908			     "alloc function: %s", strerror(errno));
909		return NULL;
910	}
911
912	fun->return_info = parse_lens(&str, NULL, 0, &fun->own_return_info);
913	if (fun->return_info == NULL
914	    || fun->return_info->type == ARGTYPE_UNKNOWN) {
915	err:
916		debug(3, " Skipping line %d", line_no);
917		destroy_fun(fun);
918		return NULL;
919	}
920	debug(4, " return_type = %d", fun->return_info->type);
921
922	eat_spaces(&str);
923	tmp = start_of_arg_sig(str);
924	if (tmp == NULL) {
925		report_error(filename, line_no, "syntax error");
926		goto err;
927	}
928	*tmp = '\0';
929	fun->name = strdup(str);
930	str = tmp + 1;
931	debug(3, " name = %s", fun->name);
932
933	size_t allocd = 0;
934	fun->num_params = 0;
935	struct param *extra_param = NULL;
936
937	int have_stop = 0;
938
939	while (1) {
940		eat_spaces(&str);
941		if (*str == ')')
942			break;
943
944		if (str[0] == '+') {
945			if (have_stop == 0) {
946				if (add_param(fun, &allocd) < 0)
947					goto add_err;
948				param_init_stop
949					(&fun->params[fun->num_params++]);
950				have_stop = 1;
951			}
952			str++;
953		}
954
955		if (add_param(fun, &allocd) < 0) {
956		add_err:
957			report_error(filename, line_no, "(re)alloc params: %s",
958				     strerror(errno));
959			goto err;
960		}
961
962		int own;
963		struct arg_type_info *type = parse_lens(&str, &extra_param,
964							fun->num_params, &own);
965		if (type == NULL) {
966			report_error(filename, line_no,
967				     "unknown argument type");
968			goto err;
969		}
970
971		/* XXX We used to allow void parameter as a synonym to
972		 * an argument that shouldn't be displayed.  We may
973		 * wish to re-introduce this when lenses are
974		 * implemented, as a synonym, but backends generally
975		 * need to know the type, so disallow bare void for
976		 * now.  */
977		if (type->type == ARGTYPE_VOID) {
978			report_warning(filename, line_no,
979				       "void parameter assumed to be 'int'");
980			if (own) {
981				type_destroy(type);
982				free(type);
983			}
984			type = type_get_simple(ARGTYPE_INT);
985			own = 0;
986		}
987
988		param_init_type(&fun->params[fun->num_params++], type, own);
989
990		eat_spaces(&str);
991		if (*str == ',') {
992			str++;
993			continue;
994		} else if (*str == ')') {
995			continue;
996		} else {
997			if (str[strlen(str) - 1] == '\n')
998				str[strlen(str) - 1] = '\0';
999			report_error(filename, line_no,
1000				     "syntax error around \"%s\"", str);
1001			goto err;
1002		}
1003	}
1004
1005	if (extra_param != NULL) {
1006		assert(fun->num_params < allocd);
1007		memcpy(&fun->params[fun->num_params++], extra_param,
1008		       sizeof(*extra_param));
1009	}
1010
1011	return fun;
1012}
1013
1014void
1015init_global_config(void)
1016{
1017	struct arg_type_info *info = malloc(2 * sizeof(*info));
1018	if (info == NULL)
1019		error(1, errno, "malloc in init_global_config");
1020
1021	memset(info, 0, 2 * sizeof(*info));
1022	info[0].type = ARGTYPE_POINTER;
1023	info[0].u.ptr_info.info = &info[1];
1024	info[1].type = ARGTYPE_VOID;
1025
1026	insert_typedef(strdup("addr"), info, 0);
1027	insert_typedef(strdup("file"), info, 1);
1028}
1029
1030void
1031read_config_file(char *file) {
1032	FILE *stream;
1033	char buf[1024];
1034
1035	filename = file;
1036	stream = fopen(filename, "r");
1037	if (!stream) {
1038		return;
1039	}
1040
1041	debug(1, "Reading config file `%s'...", filename);
1042
1043	line_no = 0;
1044	while (fgets(buf, 1024, stream)) {
1045		Function *tmp;
1046
1047		tmp = process_line(buf);
1048
1049		if (tmp) {
1050			debug(2, "New function: `%s'", tmp->name);
1051			tmp->next = list_of_functions;
1052			list_of_functions = tmp;
1053		}
1054	}
1055	fclose(stream);
1056}
1057