tools/elf4rom/libs/dwarf-20071209/dwarfdump/dwconf.c
changeset 34 92d87f2e53c2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/elf4rom/libs/dwarf-20071209/dwarfdump/dwconf.c	Fri Jan 15 09:07:44 2010 +0000
@@ -0,0 +1,1142 @@
+/*
+  Copyright (C) 2006 Silicon Graphics, Inc.  All Rights Reserved.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of version 2 of the GNU 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 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
+
+
+$Header: /plroot/cmplrs.src/v7.4.5m/.RCS/PL/dwarfdump/RCS/dwconf.c,v 1.4 2006/04/18 18:05:57 davea Exp $ */
+
+
+#include "globals.h"
+#include <ctype.h>
+#include "dwconf.h"
+#include "makename.h"
+
+
+struct token_s {
+    unsigned tk_len;
+    char *tk_data;
+};
+enum linetype_e {
+    LT_ERROR,
+    LT_COMMENT,
+    LT_BLANK,
+    LT_BEGINABI,
+    LT_REG,
+    LT_FRAME_INTERFACE,
+    LT_CFA_REG,
+    LT_INITIAL_REG_VALUE,
+    LT_REG_TABLE_SIZE,
+    LT_ENDABI
+};
+
+struct comtable_s {
+    enum linetype_e type;
+    char *name;
+    size_t namelen;
+};
+
+static int errcount = 0;	/* Count errors found in this scan of
+				   the configuration file. */
+
+static char name_begin_abi[] = "beginabi:";
+static char name_reg[] = "reg:";
+static char name_frame_interface[] = "frame_interface:";
+static char name_cfa_reg[] = "cfa_reg:";
+static char name_initial_reg_value[] = "initial_reg_value:";
+static char name_reg_table_size[] = "reg_table_size:";
+static char name_endabi[] = "endabi:";
+
+static struct comtable_s comtable[] = {
+    {LT_BEGINABI, name_begin_abi},
+    {LT_REG, name_reg},
+    {LT_FRAME_INTERFACE, name_frame_interface},
+    {LT_CFA_REG, name_cfa_reg},
+    {LT_INITIAL_REG_VALUE, name_initial_reg_value},
+    {LT_REG_TABLE_SIZE, name_reg_table_size},
+    {LT_ENDABI, name_endabi},
+};
+static int size_of_comtable = sizeof(comtable) / sizeof(comtable[0]);
+
+
+static FILE *find_a_file(char *named_file, char **defaults,
+			 string * name_used);
+static int find_abi_start(FILE * stream, char *abi_name, long *offset,
+			  unsigned long *lineno_out);
+static int parse_abi(FILE * stream, char *fname, char *abiname,
+		     struct dwconf_s *out, unsigned long lineno);
+static char *get_token(char *cp, struct token_s *outtok);
+
+
+
+
+
+/*  This finds a dwarfdump.conf file and
+    then parses it.  It updates
+    conf_out as appropriate.
+
+    This finds the first file (looking in a set of places)
+    with that name.  It then looks for the right  ABI entry.
+    If the first file it finds does not have that ABI entry it
+    gives up.
+  
+    It would also be reasonable to search every 'dwarfdump.conf'
+    it finds for the abi. But we stop at the first dwarfdump.conf
+    we find.
+*/
+int
+find_conf_file_and_read_config(char *named_file,
+			       char *named_abi, char **defaults,
+			       struct dwconf_s *conf_out)
+{
+
+    FILE *conf_stream = 0;
+    char *name_used = 0;
+    long offset = 0;
+    int res = FALSE;
+    unsigned long lineno = 0;
+
+    errcount = 0;
+
+    conf_stream = find_a_file(named_file, defaults, &name_used);
+    if (!conf_stream) {
+	++errcount;
+	printf("dwarfdump found no file %s!\n",
+	       named_file ? named_file : "readable for configuration. "
+	       "(add options -v -v to see what file names tried)\n");
+	return errcount;
+    }
+    if (verbose > 1) {
+	printf("dwarfdump using configuration file %s\n", name_used);
+    }
+
+    res = find_abi_start(conf_stream, named_abi, &offset, &lineno);
+    if (errcount > 0) {
+	++errcount;
+	printf("dwarfdump found no ABI %s in file %s.\n",
+	       named_abi, name_used);
+	return errcount;
+    }
+    res = fseek(conf_stream, offset, SEEK_SET);
+    if (res != 0) {
+	++errcount;
+	printf("dwarfdump seek to %ld offset in %s failed!\n",
+	       offset, name_used);
+	return errcount;
+    }
+    parse_abi(conf_stream, name_used, named_abi, conf_out, lineno);
+    fclose(conf_stream);
+    return errcount;
+}
+
+/* Given path strings, attempt to make a canonical file name:
+   that is, avoid superfluous '/' so that no
+    '//' (or worse) is created in the output. The path components
+    are to be separated so at least one '/'
+    is to appear between the two 'input strings' when
+    creating the output.
+*/
+static char *
+canonical_append(char *target, unsigned int target_size,
+		 char *first_string, char *second_string)
+{
+    size_t firstlen = strlen(first_string);
+
+    /* +1 +1: Leave room for added "/" and final NUL, though that is
+       overkill, as we drop a NUL byte too. */
+    if ((firstlen + strlen(second_string) + 1 + 1) >= target_size) {
+	/* Not enough space. */
+	return NULL;
+    }
+    for (; *second_string == '/'; ++second_string) {
+    }
+    for (; firstlen > 0 && first_string[firstlen - 1] == '/';
+	 --firstlen) {
+    }
+    target[0] = 0;
+    if (firstlen > 0) {
+	strncpy(target, first_string, firstlen);
+	target[firstlen + 1] = 0;
+    }
+    target[firstlen] = '/';
+    firstlen++;
+    target[firstlen] = 0;
+    strcat(target, second_string);
+    return target;
+}
+
+#ifdef BUILD_FOR_TEST
+#define CANBUF 25
+struct canap_s {
+    char *res_exp;
+    char *first;
+    char *second;
+} canap[] = {
+    {
+    "ab/c", "ab", "c"}, {
+    "ab/c", "ab/", "c"}, {
+    "ab/c", "ab", "/c"}, {
+    "ab/c", "ab////", "/////c"}, {
+    "ab/", "ab", ""}, {
+    "ab/", "ab////", ""}, {
+    "ab/", "ab////", ""}, {
+    "/a", "", "a"}, {
+    0, "/abcdefgbijkl", "pqrstuvwxyzabcd"}, {
+    0, 0, 0}
+};
+static void
+test_canonical_append(void)
+{
+    /* Make buf big, this is test code, so be safe. */
+    char lbuf[1000];
+    unsigned i;
+    unsigned failcount = 0;
+
+    printf("Entry test_canonical_append\n");
+    for (i = 0;; ++i) {
+	char *res = 0;
+
+	if (canap[i].first == 0 && canap[i].second == 0)
+	    break;
+
+	res = canonical_append(lbuf, CANBUF, canap[i].first,
+			       canap[i].second);
+	if (res == 0) {
+	    if (canap[i].res_exp == 0) {
+		/* GOOD */
+		printf("PASS %u\n", i);
+	    } else {
+		++failcount;
+		printf("FAIL: entry %u wrong, expected %s, got NULL\n",
+		       i, canap[i].res_exp);
+	    }
+	} else {
+	    if (canap[i].res_exp == 0) {
+		++failcount;
+		printf("FAIL: entry %u wrong, got %s expected NULL\n",
+		       i, res);
+	    } else {
+		if (strcmp(res, canap[i].res_exp) == 0) {
+		    printf("PASS %u\n", i);
+		    /* GOOD */
+		} else {
+		    ++failcount;
+		    printf("FAIL: entry %u wrong, expected %s got %s\n",
+			   i, canap[i].res_exp, res);
+		}
+	    }
+	}
+    }
+    printf("FAIL count %u\n", failcount);
+
+}
+#endif /* BUILD_FOR_TEST */
+/* Try to find a file as named and open for read.
+   We treat each name as a full name, we are not
+   combining separate name and path components.
+   This is  an arbitrary choice...
+
+    The defaults are listed in dwarfdump.c in the array 
+    config_file_defaults[].
+*/
+static FILE *
+find_a_file(char *named_file, char **defaults, string * name_used)
+{
+    FILE *fin = 0;
+    char *lname = named_file;
+    const char *type = "rw";
+    int i = 0;
+
+#ifdef BUILD_FOR_TEST
+    test_canonical_append();
+#endif /* BUILD_FOR_TEST */
+
+    if (lname) {
+	/* Name given, just assume it is fully correct, try no other. */
+	if (verbose > 1) {
+	    printf("dwarfdump looking for configuration as %s\n",
+		   lname);
+	}
+	fin = fopen(lname, type);
+	if (fin) {
+	    *name_used = lname;
+	    return fin;
+	}
+	return 0;
+    }
+    /* No name given, find a default, if we can. */
+    for (i = 0; defaults[i]; ++i) {
+	lname = defaults[i];
+	if (strncmp(lname, "HOME/", 5) == 0) {
+	    /* arbitrary size */
+	    char buf[2000];
+	    char *homedir = getenv("HOME");
+
+	    if (homedir) {
+		char *cp = canonical_append(buf, sizeof(buf),
+					    homedir, lname + 5);
+
+		if (!cp) {
+		    /* OOps, ignore this one. */
+		    continue;
+		}
+		lname = makename(buf);
+	    }
+	}
+	if (verbose > 1) {
+	    printf("dwarfdump looking for configuration as %s\n",
+		   lname);
+	}
+	fin = fopen(lname, type);
+	if (fin) {
+	    *name_used = lname;
+	    return fin;
+	}
+    }
+    return 0;
+}
+
+/* Start at a token begin, see how long it is,
+   return length. */
+unsigned
+find_token_len(char *cp)
+{
+    unsigned len = 0;
+
+    for (; *cp; ++cp) {
+	if (isspace(*cp)) {
+	    return len;
+	}
+	if (*cp == '#') {
+	    return len;		/* begins comment */
+	}
+	++len;
+    }
+    return len;
+}
+
+/*
+   Skip past all whitespace: the only code that even knows
+   what whitespace is.
+*/
+static char *
+skipwhite(char *cp)
+{
+    for (; *cp; ++cp) {
+	if (!isspace(*cp)) {
+	    return cp;
+	}
+    }
+    return cp;
+}
+
+/* Return TRUE if ok. FALSE if find more tokens.
+   Emit error message if error.
+*/
+static int
+ensure_has_no_more_tokens(char *cp, char *fname, unsigned long lineno)
+{
+    struct token_s tok;
+
+    cp = get_token(cp, &tok);
+    if (tok.tk_len > 0) {
+	printf("dwarfdump.conf error: "
+	       "extra characters after command operands, found "
+	       "\"%s\" in %s line %lu\n", tok.tk_data, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+    return TRUE;
+}
+
+
+/*
+	There may be many  beginabi: lines in a dwarfdump.conf file,
+	find the one we want and return it's file offset.
+*/
+static int
+find_abi_start(FILE * stream,
+	       char *abi_name, long *offset, unsigned long *lineno_out)
+{
+    char buf[100];
+    unsigned long lineno = 0;
+
+    for (; !feof(stream);) {
+
+	struct token_s tok;
+	char *line = 0;
+	long loffset = ftell(stream);
+
+	line = fgets(buf, sizeof(buf), stream);
+	++lineno;
+	if (!line) {
+	    ++errcount;
+	    return FALSE;
+	}
+
+	line = get_token(buf, &tok);
+
+	if (strcmp(tok.tk_data, name_begin_abi) != 0) {
+	    continue;
+	}
+	get_token(line, &tok);
+	if (strcmp(tok.tk_data, abi_name) != 0) {
+	    continue;
+	}
+
+	*offset = loffset;
+	*lineno_out = lineno;
+	return TRUE;
+    }
+
+    ++errcount;
+    return FALSE;
+}
+
+static char *tempstr = 0;
+static unsigned tempstr_len = 0;
+
+/*
+	Use a global buffer (tempstr) to turn a non-delimited
+	input char array into a NUL-terminated C string
+        (with the help of makename() to get a permanent
+        address for the result ing string).
+*/
+static char *
+build_string(unsigned tlen, char *cp)
+{
+    if (tlen >= tempstr_len) {
+	free(tempstr);
+	tempstr = malloc(tlen + 100);
+    }
+    strncpy(tempstr, cp, tlen);
+    tempstr[tlen] = 0;
+    return makename(tempstr);
+}
+
+/*
+	The tokenizer for our simple parser.
+*/
+static char *
+get_token(char *cp, struct token_s *outtok)
+{
+    char *lcp = skipwhite(cp);
+    unsigned tlen = find_token_len(lcp);
+
+    outtok->tk_len = tlen;
+    if (tlen > 0) {
+	outtok->tk_data = build_string(tlen, lcp);
+    } else {
+	outtok->tk_data = "";
+    }
+    return lcp + tlen;
+
+}
+
+/*
+	We can't get all the field set up statically very easily,
+        so we get the command string length set here.
+*/
+static void
+finish_comtable_setup(void)
+{
+    unsigned i;
+
+    for (i = 0; i < size_of_comtable; ++i) {
+	comtable[i].namelen = strlen(comtable[i].name);
+    }
+}
+
+/*
+    Given  a line of the table, determine if it is a command
+    or not, and if a command, which one is it.
+    Return LT_ERROR if it's not recognized.
+*/
+static enum linetype_e
+which_command(char *cp, struct comtable_s **tableentry)
+{
+    int i;
+    struct token_s tok;
+
+    if (*cp == '#')
+	return LT_COMMENT;
+    if (!*cp)
+	return LT_BLANK;
+
+    get_token(cp, &tok);
+
+    for (i = 0; i < size_of_comtable; ++i) {
+	if (tok.tk_len == comtable[i].namelen &&
+	    strcmp(comtable[i].name, tok.tk_data) == 0) {
+
+	    *tableentry = &comtable[i];
+	    return comtable[i].type;
+	}
+    }
+
+    return LT_ERROR;
+}
+
+/* We are promised it's an abiname: command
+   find the name on the line.
+*/
+static int
+parsebeginabi(char *cp, char *fname, char *abiname,
+	      unsigned long lineno, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    size_t abinamelen = strlen(abiname);
+    struct token_s tok;
+
+
+    cp = cp + clen + 1;
+    cp = skipwhite(cp);
+    get_token(cp, &tok);
+    if (tok.tk_len != abinamelen ||
+	strncmp(cp, abiname, abinamelen) != 0) {
+	printf("dwarfdump internal error: "
+	       "mismatch %s with %s   %s line %lu\n",
+	       cp, tok.tk_data, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+    {
+	int res =
+	    ensure_has_no_more_tokens(cp + tok.tk_len, fname, lineno);
+	return res;
+    }
+}
+
+/* This expands register names as required, but does not
+   ensure no names duplicated.
+*/
+#define CONF_TABLE_OVERSIZE  100
+static void
+add_to_reg_table(struct dwconf_s *conf,
+		 char *rname, unsigned long rval, char *fname,
+		 unsigned long lineno)
+{
+    if (conf->cf_regs_malloced == 0) {
+	conf->cf_regs = 0;
+	conf->cf_named_regs_table_size = 0;
+    }
+    if (rval >= conf->cf_named_regs_table_size) {
+	char **newregs = 0;
+	unsigned long newtablen = rval + CONF_TABLE_OVERSIZE;
+	unsigned long newtabsize = newtablen * sizeof(char *);
+	unsigned long oldtabsize =
+	    conf->cf_named_regs_table_size * sizeof(char *);
+	newregs = realloc(conf->cf_regs, newtabsize);
+	if (!newregs) {
+	    printf("dwarfdump: unable to malloc table %lu bytes. "
+		   " %s line %lu\n", newtabsize, fname, lineno);
+	    exit(1);
+	}
+	/* Zero out the new entries. */
+	memset((char *) newregs + (oldtabsize), 0,
+	       (newtabsize - oldtabsize));
+	conf->cf_named_regs_table_size = (unsigned long) newtablen;
+	conf->cf_regs = newregs;
+	conf->cf_regs_malloced = 1;
+    }
+    conf->cf_regs[rval] = rname;
+    return;
+}
+
+/* Our input is supposed to be a number.
+   Determine the value (and return it) or generate an error message.
+*/
+static int
+make_a_number(char *cmd, char *filename, unsigned long
+	      lineno, struct token_s *tok, unsigned long *val_out)
+{
+    char *endnum = 0;
+    unsigned long val = 0;
+
+    val = strtoul(tok->tk_data, &endnum, 0);
+    if (val == 0 && endnum == (tok->tk_data)) {
+	printf("dwarfdump.conf error: "
+	       "%s missing register number (\"%s\" not valid)  %s line %lu",
+	       cmd, tok->tk_data, filename, lineno);
+	++errcount;
+	return FALSE;
+    }
+    if (endnum != (tok->tk_data + tok->tk_len)) {
+	printf("dwarfdump.conf error: "
+	       "%s Missing register number (\"%s\" not valid)  %s line %lu",
+	       cmd, tok->tk_data, filename, lineno);
+	++errcount;
+	return FALSE;
+    }
+    *val_out = val;
+    return TRUE;
+
+
+
+}
+
+/* We are guaranteed it's a reg: command, so parse that command
+    and record the interesting data.
+*/
+static int
+parsereg(char *cp, char *fname, unsigned long lineno,
+	 struct dwconf_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s regnum;
+    struct token_s tokreg;
+    unsigned long val = 0;
+    int ok = FALSE;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tokreg);
+    cp = get_token(cp, &regnum);
+    if (tokreg.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "reg: missing register name  %s line %lu",
+	       fname, lineno);
+	++errcount;
+	return FALSE;
+
+    }
+    if (regnum.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "reg: missing register number  %s line %lu",
+	       fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &regnum, &val);
+
+    if (!ok) {
+	++errcount;
+	return FALSE;
+    }
+
+    add_to_reg_table(conf, tokreg.tk_data, val, fname, lineno);
+
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+}
+
+/*
+   We are guaranteed it's an frame_interface: command.
+   Parse it and record the value data.
+*/
+static int
+parseframe_interface(char *cp, char *fname, unsigned long lineno,
+		     struct dwconf_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s tok;
+    unsigned long val = 0;
+    int ok = FALSE;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "%s missing interface number %s line %lu",
+	       comtab->name, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+	++errcount;
+	return FALSE;
+    }
+    if (val != 2 && val != 3) {
+	printf("dwarfdump.conf error: "
+	       "%s only interface numbers 2 or 3 are allowed, "
+	       " not %lu. %s line %lu",
+	       comtab->name, val, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    conf->cf_interface_number = (int) val;
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+}
+
+/*
+   We are guaranteed it's a cfa_reg: command. Parse it
+   and record the important data.
+*/
+static int
+parsecfa_reg(char *cp, char *fname, unsigned long lineno,
+	     struct dwconf_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s tok;
+    unsigned long val = 0;
+    int ok = FALSE;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "%s missing cfa_reg number %s line %lu",
+	       comtab->name, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+	++errcount;
+	return FALSE;
+    }
+    conf->cf_cfa_reg = (int) val;
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+}
+
+
+/* We are guaranteed it's an initial_reg_value: command,
+   parse it and put the reg value where it will be remembered. 
+*/
+static int
+parseinitial_reg_value(char *cp, char *fname,
+		       unsigned long lineno,
+		       struct dwconf_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s tok;
+    unsigned long val = 0;
+    int ok = FALSE;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "%s missing initial reg value %s line %lu",
+	       comtab->name, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+
+	++errcount;
+	return FALSE;
+    }
+    conf->cf_initial_rule_value = (int) val;
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+}
+
+
+/* We are guaranteed it's a table size command, parse it
+    and record the table size.
+*/
+static int
+parsereg_table_size(char *cp, char *fname, unsigned long lineno,
+		    struct dwconf_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s tok;
+    unsigned long val = 0;
+    int ok = FALSE;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_len == 0) {
+	printf("dwarfdump.conf error: "
+	       "%s missing reg table size value %s line %lu",
+	       comtab->name, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+	++errcount;
+	return FALSE;
+    }
+    conf->cf_table_entry_count = (unsigned long) val;
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+
+}
+
+
+/*  We are guaranteed it's an endabi: command, parse it and
+    check we have the right abi.
+*/
+static int
+parseendabi(char *cp, char *fname, char *abiname, unsigned long lineno,
+	    struct comtable_s *comtab)
+{
+    size_t clen = comtab->namelen;
+    struct token_s tok;
+
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (strcmp(abiname, tok.tk_data) != 0) {
+	printf("%s error: "
+	       "mismatch abi name %s (here) vs. %s (beginabi:)  %s line %lu\n",
+	       comtab->name, tok.tk_data, abiname, fname, lineno);
+	++errcount;
+	return FALSE;
+    }
+    {
+	int res = ensure_has_no_more_tokens(cp, fname, lineno);
+
+	return res;
+    }
+
+}
+
+
+
+/* Return TRUE if we succeeded and filed in *out.
+   Return FALSE if we failed (and fill in nothing).
+  beginabi:  <abiname>
+  reg: <regname> <dwarf regnumber>
+  frame_interface: <integer value 2 or 3>
+  cfa_reg:  <number>
+  initial_reg_value:  <number: normally 1034 or 1035 >
+  reg_table_size: <size of table>
+  endabi:  <abiname>
+ 
+  We are positioned at the start of a beginabi: line when
+  called.
+
+*/
+static int
+parse_abi(FILE * stream, char *fname, char *abiname,
+	  struct dwconf_s *out, unsigned long lineno)
+{
+    struct dwconf_s localconf;
+    char buf[1000];
+    int comtype = 0;
+    long regcount = 0;
+
+    unsigned long beginabi_lineno = 0;
+    unsigned long frame_interface_lineno = 0;
+    unsigned long initial_reg_value_lineno = 0;
+    unsigned long reg_table_size_lineno = 0;
+    unsigned long cfa_reg_lineno = 0;
+    static int first_time_done = 0;
+    struct comtable_s *comtabp = 0;
+
+
+    if (first_time_done == 0) {
+	finish_comtable_setup();
+	first_time_done = 1;
+    }
+
+
+
+
+    init_conf_file_data(&localconf);
+
+    for (; !feof(stream);) {
+
+	char *line = 0;
+
+	/* long loffset = ftell(stream); */
+	line = fgets(buf, sizeof(buf), stream);
+	if (!line) {
+	    ++errcount;
+	    printf
+		("dwarfdump: end of file or error before endabi: in %s, line %lu\n",
+		 fname, lineno);
+	    return FALSE;
+	}
+	++lineno;
+	line = skipwhite(line);
+	comtype = which_command(line, &comtabp);
+	switch (comtype) {
+	case LT_ERROR:
+	    ++errcount;
+	    printf
+		("dwarfdump: Unknown text in %s is \"%s\" at line %lu\n",
+		 fname, line, lineno);
+	    break;
+	case LT_COMMENT:
+	    break;
+	case LT_BLANK:
+	    break;
+	case LT_BEGINABI:
+	    if (beginabi_lineno > 0) {
+		++errcount;
+		printf
+		    ("dwarfdump: Encountered beginabi: when not expected. "
+		     "%s line %lu previous beginabi line %lu\n", fname,
+		     lineno, beginabi_lineno);
+	    }
+	    beginabi_lineno = lineno;
+	    parsebeginabi(line, fname, abiname, lineno, comtabp);
+	    break;
+
+	case LT_REG:
+	    parsereg(line, fname, lineno, &localconf, comtabp);
+	    ++regcount;
+	    break;
+	case LT_FRAME_INTERFACE:
+	    if (frame_interface_lineno > 0) {
+		++errcount;
+		printf
+		    ("dwarfdump: Encountered duplicate frame_interface: "
+		     "%s line %lu previous frame_interface: line %lu\n",
+		     fname, lineno, frame_interface_lineno);
+	    }
+	    frame_interface_lineno = lineno;
+	    parseframe_interface(line, fname,
+				 lineno, &localconf, comtabp);
+	    break;
+	case LT_CFA_REG:
+	    if (cfa_reg_lineno > 0) {
+		printf("dwarfdump: Encountered duplicate cfa_reg: "
+		       "%s line %lu previous cfa_reg line %lu\n",
+		       fname, lineno, cfa_reg_lineno);
+		++errcount;
+	    }
+	    cfa_reg_lineno = lineno;
+	    parsecfa_reg(line, fname, lineno, &localconf, comtabp);
+	    break;
+	case LT_INITIAL_REG_VALUE:
+	    if (initial_reg_value_lineno > 0) {
+		printf
+		    ("dwarfdump: Encountered duplicate initial_reg_value_lineno: "
+		     "%s line %lu previous initial_reg_value: line %lu\n",
+		     fname, lineno, initial_reg_value_lineno);
+		++errcount;
+	    }
+	    initial_reg_value_lineno = lineno;
+
+	    parseinitial_reg_value(line, fname,
+				   lineno, &localconf, comtabp);
+	    break;
+	case LT_REG_TABLE_SIZE:
+	    if (reg_table_size_lineno > 0) {
+		printf("dwarfdump: duplicate reg_table_size: "
+		       "%s line %lu previous reg_table_size: line %lu\n",
+		       fname, lineno, reg_table_size_lineno);
+		++errcount;
+	    }
+	    reg_table_size_lineno = lineno;
+	    parsereg_table_size(line, fname,
+				lineno, &localconf, comtabp);
+	    break;
+	case LT_ENDABI:
+	    parseendabi(line, fname, abiname, lineno, comtabp);
+
+	    if (regcount > localconf.cf_table_entry_count) {
+		printf("dwarfdump: more registers named than "
+		       " in  %s  ( %lu named vs  %s %lu)  %s line %lu\n",
+		       abiname, (unsigned long) regcount,
+		       name_reg_table_size,
+		       (unsigned long) localconf.cf_table_entry_count,
+		       fname, (unsigned long) lineno);
+		++errcount;
+	    }
+
+	    *out = localconf;
+	    return TRUE;
+	default:
+	    printf
+		("dwarfdump internal error, impossible line type %d  %s %lu \n",
+		 (int) comtype, fname, lineno);
+	    exit(1);
+
+	}
+    }
+    ++errcount;
+    printf("End of file, no endabi: found. %s, line %lu\n",
+	   fname, lineno);
+    return FALSE;
+}
+
+/* MIPS/IRIX frame register names.
+   For alternate name sets, use dwarfdump.conf or
+   revise dwarf.h and libdwarf.h and this table.
+*/
+static char *regnames[] = {
+    "cfa",
+    "r1/at", "r2/v0", "r3/v1",
+    "r4/a0", "r5/a1", "r6/a2", "r7/a3",
+    "r8/t0", "r9/t1", "r10/t2", "r11/t3",
+    "r12/t4", "r13/t5", "r14/t6", "r15/t7",
+    "r16/s0", "r17/s1", "r18/s2", "r19/s3",
+    "r20/s4", "r21/s5", "r22/s6", "r23/s7",
+    "r24/t8", "r25/t9", "r26/k0", "r27/k1",
+    "r28/gp", "r29/sp", "r30/s8", "r31",
+
+    "$f0", "$f1",
+    "$f2", "$f3",
+    "$f4", "$f5",
+    "$f6", "$f7",
+    "$f8", "$f9",
+    "$f10", "$f11",
+    "$f12", "$f13",
+    "$f14", "$f15",
+    "$f16", "$f17",
+    "$f18", "$f19",
+    "$f20", "$f21",
+    "$f22", "$f23",
+    "$f24", "$f25",
+    "$f26", "$f27",
+    "$f28", "$f29",
+    "$f30", "$f31",
+    "ra", "slk",
+};
+
+
+/* These defaults match MIPS/IRIX ABI defaults.
+   For a 'generic' ABI, see -R.
+   For other ABIs, see -x abi=<whatever>
+   to configure dwarfdump (and libdwarf) frame 
+   data reporting at runtime.
+*/
+void
+init_conf_file_data(struct dwconf_s *config_file_data)
+{
+    unsigned long base_table_count =
+	sizeof(regnames) / sizeof(regnames[0]);
+
+    memset(config_file_data, 0, sizeof(*config_file_data));
+    config_file_data->cf_interface_number = 2;
+    config_file_data->cf_table_entry_count = DW_REG_TABLE_SIZE;
+    config_file_data->cf_initial_rule_value =
+	DW_FRAME_REG_INITIAL_VALUE;
+    config_file_data->cf_cfa_reg = DW_FRAME_CFA_COL;
+    config_file_data->cf_regs = regnames;
+    config_file_data->cf_named_regs_table_size = base_table_count;
+    config_file_data->cf_regs_malloced = 0;
+    if (config_file_data->cf_table_entry_count != base_table_count) {
+	printf("dwarfdump: improper base table initization, "
+	       "header files wrong: "
+	       "DW_REG_TABLE_SIZE %u != string table size %lu\n",
+	       (unsigned) DW_REG_TABLE_SIZE,
+	       (unsigned long) base_table_count);
+	exit(1);
+    }
+
+    return;
+}
+
+/* Naming a few registers makes printing these just
+   a little bit faster.
+*/
+static char *genericregnames[] = {
+  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+  "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+  "r20",
+};
+
+/* A 'generic' ABI. For up to 1000 registers. 
+   Perhaps cf_initial_rule_value should be d
+   UNDEFINED VALUE (1034) instead, but for the purposes of
+   getting the dwarfdump output correct
+   either will work.
+*/
+void
+init_generic_config_1000_regs(struct dwconf_s *config_file_data)
+{
+    unsigned long generic_table_count =
+	sizeof(genericregnames) / sizeof(genericregnames[0]);
+    config_file_data->cf_interface_number = 3;
+    config_file_data->cf_table_entry_count = 1000;
+    config_file_data->cf_initial_rule_value = 1035; /* SAME VALUE */
+    config_file_data->cf_cfa_reg = 1036;
+    config_file_data->cf_regs = genericregnames;
+    config_file_data->cf_named_regs_table_size = generic_table_count;
+    config_file_data->cf_regs_malloced = 0;
+}
+
+/*  Print the 'right' string for the register we are given.
+    Deal sensibly with the special regs as well as numbers
+    we know and those we have not been told about.
+
+*/
+void
+print_reg_from_config_data(Dwarf_Signed reg,
+			   struct dwconf_s *config_data)
+{
+    char *name = 0;
+
+    if (reg == config_data->cf_cfa_reg) {
+	fputs("cfa",stdout);
+	return;
+    }
+    if (reg == DW_FRAME_CFA_COL3) {
+	/* This should not be necessary, but sometimes one forgets to
+	   do the cfa_reg: command in dwarfdump.conf */
+	fputs("cfa",stdout);
+	return;
+    }
+    if (reg == DW_FRAME_UNDEFINED_VAL) {
+	fputs("u",stdout);
+	return;
+    }
+    if (reg == DW_FRAME_SAME_VAL) {
+	fputs("s",stdout);
+	return;
+    }
+    if (config_data->cf_regs == 0 ||
+	reg < 0 || reg > config_data->cf_named_regs_table_size) {
+	printf("r%lld", (signed long long) reg);
+	return;
+    }
+    name = config_data->cf_regs[reg];
+    if (!name) {
+        /* Can happen, the reg names table can be sparse. */
+	printf("r%lld", (signed long long) reg);
+	return;
+    }
+    fputs(name,stdout);
+    return;
+}