1 /* 2 Copyright 2009-2010 SN Systems Ltd. All rights reserved. 3 Portions Copyright 2009-2018 David Anderson. All rights reserved. 4 5 This program is free software; you can redistribute it and/or modify it 6 under the terms of version 2.1 of the GNU Lesser General Public License 7 as published by the Free Software Foundation. 8 9 This program is distributed in the hope that it would be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 Further, this software is distributed without any warranty that it is 14 free of the rightful claim of any third person regarding infringement 15 or the like. Any license provided herein, whether implied or 16 otherwise, applies only to this software file. Patent licenses, if 17 any, provided herein do not apply to combinations of this program with 18 other software, or any other product whatsoever. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this program; if not, write the Free Software 22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, 23 USA. 24 25 */ 26 27 #include "config.h" 28 #ifdef _WIN32 29 #define _CRT_SECURE_NO_WARNINGS 30 #endif /* _WIN32 */ 31 32 #include <stdio.h> 33 #ifdef HAVE_STDLIB_H 34 #include <stdlib.h> 35 #endif /* HAVE_STDLIB_H */ 36 #include <errno.h> /* For errno declaration. */ 37 #include <ctype.h> 38 #include <string.h> 39 #include "dwgetopt.h" 40 #include "libdwarf_version.h" /* for DW_VERSION_DATE_STR */ 41 42 /* gennames.c 43 Prints routines to return constant name for the associated value 44 (such as the TAG name string for a particular tag). 45 46 The input is dwarf.h 47 For each set of names with a common prefix, we create a routine 48 to return the name given the value. 49 Also print header file that gives prototypes of routines. 50 To handle cases where there are multiple names for a single 51 value (DW_AT_* has some due to ambiguities in the DWARF2 spec) 52 we take the first of a given value as the definitive name. 53 TAGs, Attributes, etc are given distinct checks. 54 55 There are multiple output files as some people find one 56 form more pleasant than the other. 57 58 The doprinting argument is so that when used by tag_tree.c, 59 and tag_attr.c that we don't get irritating messages on stderr 60 when those dwarfdump built-time applications are run. 61 62 Some compilers generate better code for switch statements than 63 others, so the -s and -t options let the user decide which 64 is better for their compiler (when building dwarfdump): 65 a simple switch or code doing binary search. 66 This choice affects the runtime speed of dwarfdump. */ 67 68 typedef int boolean; 69 #define TRUE 1 70 #define FALSE 0 71 #define FAILED 1 72 73 static void OpenAllFiles(void); 74 static void WriteFileTrailers(void); 75 static void CloseAllFiles(void); 76 static void GenerateInitialFileLines(void); 77 static void GenerateOneSet(void); 78 #ifdef TRACE_ARRAY 79 static void PrintArray(void); 80 #endif /* TRACE_ARRAY */ 81 static boolean is_skippable_line(char *pLine); 82 static void ParseDefinitionsAndWriteOutput(void); 83 84 /* We don't need really long lines: the input file is simple. */ 85 #define MAX_LINE_SIZE 1000 86 /* We don't need a variable array size, it just has to be big enough. */ 87 #define ARRAY_SIZE 300 88 89 #define MAX_NAME_LEN 64 90 91 /* To store entries from dwarf.h */ 92 typedef struct { 93 char name[MAX_NAME_LEN]; /* short name */ 94 unsigned value; /* value */ 95 /* Original spot in array. Lets us guarantee a stable sort. */ 96 unsigned original_position; 97 } array_data; 98 99 /* A group_array is a grouping from dwarf.h. 100 All the TAGs are one group, all the 101 FORMs are another group, and so on. */ 102 static array_data group_array[ARRAY_SIZE]; 103 static unsigned array_count = 0; 104 105 typedef int (*compfn)(const void *,const void *); 106 static int Compare(array_data *,array_data *); 107 108 static const char *prefix_root = "DW_"; 109 static const unsigned prefix_root_len = 3; 110 111 /* f_dwarf_in is the input dwarf.h. The others are output files. */ 112 static FILE *f_dwarf_in; 113 static FILE *f_names_h; 114 static FILE *f_names_c; 115 static FILE *f_names_enum_h; 116 static FILE *f_names_new_h; 117 118 /* Size unchecked, but large enough. */ 119 static char prefix[200] = ""; 120 121 static const char *usage[] = { 122 "Usage: gennames <options>", 123 " -i input-table-path", 124 " -o output-table-path", 125 " -s use 'switch' in generation", 126 " -t use 'tables' in generation", 127 "", 128 }; 129 130 static void 131 print_args(int argc, char *argv[]) 132 { 133 int index; 134 printf("Arguments: "); 135 for (index = 1; index < argc; ++index) { 136 printf("%s ",argv[index]); 137 } 138 printf("\n"); 139 } 140 141 142 char *program_name = 0; 143 static char *input_name = 0; 144 static char *output_name = 0; 145 static boolean use_switch = TRUE; 146 static boolean use_tables = FALSE; 147 148 static void 149 print_version(const char * name) 150 { 151 #ifdef _DEBUG 152 const char *acType = "Debug"; 153 #else 154 const char *acType = "Release"; 155 #endif /* _DEBUG */ 156 157 printf("%s [%s %s]\n",name,DW_VERSION_DATE_STR,acType); 158 } 159 160 161 static void 162 print_usage_message(const char *options[]) 163 { 164 int index; 165 for (index = 0; *options[index]; ++index) { 166 printf("%s\n",options[index]); 167 } 168 } 169 170 171 /* process arguments */ 172 static void 173 process_args(int argc, char *argv[]) 174 { 175 int c = 0; 176 boolean usage_error = FALSE; 177 178 program_name = argv[0]; 179 180 while ((c = dwgetopt(argc, argv, "i:o:st")) != EOF) { 181 switch (c) { 182 case 'i': 183 input_name = dwoptarg; 184 break; 185 case 'o': 186 output_name = dwoptarg; 187 break; 188 case 's': 189 use_switch = TRUE; 190 use_tables = FALSE; 191 break; 192 case 't': 193 use_switch = FALSE; 194 use_tables = TRUE; 195 break; 196 default: 197 usage_error = TRUE; 198 break; 199 } 200 } 201 202 if (usage_error || 1 == dwoptind || dwoptind != argc) { 203 print_usage_message(usage); 204 exit(FAILED); 205 } 206 } 207 208 int 209 main(int argc,char **argv) 210 { 211 print_version(argv[0]); 212 print_args(argc,argv); 213 process_args(argc,argv); 214 OpenAllFiles(); 215 GenerateInitialFileLines(); 216 ParseDefinitionsAndWriteOutput(); 217 WriteFileTrailers(); 218 CloseAllFiles(); 219 return 0; 220 } 221 222 /* Print the array used to hold the tags, attributes values */ 223 #ifdef TRACE_ARRAY 224 static void 225 PrintArray(void) 226 { 227 int i; 228 for (i = 0; i < array_count; ++i) { 229 printf("%d: Name %s_%s, Value 0x%04x\n", 230 i,prefix, 231 array[i].name, 232 array[i].value); 233 } 234 } 235 #endif /* TRACE_ARRAY */ 236 237 /* By including original position we force a stable sort */ 238 static int 239 Compare(array_data *elem1,array_data *elem2) 240 { 241 if (elem1->value < elem2->value) { 242 return -1; 243 } 244 if (elem1->value > elem2->value) { 245 return 1; 246 } 247 if (elem1->original_position < elem2->original_position) { 248 return -1; 249 } 250 if (elem1->original_position > elem2->original_position) { 251 return 1; 252 } 253 return 0; 254 } 255 256 static FILE * 257 open_path(const char *base, const char *file, const char *direction) 258 { 259 FILE *f = 0; 260 /* POSIX PATH_MAX would suffice, normally stdio BUFSIZ is larger 261 than PATH_MAX */ 262 static char path_name[BUFSIZ]; 263 264 /* 2 == space for / and NUL */ 265 size_t netlen = strlen(file) +strlen(base) + 2; 266 267 if (netlen >= BUFSIZ) { 268 printf("Error opening '%s/%s', name too long\n",base,file); 269 exit(1); 270 } 271 272 strcpy(path_name,base); 273 strcat(path_name,"/"); 274 strcat(path_name,file); 275 276 f = fopen(path_name,direction); 277 if (!f) { 278 printf("Error opening '%s'\n",path_name); 279 exit(1); 280 } 281 return f; 282 } 283 284 /* Open files and write the basic headers */ 285 static void 286 OpenAllFiles(void) 287 { 288 const char *dwarf_h = "dwarf.h"; 289 const char *names_h = "dwarf_names.h"; 290 const char *names_c = "dwarf_names.c"; 291 const char *names_enum_h = "dwarf_names_enum.h"; 292 const char *names_new_h = "dwarf_names_new.h"; 293 294 f_dwarf_in = open_path(input_name,dwarf_h,"r"); 295 f_names_enum_h = open_path(output_name,names_enum_h,"w"); 296 f_names_new_h = open_path(output_name,names_new_h,"w"); 297 f_names_h = open_path(output_name,names_h,"w"); 298 f_names_c = open_path(output_name,names_c,"w"); 299 } 300 301 static void 302 GenerateInitialFileLines(void) 303 { 304 /* Generate entries for 'dwarf_names_enum.h' */ 305 fprintf(f_names_enum_h,"/* Automatically generated, do not edit. */\n"); 306 fprintf(f_names_enum_h,"/* Generated sourcedate %s */\n", 307 DW_VERSION_DATE_STR); 308 fprintf(f_names_enum_h,"\n/* BEGIN FILE */\n\n"); 309 fprintf(f_names_enum_h,"#ifndef __DWARF_NAMES_ENUM_H__\n"); 310 fprintf(f_names_enum_h,"#define __DWARF_NAMES_ENUM_H__\n"); 311 312 /* Generate entries for 'dwarf_names_new.h' */ 313 fprintf(f_names_new_h,"/* Automatically generated, do not edit. */\n"); 314 fprintf(f_names_new_h,"/* Generated sourcedate %s */\n", 315 DW_VERSION_DATE_STR); 316 fprintf(f_names_new_h,"\n/* BEGIN FILE */\n\n"); 317 fprintf(f_names_new_h,"/* define DWARF_PRINT_PREFIX before this\n"); 318 fprintf(f_names_new_h," point if you wish to. */\n"); 319 fprintf(f_names_new_h,"#ifndef DWARF_PRINT_PREFIX\n"); 320 fprintf(f_names_new_h,"#define DWARF_PRINT_PREFIX dwarf_\n"); 321 fprintf(f_names_new_h,"#endif\n"); 322 fprintf(f_names_new_h,"#define dw_glue(x,y) x##y\n"); 323 fprintf(f_names_new_h,"#define dw_glue2(x,y) dw_glue(x,y)\n"); 324 fprintf(f_names_new_h,"#define DWPREFIX(x) dw_glue2(DWARF_PRINT_PREFIX,x)\n"); 325 326 /* Generate entries for 'dwarf_names.h' */ 327 fprintf(f_names_h,"/* Generated routines, do not edit. */\n"); 328 fprintf(f_names_h,"/* Generated sourcedate %s */\n", 329 DW_VERSION_DATE_STR); 330 fprintf(f_names_h,"\n/* BEGIN FILE */\n\n"); 331 332 fprintf(f_names_h,"#ifndef DWARF_NAMES_H\n"); 333 fprintf(f_names_h,"#define DWARF_NAMES_H\n\n"); 334 fprintf(f_names_h,"#ifdef __cplusplus\n"); 335 fprintf(f_names_h,"extern \"C\" {\n"); 336 fprintf(f_names_h,"#endif /* __cplusplus */\n\n"); 337 338 /* Generate entries for 'dwarf_names.c' */ 339 fprintf(f_names_c,"/* Generated routines, do not edit. */\n"); 340 fprintf(f_names_c,"/* Generated sourcedate %s */\n", 341 DW_VERSION_DATE_STR); 342 fprintf(f_names_c,"\n/* BEGIN FILE */\n\n"); 343 fprintf(f_names_c,"#include \"dwarf.h\"\n\n"); 344 fprintf(f_names_c,"#include \"libdwarf.h\"\n\n"); 345 346 if (use_tables) { 347 fprintf(f_names_c,"typedef struct Names_Data {\n"); 348 fprintf(f_names_c," const char *l_name; \n"); 349 fprintf(f_names_c," unsigned value; \n"); 350 fprintf(f_names_c,"} Names_Data;\n\n"); 351 352 /* Generate code to find an entry */ 353 fprintf(f_names_c,"/* Use standard binary search to get entry */\n"); 354 fprintf(f_names_c,"static int\nfind_entry(Names_Data *table," 355 "const int last,unsigned value, const char **s_out)\n"); 356 fprintf(f_names_c,"{\n"); 357 fprintf(f_names_c," int low = 0;\n"); 358 fprintf(f_names_c," int high = last;\n"); 359 fprintf(f_names_c," int mid;\n"); 360 fprintf(f_names_c," unsigned maxval = table[last-1].value;\n"); 361 fprintf(f_names_c,"\n"); 362 fprintf(f_names_c," if (value > maxval) {\n"); 363 fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n"); 364 fprintf(f_names_c," }\n"); 365 fprintf(f_names_c," while (low < high) {\n"); 366 fprintf(f_names_c," mid = low + ((high - low) / 2);\n"); 367 fprintf(f_names_c," if(mid == last) {\n"); 368 fprintf(f_names_c," break;\n"); 369 fprintf(f_names_c," }\n"); 370 fprintf(f_names_c," if (table[mid].value < value) {\n"); 371 fprintf(f_names_c," low = mid + 1;\n"); 372 fprintf(f_names_c," }\n"); 373 fprintf(f_names_c," else {\n"); 374 fprintf(f_names_c," high = mid;\n"); 375 fprintf(f_names_c," }\n"); 376 fprintf(f_names_c," }\n"); 377 fprintf(f_names_c,"\n"); 378 fprintf(f_names_c," if (low < last && table[low].value == value) {\n"); 379 fprintf(f_names_c," /* Found: low is the entry */\n"); 380 fprintf(f_names_c," *s_out = table[low].l_name;\n"); 381 fprintf(f_names_c," return DW_DLV_OK;\n"); 382 fprintf(f_names_c," }\n"); 383 fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n"); 384 fprintf(f_names_c,"}\n"); 385 fprintf(f_names_c,"\n"); 386 } 387 } 388 389 /* Close files and write basic trailers */ 390 static void 391 WriteFileTrailers(void) 392 { 393 /* Generate entries for 'dwarf_names_enum.h' */ 394 fprintf(f_names_enum_h,"#endif /* __DWARF_NAMES_ENUM_H__ */\n"); 395 fprintf(f_names_enum_h,"\n/* END FILE */\n"); 396 397 /* Generate entries for 'dwarf_names_new.h' */ 398 fprintf(f_names_new_h,"\n/* END FILE */\n"); 399 400 /* Generate entries for 'dwarf_names.h' */ 401 402 fprintf(f_names_h,"\n#ifdef __cplusplus\n"); 403 fprintf(f_names_h,"}\n"); 404 fprintf(f_names_h,"#endif /* __cplusplus */\n\n"); 405 fprintf(f_names_h,"#endif /* DWARF_NAMES_H */\n"); 406 fprintf(f_names_h,"\n/* END FILE */\n"); 407 408 /* Generate entries for 'dwarf_names.c' */ 409 fprintf(f_names_c,"\n/* END FILE */\n"); 410 } 411 412 static void 413 CloseAllFiles(void) 414 { 415 fclose(f_dwarf_in); 416 fclose(f_names_enum_h); 417 fclose(f_names_new_h); 418 fclose(f_names_h); 419 fclose(f_names_c); 420 } 421 422 /* Write the table and code for a common set of names */ 423 static void 424 GenerateOneSet(void) 425 { 426 unsigned u; 427 unsigned prev_value = 0; 428 size_t len; 429 char *prefix_id = prefix + prefix_root_len; 430 unsigned actual_array_count = 0; 431 432 #ifdef TRACE_ARRAY 433 printf("List before sorting:\n"); 434 PrintArray(); 435 #endif /* TRACE_ARRAY */ 436 437 /* Sort the array, because the values in 'libdwarf.h' are not in 438 ascending order; if we use '-t' we must be sure the values are 439 sorted, for the binary search to work properly. 440 We want a stable sort, hence mergesort. */ 441 qsort((void *)&group_array,array_count,sizeof(array_data),(compfn)Compare); 442 443 #ifdef TRACE_ARRAY 444 printf("\nList after sorting:\n"); 445 PrintArray(); 446 #endif /* TRACE_ARRAY */ 447 448 /* Generate entries for 'dwarf_names_enum.h' */ 449 fprintf(f_names_enum_h,"\nenum Dwarf_%s_e {\n",prefix_id); 450 451 /* Generate entries for 'dwarf_names_new.h' */ 452 fprintf(f_names_new_h,"int DWPREFIX(get_%s_name) (unsigned int, const char **);\n",prefix_id); 453 454 /* Generate entries for 'dwarf_names.h' and libdwarf.h */ 455 fprintf(f_names_h,"extern int dwarf_get_%s_name(unsigned int /*val_in*/, const char ** /*s_out */);\n",prefix_id); 456 457 /* Generate code for 'dwarf_names.c' */ 458 fprintf(f_names_c,"/* ARGSUSED */\n"); 459 fprintf(f_names_c,"int\n"); 460 fprintf(f_names_c,"dwarf_get_%s_name (unsigned int val,const char ** s_out)\n",prefix_id); 461 fprintf(f_names_c,"{\n"); 462 if (use_tables) { 463 fprintf(f_names_c," static Names_Data Dwarf_%s_n[] = {\n",prefix_id); 464 } else { 465 fprintf(f_names_c," switch (val) {\n"); 466 } 467 468 for (u = 0; u < array_count; ++u) { 469 /* Check if value already dumped */ 470 if (u > 0 && group_array[u].value == prev_value) { 471 fprintf(f_names_c, 472 " /* Skipping alternate spelling of value 0x%x. %s_%s */\n", 473 (unsigned)prev_value, 474 prefix, 475 group_array[u].name); 476 continue; 477 } 478 prev_value = group_array[u].value; 479 480 /* Generate entries for 'dwarf_names_enum.h'. 481 The 39 just makes nice formatting in the output. */ 482 len = 39 - strlen(prefix); 483 fprintf(f_names_enum_h," %s_%-*s = 0x%04x", 484 prefix,(int)len,group_array[u].name,group_array[u].value); 485 fprintf(f_names_enum_h,(u + 1 < array_count) ? ",\n" : "\n"); 486 487 /* Generate entries for 'dwarf_names.c' */ 488 if (use_tables) { 489 fprintf(f_names_c," {/* %3u */ \"%s_%s\", ", 490 actual_array_count,prefix,group_array[u].name); 491 fprintf(f_names_c," %s_%s}", prefix,group_array[u].name); 492 fprintf(f_names_c,(u + 1 < array_count) ? ",\n" : "\n"); 493 } else { 494 fprintf(f_names_c," case %s_%s:\n", 495 prefix,group_array[u].name); 496 fprintf(f_names_c," *s_out = \"%s_%s\";\n", 497 prefix,group_array[u].name); 498 fprintf(f_names_c," return DW_DLV_OK;\n"); 499 } 500 ++actual_array_count; 501 } 502 503 /* Closing entries for 'dwarf_names_enum.h' */ 504 fprintf(f_names_enum_h,"};\n"); 505 506 if (use_tables) { 507 /* Closing entries for 'dwarf_names.c' */ 508 fprintf(f_names_c," };\n\n"); 509 510 /* Closing code for 'dwarf_names.c' */ 511 fprintf(f_names_c," const int last_entry = %d;\n",actual_array_count); 512 fprintf(f_names_c," /* find the entry */\n"); 513 fprintf(f_names_c," int r = find_entry(Dwarf_%s_n,last_entry,val,s_out);\n",prefix_id); 514 fprintf(f_names_c," return r;\n"); 515 fprintf(f_names_c,"}\n"); 516 } else { 517 fprintf(f_names_c," }\n"); 518 fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n"); 519 fprintf(f_names_c,"}\n"); 520 } 521 522 /* Mark the group_array as empty */ 523 array_count = 0; 524 } 525 526 /* Detect empty lines (and other lines we do not want to read) */ 527 static boolean 528 is_skippable_line(char *pLine) 529 { 530 boolean empty = TRUE; 531 532 for (; *pLine && empty; ++pLine) { 533 empty = isspace(*pLine); 534 } 535 return empty; 536 } 537 538 static void 539 safe_strncpy(char *out, unsigned out_len, 540 char *in,unsigned in_len) 541 { 542 if(in_len >= out_len) { 543 fprintf(stderr,"Impossible input line from dwarf.h. Giving up. \n"); 544 fprintf(stderr,"Length %u is too large, limited to %u.\n", 545 in_len,out_len); 546 exit(1); 547 } 548 strncpy(out,in,in_len); 549 } 550 551 552 /* Parse the 'dwarf.h' file and generate the tables */ 553 static void 554 ParseDefinitionsAndWriteOutput(void) 555 { 556 char new_prefix[64]; 557 char *second_underscore = NULL; 558 char type[1000]; 559 char name[1000]; 560 char value[1000]; 561 char extra[1000]; 562 char line_in[MAX_LINE_SIZE]; 563 int pending = FALSE; 564 int prefix_len = 0; 565 566 /* Process each line from 'dwarf.h' */ 567 while (!feof(f_dwarf_in)) { 568 /* errno is cleared here so printing errno after 569 the fgets is showing errno as set by fgets. */ 570 char *fgbad = 0; 571 errno = 0; 572 fgbad = fgets(line_in,sizeof(line_in),f_dwarf_in); 573 if(!fgbad) { 574 if(feof(f_dwarf_in)) { 575 break; 576 } 577 /* Is error. errno must be set. */ 578 fprintf(stderr,"Error reading dwarf.h!. Errno %d\n",errno); 579 exit(1); 580 } 581 if (is_skippable_line(line_in)) { 582 continue; 583 } 584 sscanf(line_in,"%s %s %s %s",type,name,value,extra); 585 if (strcmp(type,"#define") || 586 strncmp(name,prefix_root,prefix_root_len)) { 587 continue; 588 } 589 590 second_underscore = strchr(name + prefix_root_len,'_'); 591 prefix_len = (int)(second_underscore - name); 592 safe_strncpy(new_prefix,sizeof(new_prefix),name,prefix_len); 593 new_prefix[prefix_len] = 0; 594 595 /* Check for new prefix set */ 596 if (strcmp(prefix,new_prefix)) { 597 if (pending) { 598 /* Generate current prefix set */ 599 GenerateOneSet(); 600 } 601 pending = TRUE; 602 strcpy(prefix,new_prefix); 603 } 604 605 /* Be sure we have a valid entry */ 606 if (array_count >= ARRAY_SIZE) { 607 printf("Too many entries for current group_array size of %d",ARRAY_SIZE); 608 exit(1); 609 } 610 611 /* Move past the second underscore */ 612 ++second_underscore; 613 614 { 615 unsigned long v = strtoul(value,NULL,16); 616 /* Some values are duplicated, that is ok. 617 After the sort we will weed out the duplicate values, 618 see GenerateOneSet(). */ 619 /* Record current entry */ 620 if (strlen(second_underscore) >= MAX_NAME_LEN) { 621 printf("Too long a name %s for max len %d\n", 622 second_underscore,MAX_NAME_LEN); 623 exit(1); 624 } 625 strcpy(group_array[array_count].name,second_underscore); 626 group_array[array_count].value = v; 627 group_array[array_count].original_position = array_count; 628 ++array_count; 629 } 630 } 631 if (pending) { 632 /* Generate final prefix set */ 633 GenerateOneSet(); 634 } 635 } 636