/* 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 #include #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 << "." <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 < 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 <= 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 <tk_data.size())) { ++errcount; cout << "dwarfdump.conf error: " << cmd << " Missing register number (\"" << tok->tk_data << "\" not valid) " << filename << " line " << lineno <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 <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: reg: frame_interface: cfa_reg: initial_reg_value: same_value 'reg number' : undefined_value 'reg number' : reg_table_size: endabi: 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<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 <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= 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; }