diff options
Diffstat (limited to 'dwarfdump/dwconf.c')
-rw-r--r-- | dwarfdump/dwconf.c | 1424 |
1 files changed, 1424 insertions, 0 deletions
diff --git a/dwarfdump/dwconf.c b/dwarfdump/dwconf.c new file mode 100644 index 0000000..1b59053 --- /dev/null +++ b/dwarfdump/dwconf.c @@ -0,0 +1,1424 @@ +/* + Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. + Portions Copyright 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 $ */ + + +/* Windows specific */ +#ifdef HAVE_STDAFX_H +#include "stdafx.h" +#endif /* HAVE_STDAFX_H */ + +#include "globals.h" +#include "dwarf.h" +#include "libdwarf.h" + +#include <ctype.h> +#include "dwconf.h" +#include "makename.h" + +extern int verbose; + +/* The nesting level is arbitrary, 2 should suffice. + But at least this prevents an infinite loop. +*/ +#define MAX_NEST_LEVEL 3 + +struct token_s { + unsigned tk_len; + char *tk_data; +}; +enum linetype_e { + LT_ERROR, + LT_COMMENT, + LT_BLANK, + LT_BEGINABI, + LT_REG, + LT_FRAME_INTERFACE, + LT_CFA_REG, + LT_INITIAL_REG_VALUE, + LT_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; + char *name; + size_t namelen; +}; + +static int errcount = 0; /* Count errors found in this scan of + the configuration file. */ + +static char name_begin_abi[] = "beginabi:"; +static char name_reg[] = "reg:"; +static char name_frame_interface[] = "frame_interface:"; +static char name_cfa_reg[] = "cfa_reg:"; +static char name_initial_reg_value[] = "initial_reg_value:"; +static char name_same_val_reg[] = "same_val_reg:"; +static char name_undefined_val_reg[] = "undefined_val_reg:"; +static char name_reg_table_size[] = "reg_table_size:"; +static char name_address_size[] = "address_size:"; +static char name_includeabi[] = "includeabi:"; +static char name_endabi[] = "endabi:"; + +static struct comtable_s comtable[] = { + {LT_BEGINABI, name_begin_abi}, + {LT_REG, name_reg}, + {LT_FRAME_INTERFACE, name_frame_interface}, + {LT_CFA_REG, name_cfa_reg}, + {LT_INITIAL_REG_VALUE, name_initial_reg_value}, + {LT_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}, +}; + +struct 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; + struct dwconf_s * conf_out; + const char * conf_name_used; + char ** conf_defaults; +}; +static void +init_conf_internal(struct conf_internal_s *s, + struct dwconf_s * conf_out) +{ + s->beginabi_lineno = 0; + s->frame_interface_lineno = 0; + s->initial_reg_value_lineno = 0; + s->reg_table_size_lineno = 0; + s->address_size_lineno = 0; + s->same_val_reg_lineno = 0; + s->undefined_val_reg_lineno = 0; + s->cfa_reg_lineno = 0; + s->cfa_reg_lineno = 0; + s->conf_name_used = 0; + s->conf_defaults = 0; + s->regcount = 0; + s->conf_out = conf_out; +} + +static int size_of_comtable = sizeof(comtable) / sizeof(comtable[0]); + +static FILE *find_a_file(const char *named_file, char **defaults, + const char** name_used); +static int find_abi_start(FILE * stream, const char *abi_name, long *offset, + unsigned long *lineno_out); +static int parse_abi(FILE * stream, const char *fname, const char *abiname, + struct conf_internal_s *out, unsigned long lineno, unsigned nest_level); +static char *get_token(char *cp, struct token_s *outtok); + +/* This finds a dwarfdump.conf file and + then parses it. It updates + conf_out as appropriate. + + This finds the first file (looking in a set of places) + with that name. It then looks for the right ABI entry. + If the first file it finds does not have that ABI entry it + gives up. + + It would also be reasonable to search every 'dwarfdump.conf' + it finds for the abi. But we stop at the first dwarfdump.conf + we find. + This is the internal call to get the conf data to implement + a crude 'includeabi' feature. + + Returns 0 if no errors found, else returns > 0. +*/ +static int +find_conf_file_and_read_config_inner(const char *named_file, + const char *named_abi, + struct conf_internal_s *conf_internal, + unsigned nest_level) +{ + + FILE *conf_stream = 0; + const char *name_used = 0; + long offset = 0; + int res = FALSE; + unsigned long lineno = 0; + + errcount = 0; + + conf_stream = find_a_file(named_file, conf_internal->conf_defaults, + &name_used); + if (!conf_stream) { + ++errcount; + printf("dwarfdump found no file %s!\n", + named_file ? named_file : "readable for configuration. " + "(add options -v -v to see what file names tried)\n"); + return errcount; + } + if (verbose > 1) { + printf("dwarfdump using configuration file %s\n", name_used); + } + conf_internal->conf_name_used = name_used; + + res = find_abi_start(conf_stream, named_abi, &offset, &lineno); + if (errcount > 0) { + ++errcount; + printf("dwarfdump found no ABI %s in file %s.\n", + named_abi, name_used); + return errcount; + } + res = fseek(conf_stream, offset, SEEK_SET); + if (res != 0) { + ++errcount; + printf("dwarfdump seek to %ld offset in %s failed!\n", + offset, name_used); + return errcount; + } + parse_abi(conf_stream, name_used, named_abi, conf_internal, lineno, + nest_level); + fclose(conf_stream); + return errcount; +} + +/* This is the external-facing call to get the conf data. */ +int +find_conf_file_and_read_config(const char *named_file, + const char *named_abi, char **defaults, + struct dwconf_s *conf_out) +{ + int res = 0; + struct conf_internal_s conf_internal; + init_conf_file_data(conf_out); + init_conf_internal(&conf_internal,conf_out); + conf_internal.conf_defaults = defaults; + 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 char * +canonical_append(char *target, unsigned int target_size, + const char *first_string, const char *second_string) +{ + size_t firstlen = strlen(first_string); + + /* +1 +1: Leave room for added "/" and final NUL, though that is + overkill, as we drop a NUL byte too. */ + if ((firstlen + strlen(second_string) + 1 + 1) >= target_size) { + /* Not enough space. */ + return NULL; + } + for (; *second_string == '/'; ++second_string) { + } + for (; firstlen > 0 && first_string[firstlen - 1] == '/'; + --firstlen) { + } + target[0] = 0; + if (firstlen > 0) { + strncpy(target, first_string, firstlen); + target[firstlen + 1] = 0; + } + target[firstlen] = '/'; + firstlen++; + target[firstlen] = 0; + strcat(target, second_string); + return target; +} + +#ifdef BUILD_FOR_TEST +#define CANBUF 25 +struct canap_s { + char *res_exp; + char *first; + char *second; +} canap[] = { + { + "ab/c", "ab", "c"}, { + "ab/c", "ab/", "c"}, { + "ab/c", "ab", "/c"}, { + "ab/c", "ab////", "/////c"}, { + "ab/", "ab", ""}, { + "ab/", "ab////", ""}, { + "ab/", "ab////", ""}, { + "/a", "", "a"}, { + 0, "/abcdefgbijkl", "pqrstuvwxyzabcd"}, { + 0, 0, 0} +}; +static void +test_canonical_append(void) +{ + /* Make buf big, this is test code, so be safe. */ + char lbuf[1000]; + unsigned i; + unsigned failcount = 0; + + printf("Entry test_canonical_append\n"); + for (i = 0;; ++i) { + char *res = 0; + + if (canap[i].first == 0 && canap[i].second == 0) + break; + + res = canonical_append(lbuf, CANBUF, canap[i].first, + canap[i].second); + if (res == 0) { + if (canap[i].res_exp == 0) { + /* GOOD */ + printf("PASS %u\n", i); + } else { + ++failcount; + printf("FAIL: entry %u wrong, expected %s, got NULL\n", + i, canap[i].res_exp); + } + } else { + if (canap[i].res_exp == 0) { + ++failcount; + printf("FAIL: entry %u wrong, got %s expected NULL\n", + i, res); + } else { + if (strcmp(res, canap[i].res_exp) == 0) { + printf("PASS %u\n", i); + /* GOOD */ + } else { + ++failcount; + printf("FAIL: entry %u wrong, expected %s got %s\n", + i, canap[i].res_exp, res); + } + } + } + } + printf("FAIL count %u\n", failcount); + +} +#endif /* BUILD_FOR_TEST */ +/* Try to find a file as named and open for read. + We treat each name as a full name, we are not + combining separate name and path components. + This is an arbitrary choice... + + The defaults are listed in dwarfdump.c in the array + config_file_defaults[]. +*/ +static FILE * +find_a_file(const char *named_file, char **defaults, const char ** name_used) +{ + FILE *fin = 0; + const char *lname = named_file; + const char *type = "rw"; + int i = 0; + +#ifdef BUILD_FOR_TEST + test_canonical_append(); +#endif /* BUILD_FOR_TEST */ + + if (lname) { + /* Name given, just assume it is fully correct, try no other. */ + if (verbose > 1) { + printf("dwarfdump looking for configuration as %s\n", + lname); + } + fin = fopen(lname, type); + if (fin) { + *name_used = lname; + return fin; + } + return 0; + } + /* No name given, find a default, if we can. */ + for (i = 0; defaults[i]; ++i) { + lname = defaults[i]; +#ifdef WIN32 + /* Open the configuration file, located + in the directory where the tool is loaded from */ + { + static char szPath[MAX_PATH]; + if (GetModuleFileName(NULL,szPath,MAX_PATH)) { + char *pDir = strrchr(szPath,'/'); + if (!pDir) { + pDir = strrchr(szPath,'\\'); + if (!pDir) { + /* No file was found */ + return 0; + } + } + /* Add the configuration name to the pathname */ + ++pDir; + strcpy(pDir,"dwarfdump.conf"); + lname = szPath; + } + } +#else /* non-Win */ + if (strncmp(lname, "HOME/", 5) == 0) { + /* arbitrary size */ + char buf[2000]; + char *homedir = getenv("HOME"); + if (homedir) { + char *cp = canonical_append(buf, sizeof(buf), + homedir, lname + 5); + if (!cp) { + /* OOps, ignore this one. */ + continue; + } + lname = makename(buf); + } + } +#endif /* WIN32 */ + if (verbose > 1) { + printf("dwarfdump looking for configuration as %s\n", + lname); + } + fin = fopen(lname, type); + if (fin) { + *name_used = lname; + return fin; + } + } + return 0; +} + +/* Start at a token begin, see how long it is, + return length. */ +unsigned +find_token_len(char *cp) +{ + unsigned len = 0; + + for (; *cp; ++cp) { + if (isspace(*cp)) { + return len; + } + if (*cp == '#') { + return len; /* begins comment */ + } + ++len; + } + return len; +} + +/* + Skip past all whitespace: the only code that even knows + what whitespace is. +*/ +static char * +skipwhite(char *cp) +{ + for (; *cp; ++cp) { + if (!isspace(*cp)) { + return cp; + } + } + return cp; +} + +/* Return TRUE if ok. FALSE if find more tokens. + Emit error message if error. +*/ +static int +ensure_has_no_more_tokens(char *cp, const char *fname, unsigned long lineno) +{ + struct token_s tok; + + cp = get_token(cp, &tok); + if (tok.tk_len > 0) { + printf("dwarfdump.conf error: " + "extra characters after command operands, found " + "\"%s\" in %s line %lu\n", tok.tk_data, fname, lineno); + ++errcount; + return FALSE; + } + return TRUE; +} + + +/* There may be many beginabi: lines in a dwarfdump.conf file, + find the one we want and return its file offset. +*/ +static int +find_abi_start(FILE * stream, const char *abi_name, + long *offset, unsigned long *lineno_out) +{ + char buf[100]; + unsigned long lineno = 0; + + for (; !feof(stream);) { + + struct token_s tok; + char *line = 0; + long loffset = ftell(stream); + + line = fgets(buf, sizeof(buf), stream); + ++lineno; + if (!line) { + ++errcount; + return FALSE; + } + + line = get_token(buf, &tok); + + if (strcmp(tok.tk_data, name_begin_abi) != 0) { + continue; + } + get_token(line, &tok); + if (strcmp(tok.tk_data, abi_name) != 0) { + continue; + } + + *offset = loffset; + *lineno_out = lineno; + return TRUE; + } + + ++errcount; + return FALSE; +} + +static char *tempstr = 0; +static unsigned tempstr_len = 0; + +/* Use a global buffer (tempstr) to turn a non-delimited + input char array into a NUL-terminated C string + (with the help of makename() to get a permanent + address for the result ing string). +*/ +static char * +build_string(unsigned tlen, char *cp) +{ + if (tlen >= tempstr_len) { + free(tempstr); + tempstr = malloc(tlen + 100); + } + strncpy(tempstr, cp, tlen); + tempstr[tlen] = 0; + return makename(tempstr); +} + +/* The tokenizer for our simple parser. +*/ +static char * +get_token(char *cp, struct token_s *outtok) +{ + char *lcp = skipwhite(cp); + unsigned tlen = find_token_len(lcp); + + outtok->tk_len = tlen; + if (tlen > 0) { + outtok->tk_data = build_string(tlen, lcp); + } else { + outtok->tk_data = ""; + } + return lcp + tlen; + +} + +/* + We can't get all the field set up statically very easily, + so we get the command string length set here. +*/ +static void +finish_comtable_setup(void) +{ + unsigned i; + + for (i = 0; i < size_of_comtable; ++i) { + comtable[i].namelen = strlen(comtable[i].name); + } +} + +/* + Given a line of the table, determine if it is a command + or not, and if a command, which one is it. + Return LT_ERROR if it's not recognized. +*/ +static enum linetype_e +which_command(char *cp, struct comtable_s **tableentry) +{ + int i; + struct token_s tok; + + if (*cp == '#') + return LT_COMMENT; + if (!*cp) + return LT_BLANK; + + get_token(cp, &tok); + + for (i = 0; i < size_of_comtable; ++i) { + if (tok.tk_len == comtable[i].namelen && + strcmp(comtable[i].name, tok.tk_data) == 0) { + + *tableentry = &comtable[i]; + return comtable[i].type; + } + } + + return LT_ERROR; +} + +/* We are promised it's an abiname: command + find the name on the line. +*/ +static int +parsebeginabi(char *cp, const char *fname, const char *abiname, + unsigned long lineno, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + size_t abinamelen = strlen(abiname); + struct token_s tok; + + + cp = cp + clen + 1; + cp = skipwhite(cp); + get_token(cp, &tok); + if (tok.tk_len != abinamelen || + strncmp(cp, abiname, abinamelen) != 0) { + printf("dwarfdump internal error: " + "mismatch %s with %s %s line %lu\n", + cp, tok.tk_data, fname, lineno); + ++errcount; + return FALSE; + } + ensure_has_no_more_tokens(cp + tok.tk_len, fname, lineno); + return TRUE; +} + +/* This expands register names as required, but does not + ensure no names duplicated. +*/ +#define CONF_TABLE_OVERSIZE 100 +static void +add_to_reg_table(struct dwconf_s *conf, + char *rname, unsigned long rval, const char *fname, + unsigned long lineno) +{ + if (conf->cf_regs_malloced == 0) { + conf->cf_regs = 0; + conf->cf_named_regs_table_size = 0; + } + if (rval >= conf->cf_named_regs_table_size) { + char **newregs = 0; + unsigned long newtablen = rval + CONF_TABLE_OVERSIZE; + unsigned long newtabsize = newtablen * sizeof(char *); + unsigned long oldtabsize = + conf->cf_named_regs_table_size * sizeof(char *); + newregs = realloc(conf->cf_regs, newtabsize); + if (!newregs) { + printf("dwarfdump: unable to malloc table %lu bytes. " + " %s line %lu\n", newtabsize, fname, lineno); + exit(1); + } + /* Zero out the new entries. */ + memset((char *) newregs + (oldtabsize), 0, + (newtabsize - oldtabsize)); + conf->cf_named_regs_table_size = (unsigned long) newtablen; + conf->cf_regs = newregs; + conf->cf_regs_malloced = 1; + } + conf->cf_regs[rval] = rname; + return; +} + +/* Our input is supposed to be a number. + Determine the value (and return it) or generate an error message. +*/ +static int +make_a_number(char *cmd, const char *filename, unsigned long + lineno, struct token_s *tok, unsigned long *val_out) +{ + char *endnum = 0; + unsigned long val = 0; + + val = strtoul(tok->tk_data, &endnum, 0); + if (val == 0 && endnum == (tok->tk_data)) { + printf("dwarfdump.conf error: " + "%s missing register number (\"%s\" not valid) %s line %lu\n", + cmd, tok->tk_data, filename, lineno); + ++errcount; + return FALSE; + } + if (endnum != (tok->tk_data + tok->tk_len)) { + printf("dwarfdump.conf error: " + "%s Missing register number (\"%s\" not valid) %s line %lu\n", + cmd, tok->tk_data, filename, lineno); + ++errcount; + return FALSE; + } + *val_out = val; + return TRUE; + + + +} + +/* We are guaranteed it's a reg: command, so parse that command + and record the interesting data. +*/ +static int +parsereg(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s regnum; + struct token_s tokreg; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tokreg); + cp = get_token(cp, ®num); + if (tokreg.tk_len == 0) { + printf("dwarfdump.conf error: " + "reg: missing register name %s line %lu", + fname, lineno); + ++errcount; + return FALSE; + + } + if (regnum.tk_len == 0) { + printf("dwarfdump.conf error: " + "reg: missing register number %s line %lu", + fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, ®num, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + + add_to_reg_table(conf->conf_out, tokreg.tk_data, val, fname, lineno); + + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* + We are guaranteed it's an frame_interface: command. + Parse it and record the value data. +*/ +static int +parseframe_interface(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing interface number %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + if (val != 2 && val != 3) { + printf("dwarfdump.conf error: " + "%s only interface numbers 2 or 3 are allowed, " + " not %lu. %s line %lu", + comtab->name, val, fname, lineno); + ++errcount; + return FALSE; + } + + conf->conf_out->cf_interface_number = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* + We are guaranteed it's a cfa_reg: command. Parse it + and record the important data. +*/ +static int +parsecfa_reg(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing cfa_reg number %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_cfa_reg = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + +/* We are guaranteed it's an initial_reg_value: command, + parse it and put the reg value where it will be remembered. +*/ +static int +parseinitial_reg_value(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing initial reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_initial_rule_value = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +static int +parsesame_val_reg(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing same_reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_same_val = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +static int +parseundefined_val_reg(char *cp, const char *fname, + unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing undefined_reg value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + + ++errcount; + return FALSE; + } + conf->conf_out->cf_undefined_val = (int) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + +/* We are guaranteed it's a table size command, parse it + and record the table size. +*/ +static int +parsereg_table_size(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing reg table size value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_table_entry_count = (unsigned long) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + +/* We are guaranteed it's a table size command, parse it + and record the table size. +*/ +static int +parseaddress_size(char *cp, const char *fname, unsigned long lineno, + struct conf_internal_s *conf, struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + unsigned long val = 0; + int ok = FALSE; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (tok.tk_len == 0) { + printf("dwarfdump.conf error: " + "%s missing address size value %s line %lu", + comtab->name, fname, lineno); + ++errcount; + return FALSE; + } + + ok = make_a_number(comtab->name, fname, lineno, &tok, &val); + + if (!ok) { + ++errcount; + return FALSE; + } + conf->conf_out->cf_address_size = (unsigned long) val; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + +/* We are guaranteed it's an endabi: command, parse it and + check we have the right abi. +*/ +static int +parseendabi(char *cp, const char *fname, + const char *abiname, unsigned long lineno, + struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + int res = 0; + + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + if (strcmp(abiname, tok.tk_data) != 0) { + printf("%s error: " + "mismatch abi name %s (here) vs. %s (beginabi:) %s line %lu\n", + comtab->name, tok.tk_data, abiname, fname, lineno); + ++errcount; + return FALSE; + } + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} +static int +parseincludeabi(char *cp, const char *fname, unsigned long lineno, + char **abiname_out, + struct comtable_s *comtab) +{ + size_t clen = comtab->namelen; + struct token_s tok; + char *name = 0; + int res = FALSE; + + cp = cp + clen + 1; + cp = get_token(cp, &tok); + name = makename(tok.tk_data); + + *abiname_out = name; + res = ensure_has_no_more_tokens(cp, fname, lineno); + return res; +} + + + + +/* Return TRUE if we succeeded and filed in *out. + Return FALSE if we failed (and fill in nothing). + beginabi: <abiname> + reg: <regname> <dwarf regnumber> + frame_interface: <integer value 2 or 3> + cfa_reg: <number> + initial_reg_value: <number: normally 1034 or 1035 > + reg_table_size: <size of table> + endabi: <abiname> + + We are positioned at the start of a beginabi: line when + called. + +*/ +static int +parse_abi(FILE * stream, const char *fname, const char *abiname, + struct conf_internal_s *conf_internal, + unsigned long lineno, + unsigned int nest_level) +{ + struct dwconf_s *localconf = conf_internal->conf_out; + char buf[1000]; + int comtype = 0; + + static int first_time_done = 0; + struct comtable_s *comtabp = 0; + + if( nest_level > MAX_NEST_LEVEL) { + ++errcount; + printf("dwarfdump.conf: includeabi nest too deep in %s at line %lu\n", + fname, lineno); + return FALSE; + } + + + if (first_time_done == 0) { + finish_comtable_setup(); + first_time_done = 1; + } + + for (; !feof(stream);) { + char *line = 0; + + /* long loffset = ftell(stream); */ + line = fgets(buf, sizeof(buf), stream); + if (!line) { + ++errcount; + printf + ("dwarfdump: end of file or error before endabi: in %s, line %lu\n", + fname, lineno); + return FALSE; + } + ++lineno; + line = skipwhite(line); + comtype = which_command(line, &comtabp); + switch (comtype) { + case LT_ERROR: + ++errcount; + printf + ("dwarfdump: Unknown text in %s is \"%s\" at line %lu\n", + fname, line, lineno); + break; + case LT_COMMENT: + break; + case LT_BLANK: + break; + case LT_BEGINABI: + if (conf_internal->beginabi_lineno > 0) { + ++errcount; + printf + ("dwarfdump: Encountered beginabi: when not expected. " + "%s line %lu previous beginabi line %lu\n", fname, + lineno, conf_internal->beginabi_lineno); + } + 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; + printf + ("dwarfdump: Encountered duplicate frame_interface: " + "%s line %lu previous frame_interface: line %lu\n", + fname, lineno, conf_internal->frame_interface_lineno); + } + 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) { + printf("dwarfdump: Encountered duplicate cfa_reg: " + "%s line %lu previous cfa_reg line %lu\n", + fname, lineno, conf_internal->cfa_reg_lineno); + ++errcount; + } + 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) { + printf + ("dwarfdump: Encountered duplicate initial_reg_value: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + ++errcount; + } + 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; + printf + ("dwarfdump: Encountered duplicate same_val_reg: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + } + 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; + printf + ("dwarfdump: Encountered duplicate undefined_val_reg: " + "%s line %lu previous initial_reg_value: line %lu\n", + fname, lineno, conf_internal->initial_reg_value_lineno); + } + 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) { + printf("dwarfdump: duplicate reg_table_size: " + "%s line %lu previous reg_table_size: line %lu\n", + fname, lineno, conf_internal->reg_table_size_lineno); + ++errcount; + } + 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) { + printf("dwarfdump: more registers named than " + " in %s ( %lu named vs %s %lu) %s line %lu\n", + abiname, (unsigned long) conf_internal->regcount, + name_reg_table_size, + (unsigned long) localconf->cf_table_entry_count, + fname, (unsigned long) lineno); + ++errcount; + } + return TRUE; + case LT_ADDRESS_SIZE: + if (conf_internal->address_size_lineno > 0) { + printf("dwarfdump: duplicate address_size: " + "%s line %lu previous address_size: line %lu\n", + fname, lineno, conf_internal->address_size_lineno); + ++errcount; + } + conf_internal->address_size_lineno = lineno; + parseaddress_size(line, fname, + lineno, conf_internal, comtabp); + break; + case LT_INCLUDEABI: { + char *abiname_inner = 0; + unsigned long abilno = conf_internal->beginabi_lineno; + int ires = 0; + ires = parseincludeabi(line,fname,lineno, &abiname_inner,comtabp); + if(ires == FALSE) { + return FALSE; + } + /* 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: + printf + ("dwarfdump internal error, impossible line type %d %s %lu \n", + (int) comtype, fname, lineno); + exit(1); + + } + } + ++errcount; + printf("End of file, no endabi: found. %s, line %lu\n", + fname, lineno); + return FALSE; +} + +/* MIPS/IRIX frame register names. + For alternate name sets, use dwarfdump.conf or + revise dwarf.h and libdwarf.h and this table. +*/ +static char *regnames[] = { + "cfa", + "r1/at", "r2/v0", "r3/v1", + "r4/a0", "r5/a1", "r6/a2", "r7/a3", + "r8/t0", "r9/t1", "r10/t2", "r11/t3", + "r12/t4", "r13/t5", "r14/t6", "r15/t7", + "r16/s0", "r17/s1", "r18/s2", "r19/s3", + "r20/s4", "r21/s5", "r22/s6", "r23/s7", + "r24/t8", "r25/t9", "r26/k0", "r27/k1", + "r28/gp", "r29/sp", "r30/s8", "r31", + + "$f0", "$f1", + "$f2", "$f3", + "$f4", "$f5", + "$f6", "$f7", + "$f8", "$f9", + "$f10", "$f11", + "$f12", "$f13", + "$f14", "$f15", + "$f16", "$f17", + "$f18", "$f19", + "$f20", "$f21", + "$f22", "$f23", + "$f24", "$f25", + "$f26", "$f27", + "$f28", "$f29", + "$f30", "$f31", + "ra", "slk", +}; + + +/* Naming a few registers makes printing these just + a little bit faster. +*/ +static char *genericregnames[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", + "r20" +}; + +/* 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) +{ + unsigned generic_table_count; + config_file_data->cf_abi_name = ""; + config_file_data->cf_config_file_path = ""; + 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; + config_file_data->cf_regs = genericregnames; + generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_named_regs_table_size = generic_table_count; + config_file_data->cf_regs_malloced = 0; +} + +/* 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) +{ + unsigned long base_table_count = + sizeof(regnames) / sizeof(regnames[0]); + + memset(config_file_data, 0, sizeof(*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; + config_file_data->cf_regs = regnames; + config_file_data->cf_named_regs_table_size = base_table_count; + config_file_data->cf_regs_malloced = 0; + if (config_file_data->cf_table_entry_count != base_table_count) { + printf("dwarfdump: improper base table initization, " + "header files wrong: " + "DW_REG_TABLE_SIZE %u != string table size %lu\n", + (unsigned) DW_REG_TABLE_SIZE, + (unsigned long) base_table_count); + exit(1); + } + return; +} + +/* A 'generic' ABI. For up to 1200 registers. + Perhaps cf_initial_rule_value should be d + UNDEFINED VALUE (1034) instead, but for the purposes of + getting the dwarfdump output correct + either will work. +*/ +void +init_generic_config_1200_regs(struct dwconf_s *config_file_data) +{ + unsigned long generic_table_count = + sizeof(genericregnames) / sizeof(genericregnames[0]); + config_file_data->cf_interface_number = 3; + config_file_data->cf_table_entry_count = 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; + config_file_data->cf_regs = genericregnames; + config_file_data->cf_named_regs_table_size = generic_table_count; + config_file_data->cf_regs_malloced = 0; +} + +/* Print the 'right' string for the register we are given. + Deal sensibly with the special regs as well as numbers + we know and those we have not been told about. + +*/ +void +print_reg_from_config_data(Dwarf_Signed reg, + struct dwconf_s *config_data) +{ + char *name = 0; + + if (reg == config_data->cf_cfa_reg) { + fputs("cfa",stdout); + return; + } + if (reg == config_data->cf_undefined_val) { + fputs("u",stdout); + return; + } + if (reg == config_data->cf_same_val) { + fputs("s",stdout); + return; + } + + if (config_data->cf_regs == 0 || + reg < 0 || + reg >= config_data->cf_named_regs_table_size) { + printf("r%" DW_PR_DSd "", (Dwarf_Signed) reg); + return; + } + name = config_data->cf_regs[reg]; + if (!name) { + /* Can happen, the reg names table can be sparse. */ + printf("r%" DW_PR_DSd "", (Dwarf_Signed) reg); + return; + } + fputs(name,stdout); + return; +} |