diff options
Diffstat (limited to 'sbe/tools/ppetracepp/ppetracepp.C')
-rwxr-xr-x | sbe/tools/ppetracepp/ppetracepp.C | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/sbe/tools/ppetracepp/ppetracepp.C b/sbe/tools/ppetracepp/ppetracepp.C new file mode 100755 index 00000000..d0bf5c09 --- /dev/null +++ b/sbe/tools/ppetracepp/ppetracepp.C @@ -0,0 +1,949 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: sbe/tools/ppetracepp/ppetracepp.C $ */ +/* */ +/* OpenPOWER sbe Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2015,2016 */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ + +/* +# *** ppetracepp - a fsp/common Linux trace pre processor +# this one replaces the trace strings by the corresponding hash value +# (i.e. the complete call to trace_ppe_hash is replaced) + +# *** Usage +# +# prepend compiler call with the call of this pre processor, i.e if you have +# $(CC) $(CFLAGS) -o $@ $< +# in your Makefile change it to this: +# ppetracepp $(CC) $(CFLAGS) -o $@ $< +# ppetracepp will use "$(CC) -E" to call the C pre processor "cpp". +# you can set a env var "REALCPP" to the name of a program to select +# a different programm as cpp +# +# ppetracepp creates a file "$target.ppe.hash" with the trace strings and the hash values. +# +# to enable debug mode set envvar PPETRACEPPDEBUG to 1 or give '-d' as first arg + +# *** Change History +# +# 2003-02-26 RBa created from scratch +# 2003-02-28 RBa add C++ support (C++ interface uses own type for the hash) +# 2003-05-28 RBa if cc should link instead of compile just call compiler +# 2003-07-11 AGe Change search alg. slightly and put just format back +# 2003-07-25 RBa just call gcc if called to link instead to compile +# eat argument for option -x +# 2003-11-26 RBa fix c/c++ algo: compile as c++ if realcc=*g++ +# 2004-02-02 RBa remove explicit test whether source file is readable +# it is obsolete and might lead to an error if afs is used +# 2004-02-13 RBa add support for dependency generation (-MD/-MG, -MF) +# don't prepend './' to object filename +# 2006-04-19 RBa rewrite trace_ppe_write_all support, handle C and C++ the same +# 2006-05-24 RBa fix handling of missing -o ; add TRAC_PPVER for macro/API version +# 2006-09-15 RBa add handling of \" in trace format strings ; reduce non-error output +# put object file in current dir if no -o given +# 2007-03-22 RBa handle more gcc options (-i) ; protect " in call to shell +# store output of cpp as "unmodified" output for debug +# only write string/hash file if strings found +# 2012-09-24 hlava Rewritten as C program for better build performance (was perl) +*/ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <string> +#include <time.h> +#include <fcntl.h> +#include <map> +#include <vector> +#include <unistd.h> +#include <sys/types.h> +typedef u_int32_t u32 ; +typedef u_int8_t u8 ; +#include <jhash.h> + +using namespace std; + +static string version = "2.0"; +static string macro_version = "1"; + +static bool debug = false; +#define dprintf(format, ...) if (debug) { printf(format, ##__VA_ARGS__); fflush(stdout); } +static map<string,string> hashtab; +static string hashtype; +static string hashtype_suffix; + +static string tmp; +static string cmd; +static FILE* CPP = NULL; // pipe from preprocessor +static FILE* CC = NULL; // pipe to compiler +static FILE* DEBUG = NULL; +static FILE* DEBUGIN = NULL; + +//***************************************************************************** +// replace_substr +//***************************************************************************** +void replace_substr(std::string& str, const std::string& oldStr, const std::string& newStr) +{ + size_t pos = 0; + while((pos = str.find(oldStr, pos)) != std::string::npos) + { + str.replace(pos, oldStr.length(), newStr); + pos += newStr.length(); + } + +} + +//***************************************************************************** +// fileparse +//***************************************************************************** +void fileparse(const string& in_str, string& name, string& dir, string& suff) +{ + string str(in_str); + size_t pos; + name = ""; + dir = ""; + suff = ""; + pos = str.find_last_of('.'); + if (pos != string::npos) + { + suff = str.substr(pos); + str = str.substr(0, pos); + } + pos = str.find_last_of('/'); + if (pos != string::npos) + { + name = str.substr(pos+1); + str = str.substr(0, pos+1); + } + dir = str; +} + +static const size_t TRACE_PPE_HASH_LEN = 13; +//***************************************************************************** +// chop_up_line +//***************************************************************************** +bool chop_up_line(string& in_line, string& prefix, string& strings, string& salt, string& suffix) +{ + // First see if this line matches the pattern we're looking for + // Since this will return false 95%+ of the time this function it called, we do it + // before doing any other init for performance reasons. + size_t pos = in_line.find("trace_ppe_hash"); + if (pos == string::npos) { return(false); } + + // trace_ppe_hash ( "..." ".." "..." , 2 ) + // regex: PREFIX 'trace_ppe_hash' space '(' space STRINGS space ',' space NUMBER space ')' SUFFIX + // STRINGS: '"' .* '"' space? + + + // Original perl magic incantation: + // while($line =~ m/^(.*?)trace_ppe_hash\s*\(\s*((".*?(?<!\\)"\s*)+),\s*(-?\d+)\s*\)(.*)$/) { + // ($prefix, $strings, $salt, $suffix) = ($1, $2, $4, $5); + // + // Decrypting the magic pattern matching... + // (.*?) => $1 = everything up to the word "trace_ppe_hash" + // trace_ppe_hash = delimiter + // \s*\(\s* = delimiter = <0-n whitespace chars>, left paren, <0-n whitespace chars> + // ((".*?(?<!\\)"\s*)+) => $2 = double-quote, some chars up to last closing double-quote ($3 used for nested regex) + // ,\s* = delimiter = comma followed by some whitespace + // (-?\d+)\s*\)(.*) => $4 and $5 + // $/) = end of the line input string + string line(in_line); + prefix = ""; + strings = ""; + salt = ""; + suffix = ""; + size_t pos1; + size_t pos2; + size_t pos3; + + pos1 = pos + 14; // pos1 = after "trace_ppe_hash" + pos2 = line.find("(", pos1); + if (pos2 == string::npos) { return(false); } + ++pos2; + pos3 = line.find("\"", pos2); + if (pos3 == string::npos) { return(false); } + dprintf("--------\nchop_up_line: Passed basic checks. line= %s\n", line.c_str()); + dprintf("pos1=%d, pos2=%d, pos3=%d\n", pos1, pos2, pos3); + if ((pos1 != (pos2-1)) && (line.find_first_not_of(" \t", pos1, (pos2-pos1)+1) != string::npos)) { return(false); } //non-whitespace? + if ((pos2 != pos3) && (line.find_first_not_of(" \t", pos2, (pos3-pos2)) != string::npos)) { return(false); } //non-whitespace? + + // Get the prefix data + dprintf(">chop_up_line(\"%s\",...)\n", line.c_str()); + prefix = line.substr(0, pos); + line = line.substr(pos + TRACE_PPE_HASH_LEN); + dprintf(" prefix=\"%s\"\n", prefix.c_str()); + + // Get the strings and join/fix them: Store all strings between paired double-quotes up to the + // first comma not inside a string + pos = line.find_first_of('('); + if (pos == string::npos) { return(false); } + line = line.substr(pos + 1); + strings = ""; + while(!line.empty()) + { + pos = line.find_first_of(','); + pos1 = line.find_first_of('"'); + if ((pos1 == string::npos) || ((pos != string::npos) && (pos < pos1))) { break; } // found comma before next quote + pos2 = line.find_first_of('"', (pos1+1)); + if (pos2 == string::npos) { return(false); } // unbalanced quotes! + while(line[pos2-1] == '\\') // skip escaped quotes in the string (they're not the ending quote) + { + pos2 = line.find_first_of('"', (pos2+1)); + if (pos2 == string::npos) { return(false); } // unbalanced quotes! + } + if (!strings.empty()) { strings += " "; } + strings += line.substr(pos1, (pos2-pos1)+1); + line = line.substr(pos2+1); + } + replace_substr(strings, "\" \"", ""); + replace_substr(strings, "\\\"", "ESCAPEDQUOTE"); + replace_substr(strings, "\"", ""); + replace_substr(strings, "ESCAPEDQUOTE", "\""); + // Remove trailing whitespace ah20130717 + pos = strings.find_last_not_of(" \t\n"); + if ((pos != string::npos) && (pos < (strings.length()-1))) + { + strings = strings.substr(0, pos+1); + } + + dprintf(" strings>%s<\n", strings.c_str()); + + // Get the salt + pos = line.find(","); + if (pos != string::npos) { line = line.substr(pos+1); } + pos = line.find_first_of(')'); + if (pos == string::npos) { return(false); } + salt = line.substr(0, pos); + line = line.substr(pos+1); + //dprintf(" salt=\"%s\"\n", salt.c_str()); + pos = salt.find_first_not_of(" \t\n"); + if (pos == string::npos) { return(false); } + salt = salt.substr(pos); + pos = salt.find_last_not_of(" \t\n"); + if (pos == string::npos) { return(false); } + salt = salt.substr(0, pos+1); + dprintf(" salt=\"%s\"\n", salt.c_str()); + + // Get the suffix (i.e. the rest) + suffix = line; + if (suffix[suffix.length()-1] == '\n') { suffix = suffix.substr(0, suffix.length()-1); } + dprintf(" suffix=\"%s\"\n<chop_up_line() returning true\n", suffix.c_str()); + + return(true); +} + +//***************************************************************************** +// get_format_string +//***************************************************************************** +int get_format_string(const string& in_str, string& format) +{ + int format_salt = 0; + size_t pos; + size_t pos_end; + string str(in_str); + // (@format_param) = ($strings =~ /(%[#0\- +'I]*\d*(?:\.\d*)?[hlLqjzt]*[diouxXeEfFgGaAcsCSpn])/g); + // $format = join(',', @format_param); + // Decrypting the regular expression magic... + // (%[#0\- +'I]*\d*(?:\.\d*)?[hlLqjzt]*[diouxXeEfFgGaAcsCSpn]) + + format = ""; + while(!str.empty()) + { + pos = str.find("%"); + if (pos == string::npos) { break; } + if (pos == (str.length()-1)) { break; } // last char in string? just skip it + if (str[pos+1] == '%') // double percent sign? just skip first one + { + str = str.substr(pos+1); + continue; + } + pos_end = str.find_first_of("cdieEfgGosuxXpn", pos); // find formatting specifier + if (pos_end == string::npos) + { + fprintf(stderr, "ERROR: ppetracepp could not parse trace formatting string \"%s\" in \"%s\"\n", str.c_str(), in_str.c_str()); + break; + } + + if (!format.empty()) + format += ","; + format += str.substr(pos, (pos_end-pos)+1); + ++format_salt; + + str = str.substr(pos_end+1); + } + // Correct for escaped percent signs + string temp_str(in_str); + while((pos = temp_str.find("%%")) != string::npos) + { + if (pos < (temp_str.length()-2)) // Not the last thing in the string? + { + dprintf(" decrementing salt value %d\n", format_salt); + --format_salt; + temp_str = temp_str.substr(pos+2); + } + else + { + temp_str = ""; + } + } + + return(format_salt); +} + +#define BUF_SIZE 40 +//***************************************************************************** +// get_hash +//***************************************************************************** +void get_hash(const string& i_str, const unsigned int salt_num, string& hash32, string& hash16) +{ + string str(i_str); + unsigned int hash_num = 0; + char buf[BUF_SIZE]; + + hash16 = ""; + hash32 = ""; + dprintf(">get_hash(\"%s\",%d)\n", str.c_str(), salt_num); + + // Call jhash function to get the hash value + hash_num = jhash((void*)str.c_str(), str.length(), salt_num); + dprintf("jhash() returned: %u\n", hash_num); + sprintf(buf, "%u", hash_num & 0x0000ffff); + hash16 = buf; + sprintf(buf, "%u", ((salt_num << 16) | (hash_num & 0x0000ffff))); + hash32 = buf; + + // validate the hash value + size_t pos = hash32.find_first_not_of("0123456789"); + if (pos != string::npos) + { + fprintf(stderr, "trexhash error: %s\n", hash32.c_str()); + fprintf(stderr, "for call <<%s>>\n", cmd.c_str()); + exit(1); + } + +//removing this since it doesn't seem to have any affect on the output +#if 0 + // If hash is empty, use the sum of the ord values in the original string + if ((hash == "")||(hash == "0")) + { + unsigned int len = str.length(); + unsigned int hash_num = 0; + //unsigned char conv_buf[2] = { '\0', '\0' }; + u_int8_t conv_num; + for (unsigned int i=0; i < len; ++i) + { + //conv_buf[0] = str[i]; + conv_num = (u_int8_t)str[i]; + hash_num += (unsigned int)conv_num; + } + } +#endif + + dprintf("<get_hash(\"%s\",%d) returned hash: %s\n", str.c_str(), salt_num, hash32.c_str()); +} + +//***************************************************************************** +// parse_line +//***************************************************************************** +void parse_line(map<string,string>& rhash, string& line, string& out_line) +{ + // NOTE: "line" arg may get modified by this function! Caller must not assume it's unchanged. + string format; + string prefix; + string strings; + string tmp; + string salt; + string hash16; + string hash32; + int salt_num; + int format_salt; + string suffix; + string write_all_suffix; + size_t pos; + + out_line = ""; + // trace_ppe_hash ( "..." ".." "..." , 2 ) + // regex: PREFIX 'trace_ppe_hash' space '(' space STRINGS space ',' space NUMBER space ')' SUFFIX + // STRINGS: '"' .* '"' space? + + //while($line =~ m/^(.*?)trace_ppe_hash\s*\(\s*((".*?(?<!\\)"\s*)+),\s*(-?\d+)\s*\)(.*)$/) { + // Attempt to approximate the above amazing perl regex... + while( chop_up_line(line, prefix, strings, salt, suffix) ) + { + //dprintf("\n\nprefix = %s\nstrings = %s\nsalt = %s\nsuffix = %s\n", + // prefix.c_str(), strings.c_str(), salt.c_str(), suffix.c_str()); + // is this a trace_ppe_write_all call? + pos = prefix.find("trace_ppe_write_all"); + if (pos != string::npos) + { + // yes. replace trace_ppe_hash with hash value and reduced format string + format_salt = get_format_string(strings, format); + // reduced format string will be added after hash value + write_all_suffix = ",\" "; + write_all_suffix += format; + write_all_suffix += "\""; + + if (!salt.empty()) + { + salt_num = atoi(salt.c_str()); + } + else + { + salt_num = -1; + } + + if (salt_num == -1) + { + salt_num = format_salt; + } + else if (salt_num != format_salt) + { + fprintf(stderr, "ERROR: printf mismatch in '%s': TRACE says %d, format says %d args\n", + line.c_str(), salt_num, format_salt); + } + } + else + { + write_all_suffix = ""; + salt_num = atoi(salt.c_str()); + } + + // get the trex hash value for the strings + get_hash(strings, salt_num, hash32, hash16); + + // check for duplicate and store the mapping + if ((rhash.find(hash32) != rhash.end()) && (rhash[hash32] != strings)) + { + fprintf(stderr, "hash collision: two different strings give the same hash value '%s'\n", hash32.c_str()); + fprintf(stderr, "%s\n%s\n", strings.c_str(), rhash[hash32].c_str()); + // Not breaking the compilation here. This is same as if we get hash + // collision across files. As in SBE we are using mirroring, these + // hash collisions will take some time to resolve. Till that time, + // let us allow compilation of procedures. + //return; + } + rhash[hash32] = strings; + + // add the modified line to the output + tmp = prefix; + tmp += "("; + tmp += hashtype; + tmp += " "; + tmp += hash16; + tmp += hashtype_suffix; + tmp += ")"; + tmp += write_all_suffix; + out_line += tmp; + dprintf("changed call: %s...\n", tmp.c_str()); + line = suffix; + } + out_line += line; + if (out_line[out_line.length()-1] != '\n') + out_line += "\n"; +} + +//***************************************************************************** +// main +//***************************************************************************** +int main(int argc, char** argv) +{ + char* p_env = getenv("PPETRACEPPDEBUG"); + if (p_env) + debug = true; + + + int argi = 1; + string arg; + string optarg; + if (argc > 1) arg = argv[1]; + if ((argc < 2) || (arg == "-h")) + { + fprintf(stderr, "usage: %s realcompiler compileroptions -o target source\n", argv[0]); + exit(9); + } + string realcc(argv[argi++]); + string cctype("c++"); + bool optx_found = false; + + if (realcc == "-d") + { + debug = true; + realcc = argv[argi++]; + } + + // wait until -d options is handled before checking $debug + dprintf("ppetracepp version %s - API/macro version %s\n", version.c_str(), macro_version.c_str()); + + p_env = getenv("REALCPP"); + string realcpp; + if (p_env) + realcpp = p_env; + if (realcpp.empty()) + { + dprintf("cannot find cpp, using <realcompiler> -E\n"); + realcpp = realcc; + realcpp += " -E"; + } + dprintf("realcpp is %s\n", realcpp.c_str()); + +//------------------------------------------------------------------------------ +// parse all the arguments +//------------------------------------------------------------------------------ +string source; +string object; +vector<string> ccopts; +vector<string> cppopts; +bool dodeps = false; +string depfile; +string pfx; +string sfx; +int origargi = argi; +for( ; argi < argc; ++argi) +{ + arg = argv[argi]; + dprintf("Processing argv[%d]: \"%s\"\n", argi, arg.c_str()); + if (arg.length() > 2) + { + pfx = arg.substr(0,2); + sfx = arg.substr(arg.length()-2); + } + else + { + pfx = arg; + sfx = arg; + } + dprintf(" pfx: \"%s\" sfx: \"%s\"\n", pfx.c_str(), sfx.c_str()); + + if (pfx == "-o") + { + if (! object.empty()) + { + fprintf(stderr, "two -o options, aborting\n"); + exit(1); + } + if (arg.length() > 2) + { + object = sfx; + } + else + { + object = argv[++argi]; + } + dprintf("object is now %s\n", object.c_str()); + } + else if (arg == "-c") + { + // don't call cpp with -c, this is for the compiler + ccopts.push_back(arg); + dprintf("found -c option\n"); + } + else if (pfx == "-l") + { + // cpp doesn't need library arguments + cppopts.push_back(arg); + } + else if (pfx == "-i") + { + // option takes an argument, handle it too + optarg = argv[argi++]; + ccopts.push_back(arg); + ccopts.push_back(optarg); + cppopts.push_back(arg); + cppopts.push_back(optarg); + dprintf("found option '%s %s'\n", arg.c_str(), optarg.c_str()); + } + else if ((arg == "-L") || + (arg == "-I") || + (arg == "-x") || + (arg == "-b") || + (arg == "-B") || + (arg == "-V") || + (arg == "-D") || + (arg == "--param") || + (arg == "-MQ") || + (arg == "-MT")) + { + // option takes an argument, handle it too + optarg = argv[argi++]; + ccopts.push_back(arg); + ccopts.push_back(optarg); + cppopts.push_back(arg); + cppopts.push_back(optarg); + dprintf("found option '%s %s'\n", arg.c_str(), optarg.c_str()); + if (arg == "-x") + { + // option x sets the language - c or c++ + if ((optarg != "c") && (optarg != "c++") && (optarg != "assembler-with-cpp")) + { + fprintf(stderr, "cannot process language '%s', aborting\n", optarg.c_str()); + exit(1); + } + cctype = optarg; + optx_found = true; + } + } + else if ((arg == "-MD")||(arg == "-MG")) + { + // gen deps + dodeps = true; + dprintf("found %s, creating dependencies\n", arg.c_str()); + } + else if (arg == "-MF") + { + // set dependencies file + depfile = argv[argi++]; + dprintf("set dependencies file to '%s'\n", depfile.c_str()); + } + else if (arg[0] == '-') + { + // arg starts with - so it's an option + ccopts.push_back(arg); + cppopts.push_back(arg); + dprintf("found option '%s'\n", arg.c_str()); + } + else if ((sfx == ".a") || + (sfx == ".o")) + { + // an object or archive, ignore this but give it to cc + ccopts.push_back(arg); + dprintf("found object/archive '%s'\n", arg.c_str()); + } + else if ((sfx == ".c") || + (sfx == ".C") || + (sfx == ".S") || + (arg.substr(arg.length()-4) == ".cpp") || + (arg.substr(arg.length()-4) == ".cxx")) + { + // the source file(s). we should only get one + if (!source.empty()) + { + fprintf(stderr, "don't know to handle two source files, aborting\n"); + exit(1); + } + source = arg; + // put the - (for read-from-stdin) where the source file was + // (order is important!) + ccopts.push_back("-"); + dprintf("found source file %s\n", source.c_str()); + } + else if (access(arg.c_str(), F_OK)) + { + // option but not a file, an unknown option? + ccopts.push_back(arg); + cppopts.push_back(arg); + dprintf("found unknown option '%s'\n", arg.c_str()); + } +} + +//------------------------------------------------------------------------------ +// set other parameters based on arguments specified +//------------------------------------------------------------------------------ +if (source.empty()) +{ + // this might be a call to link a program instead of compile a source (or asm source) + dprintf("NOTME: starting as cc '%s ...'\n", realcc.c_str()); + execvp(realcc.c_str(), &(argv[origargi])); + fprintf(stderr, "ERROR: returned from execvp() call to run %s\n", realcc.c_str()); +} +if (object.empty()) +{ + dprintf("no object file given, default to source name\n"); + // gcc builds object name from source name if no -o given, replacing + // suffix with .o. The file is placed in the current directory, + // not in the source directory! + string n; + string d; + string s; + fileparse(source, n, d, s); + if (!n.empty() && !s.empty()) + { + object = n + ".o"; + dprintf("tracpp: guessing object name %s\n", object.c_str()); + dprintf(" from source name %s\n", source.c_str()); + } + else + { + fprintf(stderr, "Unable to determine Source File Name\n"); + exit(1);; + } +} + +// set value of trace hash according to language +// check source file extension if no explicit -x option given +if (!optx_found) +{ + if (realcc.find("g++") != string::npos) + { + dprintf("compiler language: C++ (from compiler name)\n"); + cctype = "c++"; + } + else + { + if (source.substr(source.length()-2) == ".c") + { + dprintf("compiler language: C (from source file extension)\n"); + cctype = "c"; + } + else if (source.substr(source.length()-2) == ".S") + { + dprintf("compiler language: assembly (from source file extension)\n"); + cctype = "assembler-with-cpp"; + } + else + { + dprintf("compiler language: C++ (default)\n"); + cctype = "c++"; + } + } +} +else +{ + dprintf("compiler language: %s (from option '-x')\n", cctype.c_str()); +} + +if (cctype == "c") +{ + hashtype = "(unsigned short)"; + hashtype_suffix = "U"; +} +else if (cctype == "assembler-with-cpp") +{ + hashtype = ""; + hashtype_suffix = ""; +} +else +{ + hashtype = "(trace_hash_val)"; + hashtype_suffix = "U"; +} +// define TRAC_PPETRACEPP for macros +tmp = "-DTRAC_PPETRACEPP -DTRAC_PPVER="; +tmp += macro_version; +cppopts.push_back(tmp); +if (dodeps) +{ + if (depfile.empty()) + { + if ((p_env = getenv("DEPENDENCIES_OUTPUT")) != NULL) + { + depfile = p_env; + } + else if ((p_env = getenv("SUNPRO_DEPENDENCIES")) != NULL) + { + depfile = p_env; + } + else + { + depfile = object; + if (depfile.substr(depfile.length()-2) == ".o") + { + depfile = depfile.substr(0, depfile.length()-2); + depfile += ".d"; + } + } + } + tmp = "-MD -MF "; + tmp += depfile; + cppopts.push_back(tmp); +} + +//------------------------------------------------------------------------------ +// start cpp +//------------------------------------------------------------------------------ +cmd = realcpp; +for(vector<string>::iterator p = cppopts.begin(); p != cppopts.end(); ++p) +{ + cmd += " "; + cmd += *p; +} +cmd += " "; +cmd += source; +cmd += " -o-"; +dprintf("starting as cpp '%s'\n", cmd.c_str()); +CPP = popen(cmd.c_str(), "r"); +if (CPP == NULL) +{ + fprintf(stderr, "cannot start cpp '%s'\n", realcpp.c_str()); + perror(""); + exit(1); +} + +//------------------------------------------------------------------------------ +// start cc. manually set language as source file extension not available to cc +//------------------------------------------------------------------------------ +string type_str = ""; +if (!optx_found) +{ + // no option -x given by caller, set manually + type_str = "-x "; + type_str += cctype; +} +cmd = realcc; +cmd += " "; +cmd += type_str; +for(vector<string>::iterator p = ccopts.begin(); p != ccopts.end(); ++p) +{ + cmd += " "; + cmd += *p; +} +cmd += " -o "; +cmd += object; +dprintf("starting as cc '%s'\n", cmd.c_str()); +CC = popen(cmd.c_str(), "w"); +if (CC == NULL) +{ + fprintf(stderr, "cannot start cc '%s'\n", realcc.c_str()); + perror(""); + exit(1); +} + +string modifiedfile; +string unmodifiedfile; +if (debug) +{ + modifiedfile = object + ".debug"; + DEBUG = fopen(modifiedfile.c_str(), "w"); + if (DEBUG == NULL) + { + string msg = "cannot open file "; + msg += modifiedfile; + perror(msg.c_str()); + modifiedfile = ""; + } + else + { + fprintf(stderr, "writing preprocessed source to %s\n", modifiedfile.c_str()); + } + unmodifiedfile = object + ".debug_in"; + DEBUGIN = fopen(unmodifiedfile.c_str(), "w"); + if (DEBUGIN == NULL) + { + string msg = "cannot open file "; + msg += unmodifiedfile; + perror(msg.c_str()); + unmodifiedfile = ""; + } + else + { + fprintf(stderr, "writing unprocessed source to %s\n", unmodifiedfile.c_str()); + } +} + +string oldline; +string newline; +static const int MAX_BUFFER = 51200; +char buf[MAX_BUFFER]; +while (!feof(CPP)) +{ + if (fgets(buf, MAX_BUFFER, CPP) != NULL) + { + oldline = buf; + if (DEBUGIN) { fprintf(DEBUGIN, "%s", oldline.c_str()); } + parse_line(hashtab, oldline, newline); + //#print "oldline = $oldline"; + //#print "newline = $newline"; + if (newline.empty()) + { + fprintf(stderr, "hash error in/with file %s\n", source.c_str()); + exit(1); + } + //#print "newline = $newline\n"; + fprintf(CC, "%s", newline.c_str()); + if (DEBUG) { fprintf(DEBUG, "%s", newline.c_str()); } + } +} +if (DEBUG) { fclose(DEBUG); } +if (DEBUGIN) { fclose(DEBUGIN); } +int cmd_rc = pclose(CPP); +if (cmd_rc) +{ + fprintf(stderr, "error from cpp\n"); + if (cmd_rc & 127) + { + fprintf(stderr, "cpp got signal %d\n", (cmd_rc & 127)); + exit(1); + } + else if (cmd_rc >> 8) + { + fprintf(stderr, "cpp returned %d\n", (cmd_rc >> 8)); + exit(cmd_rc >> 8); + } +} +cmd_rc = pclose(CC); +if (cmd_rc) +{ + fprintf(stderr, "error from cc\n"); + if (cmd_rc & 127) + { + fprintf(stderr, "cc got signal %d\n", (cmd_rc & 127)); + exit(1); + } + else if (cmd_rc >> 8) + { + fprintf(stderr, "cc returned %d\n", (cmd_rc >> 8)); + exit(cmd_rc >> 8); + } +} + +if (!hashtab.empty()) +{ + string stringfile = object; + stringfile += ".ppe.hash"; + // open trace string file + FILE* TRC = fopen(stringfile.c_str(), "w"); + if (TRC == NULL) + { + fprintf(stderr, "cannot write trace string file '%s'\n", stringfile.c_str()); + exit(1); + } + dprintf("Writing to file %s\n", stringfile.c_str()); + + string pwd; + FILE* PWD = popen("pwd", "r"); + fgets(buf, MAX_BUFFER, PWD); + pwd = buf; + pclose(PWD); + time_t tt = time(NULL); + sprintf(buf, "%s", asctime(localtime(&tt))); + buf[strlen(buf)-1] = '\0'; // chop off extra newline + fprintf(TRC, "#FSP_TRACE_v2|||%s|||BUILD:%s", buf, pwd.c_str()); + + string srch_str = "||"; + srch_str += source; + int srch_str_len = srch_str.length(); + size_t pos; + for(map<string,string>::iterator p = hashtab.begin(); p != hashtab.end(); ++p) + { + pos = (p->second).find(srch_str); + if ((pos != string::npos) && ((pos + srch_str_len) == (p->second).length())) + { + // source file name is already part of the string + fprintf(TRC, "%s||%s\n", (p->first).c_str(), (p->second).c_str()); + } + else + { + fprintf(TRC, "%s||%s||%s\n", (p->first).c_str(), (p->second).c_str(), source.c_str()); + } + //#print TRC "$key||$source||$hashtab{$key}\n"; + } + fclose(TRC); +} +else +{ + dprintf("No trace calls/strings found, not writing hash file\n"); +} +} // end main |