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