read_config_file.c revision 3f55bc8b8cdc0c795462c007b651b04ac354f96c
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/* 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))) 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, struct expr_node *ret, 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 free(ret); 283 *ownp = 0; 284 return expr_node_zero(); 285 } 286} 287 288static int 289wrap_in_zero(struct expr_node **nodep) 290{ 291 struct expr_node *n = build_zero_w_arg(*nodep, 1); 292 if (n == NULL) 293 return -1; 294 *nodep = n; 295 return 0; 296} 297 298/* 299 * Input: 300 * argN : The value of argument #N, counting from 1 301 * eltN : The value of element #N of the containing structure 302 * retval : The return value 303 * N : The numeric value N 304 */ 305static struct expr_node * 306parse_argnum(struct locus *loc, char **str, int *ownp, int zero) 307{ 308 struct expr_node *expr = malloc(sizeof(*expr)); 309 if (expr == NULL) 310 return NULL; 311 312 if (isdigit(CTYPE_CONV(**str))) { 313 long l; 314 if (parse_int(loc, str, &l) < 0 315 || check_nonnegative(loc, l) < 0 316 || check_int(loc, l) < 0) 317 goto fail; 318 319 expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0); 320 321 if (zero && wrap_in_zero(&expr) < 0) 322 goto fail; 323 324 *ownp = 1; 325 return expr; 326 327 } else { 328 char *const name = parse_ident(loc, str); 329 if (name == NULL) { 330 fail_ident: 331 free(name); 332 goto fail; 333 } 334 335 int is_arg = strncmp(name, "arg", 3) == 0; 336 if (is_arg || strncmp(name, "elt", 3) == 0) { 337 long l; 338 char *num = name + 3; 339 if (parse_int(loc, &num, &l) < 0 340 || check_int(loc, l) < 0) 341 goto fail_ident; 342 343 if (is_arg) { 344 if (l == 0) 345 expr_init_named(expr, "retval", 0); 346 else 347 expr_init_argno(expr, l - 1); 348 } else { 349 struct expr_node *e_up = malloc(sizeof(*e_up)); 350 struct expr_node *e_ix = malloc(sizeof(*e_ix)); 351 if (e_up == NULL || e_ix == NULL) { 352 free(e_up); 353 free(e_ix); 354 goto fail_ident; 355 } 356 357 expr_init_up(e_up, expr_self(), 0); 358 struct arg_type_info *ti 359 = type_get_simple(ARGTYPE_LONG); 360 expr_init_const_word(e_ix, l - 1, ti, 0); 361 expr_init_index(expr, e_up, 1, e_ix, 1); 362 } 363 364 } else if (strcmp(name, "retval") == 0) { 365 expr_init_named(expr, "retval", 0); 366 367 } else if (strcmp(name, "zero") == 0) { 368 struct expr_node *ret 369 = parse_zero(loc, str, expr, ownp); 370 if (ret == NULL) 371 goto fail_ident; 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); 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(&g_prototypes, name); 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 struct named_type *this_nt = malloc(sizeof(*this_nt)); 443 if (this_nt == NULL) { 444 free(this_nt); 445 goto err; 446 } 447 448 int fwd = 0; 449 int own = 0; 450 struct arg_type_info *info 451 = parse_lens(plib, loc, str, NULL, 0, &own, &fwd); 452 if (info == NULL) { 453 free(this_nt); 454 goto err; 455 } 456 named_type_init(this_nt, info, own); 457 this_nt->forward = fwd; 458 459 if (forward == NULL) { 460 if (protolib_add_named_type(&g_prototypes, name, 461 1, this_nt) < 0) { 462 err2: 463 named_type_destroy(this_nt); 464 free(this_nt); 465 return -1; 466 } 467 return 0; 468 } 469 470 /* If we are defining a forward, make sure the definition is a 471 * structure as well. */ 472 if (this_nt->info->type != ARGTYPE_STRUCT) { 473 report_error(loc->filename, loc->line_no, 474 "Definition of forward '%s' must be a structure.", 475 name); 476 goto err2; 477 } 478 479 /* Now move guts of the actual type over to the forward type. 480 * We can't just move pointers around, because references to 481 * forward must stay intact. */ 482 assert(this_nt->own_type); 483 type_destroy(forward->info); 484 *forward->info = *this_nt->info; 485 forward->forward = 0; 486 free(this_nt->info); 487 free(name); 488 free(this_nt); 489 return 0; 490} 491 492/* Syntax: struct ( type,type,type,... ) */ 493static int 494parse_struct(struct protolib *plib, struct locus *loc, 495 char **str, struct arg_type_info *info, 496 int *forwardp) 497{ 498 eat_spaces(str); 499 500 if (**str == ';') { 501 if (forwardp == NULL) { 502 report_error(loc->filename, loc->line_no, 503 "Forward struct can be declared only " 504 "directly after a typedef."); 505 return -1; 506 } 507 508 /* Forward declaration is currently handled as an 509 * empty struct. */ 510 type_init_struct(info); 511 *forwardp = 1; 512 return 0; 513 } 514 515 if (parse_char(loc, str, '(') < 0) 516 return -1; 517 518 eat_spaces(str); // Empty arg list with whitespace inside 519 520 type_init_struct(info); 521 522 while (1) { 523 eat_spaces(str); 524 if (**str == 0 || **str == ')') { 525 parse_char(loc, str, ')'); 526 return 0; 527 } 528 529 /* Field delimiter. */ 530 if (type_struct_size(info) > 0) 531 parse_char(loc, str, ','); 532 533 eat_spaces(str); 534 int own; 535 struct arg_type_info *field 536 = parse_lens(plib, loc, str, NULL, 0, &own, NULL); 537 if (field == NULL || type_struct_add(info, field, own)) { 538 type_destroy(info); 539 return -1; 540 } 541 } 542} 543 544static int 545parse_string(struct protolib *plib, struct locus *loc, 546 char **str, struct arg_type_info **retp, int *ownp) 547{ 548 struct arg_type_info *info = malloc(sizeof(*info) * 2); 549 if (info == NULL) { 550 fail: 551 free(info); 552 return -1; 553 } 554 555 struct expr_node *length; 556 int own_length; 557 int with_arg = 0; 558 559 if (isdigit(CTYPE_CONV(**str))) { 560 /* string0 is string[retval], length is zero(retval) 561 * stringN is string[argN], length is zero(argN) */ 562 long l; 563 if (parse_int(loc, str, &l) < 0 564 || check_int(loc, l) < 0) 565 goto fail; 566 567 struct expr_node *length_arg = malloc(sizeof(*length_arg)); 568 if (length_arg == NULL) 569 goto fail; 570 571 if (l == 0) 572 expr_init_named(length_arg, "retval", 0); 573 else 574 expr_init_argno(length_arg, l - 1); 575 576 length = build_zero_w_arg(length_arg, 1); 577 if (length == NULL) { 578 expr_destroy(length_arg); 579 free(length_arg); 580 goto fail; 581 } 582 own_length = 1; 583 584 } else { 585 eat_spaces(str); 586 if (**str == '[') { 587 (*str)++; 588 eat_spaces(str); 589 590 length = parse_argnum(loc, str, &own_length, 1); 591 if (length == NULL) 592 goto fail; 593 594 eat_spaces(str); 595 parse_char(loc, str, ']'); 596 597 } else if (**str == '(') { 598 /* Usage of "string" as lens. */ 599 ++*str; 600 601 free(info); 602 603 eat_spaces(str); 604 info = parse_type(plib, loc, str, NULL, 0, ownp, NULL); 605 if (info == NULL) 606 goto fail; 607 608 eat_spaces(str); 609 parse_char(loc, str, ')'); 610 611 with_arg = 1; 612 613 } else { 614 /* It was just a simple string after all. */ 615 length = expr_node_zero(); 616 own_length = 0; 617 } 618 } 619 620 /* String is a pointer to array of chars. */ 621 if (!with_arg) { 622 type_init_array(&info[1], type_get_simple(ARGTYPE_CHAR), 0, 623 length, own_length); 624 625 type_init_pointer(&info[0], &info[1], 0); 626 *ownp = 1; 627 } 628 629 info->lens = &string_lens; 630 info->own_lens = 0; 631 632 *retp = info; 633 return 0; 634} 635 636static int 637build_printf_pack(struct locus *loc, struct param **packp, size_t param_num) 638{ 639 if (packp == NULL) { 640 report_error(loc->filename, loc->line_no, 641 "'format' type in unexpected context"); 642 return -1; 643 } 644 if (*packp != NULL) { 645 report_error(loc->filename, loc->line_no, 646 "only one 'format' type per function supported"); 647 return -1; 648 } 649 650 *packp = malloc(sizeof(**packp)); 651 if (*packp == NULL) 652 return -1; 653 654 struct expr_node *node = malloc(sizeof(*node)); 655 if (node == NULL) { 656 free(*packp); 657 return -1; 658 } 659 660 expr_init_argno(node, param_num); 661 662 param_pack_init_printf(*packp, node, 1); 663 664 return 0; 665} 666 667/* Match and consume KWD if it's next in stream, and return 0. 668 * Otherwise return negative number. */ 669static int 670try_parse_kwd(char **str, const char *kwd) 671{ 672 size_t len = strlen(kwd); 673 if (strncmp(*str, kwd, len) == 0 674 && !isalnum(CTYPE_CONV((*str)[len]))) { 675 (*str) += len; 676 return 0; 677 } 678 return -1; 679} 680 681/* Make a copy of INFO and set the *OWN bit if it's not already 682 * owned. */ 683static int 684unshare_type_info(struct locus *loc, struct arg_type_info **infop, int *ownp) 685{ 686 if (*ownp) 687 return 0; 688 689 struct arg_type_info *ninfo = malloc(sizeof(*ninfo)); 690 if (ninfo == NULL) { 691 report_error(loc->filename, loc->line_no, 692 "malloc: %s", strerror(errno)); 693 return -1; 694 } 695 *ninfo = **infop; 696 *infop = ninfo; 697 *ownp = 1; 698 return 0; 699} 700 701/* XXX extra_param and param_num are a kludge to get in 702 * backward-compatible support for "format" parameter type. The 703 * latter is only valid if the former is non-NULL, which is only in 704 * top-level context. */ 705static int 706parse_alias(struct protolib *plib, struct locus *loc, 707 char **str, struct arg_type_info **retp, int *ownp, 708 struct param **extra_param, size_t param_num) 709{ 710 /* For backward compatibility, we need to support things like 711 * stringN (which is like string[argN], string[N], and also 712 * bare string. We might, in theory, replace this by 713 * preprocessing configure file sources with M4, but for now, 714 * "string" is syntax. */ 715 if (strncmp(*str, "string", 6) == 0) { 716 (*str) += 6; 717 return parse_string(plib, loc, str, retp, ownp); 718 719 } else if (try_parse_kwd(str, "format") >= 0 720 && extra_param != NULL) { 721 /* For backward compatibility, format is parsed as 722 * "string", but it smuggles to the parameter list of 723 * a function a "printf" argument pack with this 724 * parameter as argument. */ 725 if (parse_string(plib, loc, str, retp, ownp) < 0) 726 return -1; 727 728 return build_printf_pack(loc, extra_param, param_num); 729 730 } else if (try_parse_kwd(str, "enum") >=0) { 731 732 return parse_enum(plib, loc, str, retp, ownp); 733 734 } else { 735 *retp = NULL; 736 return 0; 737 } 738} 739 740/* Syntax: array ( type, N|argN ) */ 741static int 742parse_array(struct protolib *plib, struct locus *loc, 743 char **str, struct arg_type_info *info) 744{ 745 eat_spaces(str); 746 if (parse_char(loc, str, '(') < 0) 747 return -1; 748 749 eat_spaces(str); 750 int own; 751 struct arg_type_info *elt_info 752 = parse_lens(plib, loc, str, NULL, 0, &own, NULL); 753 if (elt_info == NULL) 754 return -1; 755 756 eat_spaces(str); 757 parse_char(loc, str, ','); 758 759 eat_spaces(str); 760 int own_length; 761 struct expr_node *length = parse_argnum(loc, str, &own_length, 0); 762 if (length == NULL) { 763 if (own) { 764 type_destroy(elt_info); 765 free(elt_info); 766 } 767 return -1; 768 } 769 770 type_init_array(info, elt_info, own, length, own_length); 771 772 eat_spaces(str); 773 parse_char(loc, str, ')'); 774 return 0; 775} 776 777/* Syntax: 778 * enum (keyname[=value],keyname[=value],... ) 779 * enum<type> (keyname[=value],keyname[=value],... ) 780 */ 781static int 782parse_enum(struct protolib *plib, struct locus *loc, char **str, 783 struct arg_type_info **retp, int *ownp) 784{ 785 /* Optional type argument. */ 786 eat_spaces(str); 787 if (**str == '[') { 788 parse_char(loc, str, '['); 789 eat_spaces(str); 790 *retp = parse_nonpointer_type(plib, loc, str, NULL, 0, ownp, 0); 791 if (*retp == NULL) 792 return -1; 793 794 if (!type_is_integral((*retp)->type)) { 795 report_error(loc->filename, loc->line_no, 796 "integral type required as enum argument"); 797 fail: 798 if (*ownp) { 799 /* This also releases associated lens 800 * if any was set so far. */ 801 type_destroy(*retp); 802 free(*retp); 803 } 804 return -1; 805 } 806 807 eat_spaces(str); 808 if (parse_char(loc, str, ']') < 0) 809 goto fail; 810 811 } else { 812 *retp = type_get_simple(ARGTYPE_INT); 813 *ownp = 0; 814 } 815 816 /* We'll need to set the lens, so unshare. */ 817 if (unshare_type_info(loc, retp, ownp) < 0) 818 goto fail; 819 820 eat_spaces(str); 821 if (parse_char(loc, str, '(') < 0) 822 goto fail; 823 824 struct enum_lens *lens = malloc(sizeof(*lens)); 825 if (lens == NULL) { 826 report_error(loc->filename, loc->line_no, 827 "malloc enum lens: %s", strerror(errno)); 828 return -1; 829 } 830 831 lens_init_enum(lens); 832 (*retp)->lens = &lens->super; 833 (*retp)->own_lens = 1; 834 835 long last_val = 0; 836 while (1) { 837 eat_spaces(str); 838 if (**str == 0 || **str == ')') { 839 parse_char(loc, str, ')'); 840 return 0; 841 } 842 843 /* Field delimiter. XXX should we support the C 844 * syntax, where the enumeration can end in pending 845 * comma? */ 846 if (lens_enum_size(lens) > 0) 847 parse_char(loc, str, ','); 848 849 eat_spaces(str); 850 char *key = parse_ident(loc, str); 851 if (key == NULL) { 852 err: 853 free(key); 854 goto fail; 855 } 856 857 if (**str == '=') { 858 ++*str; 859 eat_spaces(str); 860 if (parse_int(loc, str, &last_val) < 0) 861 goto err; 862 } 863 864 struct value *value = malloc(sizeof(*value)); 865 if (value == NULL) 866 goto err; 867 value_init_detached(value, NULL, *retp, 0); 868 value_set_word(value, last_val); 869 870 if (lens_enum_add(lens, key, 1, value, 1) < 0) 871 goto err; 872 873 last_val++; 874 } 875 876 return 0; 877} 878 879static struct arg_type_info * 880parse_nonpointer_type(struct protolib *plib, struct locus *loc, 881 char **str, struct param **extra_param, size_t param_num, 882 int *ownp, int *forwardp) 883{ 884 enum arg_type type; 885 if (parse_arg_type(str, &type) < 0) { 886 struct arg_type_info *simple; 887 if (parse_alias(plib, loc, str, &simple, 888 ownp, extra_param, param_num) < 0) 889 return NULL; 890 if (simple == NULL) 891 simple = parse_typedef_name(plib, str); 892 if (simple != NULL) { 893 *ownp = 0; 894 return simple; 895 } 896 897 report_error(loc->filename, loc->line_no, 898 "unknown type around '%s'", *str); 899 return NULL; 900 } 901 902 /* For some types that's all we need. */ 903 switch (type) { 904 case ARGTYPE_VOID: 905 case ARGTYPE_INT: 906 case ARGTYPE_UINT: 907 case ARGTYPE_LONG: 908 case ARGTYPE_ULONG: 909 case ARGTYPE_CHAR: 910 case ARGTYPE_SHORT: 911 case ARGTYPE_USHORT: 912 case ARGTYPE_FLOAT: 913 case ARGTYPE_DOUBLE: 914 *ownp = 0; 915 return type_get_simple(type); 916 917 case ARGTYPE_ARRAY: 918 case ARGTYPE_STRUCT: 919 break; 920 921 case ARGTYPE_POINTER: 922 /* Pointer syntax is not based on keyword, so we 923 * should never get this type. */ 924 assert(type != ARGTYPE_POINTER); 925 abort(); 926 } 927 928 struct arg_type_info *info = malloc(sizeof(*info)); 929 if (info == NULL) { 930 report_error(loc->filename, loc->line_no, 931 "malloc: %s", strerror(errno)); 932 return NULL; 933 } 934 *ownp = 1; 935 936 if (type == ARGTYPE_ARRAY) { 937 if (parse_array(plib, loc, str, info) < 0) { 938 fail: 939 free(info); 940 return NULL; 941 } 942 } else { 943 assert(type == ARGTYPE_STRUCT); 944 if (parse_struct(plib, loc, str, info, forwardp) < 0) 945 goto fail; 946 } 947 948 return info; 949} 950 951static struct named_lens { 952 const char *name; 953 struct lens *lens; 954} lenses[] = { 955 { "hide", &blind_lens }, 956 { "octal", &octal_lens }, 957 { "oct", &octal_lens }, 958 { "bitvec", &bitvect_lens }, 959 { "hex", &hex_lens }, 960 { "bool", &bool_lens }, 961 { "guess", &guess_lens }, 962}; 963 964static struct lens * 965name2lens(char **str, int *own_lensp) 966{ 967 size_t i; 968 for (i = 0; i < sizeof(lenses)/sizeof(*lenses); ++i) 969 if (try_parse_kwd(str, lenses[i].name) == 0) { 970 *own_lensp = 0; 971 return lenses[i].lens; 972 } 973 974 return NULL; 975} 976 977static struct arg_type_info * 978parse_type(struct protolib *plib, struct locus *loc, char **str, 979 struct param **extra_param, size_t param_num, 980 int *ownp, int *forwardp) 981{ 982 struct arg_type_info *info 983 = parse_nonpointer_type(plib, loc, str, extra_param, 984 param_num, ownp, forwardp); 985 if (info == NULL) 986 return NULL; 987 988 while (1) { 989 eat_spaces(str); 990 if (**str == '*') { 991 struct arg_type_info *outer = malloc(sizeof(*outer)); 992 if (outer == NULL) { 993 if (*ownp) { 994 type_destroy(info); 995 free(info); 996 } 997 report_error(loc->filename, loc->line_no, 998 "malloc: %s", strerror(errno)); 999 return NULL; 1000 } 1001 type_init_pointer(outer, info, *ownp); 1002 *ownp = 1; 1003 (*str)++; 1004 info = outer; 1005 } else 1006 break; 1007 } 1008 return info; 1009} 1010 1011static struct arg_type_info * 1012parse_lens(struct protolib *plib, struct locus *loc, 1013 char **str, struct param **extra_param, 1014 size_t param_num, int *ownp, int *forwardp) 1015{ 1016 int own_lens; 1017 struct lens *lens = name2lens(str, &own_lens); 1018 int has_args = 1; 1019 struct arg_type_info *info; 1020 if (lens != NULL) { 1021 eat_spaces(str); 1022 1023 /* Octal lens gets special treatment, because of 1024 * backward compatibility. */ 1025 if (lens == &octal_lens && **str != '(') { 1026 has_args = 0; 1027 info = type_get_simple(ARGTYPE_INT); 1028 *ownp = 0; 1029 } else if (parse_char(loc, str, '(') < 0) { 1030 report_error(loc->filename, loc->line_no, 1031 "expected type argument after the lens"); 1032 return NULL; 1033 } 1034 } 1035 1036 if (has_args) { 1037 eat_spaces(str); 1038 info = parse_type(plib, loc, str, extra_param, param_num, 1039 ownp, forwardp); 1040 if (info == NULL) { 1041 fail: 1042 if (own_lens && lens != NULL) 1043 lens_destroy(lens); 1044 return NULL; 1045 } 1046 } 1047 1048 if (lens != NULL && has_args) { 1049 eat_spaces(str); 1050 parse_char(loc, str, ')'); 1051 } 1052 1053 /* We can't modify shared types. Make a copy if we have a 1054 * lens. */ 1055 if (lens != NULL && unshare_type_info(loc, &info, ownp) < 0) 1056 goto fail; 1057 1058 if (lens != NULL) { 1059 info->lens = lens; 1060 info->own_lens = own_lens; 1061 } 1062 1063 return info; 1064} 1065 1066static int 1067param_is_void(struct param *param) 1068{ 1069 return param->flavor == PARAM_FLAVOR_TYPE 1070 && param->u.type.type->type == ARGTYPE_VOID; 1071} 1072 1073static struct arg_type_info * 1074get_hidden_int(void) 1075{ 1076 static struct arg_type_info *info = NULL; 1077 if (info != NULL) 1078 return info; 1079 1080 char *str = strdup("hide(int)"); 1081 char *ptr = str; 1082 assert(str != NULL); 1083 int own; 1084 struct locus loc = { NULL, 0 }; 1085 1086 struct protolib fake_plib; 1087 protolib_init(&fake_plib); 1088 1089 info = parse_lens(&fake_plib, &loc, &ptr, NULL, 0, &own, NULL); 1090 1091 protolib_destroy(&fake_plib); 1092 assert(info != NULL); 1093 free(str); 1094 1095 return info; 1096} 1097 1098static enum callback_status 1099void_to_hidden_int(struct prototype *proto, struct param *param, void *data) 1100{ 1101 struct locus *loc = data; 1102 if (param_is_void(param)) { 1103 report_warning(loc->filename, loc->line_no, 1104 "void parameter assumed to be 'hide(int)'"); 1105 1106 static struct arg_type_info *type = NULL; 1107 if (type == NULL) 1108 type = get_hidden_int(); 1109 param_destroy(param); 1110 param_init_type(param, type, 0); 1111 } 1112 return CBS_CONT; 1113} 1114 1115static int 1116process_line(struct protolib *plib, struct locus *loc, char *buf) 1117{ 1118 char *str = buf; 1119 char *tmp; 1120 1121 debug(3, "Reading line %d of `%s'", loc->line_no, loc->filename); 1122 eat_spaces(&str); 1123 1124 /* A comment or empty line. */ 1125 if (*str == ';' || *str == 0 || *str == '\n') 1126 return 0; 1127 1128 if (strncmp(str, "typedef", 7) == 0) { 1129 parse_typedef(plib, loc, &str); 1130 return 0; 1131 } 1132 1133 struct prototype *fun = calloc(1, sizeof(*fun)); 1134 if (fun == NULL) { 1135 report_error(loc->filename, loc->line_no, 1136 "%s", strerror(errno)); 1137 return -1; 1138 } 1139 prototype_init(fun); 1140 1141 char *proto_name = NULL; 1142 int own; 1143 fun->return_info = parse_lens(plib, loc, &str, NULL, 0, &own, NULL); 1144 if (fun->return_info == NULL) { 1145 err: 1146 debug(3, " Skipping line %d", loc->line_no); 1147 prototype_destroy(fun); 1148 free(fun); 1149 free(proto_name); 1150 return -1; 1151 } 1152 fun->own_return_info = own; 1153 debug(4, " return_type = %d", fun->return_info->type); 1154 1155 eat_spaces(&str); 1156 tmp = start_of_arg_sig(str); 1157 if (tmp == NULL) { 1158 report_error(loc->filename, loc->line_no, "syntax error"); 1159 goto err; 1160 } 1161 *tmp = '\0'; 1162 1163 proto_name = strdup(str); 1164 if (proto_name == NULL) { 1165 oom: 1166 report_error(loc->filename, loc->line_no, 1167 "%s", strerror(errno)); 1168 goto err; 1169 } 1170 1171 str = tmp + 1; 1172 debug(3, " name = %s", proto_name); 1173 1174 struct param *extra_param = NULL; 1175 int have_stop = 0; 1176 1177 while (1) { 1178 eat_spaces(&str); 1179 if (*str == ')') 1180 break; 1181 1182 if (str[0] == '+') { 1183 if (have_stop == 0) { 1184 struct param param; 1185 param_init_stop(¶m); 1186 if (prototype_push_param(fun, ¶m) < 0) 1187 goto oom; 1188 have_stop = 1; 1189 } 1190 str++; 1191 } 1192 1193 int own; 1194 size_t param_num = prototype_num_params(fun) - have_stop; 1195 struct arg_type_info *type 1196 = parse_lens(plib, loc, &str, &extra_param, 1197 param_num, &own, NULL); 1198 if (type == NULL) { 1199 report_error(loc->filename, loc->line_no, 1200 "unknown argument type"); 1201 goto err; 1202 } 1203 1204 struct param param; 1205 param_init_type(¶m, type, own); 1206 if (prototype_push_param(fun, ¶m) < 0) 1207 goto oom; 1208 1209 eat_spaces(&str); 1210 if (*str == ',') { 1211 str++; 1212 continue; 1213 } else if (*str == ')') { 1214 continue; 1215 } else { 1216 if (str[strlen(str) - 1] == '\n') 1217 str[strlen(str) - 1] = '\0'; 1218 report_error(loc->filename, loc->line_no, 1219 "syntax error around \"%s\"", str); 1220 goto err; 1221 } 1222 } 1223 1224 /* We used to allow void parameter as a synonym to an argument 1225 * that shouldn't be displayed. But backends really need to 1226 * know the exact type that they are dealing with. The proper 1227 * way to do this these days is to use the hide lens. 1228 * 1229 * So if there are any voids in the parameter list, show a 1230 * warning and assume that they are ints. If there's a sole 1231 * void, assume the function doesn't take any arguments. The 1232 * latter is conservative, we can drop the argument 1233 * altogether, instead of fetching and then not showing it, 1234 * without breaking any observable behavior. */ 1235 if (prototype_num_params(fun) == 1 1236 && param_is_void(prototype_get_nth_param(fun, 0))) { 1237 if (0) 1238 /* Don't show this warning. Pre-0.7.0 1239 * ltrace.conf often used this idiom. This 1240 * should be postponed until much later, when 1241 * extant uses are likely gone. */ 1242 report_warning(loc->filename, loc->line_no, 1243 "sole void parameter ignored"); 1244 prototype_destroy_nth_param(fun, 0); 1245 } else { 1246 prototype_each_param(fun, NULL, void_to_hidden_int, loc); 1247 } 1248 1249 if (extra_param != NULL) { 1250 prototype_push_param(fun, extra_param); 1251 free(extra_param); 1252 } 1253 1254 if (protolib_add_prototype(plib, proto_name, 1, fun) < 0) { 1255 report_error(loc->filename, loc->line_no, 1256 "couldn't add prototype: %s", 1257 strerror(errno)); 1258 goto err; 1259 } 1260 1261 return 0; 1262} 1263 1264int 1265read_config_file(struct protolib *plib, const char *path) 1266{ 1267 FILE *stream = fopen(path, "r"); 1268 if (stream == NULL) 1269 return -1; 1270 1271 debug(DEBUG_FUNCTION, "Reading config file `%s'...", path); 1272 1273 struct locus loc = { path, 0 }; 1274 char *line = NULL; 1275 size_t len = 0; 1276 while (getline(&line, &len, stream) >= 0) { 1277 loc.line_no++; 1278 process_line(&g_prototypes, &loc, line); 1279 } 1280 1281 free(line); 1282 fclose(stream); 1283 return 0; 1284} 1285 1286void 1287init_global_config(void) 1288{ 1289 protolib_init(&g_prototypes); 1290 1291 struct arg_type_info *void_info = type_get_simple(ARGTYPE_VOID); 1292 static struct arg_type_info ptr_info; 1293 type_init_pointer(&ptr_info, void_info, 0); 1294 1295 static struct named_type voidptr_type; 1296 named_type_init(&voidptr_type, &ptr_info, 0); 1297 1298 if (protolib_add_named_type(&g_prototypes, "addr", 0, 1299 &voidptr_type) < 0 1300 || protolib_add_named_type(&g_prototypes, "file", 0, 1301 &voidptr_type) < 0) { 1302 fprintf(stderr, 1303 "Couldn't initialize aliases `addr' and `file'.\n"); 1304 exit(1); 1305 } 1306} 1307 1308void 1309destroy_global_config(void) 1310{ 1311 protolib_destroy(&g_prototypes); 1312} 1313