1/* 2 * 'sparse' library helper routines. 3 * 4 * Copyright (C) 2003 Transmeta Corp. 5 * 2003-2004 Linus Torvalds 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and associated documentation files (the "Software"), to deal 9 * in the Software without restriction, including without limitation the rights 10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 * copies of the Software, and to permit persons to whom the Software is 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 * THE SOFTWARE. 24 */ 25#include <ctype.h> 26#include <errno.h> 27#include <fcntl.h> 28#include <stdarg.h> 29#include <stddef.h> 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <unistd.h> 34#include <assert.h> 35 36#include <sys/types.h> 37 38#include "lib.h" 39#include "allocate.h" 40#include "token.h" 41#include "parse.h" 42#include "symbol.h" 43#include "expression.h" 44#include "evaluate.h" 45#include "scope.h" 46#include "linearize.h" 47#include "target.h" 48#include "machine.h" 49#include "bits.h" 50 51static int prettify(const char **fnamep) 52{ 53 const char *name = *fnamep; 54 int len = strlen(name); 55 56 if (len > 2 && !memcmp(name, "./", 2)) { 57 name += 2; 58 len -= 2; 59 } 60 61 *fnamep = name; 62 return len; 63} 64 65static const char *show_include_chain(int stream, const char *base) 66{ 67 static char buffer[200]; 68 int len = 0; 69 70 while ((stream = stream_prev(stream)) >= 0) { 71 const char *p = stream_name(stream); 72 int pretty_len; 73 74 if (p == base) 75 break; 76 77 pretty_len = prettify(&p); 78 if (pretty_len <= 0) 79 break; 80 81 /* 82 * At worst, we'll need " (through %s, ...)" in addition to the 83 * new filename 84 */ 85 if (pretty_len + len + 20 > sizeof(buffer)) { 86 if (!len) 87 return ""; 88 memcpy(buffer+len, ", ...", 5); 89 len += 5; 90 break; 91 } 92 93 if (!len) { 94 memcpy(buffer, " (through ", 10); 95 len = 10; 96 } else { 97 buffer[len++] = ','; 98 buffer[len++] = ' '; 99 } 100 101 memcpy(buffer+len, p, pretty_len); 102 len += pretty_len; 103 } 104 if (!len) 105 return ""; 106 107 buffer[len] = ')'; 108 buffer[len+1] = 0; 109 return buffer; 110} 111 112static const char *show_stream_name(struct position pos) 113{ 114 const char *name = stream_name(pos.stream); 115 static const char *last; 116 117 if (name == base_filename) 118 return name; 119 if (name == last) 120 return name; 121 last = name; 122 123 fprintf(stderr, "%s: note: in included file%s:\n", 124 base_filename, 125 show_include_chain(pos.stream, base_filename)); 126 return name; 127} 128 129static void do_warn(const char *type, struct position pos, const char * fmt, va_list args) 130{ 131 static char buffer[512]; 132 133 /* Shut up warnings if position is bad_token.pos */ 134 if (pos.type == TOKEN_BAD) 135 return; 136 137 vsprintf(buffer, fmt, args); 138 139 fflush(stdout); 140 fprintf(stderr, "%s:%d:%d: %s%s%s\n", 141 show_stream_name(pos), pos.line, pos.pos, 142 diag_prefix, type, buffer); 143} 144 145static int show_info = 1; 146 147void info(struct position pos, const char * fmt, ...) 148{ 149 va_list args; 150 151 if (!show_info) 152 return; 153 va_start(args, fmt); 154 do_warn("", pos, fmt, args); 155 va_end(args); 156} 157 158static void do_error(struct position pos, const char * fmt, va_list args) 159{ 160 static int errors = 0; 161 die_if_error = 1; 162 show_info = 1; 163 /* Shut up warnings if position is bad_token.pos */ 164 if (pos.type == TOKEN_BAD) 165 return; 166 /* Shut up warnings after an error */ 167 has_error |= ERROR_CURR_PHASE; 168 if (errors > fmax_errors) { 169 static int once = 0; 170 show_info = 0; 171 if (once) 172 return; 173 fmt = "too many errors"; 174 once = 1; 175 } 176 177 do_warn("error: ", pos, fmt, args); 178 errors++; 179} 180 181void warning(struct position pos, const char * fmt, ...) 182{ 183 va_list args; 184 185 if (Wsparse_error) { 186 va_start(args, fmt); 187 do_error(pos, fmt, args); 188 va_end(args); 189 return; 190 } 191 192 if (!fmax_warnings || has_error) { 193 show_info = 0; 194 return; 195 } 196 197 if (!--fmax_warnings) { 198 show_info = 0; 199 fmt = "too many warnings"; 200 } 201 202 va_start(args, fmt); 203 do_warn("warning: ", pos, fmt, args); 204 va_end(args); 205} 206 207void sparse_error(struct position pos, const char * fmt, ...) 208{ 209 va_list args; 210 va_start(args, fmt); 211 do_error(pos, fmt, args); 212 va_end(args); 213} 214 215void expression_error(struct expression *expr, const char *fmt, ...) 216{ 217 va_list args; 218 va_start(args, fmt); 219 do_error(expr->pos, fmt, args); 220 va_end(args); 221 expr->ctype = &bad_ctype; 222} 223 224NORETURN_ATTR 225void error_die(struct position pos, const char * fmt, ...) 226{ 227 va_list args; 228 va_start(args, fmt); 229 do_warn("error: ", pos, fmt, args); 230 va_end(args); 231 exit(1); 232} 233 234NORETURN_ATTR 235void die(const char *fmt, ...) 236{ 237 va_list args; 238 static char buffer[512]; 239 240 va_start(args, fmt); 241 vsnprintf(buffer, sizeof(buffer), fmt, args); 242 va_end(args); 243 244 fprintf(stderr, "%s%s\n", diag_prefix, buffer); 245 exit(1); 246} 247 248//////////////////////////////////////////////////////////////////////////////// 249 250static struct token *pre_buffer_begin = NULL; 251static struct token **pre_buffer_next = &pre_buffer_begin; 252 253void add_pre_buffer(const char *fmt, ...) 254{ 255 va_list args; 256 unsigned int size; 257 struct token *begin, *end; 258 char buffer[4096]; 259 260 va_start(args, fmt); 261 size = vsnprintf(buffer, sizeof(buffer), fmt, args); 262 va_end(args); 263 begin = tokenize_buffer(buffer, size, &end); 264 *pre_buffer_next = begin; 265 pre_buffer_next = &end->next; 266} 267 268static void create_builtin_stream(void) 269{ 270 // Temporary hack 271 add_pre_buffer("#define _Pragma(x)\n"); 272 273 /* add the multiarch include directories, if any */ 274 if (multiarch_dir && *multiarch_dir) { 275 add_pre_buffer("#add_system \"/usr/include/%s\"\n", multiarch_dir); 276 add_pre_buffer("#add_system \"/usr/local/include/%s\"\n", multiarch_dir); 277 } 278 279 /* We add compiler headers path here because we have to parse 280 * the arguments to get it, falling back to default. */ 281 add_pre_buffer("#add_system \"%s/include\"\n", gcc_base_dir); 282 add_pre_buffer("#add_system \"%s/include-fixed\"\n", gcc_base_dir); 283 284 add_pre_buffer("#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); 285 add_pre_buffer("#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); 286 add_pre_buffer("#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n"); 287 add_pre_buffer("#define __builtin_va_arg(arg,type) ({ type __va_arg_ret = *(type *)(arg); arg += sizeof(type); __va_arg_ret; })\n"); 288 add_pre_buffer("#define __builtin_va_alist (*(void *)0)\n"); 289 add_pre_buffer("#define __builtin_va_arg_incr(x) ((x) + 1)\n"); 290 add_pre_buffer("#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n"); 291 add_pre_buffer("#define __builtin_ms_va_copy(dest, src) ({ dest = src; (void)0; })\n"); 292 add_pre_buffer("#define __builtin_va_end(arg)\n"); 293 add_pre_buffer("#define __builtin_ms_va_end(arg)\n"); 294 add_pre_buffer("#define __builtin_va_arg_pack()\n"); 295} 296 297static struct symbol_list *sparse_tokenstream(struct token *token) 298{ 299 int builtin = token && !token->pos.stream; 300 301 // Preprocess the stream 302 token = preprocess(token); 303 304 if (dump_macro_defs || dump_macros_only) { 305 if (!builtin) 306 dump_macro_definitions(); 307 if (dump_macros_only) 308 return NULL; 309 } 310 311 if (preprocess_only) { 312 while (!eof_token(token)) { 313 int prec = 1; 314 struct token *next = token->next; 315 const char *separator = ""; 316 if (next->pos.whitespace) 317 separator = " "; 318 if (next->pos.newline) { 319 separator = "\n\t\t\t\t\t"; 320 prec = next->pos.pos; 321 if (prec > 4) 322 prec = 4; 323 } 324 printf("%s%.*s", show_token(token), prec, separator); 325 token = next; 326 } 327 putchar('\n'); 328 329 return NULL; 330 } 331 332 // Parse the resulting C code 333 while (!eof_token(token)) 334 token = external_declaration(token, &translation_unit_used_list, NULL); 335 return translation_unit_used_list; 336} 337 338static struct symbol_list *sparse_file(const char *filename) 339{ 340 int fd; 341 struct token *token; 342 343 if (strcmp(filename, "-") == 0) { 344 fd = 0; 345 } else { 346 fd = open(filename, O_RDONLY); 347 if (fd < 0) 348 die("No such file: %s", filename); 349 } 350 base_filename = filename; 351 352 // Tokenize the input stream 353 token = tokenize(NULL, filename, fd, NULL, includepath); 354 close(fd); 355 356 return sparse_tokenstream(token); 357} 358 359/* 360 * This handles the "-include" directive etc: we're in global 361 * scope, and all types/macros etc will affect all the following 362 * files. 363 * 364 * NOTE NOTE NOTE! "#undef" of anything in this stage will 365 * affect all subsequent files too, i.e. we can have non-local 366 * behaviour between files! 367 */ 368static struct symbol_list *sparse_initial(void) 369{ 370 int i; 371 372 // Prepend any "include" file to the stream. 373 // We're in global scope, it will affect all files! 374 for (i = 0; i < cmdline_include_nr; i++) 375 add_pre_buffer("#argv_include \"%s\"\n", cmdline_include[i]); 376 377 return sparse_tokenstream(pre_buffer_begin); 378} 379 380struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **filelist) 381{ 382 char **args; 383 struct symbol_list *list; 384 385 base_filename = "command-line"; 386 387 // Initialize symbol stream first, so that we can add defines etc 388 init_symbols(); 389 390 // initialize the default target to the native 'machine' 391 target_config(MACH_NATIVE); 392 393 args = argv; 394 for (;;) { 395 char *arg = *++args; 396 if (!arg) 397 break; 398 399 if (arg[0] == '-' && arg[1]) { 400 args = handle_switch(arg+1, args); 401 continue; 402 } 403 add_ptr_list(filelist, arg); 404 } 405 handle_switch_finalize(); 406 407 // Redirect stdout if needed 408 if (dump_macro_defs || preprocess_only) 409 do_output = 1; 410 if (do_output && outfile && strcmp(outfile, "-")) { 411 if (!freopen(outfile, "w", stdout)) 412 die("error: cannot open %s: %s", outfile, strerror(errno)); 413 } 414 415 if (fdump_ir == 0) 416 fdump_ir = PASS_FINAL; 417 418 list = NULL; 419 if (filelist) { 420 // Initialize type system 421 target_init(); 422 init_ctype(); 423 424 predefined_macros(); 425 create_builtin_stream(); 426 init_builtins(0); 427 428 list = sparse_initial(); 429 430 /* 431 * Protect the initial token allocations, since 432 * they need to survive all the others 433 */ 434 protect_token_alloc(); 435 } 436 /* 437 * Evaluate the complete symbol list 438 * Note: This is not needed for normal cases. 439 * These symbols should only be predefined defines and 440 * declaratons which will be evaluated later, when needed. 441 * This is also the case when a file is directly included via 442 * '-include <file>' on the command line *AND* the file only 443 * contains defines, declarations and inline definitions. 444 * However, in the rare cases where the given file should 445 * contain some definitions, these will never be evaluated 446 * and thus won't be able to be linearized correctly. 447 * Hence the evaluate_symbol_list() here under. 448 */ 449 evaluate_symbol_list(list); 450 return list; 451} 452 453struct symbol_list * sparse_keep_tokens(char *filename) 454{ 455 struct symbol_list *res; 456 457 /* Clear previous symbol list */ 458 translation_unit_used_list = NULL; 459 460 new_file_scope(); 461 res = sparse_file(filename); 462 463 /* And return it */ 464 return res; 465} 466 467 468struct symbol_list * __sparse(char *filename) 469{ 470 struct symbol_list *res; 471 472 res = sparse_keep_tokens(filename); 473 474 /* Drop the tokens for this file after parsing */ 475 clear_token_alloc(); 476 477 /* And return it */ 478 return res; 479} 480 481struct symbol_list * sparse(char *filename) 482{ 483 struct symbol_list *res = __sparse(filename); 484 485 if (has_error & ERROR_CURR_PHASE) 486 has_error = ERROR_PREV_PHASE; 487 /* Evaluate the complete symbol list */ 488 evaluate_symbol_list(res); 489 490 return res; 491} 492