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