diff options
Diffstat (limited to 'dwarfdump2/dwconf.cc')
-rw-r--r-- | dwarfdump2/dwconf.cc | 1291 |
1 files changed, 1291 insertions, 0 deletions
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, ®num); + 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, ®num, &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; +} |