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
print_args(int argc,char * argv[])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
print_version(const char * name)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
print_usage_message(const char * options[])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
process_args(int argc,char * argv[])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
main(int argc,char ** argv)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
PrintArray(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
Compare(array_data * elem1,array_data * elem2)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 *
open_path(const char * base,const char * file,const char * direction)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
OpenAllFiles(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
GenerateInitialFileLines(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
WriteFileTrailers(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
CloseAllFiles(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
GenerateOneSet(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
is_skippable_line(char * pLine)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
safe_strncpy(char * out,unsigned out_len,char * in,unsigned in_len)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
ParseDefinitionsAndWriteOutput(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