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