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