diff options
Diffstat (limited to 'libdwarf/gennames.c')
-rw-r--r-- | libdwarf/gennames.c | 541 |
1 files changed, 541 insertions, 0 deletions
diff --git a/libdwarf/gennames.c b/libdwarf/gennames.c new file mode 100644 index 0000000..6cfe0a3 --- /dev/null +++ b/libdwarf/gennames.c @@ -0,0 +1,541 @@ +/* + Copyright 2009-2010 SN Systems Ltd. All rights reserved. + Portions Copyright 2009-2011 David Anderson. All rights reserved. + + This program is free software; you can redistribute it and/or modify it + under the terms of version 2.1 of the GNU Lesser General Public License + as published by the Free Software Foundation. + + This program is distributed in the hope that it would be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Further, this software is distributed without any warranty that it is + free of the rightful claim of any third person regarding infringement + or the like. Any license provided herein, whether implied or + otherwise, applies only to this software file. Patent licenses, if + any, provided herein do not apply to combinations of this program with + other software, or any other product whatsoever. + + You should have received a copy of the GNU Lesser General Public + License along with this program; if not, write the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, + USA. + + Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, + Mountain View, CA 94043, or: + + http://www.sgi.com + + For further information regarding this notice, see: + + http://oss.sgi.com/projects/GenInfo/NoticeExplan + +*/ + +/* The address of the Free Software Foundation is + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. + SGI has moved from the Crittenden Lane address. +*/ + +#include <stdio.h> +#include <stdlib.h> /* For exit() declaration etc. */ +#include <errno.h> /* For errno declaration. */ +#include <ctype.h> +#include <string.h> +#include <unistd.h> /* For getopt */ +#include "dwarf.h" +#include "common.h" + +/* gennames.c + Prints routines to return constant name for the associated value + (such as the TAG name string for a particular tag). + + The input is dwarf.h + For each set of names with a common prefix, we create a routine + to return the name given the value. + Also print header file that gives prototypes of routines. + To handle cases where there are multiple names for a single + value (DW_AT_* has some due to ambiguities in the DWARF2 spec) + we take the first of a given value as the definitive name. + TAGs, Attributes, etc are given distinct checks. + + There are multiple output files as some people find one + form more pleasant than the other. + + The doprinting argument is so that when used by tag_tree.c, + and tag_attr.c that we don't get irritating messages on stderr + when those dwarfdump built-time applications are run. + + Some compilers generate better code for switch statements than + others, so the -s and -t options let the user decide which + is better for their compiler (when building dwarfdump): + a simple switch or code doing binary search. + This choice affects the runtime speed of dwarfdump. */ + +typedef int boolean; +#define TRUE 1 +#define FALSE 0 +#define FAILED 1 + +static void OpenAllFiles(); +static void WriteFileTrailers(); +static void CloseAllFiles(); +static void GenerateInitialFileLines(); +static void GenerateOneSet(); +#ifdef TRACE_ARRAY +static void PrintArray(void); +#endif /* TRACE_ARRAY */ +static boolean is_skippable_line(char *pLine); +static void ParseDefinitionsAndWriteOutput(); + +/* We don't need really long lines: the input file is simple. */ +#define MAX_LINE_SIZE 1000 +/* We don't need a variable array size, it just has to be big enough. */ +#define ARRAY_SIZE 256 + +/* To store entries from dwarf.h */ +typedef struct { + char name[64]; /* short name */ + unsigned value; /* value */ +} array_data; + +/* A group_array is a grouping from dwarf.h. + All the TAGs are one group, all the + FORMs are another group, and so on. */ +static array_data group_array[ARRAY_SIZE]; +static unsigned array_count = 0; + +typedef int (*compfn)(const void *,const void *); +static int Compare(array_data *,array_data *); + +static char *prefix_root = "DW_"; +static unsigned prefix_root_len = 3; + +/* f_dwarf_in is the input dwarf.h. The others are output files. */ +static FILE *f_dwarf_in; +static FILE *f_names_h; +static FILE *f_names_c; +static FILE *f_names_enum_h; +static FILE *f_names_new_h; + +/* Size unchecked, but large enough. */ +static char prefix[200] = ""; + +static const char *usage[] = { + "Usage: gennames <options>", + " -i input-table-path", + " -o output-table-path", + " -s use 'switch' in generation", + " -t use 'tables' in generation", + "", +}; + +char *program_name = 0; +static char *input_name = 0; +static char *output_name = 0; +static boolean use_switch = TRUE; +static boolean use_tables = FALSE; + + +/* process arguments */ +static void +process_args(int argc, char *argv[]) +{ + int c = 0; + boolean usage_error = FALSE; + + program_name = argv[0]; + + while ((c = getopt(argc, argv, "i:o:st")) != EOF) { + switch (c) { + case 'i': + input_name = optarg; + break; + case 'o': + output_name = optarg; + break; + case 's': + use_switch = TRUE; + use_tables = FALSE; + break; + case 't': + use_switch = FALSE; + use_tables = TRUE; + break; + default: + usage_error = TRUE; + break; + } + } + + if (usage_error || 1 == optind || optind != argc) { + print_usage_message(usage); + exit(FAILED); + } +} + +int +main(int argc,char **argv) +{ + print_version(argv[0]); + process_args(argc,argv); + print_args(argc,argv); + OpenAllFiles(); + GenerateInitialFileLines(); + ParseDefinitionsAndWriteOutput(); + WriteFileTrailers(); + CloseAllFiles(); + return 0; +} + +/* Print the array used to hold the tags, attributes values */ +#ifdef TRACE_ARRAY +static void +PrintArray(void) +{ + int index; + for (index = 0; index < array_count; ++index) { + printf("%d: Name %s_%s, Value 0x%04x\n", + index,prefix, + array[index].name, + array[index].value); + } +} +#endif /* TRACE_ARRAY */ + +static int +Compare(array_data *elem1,array_data *elem2) +{ + if (elem1->value < elem2->value) { + return -1; + } + if (elem1->value > elem2->value) { + return 1; + } + return 0; +} + +static FILE * +open_path(const char *base, const char *file, const char *direction) +{ + FILE *f = 0; + /* POSIX PATH_MAX would suffice, normally stdio BUFSIZ is larger + than PATH_MAX */ + char path_name[BUFSIZ]; + snprintf(path_name,sizeof(path_name),"%s/%s",base,file); + f = fopen(path_name,direction); + if (!f) { + printf("Error openning '%s'\n",path_name); + exit(1); + } + return f; +} + +/* Open files and write the basic headers */ +static void +OpenAllFiles() +{ + char *dwarf_h = "dwarf.h"; + char *names_h = "dwarf_names.h"; + char *names_c = "dwarf_names.c"; + char *names_enum_h = "dwarf_names_enum.h"; + char *names_new_h = "dwarf_names_new.h"; + + f_dwarf_in = open_path(input_name,dwarf_h,"r"); + f_names_enum_h = open_path(output_name,names_enum_h,"w"); + f_names_new_h = open_path(output_name,names_new_h,"w"); + f_names_h = open_path(output_name,names_h,"w"); + f_names_c = open_path(output_name,names_c,"w"); +} + +static void +GenerateInitialFileLines() +{ + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"/* Automatically generated, do not edit. */\n"); + fprintf(f_names_enum_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_enum_h,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_enum_h,"#ifndef __DWARF_NAMES_ENUM_H__\n"); + fprintf(f_names_enum_h,"#define __DWARF_NAMES_ENUM_H__\n"); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"/* Automatically generated, do not edit. */\n"); + fprintf(f_names_new_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_new_h,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_new_h,"/* define DWARF_PRINT_PREFIX before this \n"); + fprintf(f_names_new_h," point if you wish to. */\n"); + fprintf(f_names_new_h,"#ifndef DWARF_PRINT_PREFIX \n"); + fprintf(f_names_new_h,"#define DWARF_PRINT_PREFIX dwarf_\n"); + fprintf(f_names_new_h,"#endif\n"); + fprintf(f_names_new_h,"#define dw_glue(x,y) x##y\n"); + fprintf(f_names_new_h,"#define dw_glue2(x,y) dw_glue(x,y)\n"); + fprintf(f_names_new_h,"#define DWPREFIX(x) dw_glue2(DWARF_PRINT_PREFIX,x)\n"); + + /* Generate entries for 'dwarf_names.h' */ + fprintf(f_names_h,"/* Generated routines, do not edit. */\n"); + fprintf(f_names_h,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_h,"\n/* BEGIN FILE */\n\n"); + + /* Generate entries for 'dwarf_names.c' */ + fprintf(f_names_c,"/* Generated routines, do not edit. */\n"); + fprintf(f_names_c,"/* Generated on %s %s */\n",__DATE__,__TIME__); + fprintf(f_names_c,"\n/* BEGIN FILE */\n\n"); + fprintf(f_names_c,"#include \"dwarf.h\"\n\n"); + fprintf(f_names_c,"#include \"libdwarf.h\"\n\n"); + + if (use_tables) { + fprintf(f_names_c,"typedef struct Names_Data {\n"); + fprintf(f_names_c," const char *l_name; \n"); + fprintf(f_names_c," unsigned value; \n"); + fprintf(f_names_c,"} Names_Data;\n\n"); + + /* Generate code to find an entry */ + fprintf(f_names_c,"/* Use standard binary search to get entry */\n"); + fprintf(f_names_c,"static int\nfind_entry(Names_Data *table," + "const int last,unsigned value, const char **s_out)\n"); + fprintf(f_names_c,"{\n"); + fprintf(f_names_c," int low = 0;\n"); + fprintf(f_names_c," int high = last;\n"); + fprintf(f_names_c," int mid;\n"); + fprintf(f_names_c,"\n"); + fprintf(f_names_c," while (low < high) {\n"); + fprintf(f_names_c," mid = low + ((high - low) / 2);\n"); + fprintf(f_names_c," if (table[mid].value < value) {\n"); + fprintf(f_names_c," low = mid + 1;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," else {\n"); + fprintf(f_names_c," high = mid;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c,"\n"); + fprintf(f_names_c," if (low < last && table[low].value == value) {\n"); + fprintf(f_names_c," /* Found: low is the entry */\n"); + fprintf(f_names_c," *s_out = table[low].l_name;\n"); + fprintf(f_names_c," return DW_DLV_OK;\n"); + fprintf(f_names_c," }\n"); + fprintf(f_names_c," return DW_DLV_NO_ENTRY;\n"); + fprintf(f_names_c,"}\n"); + fprintf(f_names_c,"\n"); + } +} + +/* Close files and write basic trailers */ +static void +WriteFileTrailers() +{ + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"#endif /* __DWARF_NAMES_ENUM_H__ */\n"); + fprintf(f_names_enum_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names.h' */ + fprintf(f_names_h,"\n/* END FILE */\n"); + + /* Generate entries for 'dwarf_names.c' */ + fprintf(f_names_c,"\n/* END FILE */\n"); +} + +static void +CloseAllFiles() +{ + fclose(f_dwarf_in); + fclose(f_names_enum_h); + fclose(f_names_new_h); + fclose(f_names_h); + fclose(f_names_c); +} + +/* Write the table and code for a common set of names */ +static void +GenerateOneSet() +{ + unsigned index; + unsigned prev_value = 0; + size_t len; + char *prefix_id = prefix + prefix_root_len; + +#ifdef TRACE_ARRAY + printf("List before sorting:\n"); + PrintArray(); +#endif /* TRACE_ARRAY */ + + /* Sort the array, because the values in 'libdwarf.h' are not in + ascending order; if we use '-t' we must be sure the values are + sorted, for the binary search to work properly */ + qsort((void *)&group_array,array_count,sizeof(array_data),(compfn)Compare); + +#ifdef TRACE_ARRAY + printf("\nList after sorting:\n"); + PrintArray(); +#endif /* TRACE_ARRAY */ + + /* Generate entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"\nenum Dwarf_%s_e {\n",prefix_id); + + /* Generate entries for 'dwarf_names_new.h' */ + fprintf(f_names_new_h,"int DWPREFIX(get_%s_name) (unsigned int, const char **);\n",prefix_id); + + /* Generate entries for 'dwarf_names.h' and libdwarf.h */ + fprintf(f_names_h,"extern int dwarf_get_%s_name(unsigned int /*val_in*/, const char ** /*s_out */);\n",prefix_id); + + /* Generate code for 'dwarf_names.c' */ + fprintf(f_names_c,"/* ARGSUSED */\n"); + fprintf(f_names_c,"int\n"); + fprintf(f_names_c,"dwarf_get_%s_name (unsigned int val,const char ** s_out)\n",prefix_id); + fprintf(f_names_c,"{\n"); + if (use_tables) { + fprintf(f_names_c," static Names_Data Dwarf_%s_n[] = {\n",prefix_id); + } else { + fprintf(f_names_c," switch (val) {\n"); + } + + for (index = 0; index < array_count; ++index) { + /* Check if value already dumped */ + if (index > 0 && group_array[index].value == prev_value) { + continue; + } + prev_value = group_array[index].value; + + len = 39 - strlen(prefix); + fprintf(f_names_enum_h," %s_%-*s = 0x%04x", + prefix,(int)len,group_array[index].name,group_array[index].value); + fprintf(f_names_enum_h,(index + 1 < array_count) ? ",\n" : "\n"); + + /* Generate entries for 'dwarf_names.c' */ + if (use_tables) { + /* The 20 just makes nice formatting in the output. */ + len = 20 - strlen(group_array[index].name); + fprintf(f_names_c," {/* %3d */ \"%s_%s\", ", + index,prefix,group_array[index].name); + fprintf(f_names_c," %s_%s}", prefix,group_array[index].name); + fprintf(f_names_c,(index + 1 < array_count) ? ",\n" : "\n"); + } else { + fprintf(f_names_c," case %s_%s:\n", + prefix,group_array[index].name); + fprintf(f_names_c," *s_out = \"%s_%s\";\n", + prefix,group_array[index].name); + fprintf(f_names_c," return DW_DLV_OK;\n"); + } + } + + /* Closing entries for 'dwarf_names_enum.h' */ + fprintf(f_names_enum_h,"};\n"); + + if (use_tables) { + /* Closing entries for 'dwarf_names.c' */ + fprintf(f_names_c," };\n\n"); + + /* Closing code for 'dwarf_names.c' */ + fprintf(f_names_c," const int last_entry = %d;\n",array_count); + fprintf(f_names_c," /* find the entry */\n"); + fprintf(f_names_c," int r = find_entry(Dwarf_%s_n,last_entry,val,s_out);\n",prefix_id); + fprintf(f_names_c," return r; \n"); + fprintf(f_names_c,"}\n"); + } else { + fprintf(f_names_c," }\n"); + fprintf(f_names_c," return DW_DLV_NO_ENTRY; \n"); + fprintf(f_names_c,"}\n"); + } + + /* Mark the group_array as empty */ + array_count = 0; +} + +/* Detect empty lines (and other lines we do not want to read) */ +static boolean +is_skippable_line(char *pLine) +{ + boolean empty = TRUE; + + for (; *pLine && empty; ++pLine) { + empty = isspace(*pLine); + } + return empty; +} + +static void safe_strncpy(char *out, unsigned out_len, +char *in,unsigned in_len) +{ + if(in_len >= out_len) { + fprintf(stderr,"Impossible input line from dwarf.h. Giving up. \n"); + fprintf(stderr,"Length %u is too large, limited to %u.\n", + in_len,out_len); + exit(1); + } + strncpy(out,in,in_len); +} + + +/* Parse the 'dwarf.h' file and generate the tables */ +static void +ParseDefinitionsAndWriteOutput() +{ + char new_prefix[64]; + char *second_underscore = NULL; + char type[1000]; + char name[1000]; + char value[1000]; + char extra[1000]; + char line_in[MAX_LINE_SIZE]; + int pending = FALSE; + int prefix_len = 0; + + /* Process each line from 'dwarf.h' */ + while (!feof(f_dwarf_in)) { + errno = 0; + char *fgbad = fgets(line_in,sizeof(line_in),f_dwarf_in); + if(!fgbad) { + if(feof(f_dwarf_in)) { + break; + } + /* Is error. errno must be set. */ + fprintf(stderr,"Error reading dwarf.h!. Errno %d\n",errno); + exit(1); + } + if (is_skippable_line(line_in)) { + continue; + } + sscanf(line_in,"%s %s %s %s",type,name,value,extra); + if (strcmp(type,"#define") || + strncmp(name,prefix_root,prefix_root_len)) { + continue; + } + + second_underscore = strchr(name + prefix_root_len,'_'); + prefix_len = (int)(second_underscore - name); + safe_strncpy(new_prefix,sizeof(new_prefix),name,prefix_len); + new_prefix[prefix_len] = 0; + + /* Check for new prefix set */ + if (strcmp(prefix,new_prefix)) { + if (pending) { + /* Generate current prefix set */ + GenerateOneSet(); + } + pending = TRUE; + strcpy(prefix,new_prefix); + } + + /* Be sure we have a valid entry */ + if (array_count >= ARRAY_SIZE) { + printf("Too many entries for current group_array size"); + exit(1); + } + + /* Move past the second underscore */ + ++second_underscore; + + /* Record current entry */ + strcpy(group_array[array_count].name,second_underscore); + group_array[array_count].value = strtoul(value,NULL,16); + ++array_count; + } + if (pending) { + /* Generate final prefix set */ + GenerateOneSet(); + } +} |