tools/elf4rom/libs/dwarf-20071209/dwarfdump/dwconf.c
changeset 34 92d87f2e53c2
equal deleted inserted replaced
33:1af5c1be89f8 34:92d87f2e53c2
       
     1 /*
       
     2   Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
       
     3 
       
     4   This program is free software; you can redistribute it and/or modify it
       
     5   under the terms of version 2 of the GNU General Public License as
       
     6   published by the Free Software Foundation.
       
     7 
       
     8   This program is distributed in the hope that it would be useful, but
       
     9   WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
       
    11 
       
    12   Further, this software is distributed without any warranty that it is
       
    13   free of the rightful claim of any third person regarding infringement
       
    14   or the like.  Any license provided herein, whether implied or
       
    15   otherwise, applies only to this software file.  Patent licenses, if
       
    16   any, provided herein do not apply to combinations of this program with
       
    17   other software, or any other product whatsoever.
       
    18 
       
    19   You should have received a copy of the GNU General Public License along
       
    20   with this program; if not, write the Free Software Foundation, Inc., 51
       
    21   Franklin Street - Fifth Floor, Boston MA 02110-1301, USA.
       
    22 
       
    23   Contact information:  Silicon Graphics, Inc., 1500 Crittenden Lane,
       
    24   Mountain View, CA 94043, or:
       
    25 
       
    26   http://www.sgi.com
       
    27 
       
    28   For further information regarding this notice, see:
       
    29 
       
    30   http://oss.sgi.com/projects/GenInfo/NoticeExplan
       
    31 
       
    32 
       
    33 $Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/dwconf.c,v 1.4 2006/04/18 18:05:57 davea Exp $ */
       
    34 
       
    35 
       
    36 #include "globals.h"
       
    37 #include <ctype.h>
       
    38 #include "dwconf.h"
       
    39 #include "makename.h"
       
    40 
       
    41 
       
    42 struct token_s {
       
    43     unsigned tk_len;
       
    44     char *tk_data;
       
    45 };
       
    46 enum linetype_e {
       
    47     LT_ERROR,
       
    48     LT_COMMENT,
       
    49     LT_BLANK,
       
    50     LT_BEGINABI,
       
    51     LT_REG,
       
    52     LT_FRAME_INTERFACE,
       
    53     LT_CFA_REG,
       
    54     LT_INITIAL_REG_VALUE,
       
    55     LT_REG_TABLE_SIZE,
       
    56     LT_ENDABI
       
    57 };
       
    58 
       
    59 struct comtable_s {
       
    60     enum linetype_e type;
       
    61     char *name;
       
    62     size_t namelen;
       
    63 };
       
    64 
       
    65 static int errcount = 0;	/* Count errors found in this scan of
       
    66 				   the configuration file. */
       
    67 
       
    68 static char name_begin_abi[] = "beginabi:";
       
    69 static char name_reg[] = "reg:";
       
    70 static char name_frame_interface[] = "frame_interface:";
       
    71 static char name_cfa_reg[] = "cfa_reg:";
       
    72 static char name_initial_reg_value[] = "initial_reg_value:";
       
    73 static char name_reg_table_size[] = "reg_table_size:";
       
    74 static char name_endabi[] = "endabi:";
       
    75 
       
    76 static struct comtable_s comtable[] = {
       
    77     {LT_BEGINABI, name_begin_abi},
       
    78     {LT_REG, name_reg},
       
    79     {LT_FRAME_INTERFACE, name_frame_interface},
       
    80     {LT_CFA_REG, name_cfa_reg},
       
    81     {LT_INITIAL_REG_VALUE, name_initial_reg_value},
       
    82     {LT_REG_TABLE_SIZE, name_reg_table_size},
       
    83     {LT_ENDABI, name_endabi},
       
    84 };
       
    85 static int size_of_comtable = sizeof(comtable) / sizeof(comtable[0]);
       
    86 
       
    87 
       
    88 static FILE *find_a_file(char *named_file, char **defaults,
       
    89 			 string * name_used);
       
    90 static int find_abi_start(FILE * stream, char *abi_name, long *offset,
       
    91 			  unsigned long *lineno_out);
       
    92 static int parse_abi(FILE * stream, char *fname, char *abiname,
       
    93 		     struct dwconf_s *out, unsigned long lineno);
       
    94 static char *get_token(char *cp, struct token_s *outtok);
       
    95 
       
    96 
       
    97 
       
    98 
       
    99 
       
   100 /*  This finds a dwarfdump.conf file and
       
   101     then parses it.  It updates
       
   102     conf_out as appropriate.
       
   103 
       
   104     This finds the first file (looking in a set of places)
       
   105     with that name.  It then looks for the right  ABI entry.
       
   106     If the first file it finds does not have that ABI entry it
       
   107     gives up.
       
   108   
       
   109     It would also be reasonable to search every 'dwarfdump.conf'
       
   110     it finds for the abi. But we stop at the first dwarfdump.conf
       
   111     we find.
       
   112 */
       
   113 int
       
   114 find_conf_file_and_read_config(char *named_file,
       
   115 			       char *named_abi, char **defaults,
       
   116 			       struct dwconf_s *conf_out)
       
   117 {
       
   118 
       
   119     FILE *conf_stream = 0;
       
   120     char *name_used = 0;
       
   121     long offset = 0;
       
   122     int res = FALSE;
       
   123     unsigned long lineno = 0;
       
   124 
       
   125     errcount = 0;
       
   126 
       
   127     conf_stream = find_a_file(named_file, defaults, &name_used);
       
   128     if (!conf_stream) {
       
   129 	++errcount;
       
   130 	printf("dwarfdump found no file %s!\n",
       
   131 	       named_file ? named_file : "readable for configuration. "
       
   132 	       "(add options -v -v to see what file names tried)\n");
       
   133 	return errcount;
       
   134     }
       
   135     if (verbose > 1) {
       
   136 	printf("dwarfdump using configuration file %s\n", name_used);
       
   137     }
       
   138 
       
   139     res = find_abi_start(conf_stream, named_abi, &offset, &lineno);
       
   140     if (errcount > 0) {
       
   141 	++errcount;
       
   142 	printf("dwarfdump found no ABI %s in file %s.\n",
       
   143 	       named_abi, name_used);
       
   144 	return errcount;
       
   145     }
       
   146     res = fseek(conf_stream, offset, SEEK_SET);
       
   147     if (res != 0) {
       
   148 	++errcount;
       
   149 	printf("dwarfdump seek to %ld offset in %s failed!\n",
       
   150 	       offset, name_used);
       
   151 	return errcount;
       
   152     }
       
   153     parse_abi(conf_stream, name_used, named_abi, conf_out, lineno);
       
   154     fclose(conf_stream);
       
   155     return errcount;
       
   156 }
       
   157 
       
   158 /* Given path strings, attempt to make a canonical file name:
       
   159    that is, avoid superfluous '/' so that no
       
   160     '//' (or worse) is created in the output. The path components
       
   161     are to be separated so at least one '/'
       
   162     is to appear between the two 'input strings' when
       
   163     creating the output.
       
   164 */
       
   165 static char *
       
   166 canonical_append(char *target, unsigned int target_size,
       
   167 		 char *first_string, char *second_string)
       
   168 {
       
   169     size_t firstlen = strlen(first_string);
       
   170 
       
   171     /* +1 +1: Leave room for added "/" and final NUL, though that is
       
   172        overkill, as we drop a NUL byte too. */
       
   173     if ((firstlen + strlen(second_string) + 1 + 1) >= target_size) {
       
   174 	/* Not enough space. */
       
   175 	return NULL;
       
   176     }
       
   177     for (; *second_string == '/'; ++second_string) {
       
   178     }
       
   179     for (; firstlen > 0 && first_string[firstlen - 1] == '/';
       
   180 	 --firstlen) {
       
   181     }
       
   182     target[0] = 0;
       
   183     if (firstlen > 0) {
       
   184 	strncpy(target, first_string, firstlen);
       
   185 	target[firstlen + 1] = 0;
       
   186     }
       
   187     target[firstlen] = '/';
       
   188     firstlen++;
       
   189     target[firstlen] = 0;
       
   190     strcat(target, second_string);
       
   191     return target;
       
   192 }
       
   193 
       
   194 #ifdef BUILD_FOR_TEST
       
   195 #define CANBUF 25
       
   196 struct canap_s {
       
   197     char *res_exp;
       
   198     char *first;
       
   199     char *second;
       
   200 } canap[] = {
       
   201     {
       
   202     "ab/c", "ab", "c"}, {
       
   203     "ab/c", "ab/", "c"}, {
       
   204     "ab/c", "ab", "/c"}, {
       
   205     "ab/c", "ab////", "/////c"}, {
       
   206     "ab/", "ab", ""}, {
       
   207     "ab/", "ab////", ""}, {
       
   208     "ab/", "ab////", ""}, {
       
   209     "/a", "", "a"}, {
       
   210     0, "/abcdefgbijkl", "pqrstuvwxyzabcd"}, {
       
   211     0, 0, 0}
       
   212 };
       
   213 static void
       
   214 test_canonical_append(void)
       
   215 {
       
   216     /* Make buf big, this is test code, so be safe. */
       
   217     char lbuf[1000];
       
   218     unsigned i;
       
   219     unsigned failcount = 0;
       
   220 
       
   221     printf("Entry test_canonical_append\n");
       
   222     for (i = 0;; ++i) {
       
   223 	char *res = 0;
       
   224 
       
   225 	if (canap[i].first == 0 && canap[i].second == 0)
       
   226 	    break;
       
   227 
       
   228 	res = canonical_append(lbuf, CANBUF, canap[i].first,
       
   229 			       canap[i].second);
       
   230 	if (res == 0) {
       
   231 	    if (canap[i].res_exp == 0) {
       
   232 		/* GOOD */
       
   233 		printf("PASS %u\n", i);
       
   234 	    } else {
       
   235 		++failcount;
       
   236 		printf("FAIL: entry %u wrong, expected %s, got NULL\n",
       
   237 		       i, canap[i].res_exp);
       
   238 	    }
       
   239 	} else {
       
   240 	    if (canap[i].res_exp == 0) {
       
   241 		++failcount;
       
   242 		printf("FAIL: entry %u wrong, got %s expected NULL\n",
       
   243 		       i, res);
       
   244 	    } else {
       
   245 		if (strcmp(res, canap[i].res_exp) == 0) {
       
   246 		    printf("PASS %u\n", i);
       
   247 		    /* GOOD */
       
   248 		} else {
       
   249 		    ++failcount;
       
   250 		    printf("FAIL: entry %u wrong, expected %s got %s\n",
       
   251 			   i, canap[i].res_exp, res);
       
   252 		}
       
   253 	    }
       
   254 	}
       
   255     }
       
   256     printf("FAIL count %u\n", failcount);
       
   257 
       
   258 }
       
   259 #endif /* BUILD_FOR_TEST */
       
   260 /* Try to find a file as named and open for read.
       
   261    We treat each name as a full name, we are not
       
   262    combining separate name and path components.
       
   263    This is  an arbitrary choice...
       
   264 
       
   265     The defaults are listed in dwarfdump.c in the array 
       
   266     config_file_defaults[].
       
   267 */
       
   268 static FILE *
       
   269 find_a_file(char *named_file, char **defaults, string * name_used)
       
   270 {
       
   271     FILE *fin = 0;
       
   272     char *lname = named_file;
       
   273     const char *type = "rw";
       
   274     int i = 0;
       
   275 
       
   276 #ifdef BUILD_FOR_TEST
       
   277     test_canonical_append();
       
   278 #endif /* BUILD_FOR_TEST */
       
   279 
       
   280     if (lname) {
       
   281 	/* Name given, just assume it is fully correct, try no other. */
       
   282 	if (verbose > 1) {
       
   283 	    printf("dwarfdump looking for configuration as %s\n",
       
   284 		   lname);
       
   285 	}
       
   286 	fin = fopen(lname, type);
       
   287 	if (fin) {
       
   288 	    *name_used = lname;
       
   289 	    return fin;
       
   290 	}
       
   291 	return 0;
       
   292     }
       
   293     /* No name given, find a default, if we can. */
       
   294     for (i = 0; defaults[i]; ++i) {
       
   295 	lname = defaults[i];
       
   296 	if (strncmp(lname, "HOME/", 5) == 0) {
       
   297 	    /* arbitrary size */
       
   298 	    char buf[2000];
       
   299 	    char *homedir = getenv("HOME");
       
   300 
       
   301 	    if (homedir) {
       
   302 		char *cp = canonical_append(buf, sizeof(buf),
       
   303 					    homedir, lname + 5);
       
   304 
       
   305 		if (!cp) {
       
   306 		    /* OOps, ignore this one. */
       
   307 		    continue;
       
   308 		}
       
   309 		lname = makename(buf);
       
   310 	    }
       
   311 	}
       
   312 	if (verbose > 1) {
       
   313 	    printf("dwarfdump looking for configuration as %s\n",
       
   314 		   lname);
       
   315 	}
       
   316 	fin = fopen(lname, type);
       
   317 	if (fin) {
       
   318 	    *name_used = lname;
       
   319 	    return fin;
       
   320 	}
       
   321     }
       
   322     return 0;
       
   323 }
       
   324 
       
   325 /* Start at a token begin, see how long it is,
       
   326    return length. */
       
   327 unsigned
       
   328 find_token_len(char *cp)
       
   329 {
       
   330     unsigned len = 0;
       
   331 
       
   332     for (; *cp; ++cp) {
       
   333 	if (isspace(*cp)) {
       
   334 	    return len;
       
   335 	}
       
   336 	if (*cp == '#') {
       
   337 	    return len;		/* begins comment */
       
   338 	}
       
   339 	++len;
       
   340     }
       
   341     return len;
       
   342 }
       
   343 
       
   344 /*
       
   345    Skip past all whitespace: the only code that even knows
       
   346    what whitespace is.
       
   347 */
       
   348 static char *
       
   349 skipwhite(char *cp)
       
   350 {
       
   351     for (; *cp; ++cp) {
       
   352 	if (!isspace(*cp)) {
       
   353 	    return cp;
       
   354 	}
       
   355     }
       
   356     return cp;
       
   357 }
       
   358 
       
   359 /* Return TRUE if ok. FALSE if find more tokens.
       
   360    Emit error message if error.
       
   361 */
       
   362 static int
       
   363 ensure_has_no_more_tokens(char *cp, char *fname, unsigned long lineno)
       
   364 {
       
   365     struct token_s tok;
       
   366 
       
   367     cp = get_token(cp, &tok);
       
   368     if (tok.tk_len > 0) {
       
   369 	printf("dwarfdump.conf error: "
       
   370 	       "extra characters after command operands, found "
       
   371 	       "\"%s\" in %s line %lu\n", tok.tk_data, fname, lineno);
       
   372 	++errcount;
       
   373 	return FALSE;
       
   374     }
       
   375     return TRUE;
       
   376 }
       
   377 
       
   378 
       
   379 /*
       
   380 	There may be many  beginabi: lines in a dwarfdump.conf file,
       
   381 	find the one we want and return it's file offset.
       
   382 */
       
   383 static int
       
   384 find_abi_start(FILE * stream,
       
   385 	       char *abi_name, long *offset, unsigned long *lineno_out)
       
   386 {
       
   387     char buf[100];
       
   388     unsigned long lineno = 0;
       
   389 
       
   390     for (; !feof(stream);) {
       
   391 
       
   392 	struct token_s tok;
       
   393 	char *line = 0;
       
   394 	long loffset = ftell(stream);
       
   395 
       
   396 	line = fgets(buf, sizeof(buf), stream);
       
   397 	++lineno;
       
   398 	if (!line) {
       
   399 	    ++errcount;
       
   400 	    return FALSE;
       
   401 	}
       
   402 
       
   403 	line = get_token(buf, &tok);
       
   404 
       
   405 	if (strcmp(tok.tk_data, name_begin_abi) != 0) {
       
   406 	    continue;
       
   407 	}
       
   408 	get_token(line, &tok);
       
   409 	if (strcmp(tok.tk_data, abi_name) != 0) {
       
   410 	    continue;
       
   411 	}
       
   412 
       
   413 	*offset = loffset;
       
   414 	*lineno_out = lineno;
       
   415 	return TRUE;
       
   416     }
       
   417 
       
   418     ++errcount;
       
   419     return FALSE;
       
   420 }
       
   421 
       
   422 static char *tempstr = 0;
       
   423 static unsigned tempstr_len = 0;
       
   424 
       
   425 /*
       
   426 	Use a global buffer (tempstr) to turn a non-delimited
       
   427 	input char array into a NUL-terminated C string
       
   428         (with the help of makename() to get a permanent
       
   429         address for the result ing string).
       
   430 */
       
   431 static char *
       
   432 build_string(unsigned tlen, char *cp)
       
   433 {
       
   434     if (tlen >= tempstr_len) {
       
   435 	free(tempstr);
       
   436 	tempstr = malloc(tlen + 100);
       
   437     }
       
   438     strncpy(tempstr, cp, tlen);
       
   439     tempstr[tlen] = 0;
       
   440     return makename(tempstr);
       
   441 }
       
   442 
       
   443 /*
       
   444 	The tokenizer for our simple parser.
       
   445 */
       
   446 static char *
       
   447 get_token(char *cp, struct token_s *outtok)
       
   448 {
       
   449     char *lcp = skipwhite(cp);
       
   450     unsigned tlen = find_token_len(lcp);
       
   451 
       
   452     outtok->tk_len = tlen;
       
   453     if (tlen > 0) {
       
   454 	outtok->tk_data = build_string(tlen, lcp);
       
   455     } else {
       
   456 	outtok->tk_data = "";
       
   457     }
       
   458     return lcp + tlen;
       
   459 
       
   460 }
       
   461 
       
   462 /*
       
   463 	We can't get all the field set up statically very easily,
       
   464         so we get the command string length set here.
       
   465 */
       
   466 static void
       
   467 finish_comtable_setup(void)
       
   468 {
       
   469     unsigned i;
       
   470 
       
   471     for (i = 0; i < size_of_comtable; ++i) {
       
   472 	comtable[i].namelen = strlen(comtable[i].name);
       
   473     }
       
   474 }
       
   475 
       
   476 /*
       
   477     Given  a line of the table, determine if it is a command
       
   478     or not, and if a command, which one is it.
       
   479     Return LT_ERROR if it's not recognized.
       
   480 */
       
   481 static enum linetype_e
       
   482 which_command(char *cp, struct comtable_s **tableentry)
       
   483 {
       
   484     int i;
       
   485     struct token_s tok;
       
   486 
       
   487     if (*cp == '#')
       
   488 	return LT_COMMENT;
       
   489     if (!*cp)
       
   490 	return LT_BLANK;
       
   491 
       
   492     get_token(cp, &tok);
       
   493 
       
   494     for (i = 0; i < size_of_comtable; ++i) {
       
   495 	if (tok.tk_len == comtable[i].namelen &&
       
   496 	    strcmp(comtable[i].name, tok.tk_data) == 0) {
       
   497 
       
   498 	    *tableentry = &comtable[i];
       
   499 	    return comtable[i].type;
       
   500 	}
       
   501     }
       
   502 
       
   503     return LT_ERROR;
       
   504 }
       
   505 
       
   506 /* We are promised it's an abiname: command
       
   507    find the name on the line.
       
   508 */
       
   509 static int
       
   510 parsebeginabi(char *cp, char *fname, char *abiname,
       
   511 	      unsigned long lineno, struct comtable_s *comtab)
       
   512 {
       
   513     size_t clen = comtab->namelen;
       
   514     size_t abinamelen = strlen(abiname);
       
   515     struct token_s tok;
       
   516 
       
   517 
       
   518     cp = cp + clen + 1;
       
   519     cp = skipwhite(cp);
       
   520     get_token(cp, &tok);
       
   521     if (tok.tk_len != abinamelen ||
       
   522 	strncmp(cp, abiname, abinamelen) != 0) {
       
   523 	printf("dwarfdump internal error: "
       
   524 	       "mismatch %s with %s   %s line %lu\n",
       
   525 	       cp, tok.tk_data, fname, lineno);
       
   526 	++errcount;
       
   527 	return FALSE;
       
   528     }
       
   529     {
       
   530 	int res =
       
   531 	    ensure_has_no_more_tokens(cp + tok.tk_len, fname, lineno);
       
   532 	return res;
       
   533     }
       
   534 }
       
   535 
       
   536 /* This expands register names as required, but does not
       
   537    ensure no names duplicated.
       
   538 */
       
   539 #define CONF_TABLE_OVERSIZE  100
       
   540 static void
       
   541 add_to_reg_table(struct dwconf_s *conf,
       
   542 		 char *rname, unsigned long rval, char *fname,
       
   543 		 unsigned long lineno)
       
   544 {
       
   545     if (conf->cf_regs_malloced == 0) {
       
   546 	conf->cf_regs = 0;
       
   547 	conf->cf_named_regs_table_size = 0;
       
   548     }
       
   549     if (rval >= conf->cf_named_regs_table_size) {
       
   550 	char **newregs = 0;
       
   551 	unsigned long newtablen = rval + CONF_TABLE_OVERSIZE;
       
   552 	unsigned long newtabsize = newtablen * sizeof(char *);
       
   553 	unsigned long oldtabsize =
       
   554 	    conf->cf_named_regs_table_size * sizeof(char *);
       
   555 	newregs = realloc(conf->cf_regs, newtabsize);
       
   556 	if (!newregs) {
       
   557 	    printf("dwarfdump: unable to malloc table %lu bytes. "
       
   558 		   " %s line %lu\n", newtabsize, fname, lineno);
       
   559 	    exit(1);
       
   560 	}
       
   561 	/* Zero out the new entries. */
       
   562 	memset((char *) newregs + (oldtabsize), 0,
       
   563 	       (newtabsize - oldtabsize));
       
   564 	conf->cf_named_regs_table_size = (unsigned long) newtablen;
       
   565 	conf->cf_regs = newregs;
       
   566 	conf->cf_regs_malloced = 1;
       
   567     }
       
   568     conf->cf_regs[rval] = rname;
       
   569     return;
       
   570 }
       
   571 
       
   572 /* Our input is supposed to be a number.
       
   573    Determine the value (and return it) or generate an error message.
       
   574 */
       
   575 static int
       
   576 make_a_number(char *cmd, char *filename, unsigned long
       
   577 	      lineno, struct token_s *tok, unsigned long *val_out)
       
   578 {
       
   579     char *endnum = 0;
       
   580     unsigned long val = 0;
       
   581 
       
   582     val = strtoul(tok->tk_data, &endnum, 0);
       
   583     if (val == 0 && endnum == (tok->tk_data)) {
       
   584 	printf("dwarfdump.conf error: "
       
   585 	       "%s missing register number (\"%s\" not valid)  %s line %lu",
       
   586 	       cmd, tok->tk_data, filename, lineno);
       
   587 	++errcount;
       
   588 	return FALSE;
       
   589     }
       
   590     if (endnum != (tok->tk_data + tok->tk_len)) {
       
   591 	printf("dwarfdump.conf error: "
       
   592 	       "%s Missing register number (\"%s\" not valid)  %s line %lu",
       
   593 	       cmd, tok->tk_data, filename, lineno);
       
   594 	++errcount;
       
   595 	return FALSE;
       
   596     }
       
   597     *val_out = val;
       
   598     return TRUE;
       
   599 
       
   600 
       
   601 
       
   602 }
       
   603 
       
   604 /* We are guaranteed it's a reg: command, so parse that command
       
   605     and record the interesting data.
       
   606 */
       
   607 static int
       
   608 parsereg(char *cp, char *fname, unsigned long lineno,
       
   609 	 struct dwconf_s *conf, struct comtable_s *comtab)
       
   610 {
       
   611     size_t clen = comtab->namelen;
       
   612     struct token_s regnum;
       
   613     struct token_s tokreg;
       
   614     unsigned long val = 0;
       
   615     int ok = FALSE;
       
   616 
       
   617     cp = cp + clen + 1;
       
   618     cp = get_token(cp, &tokreg);
       
   619     cp = get_token(cp, &regnum);
       
   620     if (tokreg.tk_len == 0) {
       
   621 	printf("dwarfdump.conf error: "
       
   622 	       "reg: missing register name  %s line %lu",
       
   623 	       fname, lineno);
       
   624 	++errcount;
       
   625 	return FALSE;
       
   626 
       
   627     }
       
   628     if (regnum.tk_len == 0) {
       
   629 	printf("dwarfdump.conf error: "
       
   630 	       "reg: missing register number  %s line %lu",
       
   631 	       fname, lineno);
       
   632 	++errcount;
       
   633 	return FALSE;
       
   634     }
       
   635 
       
   636     ok = make_a_number(comtab->name, fname, lineno, &regnum, &val);
       
   637 
       
   638     if (!ok) {
       
   639 	++errcount;
       
   640 	return FALSE;
       
   641     }
       
   642 
       
   643     add_to_reg_table(conf, tokreg.tk_data, val, fname, lineno);
       
   644 
       
   645     {
       
   646 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   647 
       
   648 	return res;
       
   649     }
       
   650 }
       
   651 
       
   652 /*
       
   653    We are guaranteed it's an frame_interface: command.
       
   654    Parse it and record the value data.
       
   655 */
       
   656 static int
       
   657 parseframe_interface(char *cp, char *fname, unsigned long lineno,
       
   658 		     struct dwconf_s *conf, struct comtable_s *comtab)
       
   659 {
       
   660     size_t clen = comtab->namelen;
       
   661     struct token_s tok;
       
   662     unsigned long val = 0;
       
   663     int ok = FALSE;
       
   664 
       
   665     cp = cp + clen + 1;
       
   666     cp = get_token(cp, &tok);
       
   667     if (tok.tk_len == 0) {
       
   668 	printf("dwarfdump.conf error: "
       
   669 	       "%s missing interface number %s line %lu",
       
   670 	       comtab->name, fname, lineno);
       
   671 	++errcount;
       
   672 	return FALSE;
       
   673     }
       
   674 
       
   675     ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
       
   676 
       
   677     if (!ok) {
       
   678 	++errcount;
       
   679 	return FALSE;
       
   680     }
       
   681     if (val != 2 && val != 3) {
       
   682 	printf("dwarfdump.conf error: "
       
   683 	       "%s only interface numbers 2 or 3 are allowed, "
       
   684 	       " not %lu. %s line %lu",
       
   685 	       comtab->name, val, fname, lineno);
       
   686 	++errcount;
       
   687 	return FALSE;
       
   688     }
       
   689 
       
   690     conf->cf_interface_number = (int) val;
       
   691     {
       
   692 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   693 
       
   694 	return res;
       
   695     }
       
   696 }
       
   697 
       
   698 /*
       
   699    We are guaranteed it's a cfa_reg: command. Parse it
       
   700    and record the important data.
       
   701 */
       
   702 static int
       
   703 parsecfa_reg(char *cp, char *fname, unsigned long lineno,
       
   704 	     struct dwconf_s *conf, struct comtable_s *comtab)
       
   705 {
       
   706     size_t clen = comtab->namelen;
       
   707     struct token_s tok;
       
   708     unsigned long val = 0;
       
   709     int ok = FALSE;
       
   710 
       
   711     cp = cp + clen + 1;
       
   712     cp = get_token(cp, &tok);
       
   713     if (tok.tk_len == 0) {
       
   714 	printf("dwarfdump.conf error: "
       
   715 	       "%s missing cfa_reg number %s line %lu",
       
   716 	       comtab->name, fname, lineno);
       
   717 	++errcount;
       
   718 	return FALSE;
       
   719     }
       
   720 
       
   721     ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
       
   722 
       
   723     if (!ok) {
       
   724 	++errcount;
       
   725 	return FALSE;
       
   726     }
       
   727     conf->cf_cfa_reg = (int) val;
       
   728     {
       
   729 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   730 
       
   731 	return res;
       
   732     }
       
   733 }
       
   734 
       
   735 
       
   736 /* We are guaranteed it's an initial_reg_value: command,
       
   737    parse it and put the reg value where it will be remembered. 
       
   738 */
       
   739 static int
       
   740 parseinitial_reg_value(char *cp, char *fname,
       
   741 		       unsigned long lineno,
       
   742 		       struct dwconf_s *conf, struct comtable_s *comtab)
       
   743 {
       
   744     size_t clen = comtab->namelen;
       
   745     struct token_s tok;
       
   746     unsigned long val = 0;
       
   747     int ok = FALSE;
       
   748 
       
   749     cp = cp + clen + 1;
       
   750     cp = get_token(cp, &tok);
       
   751     if (tok.tk_len == 0) {
       
   752 	printf("dwarfdump.conf error: "
       
   753 	       "%s missing initial reg value %s line %lu",
       
   754 	       comtab->name, fname, lineno);
       
   755 	++errcount;
       
   756 	return FALSE;
       
   757     }
       
   758 
       
   759     ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
       
   760 
       
   761     if (!ok) {
       
   762 
       
   763 	++errcount;
       
   764 	return FALSE;
       
   765     }
       
   766     conf->cf_initial_rule_value = (int) val;
       
   767     {
       
   768 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   769 
       
   770 	return res;
       
   771     }
       
   772 }
       
   773 
       
   774 
       
   775 /* We are guaranteed it's a table size command, parse it
       
   776     and record the table size.
       
   777 */
       
   778 static int
       
   779 parsereg_table_size(char *cp, char *fname, unsigned long lineno,
       
   780 		    struct dwconf_s *conf, struct comtable_s *comtab)
       
   781 {
       
   782     size_t clen = comtab->namelen;
       
   783     struct token_s tok;
       
   784     unsigned long val = 0;
       
   785     int ok = FALSE;
       
   786 
       
   787     cp = cp + clen + 1;
       
   788     cp = get_token(cp, &tok);
       
   789     if (tok.tk_len == 0) {
       
   790 	printf("dwarfdump.conf error: "
       
   791 	       "%s missing reg table size value %s line %lu",
       
   792 	       comtab->name, fname, lineno);
       
   793 	++errcount;
       
   794 	return FALSE;
       
   795     }
       
   796 
       
   797     ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
       
   798 
       
   799     if (!ok) {
       
   800 	++errcount;
       
   801 	return FALSE;
       
   802     }
       
   803     conf->cf_table_entry_count = (unsigned long) val;
       
   804     {
       
   805 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   806 
       
   807 	return res;
       
   808     }
       
   809 
       
   810 }
       
   811 
       
   812 
       
   813 /*  We are guaranteed it's an endabi: command, parse it and
       
   814     check we have the right abi.
       
   815 */
       
   816 static int
       
   817 parseendabi(char *cp, char *fname, char *abiname, unsigned long lineno,
       
   818 	    struct comtable_s *comtab)
       
   819 {
       
   820     size_t clen = comtab->namelen;
       
   821     struct token_s tok;
       
   822 
       
   823 
       
   824     cp = cp + clen + 1;
       
   825     cp = get_token(cp, &tok);
       
   826     if (strcmp(abiname, tok.tk_data) != 0) {
       
   827 	printf("%s error: "
       
   828 	       "mismatch abi name %s (here) vs. %s (beginabi:)  %s line %lu\n",
       
   829 	       comtab->name, tok.tk_data, abiname, fname, lineno);
       
   830 	++errcount;
       
   831 	return FALSE;
       
   832     }
       
   833     {
       
   834 	int res = ensure_has_no_more_tokens(cp, fname, lineno);
       
   835 
       
   836 	return res;
       
   837     }
       
   838 
       
   839 }
       
   840 
       
   841 
       
   842 
       
   843 /* Return TRUE if we succeeded and filed in *out.
       
   844    Return FALSE if we failed (and fill in nothing).
       
   845   beginabi:  <abiname>
       
   846   reg: <regname> <dwarf regnumber>
       
   847   frame_interface: <integer value 2 or 3>
       
   848   cfa_reg:  <number>
       
   849   initial_reg_value:  <number: normally 1034 or 1035 >
       
   850   reg_table_size: <size of table>
       
   851   endabi:  <abiname>
       
   852  
       
   853   We are positioned at the start of a beginabi: line when
       
   854   called.
       
   855 
       
   856 */
       
   857 static int
       
   858 parse_abi(FILE * stream, char *fname, char *abiname,
       
   859 	  struct dwconf_s *out, unsigned long lineno)
       
   860 {
       
   861     struct dwconf_s localconf;
       
   862     char buf[1000];
       
   863     int comtype = 0;
       
   864     long regcount = 0;
       
   865 
       
   866     unsigned long beginabi_lineno = 0;
       
   867     unsigned long frame_interface_lineno = 0;
       
   868     unsigned long initial_reg_value_lineno = 0;
       
   869     unsigned long reg_table_size_lineno = 0;
       
   870     unsigned long cfa_reg_lineno = 0;
       
   871     static int first_time_done = 0;
       
   872     struct comtable_s *comtabp = 0;
       
   873 
       
   874 
       
   875     if (first_time_done == 0) {
       
   876 	finish_comtable_setup();
       
   877 	first_time_done = 1;
       
   878     }
       
   879 
       
   880 
       
   881 
       
   882 
       
   883     init_conf_file_data(&localconf);
       
   884 
       
   885     for (; !feof(stream);) {
       
   886 
       
   887 	char *line = 0;
       
   888 
       
   889 	/* long loffset = ftell(stream); */
       
   890 	line = fgets(buf, sizeof(buf), stream);
       
   891 	if (!line) {
       
   892 	    ++errcount;
       
   893 	    printf
       
   894 		("dwarfdump: end of file or error before endabi: in %s, line %lu\n",
       
   895 		 fname, lineno);
       
   896 	    return FALSE;
       
   897 	}
       
   898 	++lineno;
       
   899 	line = skipwhite(line);
       
   900 	comtype = which_command(line, &comtabp);
       
   901 	switch (comtype) {
       
   902 	case LT_ERROR:
       
   903 	    ++errcount;
       
   904 	    printf
       
   905 		("dwarfdump: Unknown text in %s is \"%s\" at line %lu\n",
       
   906 		 fname, line, lineno);
       
   907 	    break;
       
   908 	case LT_COMMENT:
       
   909 	    break;
       
   910 	case LT_BLANK:
       
   911 	    break;
       
   912 	case LT_BEGINABI:
       
   913 	    if (beginabi_lineno > 0) {
       
   914 		++errcount;
       
   915 		printf
       
   916 		    ("dwarfdump: Encountered beginabi: when not expected. "
       
   917 		     "%s line %lu previous beginabi line %lu\n", fname,
       
   918 		     lineno, beginabi_lineno);
       
   919 	    }
       
   920 	    beginabi_lineno = lineno;
       
   921 	    parsebeginabi(line, fname, abiname, lineno, comtabp);
       
   922 	    break;
       
   923 
       
   924 	case LT_REG:
       
   925 	    parsereg(line, fname, lineno, &localconf, comtabp);
       
   926 	    ++regcount;
       
   927 	    break;
       
   928 	case LT_FRAME_INTERFACE:
       
   929 	    if (frame_interface_lineno > 0) {
       
   930 		++errcount;
       
   931 		printf
       
   932 		    ("dwarfdump: Encountered duplicate frame_interface: "
       
   933 		     "%s line %lu previous frame_interface: line %lu\n",
       
   934 		     fname, lineno, frame_interface_lineno);
       
   935 	    }
       
   936 	    frame_interface_lineno = lineno;
       
   937 	    parseframe_interface(line, fname,
       
   938 				 lineno, &localconf, comtabp);
       
   939 	    break;
       
   940 	case LT_CFA_REG:
       
   941 	    if (cfa_reg_lineno > 0) {
       
   942 		printf("dwarfdump: Encountered duplicate cfa_reg: "
       
   943 		       "%s line %lu previous cfa_reg line %lu\n",
       
   944 		       fname, lineno, cfa_reg_lineno);
       
   945 		++errcount;
       
   946 	    }
       
   947 	    cfa_reg_lineno = lineno;
       
   948 	    parsecfa_reg(line, fname, lineno, &localconf, comtabp);
       
   949 	    break;
       
   950 	case LT_INITIAL_REG_VALUE:
       
   951 	    if (initial_reg_value_lineno > 0) {
       
   952 		printf
       
   953 		    ("dwarfdump: Encountered duplicate initial_reg_value_lineno: "
       
   954 		     "%s line %lu previous initial_reg_value: line %lu\n",
       
   955 		     fname, lineno, initial_reg_value_lineno);
       
   956 		++errcount;
       
   957 	    }
       
   958 	    initial_reg_value_lineno = lineno;
       
   959 
       
   960 	    parseinitial_reg_value(line, fname,
       
   961 				   lineno, &localconf, comtabp);
       
   962 	    break;
       
   963 	case LT_REG_TABLE_SIZE:
       
   964 	    if (reg_table_size_lineno > 0) {
       
   965 		printf("dwarfdump: duplicate reg_table_size: "
       
   966 		       "%s line %lu previous reg_table_size: line %lu\n",
       
   967 		       fname, lineno, reg_table_size_lineno);
       
   968 		++errcount;
       
   969 	    }
       
   970 	    reg_table_size_lineno = lineno;
       
   971 	    parsereg_table_size(line, fname,
       
   972 				lineno, &localconf, comtabp);
       
   973 	    break;
       
   974 	case LT_ENDABI:
       
   975 	    parseendabi(line, fname, abiname, lineno, comtabp);
       
   976 
       
   977 	    if (regcount > localconf.cf_table_entry_count) {
       
   978 		printf("dwarfdump: more registers named than "
       
   979 		       " in  %s  ( %lu named vs  %s %lu)  %s line %lu\n",
       
   980 		       abiname, (unsigned long) regcount,
       
   981 		       name_reg_table_size,
       
   982 		       (unsigned long) localconf.cf_table_entry_count,
       
   983 		       fname, (unsigned long) lineno);
       
   984 		++errcount;
       
   985 	    }
       
   986 
       
   987 	    *out = localconf;
       
   988 	    return TRUE;
       
   989 	default:
       
   990 	    printf
       
   991 		("dwarfdump internal error, impossible line type %d  %s %lu \n",
       
   992 		 (int) comtype, fname, lineno);
       
   993 	    exit(1);
       
   994 
       
   995 	}
       
   996     }
       
   997     ++errcount;
       
   998     printf("End of file, no endabi: found. %s, line %lu\n",
       
   999 	   fname, lineno);
       
  1000     return FALSE;
       
  1001 }
       
  1002 
       
  1003 /* MIPS/IRIX frame register names.
       
  1004    For alternate name sets, use dwarfdump.conf or
       
  1005    revise dwarf.h and libdwarf.h and this table.
       
  1006 */
       
  1007 static char *regnames[] = {
       
  1008     "cfa",
       
  1009     "r1/at", "r2/v0", "r3/v1",
       
  1010     "r4/a0", "r5/a1", "r6/a2", "r7/a3",
       
  1011     "r8/t0", "r9/t1", "r10/t2", "r11/t3",
       
  1012     "r12/t4", "r13/t5", "r14/t6", "r15/t7",
       
  1013     "r16/s0", "r17/s1", "r18/s2", "r19/s3",
       
  1014     "r20/s4", "r21/s5", "r22/s6", "r23/s7",
       
  1015     "r24/t8", "r25/t9", "r26/k0", "r27/k1",
       
  1016     "r28/gp", "r29/sp", "r30/s8", "r31",
       
  1017 
       
  1018     "$f0", "$f1",
       
  1019     "$f2", "$f3",
       
  1020     "$f4", "$f5",
       
  1021     "$f6", "$f7",
       
  1022     "$f8", "$f9",
       
  1023     "$f10", "$f11",
       
  1024     "$f12", "$f13",
       
  1025     "$f14", "$f15",
       
  1026     "$f16", "$f17",
       
  1027     "$f18", "$f19",
       
  1028     "$f20", "$f21",
       
  1029     "$f22", "$f23",
       
  1030     "$f24", "$f25",
       
  1031     "$f26", "$f27",
       
  1032     "$f28", "$f29",
       
  1033     "$f30", "$f31",
       
  1034     "ra", "slk",
       
  1035 };
       
  1036 
       
  1037 
       
  1038 /* These defaults match MIPS/IRIX ABI defaults.
       
  1039    For a 'generic' ABI, see -R.
       
  1040    For other ABIs, see -x abi=<whatever>
       
  1041    to configure dwarfdump (and libdwarf) frame 
       
  1042    data reporting at runtime.
       
  1043 */
       
  1044 void
       
  1045 init_conf_file_data(struct dwconf_s *config_file_data)
       
  1046 {
       
  1047     unsigned long base_table_count =
       
  1048 	sizeof(regnames) / sizeof(regnames[0]);
       
  1049 
       
  1050     memset(config_file_data, 0, sizeof(*config_file_data));
       
  1051     config_file_data->cf_interface_number = 2;
       
  1052     config_file_data->cf_table_entry_count = DW_REG_TABLE_SIZE;
       
  1053     config_file_data->cf_initial_rule_value =
       
  1054 	DW_FRAME_REG_INITIAL_VALUE;
       
  1055     config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL;
       
  1056     config_file_data->cf_regs = regnames;
       
  1057     config_file_data->cf_named_regs_table_size = base_table_count;
       
  1058     config_file_data->cf_regs_malloced = 0;
       
  1059     if (config_file_data->cf_table_entry_count != base_table_count) {
       
  1060 	printf("dwarfdump: improper base table initization, "
       
  1061 	       "header files wrong: "
       
  1062 	       "DW_REG_TABLE_SIZE %u != string table size %lu\n",
       
  1063 	       (unsigned) DW_REG_TABLE_SIZE,
       
  1064 	       (unsigned long) base_table_count);
       
  1065 	exit(1);
       
  1066     }
       
  1067 
       
  1068     return;
       
  1069 }
       
  1070 
       
  1071 /* Naming a few registers makes printing these just
       
  1072    a little bit faster.
       
  1073 */
       
  1074 static char *genericregnames[] = {
       
  1075   "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
       
  1076   "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
       
  1077   "r20",
       
  1078 };
       
  1079 
       
  1080 /* A 'generic' ABI. For up to 1000 registers. 
       
  1081    Perhaps cf_initial_rule_value should be d
       
  1082    UNDEFINED VALUE (1034) instead, but for the purposes of
       
  1083    getting the dwarfdump output correct
       
  1084    either will work.
       
  1085 */
       
  1086 void
       
  1087 init_generic_config_1000_regs(struct dwconf_s *config_file_data)
       
  1088 {
       
  1089     unsigned long generic_table_count =
       
  1090 	sizeof(genericregnames) / sizeof(genericregnames[0]);
       
  1091     config_file_data->cf_interface_number = 3;
       
  1092     config_file_data->cf_table_entry_count = 1000;
       
  1093     config_file_data->cf_initial_rule_value = 1035; /* SAME VALUE */
       
  1094     config_file_data->cf_cfa_reg = 1036;
       
  1095     config_file_data->cf_regs = genericregnames;
       
  1096     config_file_data->cf_named_regs_table_size = generic_table_count;
       
  1097     config_file_data->cf_regs_malloced = 0;
       
  1098 }
       
  1099 
       
  1100 /*  Print the 'right' string for the register we are given.
       
  1101     Deal sensibly with the special regs as well as numbers
       
  1102     we know and those we have not been told about.
       
  1103 
       
  1104 */
       
  1105 void
       
  1106 print_reg_from_config_data(Dwarf_Signed reg,
       
  1107 			   struct dwconf_s *config_data)
       
  1108 {
       
  1109     char *name = 0;
       
  1110 
       
  1111     if (reg == config_data->cf_cfa_reg) {
       
  1112 	fputs("cfa",stdout);
       
  1113 	return;
       
  1114     }
       
  1115     if (reg == DW_FRAME_CFA_COL3) {
       
  1116 	/* This should not be necessary, but sometimes one forgets to
       
  1117 	   do the cfa_reg: command in dwarfdump.conf */
       
  1118 	fputs("cfa",stdout);
       
  1119 	return;
       
  1120     }
       
  1121     if (reg == DW_FRAME_UNDEFINED_VAL) {
       
  1122 	fputs("u",stdout);
       
  1123 	return;
       
  1124     }
       
  1125     if (reg == DW_FRAME_SAME_VAL) {
       
  1126 	fputs("s",stdout);
       
  1127 	return;
       
  1128     }
       
  1129     if (config_data->cf_regs == 0 ||
       
  1130 	reg < 0 || reg > config_data->cf_named_regs_table_size) {
       
  1131 	printf("r%lld", (signed long long) reg);
       
  1132 	return;
       
  1133     }
       
  1134     name = config_data->cf_regs[reg];
       
  1135     if (!name) {
       
  1136         /* Can happen, the reg names table can be sparse. */
       
  1137 	printf("r%lld", (signed long long) reg);
       
  1138 	return;
       
  1139     }
       
  1140     fputs(name,stdout);
       
  1141     return;
       
  1142 }