From bb1c3da3c12651f1c408d96dd6d33ae157bdadd6 Mon Sep 17 00:00:00 2001
From: Igor Pashev <pashev.igor@gmail.com>
Date: Sat, 20 Oct 2012 14:42:03 +0400
Subject: Imported Upstream version 20120410

---
 dwarfdump2/dwconf.cc | 1291 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1291 insertions(+)
 create mode 100644 dwarfdump2/dwconf.cc

(limited to 'dwarfdump2/dwconf.cc')

diff --git a/dwarfdump2/dwconf.cc b/dwarfdump2/dwconf.cc
new file mode 100644
index 0000000..b484a93
--- /dev/null
+++ b/dwarfdump2/dwconf.cc
@@ -0,0 +1,1291 @@
+/*
+  Copyright (C) 2006 Silicon Graphics, Inc.  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 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 <vector>
+#include <ctype.h>
+#include "dwconf.h"
+using std::string;
+using std::cerr;
+using std::cout;
+using std::endl;
+
+// The nesting level is arbitrary,  2 should suffice.
+// But at least this prevents an infinite loop.
+#define MAX_NEST_LEVEL 3 
+
+
+
+struct token_s {
+    token_s() {};
+    ~token_s() {};
+    const char *c_str() { return tk_data.c_str(); };
+    string 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_SAME_VAL_REG,
+    LT_UNDEFINED_VAL_REG,
+    LT_REG_TABLE_SIZE,
+    LT_ADDRESS_SIZE,
+    LT_INCLUDEABI,
+    LT_ENDABI
+};
+
+struct comtable_s {
+    enum linetype_e type;
+    string name;
+};
+
+/* Count errors found in this scan of the configuration file. */
+static int errcount = 0;        
+
+static string name_begin_abi("beginabi:");
+static string name_reg("reg:");
+static string name_frame_interface("frame_interface:");
+static string name_cfa_reg("cfa_reg:");
+static string name_initial_reg_value("initial_reg_value:");
+static string name_same_val_reg("same_val_reg:");
+static string name_undefined_val_reg("undefined_val_reg:");
+static string name_reg_table_size("reg_table_size:");
+static string name_address_size("address_size:");
+static string name_includeabi("includeabi:");
+static string 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_SAME_VAL_REG,name_same_val_reg},
+    {LT_UNDEFINED_VAL_REG,name_undefined_val_reg},
+    {LT_REG_TABLE_SIZE, name_reg_table_size},
+    {LT_ADDRESS_SIZE, name_address_size},
+    {LT_INCLUDEABI, name_includeabi},
+    {LT_ENDABI, name_endabi},
+};
+static unsigned size_of_comtable = sizeof(comtable) / sizeof(comtable[0]);
+
+struct conf_internal_s {
+    conf_internal_s(struct dwconf_s *out): beginabi_lineno(0),
+        frame_interface_lineno(0), initial_reg_value_lineno(0),
+        reg_table_size_lineno(0),address_size_lineno(0),
+        same_val_reg_lineno(0),
+        undefined_val_reg_lineno(0), cfa_reg_lineno(0),
+        regcount(0),
+        conf_out(out),conf_defaults(0) {};
+    ~conf_internal_s() {};
+    unsigned long beginabi_lineno;
+    unsigned long frame_interface_lineno;
+    unsigned long initial_reg_value_lineno;
+    unsigned long reg_table_size_lineno;
+    unsigned long address_size_lineno;
+    unsigned long same_val_reg_lineno;
+    unsigned long undefined_val_reg_lineno;
+    unsigned long cfa_reg_lineno;
+    unsigned long regcount;
+    std::string conf_name_used;
+    struct dwconf_s *conf_out;
+    std::string conf_named_used;
+    const char ** conf_defaults;
+private:
+    // Do not use this, not implemented.
+    conf_internal_s();
+};
+
+
+
+static FILE *find_a_file(const string &named_file, const char **defaults,
+    string & name_used);
+static bool find_abi_start(FILE * stream, const string &abi_name, long *offset,
+    unsigned long *lineno_out);
+static bool parse_abi(FILE * stream, const std::string &fname, 
+    const std::string &abiname,
+    struct conf_internal_s *out, unsigned long lineno,unsigned nestlevel);
+static char * get_token(char *cp, token_s *tok);
+
+
+
+
+
+/*  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.
+
+    This is the internal call to read the configure file.
+    Implements a crude 'includeabi' feature.
+
+    Returns  the number of errors found.
+*/
+int
+find_conf_file_and_read_config_inner(const string &named_file,
+    const string &named_abi, 
+    struct conf_internal_s *conf_internal,
+    unsigned nest_level)
+{
+
+    errcount = 0;
+
+    string name_used;
+    FILE *conf_stream = find_a_file(named_file, 
+        conf_internal->conf_defaults, name_used);
+    if (!conf_stream) {
+        ++errcount;
+        cout << "dwarfdump found no file \"" <<
+            named_file << "\"!"<< endl;
+        cout << "(add options -v -v to see what file names tried)"<<
+            endl;
+        return errcount;
+    }
+    if (verbose > 1) {
+        cout << "dwarfdump using configuration file " <<
+            name_used << endl;
+    }
+    conf_internal->conf_name_used = name_used;
+
+    long offset = 0;
+    unsigned long lineno = 0;
+    bool res = find_abi_start(conf_stream, named_abi, &offset, &lineno);
+    if (!res) {
+        ++errcount;
+        cout << "dwarfdump found no ABI " <<
+            named_abi << " in file " <<
+            name_used << "." <<endl;
+        return errcount;
+    }
+    int seekres = fseek(conf_stream, offset, SEEK_SET);
+    if (seekres != 0) {
+        ++errcount;
+        cout << "dwarfdump seek to " <<
+            offset << " offset in " <<
+            name_used << 
+            " failed!" << endl;
+        return errcount;
+    }
+    parse_abi(conf_stream, name_used, named_abi, conf_internal, lineno,
+        nest_level);
+    fclose(conf_stream);
+    return errcount;
+}
+
+// This is the exteral-facing call to read the configure file.
+int
+find_conf_file_and_read_config(const string &named_file,
+    const string &named_abi, 
+    const char **defaults,
+    struct dwconf_s *conf_out)
+{
+    // The cf_regs are to be set below, not from
+    // the default set, so clear the exsting data out.
+    conf_out->cf_regs.clear();
+    // Ensure a reasonable minimum vector size.
+    conf_out->cf_regs.resize(100);
+    conf_internal_s conf_internal(conf_out);
+    conf_internal.conf_defaults = defaults;
+
+    int res = find_conf_file_and_read_config_inner(named_file,
+        named_abi, 
+        &conf_internal,0);
+    return res;
+}
+
+/*  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 bool
+canonical_append(string &target,
+    const string &first_string, const string &second_string)
+{
+    // Do not take any ending /
+    size_t firstlen = first_string.size();
+    for (; firstlen > 0 && first_string[firstlen - 1] == '/';
+        --firstlen) {
+    }
+
+    // Do not take any leading /
+    unsigned secondskipto = 0;
+    for (; second_string[secondskipto] == '/'; ++secondskipto) {
+    }
+
+    target = first_string.substr(0,firstlen) + string("/") +
+        second_string.substr(secondskipto);
+    return true;
+}
+
+#ifdef BUILD_FOR_TEST
+struct canap_s {
+    const char *res_exp;
+    const char *first;
+    const 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)
+{
+    unsigned failcount = 0;
+
+    cout <<"Entry test_canonical_append" << endl;
+    for (unsigned i = 0;; ++i) {
+
+        if (canap[i].first == 0 && canap[i].second == 0)
+            break;
+
+        string targ;
+        bool ok = canonical_append(targ, canap[i].first,
+            canap[i].second);
+        if (ok) {
+            if (canap[i].res_exp == 0) {
+                /* GOOD */
+                cout <<"PASS " << i <<endl;
+            } else {
+                ++failcount;
+                cout << "FAIL: entry " << i <<
+                    " wrong, expected " << canap[i].res_exp <<
+                    " got NULL " << endl;
+            }
+        } else {
+            // Impossible now.
+            ++failcount;
+            cout << "FAIL: entry " << i <<
+                " wrong,  expected an ok result " << endl;
+        }
+    }
+    cout << "FAIL count " <<  failcount << endl;
+
+}
+#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(const std::string &named_file, const char **defaults, 
+   string & name_used_out)
+{
+    string lname = named_file;
+    const char *type = "rw";
+
+#ifdef BUILD_FOR_TEST
+    test_canonical_append();
+#endif /* BUILD_FOR_TEST */
+
+    if (!lname.empty()) {
+        /* Name given, just assume it is fully correct, try no other. */
+        if (verbose > 1) {
+            cout << "dwarfdump looking for configuration as " <<
+                lname << endl;
+        }
+        FILE *fin = fopen(lname.c_str(), type);
+        if (fin) {
+            name_used_out = lname;
+            return fin;
+        }
+        return 0;
+    }
+    /* No name given, find a default, if we can. */
+    for (unsigned i = 0; defaults[i]; ++i) {
+        string lname2 = defaults[i];
+        if (strncmp(lname2.c_str(), "HOME/", 5) == 0) {
+            char *homedir = getenv("HOME");
+            if (homedir) {
+                string tname;
+                canonical_append(tname,homedir, lname2.substr(5));
+                lname2 = tname;
+            }
+        }
+        if (verbose > 1) {
+            cout << "dwarfdump looking for configuration as " <<
+                lname2 << endl;
+        }
+        FILE *fin = fopen(lname2.c_str(), type);
+        if (fin) {
+            name_used_out = lname2;
+            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 bool
+ensure_has_no_more_tokens(char *cp, const string &fname, unsigned long lineno)
+{
+    token_s tok ;
+    get_token(cp, &tok);
+    if (!tok.tk_data.empty() ) {
+        cout << "dwarfdump.conf error: " <<
+            "extra characters after command operands, found " <<
+            "\"" << tok.tk_data << "\" in " << fname <<
+            " line " << lineno << endl;
+        ++errcount;
+        return false;
+    }
+    return true;
+}
+
+
+/*  There may be many  beginabi: lines in a dwarfdump.conf file,
+    find the one we want and return its file offset.  */
+static bool
+find_abi_start(FILE * stream, const string &abi_name, 
+    long *offset, unsigned long *lineno_out)
+{
+    char buf[100];
+    unsigned long lineno = 0;
+
+    for (; !feof(stream);) {
+
+        long loffset = ftell(stream);
+
+        char *line = fgets(buf, sizeof(buf), stream);
+        ++lineno;
+        if (!line) {
+            ++errcount;
+            return false;
+        }
+
+        token_s tok;
+        line = get_token(buf, &tok);
+
+        if (tok.tk_data !=  name_begin_abi ) {
+            continue;
+        }
+        token_s tok2;
+        get_token(line,&tok2);
+        if (tok2.tk_data !=  abi_name) {
+            continue;
+        }
+
+        *offset = loffset;
+        *lineno_out = lineno;
+        return true;
+    }
+
+    ++errcount;
+    return false;
+}
+
+/* The tokenizer for our simple parser.  */
+static char *
+get_token(char *cp, token_s *outtok)
+{
+    char *lcp = skipwhite(cp);
+    unsigned tlen = find_token_len(lcp);
+
+    if (tlen > 0) {
+        string s(lcp);
+        outtok->tk_data = s.substr(0,tlen);
+    } else {
+        outtok->tk_data = "";
+    }
+    return lcp + tlen;
+
+}
+
+/*  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)
+{
+
+    if (*cp == '#') {
+        return LT_COMMENT;
+    }
+    if (!*cp) {
+        return LT_BLANK;
+    }
+    token_s tok;
+    get_token(cp, &tok);
+    for (unsigned i = 0; i < size_of_comtable; ++i) {
+        if (tok.tk_data == comtable[i].name) {
+            *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 bool
+parsebeginabi(char *cp, const string &fname, const string &abiname,
+    unsigned long lineno, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    size_t abinamelen = abiname.size();
+
+    cp = cp + clen + 1;
+    cp = skipwhite(cp);
+    token_s tok;
+    get_token(cp, &tok);
+    if (tok.tk_data.size() != abinamelen ||
+        strncmp(cp, abiname.c_str(), abinamelen) != 0) {
+        ++errcount;
+        cout << "dwarfdump internal error: mismatch " <<
+            cp << " with " << tok.tk_data << "   " <<
+            fname << " line " << lineno  <<endl;
+        return false;
+    }
+    bool res = ensure_has_no_more_tokens(cp + tok.tk_data.size(), 
+        fname, lineno);
+    return res;
+}
+
+/*  This expands register names as required, but does not
+    ensure no names duplicated.  */
+static void
+add_to_reg_table(struct dwconf_s *conf,
+    const string &rname, unsigned long rval, 
+    const string &fname,
+    unsigned long lineno)
+{
+    if( rval >= conf->cf_regs.size()) {
+        conf->cf_regs.resize(rval+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(const string &cmd, const string &filename, 
+    unsigned long lineno, struct token_s *tok, unsigned long *val_out)
+{
+    char *endnum = 0;
+    unsigned long val = 0;
+    const char *begin = tok->tk_data.c_str();
+    val = strtoul(begin, &endnum, 0);
+    if (val == 0 && endnum == begin) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            cmd << " missing register number (\"" <<
+            tok->tk_data << "\" not valid)  " <<
+            filename << " line " << lineno <<endl;
+        return false;
+    }
+    if (endnum != (begin + tok->tk_data.size())) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            cmd << " Missing register number (\"" <<
+            tok->tk_data << "\" not valid)  " <<
+            filename << " line " << lineno <<endl;
+        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 bool
+parsereg(char *cp, const string &fname, unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    token_s regnum;
+    token_s tokreg;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tokreg);
+    cp = get_token(cp, &regnum);
+    if (tokreg.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: reg: missing register name  " <<
+            fname << " line " << lineno  <<endl;
+        return false;
+
+    }
+    if (regnum.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: reg: Missing register name  " <<
+            fname << " line " << lineno  <<endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &regnum, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+
+    add_to_reg_table(conf->conf_out, tokreg.tk_data, val, fname, lineno);
+
+    {
+        bool 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 bool
+parseframe_interface(char *cp, const string &fname, unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    cp = cp + clen + 1;
+    token_s tok;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing interface number " <<
+            fname << " line " << lineno  << endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    if (val != 2 && val != 3) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " only interface numbers 2 or 3 are allowed, not " <<
+            val <<
+            ". " <<
+            fname << " line " << lineno  << endl;
+        return false;
+    }
+
+    conf->conf_out->cf_interface_number = (int) val;
+    bool 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 bool
+parsecfa_reg(char *cp, const string &fname, unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    token_s tok;
+    unsigned long val = 0;
+    bool ok = false;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing cfa_reg number " << 
+            fname << " line " << lineno  << endl;
+        return false;
+    }
+
+    ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_cfa_reg = (int) val;
+    bool 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 bool
+parseinitial_reg_value(char *cp, const string &fname,
+    unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    cp = cp + clen + 1;
+    struct token_s tok;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing initial reg value " <<
+            fname << " line " << lineno << endl; 
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_initial_rule_value = (int) val;
+    bool 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 bool
+parsesame_val_reg(char *cp, const string &fname,
+    unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    cp = cp + clen + 1;
+    struct token_s tok;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing same_val_reg value " <<
+            fname << " line " << lineno << endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_same_val = (int) val;
+    bool 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 bool
+parseundefined_val_reg(char *cp, const string &fname,
+    unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    cp = cp + clen + 1;
+    struct token_s tok;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing undefined_val_reg value " <<
+            fname << " line " << lineno << endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_undefined_val = (int) val;
+    bool 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 bool
+parsereg_table_size(char *cp, const string &fname, unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    token_s tok;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing reg table size value " <<
+            fname << " line " << lineno << endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_table_entry_count = (unsigned long) val;
+    bool res = ensure_has_no_more_tokens(cp, fname, lineno);
+    return res;
+}
+/* We are guaranteed it's an address size command, parse it
+    and record the address size.
+*/
+static bool
+parseaddress_size(char *cp, const string &fname, unsigned long lineno,
+    struct conf_internal_s *conf, struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    token_s tok;
+
+    cp = cp + clen + 1;
+    cp = get_token(cp, &tok);
+    if (tok.tk_data.empty()) {
+        ++errcount;
+        cout << "dwarfdump.conf error: " <<
+            comtab->name <<
+            " missing address size value " <<
+            fname << " line " << lineno << endl;
+        return false;
+    }
+
+    unsigned long val = 0;
+    bool ok = make_a_number(comtab->name, fname, lineno, &tok, &val);
+
+    if (!ok) {
+        ++errcount;
+        return false;
+    }
+    conf->conf_out->cf_address_size = (unsigned long) val;
+    bool 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 bool
+parseendabi(char *cp, const string &fname, 
+    const string &abiname, unsigned long lineno,
+    struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+
+
+    cp = cp + clen + 1;
+    struct token_s tok;
+    cp = get_token(cp, &tok);
+    if (abiname != tok.tk_data) {
+        ++errcount;
+        cout << comtab->name <<
+            " error: mismatch abi name " <<
+            tok.tk_data << " (here) vs. " <<
+            abiname <<
+            " (beginabi:)  " <<
+            fname << " line " << lineno << endl;
+        return false;
+    }
+    bool res = ensure_has_no_more_tokens(cp, fname, lineno);
+    return res;
+}
+
+static int 
+parseincludeabi(char *cp,const string &fname,unsigned long lineno,
+    std::string &abiname_out,struct comtable_s *comtab)
+{
+    size_t clen = comtab->name.size();
+    struct token_s tok;
+    cp = cp + clen + 1;
+    cp = get_token(cp,&tok);
+    abiname_out = tok.tk_data;
+    bool 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 >
+  same_value 'reg number' :  <number: normally 1034  >
+  undefined_value 'reg number' :  <number: normally 1035 >
+  reg_table_size: <size of table>
+  endabi:  <abiname>
+ 
+  We are positioned at the start of a beginabi: line when
+  called.
+
+*/
+static bool
+parse_abi(FILE * stream, const string &fname, const string &abiname,
+    struct conf_internal_s *conf_internal, unsigned long lineno,
+    unsigned int nest_level)
+{
+    struct dwconf_s *localconf = conf_internal->conf_out;
+
+    if( nest_level > MAX_NEST_LEVEL) {
+        ++errcount;
+        cout <<"dwarfdump.conf: includeabi nest too deep  in " <<
+            fname << " at line " << lineno<<endl;
+        return false;
+    }
+
+    for (; !feof(stream);) {
+
+        char *line = 0;
+        char buf[1000];
+        /* long loffset = ftell(stream); */
+        line = fgets(buf, sizeof(buf), stream);
+        if (!line) {
+            ++errcount;
+            cout << "dwarfdump: end of file or error before endabi: in "<<
+                fname << ", line " << lineno << endl;
+            return false;
+        }
+        ++lineno;
+        line = skipwhite(line);
+        // comtabp points to the table entry
+        // of interest (identified by which_command()).
+        struct comtable_s *comtabp = 0;
+        int comtype = which_command(line, &comtabp);
+        switch (comtype) {
+        case LT_ERROR:
+            ++errcount;
+            cout << "dwarfdump: Unknown text in "<<
+                fname << " is \"" <<
+                line << "\" at line " <<  lineno << endl;
+            break;
+        case LT_COMMENT:
+            break;
+        case LT_BLANK:
+            break;
+        case LT_BEGINABI:
+            if (conf_internal->beginabi_lineno > 0 &&
+                nest_level == 0) {
+                ++errcount;
+                cout << "dwarfdump: Encountered beginabi: when not expected. "
+                    << fname <<
+                    " line " << lineno <<
+                    " previous beginabi line " <<
+                    conf_internal->beginabi_lineno << endl;
+            }
+            conf_internal->beginabi_lineno = lineno;
+            parsebeginabi(line, fname, abiname, lineno, comtabp);
+            break;
+
+        case LT_REG:
+            parsereg(line, fname, lineno, conf_internal, comtabp);
+            conf_internal->regcount++;
+            break;
+        case LT_FRAME_INTERFACE:
+            if (conf_internal->frame_interface_lineno > 0) {
+                ++errcount;
+                cout << "dwarfdump: Encountered duplicate frame_interface: " 
+                    << fname <<
+                    " line " << lineno <<
+                    " previous frame_interface: line " <<
+                    conf_internal->frame_interface_lineno << endl;
+            }
+            conf_internal->frame_interface_lineno = lineno;
+            parseframe_interface(line, fname,
+                lineno, conf_internal, comtabp);
+            break;
+        case LT_CFA_REG:
+            if (conf_internal->cfa_reg_lineno > 0) {
+                ++errcount;
+                cout << "dwarfdump: Encountered duplicate cfa_reg: " 
+                    << fname <<
+                    " line " << lineno <<
+                    " previous cfa_reg line " <<
+                    conf_internal->cfa_reg_lineno << endl;
+            }
+            conf_internal->cfa_reg_lineno = lineno;
+            parsecfa_reg(line, fname, lineno, conf_internal, comtabp);
+            break;
+        case LT_INITIAL_REG_VALUE:
+            if (conf_internal->initial_reg_value_lineno > 0) {
+                ++errcount;
+                cout << 
+                    "dwarfdump: Encountered duplicate " <<
+                    "initial_reg_value: " <<
+                    fname <<
+                    " line " << lineno <<
+                    " previous initial_reg_value: line " <<
+                    conf_internal->initial_reg_value_lineno<< endl;
+            }
+            conf_internal->initial_reg_value_lineno = lineno;
+            parseinitial_reg_value(line, fname,
+                lineno,conf_internal, comtabp);
+            break;
+        case LT_SAME_VAL_REG:
+            if (conf_internal->same_val_reg_lineno > 0) {
+                ++errcount;
+                cout << 
+                    "dwarfdump: Encountered duplicate " <<
+                    "same_val_reg: " <<
+                    fname <<
+                    " line " << lineno <<
+                    " previous same_reg_value: line " <<
+                    conf_internal->same_val_reg_lineno << endl;
+            }
+            conf_internal->same_val_reg_lineno = lineno;
+            parsesame_val_reg(line, fname,
+                lineno, conf_internal, comtabp);
+            break;
+        case LT_UNDEFINED_VAL_REG:
+            if (conf_internal->undefined_val_reg_lineno > 0) {
+                ++errcount;
+                cout << 
+                    "dwarfdump: Encountered duplicate " <<
+                    "undefined_val_reg: " <<
+                    fname <<
+                    " line " << lineno <<
+                    " previous same_val_reg: line " <<
+                    conf_internal->same_val_reg_lineno << endl;
+            }
+            conf_internal->undefined_val_reg_lineno = lineno;
+            parseundefined_val_reg(line, fname,
+                lineno, conf_internal, comtabp);
+            break;
+
+        case LT_REG_TABLE_SIZE:
+            if (conf_internal->reg_table_size_lineno > 0) {
+                ++errcount;
+                cout << "dwarfdump: duplicate reg_table_size: " 
+                    << fname <<
+                    " line " << lineno <<
+                    " previous reg_table_size: line " <<
+                    conf_internal->reg_table_size_lineno << endl;
+            }
+            conf_internal->reg_table_size_lineno = lineno;
+            parsereg_table_size(line, fname,
+                lineno, conf_internal, comtabp);
+            break;
+        case LT_ENDABI:
+            parseendabi(line, fname, abiname, lineno, comtabp);
+
+            if (conf_internal->regcount > localconf->cf_table_entry_count) {
+                ++errcount;
+                cout << "dwarfdump: more registers named than  in  "
+                    << abiname <<
+                    "  ( " << conf_internal->regcount <<
+                    " named vs  " << name_reg_table_size <<
+                    " " << localconf->cf_table_entry_count <<
+                    ")  " <<
+                    fname << " line " << lineno << endl;
+            }
+
+            return true;
+        case LT_ADDRESS_SIZE:
+            if (conf_internal->address_size_lineno > 0) {
+                ++errcount;
+                cout << "dwarfdump: duplicate address_size:: "
+                    << fname <<
+                    " line " << lineno <<
+                    " previous address_size: line " <<
+                    conf_internal->address_size_lineno << endl;
+            }
+            conf_internal->address_size_lineno = lineno;
+            parseaddress_size(line, fname,
+                lineno, conf_internal, comtabp);
+            break;
+        case LT_INCLUDEABI: {
+            std::string abiname_inner;
+            unsigned long abilno = conf_internal->beginabi_lineno;
+            bool ires = parseincludeabi(line,fname,lineno,abiname_inner,
+                comtabp);
+            if (ires == false) {
+                return ires;
+            }
+            // For the nested abi read, the abi line number must be
+            // set as if not-yet-read, and then restored. 
+            conf_internal->beginabi_lineno = 0;
+            find_conf_file_and_read_config_inner(conf_internal->conf_name_used,
+                abiname_inner,conf_internal,nest_level+1);
+            conf_internal->beginabi_lineno = abilno;
+            }
+            break;
+        default:
+            cout << "dwarfdump internal error, impossible line type " <<
+                comtype << " " << fname << " " << lineno <<endl;
+            exit(1);
+
+        }
+    }
+    ++errcount;
+    cout << "End of file, no endabi: found.  " <<
+        fname << ", line " << lineno << endl;
+    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 const char *mipsregnames[] = {
+    "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",
+};
+
+/*  Naming a few registers makes printing these just
+    a little bit faster.
+*/
+static const char *genericregnames[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9",
+    "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19",
+    "r20"
+};
+
+/*  This is a simple generic set of registers.  The 
+    table entry count is pretty arbitrary.
+*/
+void
+init_conf_file_data(struct dwconf_s *config_file_data) 
+{
+    config_file_data->cf_interface_number = 3;
+    config_file_data->cf_table_entry_count = 100;
+    config_file_data->cf_initial_rule_value = DW_FRAME_UNDEFINED_VAL;
+    config_file_data->cf_cfa_reg =  DW_FRAME_CFA_COL3;
+    config_file_data->cf_address_size = 0;
+    config_file_data->cf_same_val = DW_FRAME_SAME_VAL;
+    config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL;
+    unsigned generic_table_count =
+        sizeof(genericregnames) / sizeof(genericregnames[0]);
+    config_file_data->cf_regs.clear();
+    config_file_data->cf_regs.reserve(generic_table_count);
+    for(unsigned i = 0; i < generic_table_count; ++i) {
+        config_file_data->cf_regs.push_back(genericregnames[i]);
+    }
+}
+
+/*  These defaults match MIPS/IRIX ABI defaults, but this
+    function is not actually used.
+    For a 'generic' ABI, see -R or init_conf_file_data().
+    To really get the old MIPS, use '-x abi=mips'. 
+    For other ABIs, see -x abi=<whatever>
+    to configure dwarfdump (and libdwarf) frame 
+    data reporting at runtime.
+*/
+void
+init_mips_conf_file_data(struct dwconf_s *config_file_data)
+{
+    /*  Interface 2 is deprecated, but for testing purposes
+        is acceptable. */
+    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_address_size = 0;
+    config_file_data->cf_same_val = DW_FRAME_SAME_VAL;
+    config_file_data->cf_undefined_val = DW_FRAME_UNDEFINED_VAL;
+    unsigned mips_table_count =
+        sizeof(mipsregnames) / sizeof(mipsregnames[0]);
+    config_file_data->cf_regs.clear();
+    config_file_data->cf_regs.reserve(mips_table_count);
+    for(unsigned i = 0; i < mips_table_count; ++i) {
+        config_file_data->cf_regs.push_back(mipsregnames[i]);
+    }
+    return;
+}
+
+
+/* A 'generic' ABI. For up to 1200 registers. 
+*/
+void
+init_generic_config_1200_regs(struct dwconf_s *config_file_data)
+{
+    config_file_data->cf_interface_number = 3;
+    config_file_data->cf_table_entry_count = 1200;
+    /*  There is no defined name for cf_initial_rule_value,
+        cf_same_val, or cf_undefined_val in libdwarf.h, 
+        these must just be high enough to be higher than 
+        any real register number. 
+        DW_FRAME_CFA_COL3 must also be higher than any
+        real register number. */
+    config_file_data->cf_initial_rule_value = 1235; /* SAME VALUE */
+    config_file_data->cf_cfa_reg =  DW_FRAME_CFA_COL3;
+    config_file_data->cf_address_size = 0;
+    config_file_data->cf_same_val = 1235;
+    config_file_data->cf_undefined_val = 1234;
+    unsigned generic_table_count =
+        sizeof(genericregnames) / sizeof(genericregnames[0]);
+    config_file_data->cf_regs.clear();
+    config_file_data->cf_regs.reserve(generic_table_count);
+    for(unsigned i = 0; i < generic_table_count; ++i) {
+        config_file_data->cf_regs.push_back(genericregnames[i]);
+    }
+}
+
+/*  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)
+{
+
+    if (reg == config_data->cf_cfa_reg) {
+        cout << "cfa";
+        return;
+    }
+    if (reg == config_data->cf_undefined_val) {
+        cout << "u";
+        return;
+    }
+    if (reg == config_data->cf_same_val) {
+        cout << "s";
+        return;
+    }
+    if ( reg < 0 || 
+        reg >= config_data->cf_regs.size()) {
+        cout << "r" << reg;
+        return;
+    }
+    const string &name = config_data->cf_regs[reg];
+    if (name.empty()) {
+        /* Can happen, the reg names table can be sparse. */
+        cout << "r" << reg;
+        return;
+    }
+    cout << name;
+    return;
+}
-- 
cgit v1.2.3