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