Commit f92b0126 authored by Jason Hiser's avatar Jason Hiser 🚜

Merge branch 'master' of git.zephyr-software.com:opensrc/irdb-cookbook-examples

Conflicts:
	initialize_stack/initialize_stack_driver.cpp
parents 74e1d6e9 aad5c637
Pipeline #2573 passed with stages
in 11 minutes and 39 seconds
import os
#
# import the environment and clone it so we can make changes.
#
Import('env')
irdb_env=env.Clone()
irdb_env.Append(CXXFLAGS=" -std=c++11 -Wall -Werror -fmax-errors=2 " )
irdb_env.Append(LIBS= Split("irdb-core irdb-transform" ))
irdb_env.Append(CPPPATH= " $IRDB_SDK/include " )
irdb_env.Append(LIBPATH= Split(" "+os.environ['PEASOUP_HOME']+"/irdb-libs/lib "))
irdb_env.Replace(INSTALL_PATH=os.environ['PWD']+"/plugins_install" )
#
# These settings are recommended, but you can choose what you like
#
irdb_env.Append(CXXFLAGS=" -Wall -Werror -fmax-errors=2 " ) # be strict about syntax/warnings
irdb_env.Append(LIBS= Split("irdb-core irdb-transform" )) # link against core and transform libraries
irdb_env.Append(CPPPATH= " $IRDB_SDK/include " ) # be able to include the SDK files
irdb_env.Append(LIBPATH= Split(" $IRDB_LIBS " )) # this is where the libraries are.
irdb_env.Replace(INSTALL_PATH=os.environ['PWD']+"/plugins_install" ) # this is where to place plugins.
#
# export the new environment for children subconstructs
#
Export('irdb_env')
#
# include the child sconscript files.
#
dirs=Split("initialize_stack kill_deads stack_stamp")
libs = list()
for dir in dirs:
lib=irdb_env.SConscript(dir+"/SConscript", variant_dir='scons_build/'+dir)
libs = libs + lib
libs = libs + irdb_env.SConscript(dir+"/SConscript")
#
# And we are done
#
Return('libs')
import os
#
# create a basic scons environment
#
env=Environment()
#
# Include environment variables. These lines throw semi-readable errors if environment is not defined properly.
#
env.Replace(COOKBOOK_HOME=os.environ['COOKBOOK_HOME']) # add cookbook home var to env. for other scons files
env.Replace(IRDB_SDK=os.environ['IRDB_SDK']) # IRDB_SDK and IRDB_LIB by convention to find headers and libraries.
env.Replace(IRDB_LIBS=os.environ['IRDB_LIBS'])
# default build options
env.Replace(CFLAGS="-fPIC -Wall ")
env.Replace(CXXFLAGS="-fPIC -Wall ")
env.Replace(LINKFLAGS="-fPIC -Wall ")
# parse arguments
env.Replace(COOKBOOK_HOME=os.environ['COOKBOOK_HOME'])
env.Replace(IRDB_SDK=os.environ['IRDB_SDK'])
env.Replace(debug=ARGUMENTS.get("debug",0))
#
# Check for "debug=1" on the scons command line
#
env.Replace(debug=ARGUMENTS.get("debug",0)) # build in debug mode?
#
# Required: need these flag to appropriately include/link IRDB files.
#
env.Append(CXXFLAGS=" -std=c++11 ") # enable c++11
env.Append(LINKFLAGS=" -Wl,-unresolved-symbols=ignore-in-shared-libs ") # irdb libs may have symbols that resolve OK at runtime, but not linktime.
env.Append(LINKFLAGS=" -Wl,-unresolved-symbols=ignore-in-shared-libs ")
# if we are building in debug mode, use -g, else use -O
if int(env['debug']) == 1:
print "Setting debug mode"
env.Append(CFLAGS=" -g ")
......@@ -26,10 +35,10 @@ if int(env['debug']) == 1:
env.Append(SHLINKFLAGS=" -g ")
else:
print "Setting release mode"
env.Append(CFLAGS=" -O3 ")
env.Append(CXXFLAGS=" -O3 ")
env.Append(LINKFLAGS=" -O3 ")
env.Append(SHLINKFLAGS=" -O3 ")
env.Append(CFLAGS=" -O ")
env.Append(CXXFLAGS=" -O ")
env.Append(LINKFLAGS=" -O ")
env.Append(SHLINKFLAGS=" -O ")
Export('env')
......
......@@ -7,9 +7,13 @@ orig_dir=$(pwd)
# set env vars.
cd $CICD_MODULE_WORK_DIR/cookbook_test
source set_env_vars
cd $orig_dir
cd /tmp/cookbook_tmp
source set_env_vars
echo 'The plugins are:'
ls $(echo $PSPATH|sed "s/:/ /g")
# run tests
cd $PEASOUP_HOME/tests
make clean;
......
......@@ -14,6 +14,8 @@ main()
git submodule sync
git submodule update --init --recursive
time rsync -a --exclude='.git' $CICD_TO_TEST_DIR/ /tmp/cookbook_tmp
local orig_dir=$(pwd)
......@@ -31,9 +33,14 @@ main()
dropdb $PGDATABASE 2>/dev/null || true
./postgres_setup.sh
cd $orig_dir
cd /tmp/cookbook_tmp
source set_env_vars
scons -j 3
echo 'The plugins are:'
ls $(echo $PSPATH|sed "s/:/ /g")
}
main "$@"
......
......@@ -12,7 +12,7 @@ main()
whoami
env|grep CICD
rm -rf $CICD_MODULE_WORK_DIR/cookbook_test
rm -rf $CICD_MODULE_WORK_DIR/cookbook_test /tmp/cookbook_tmp
fi
}
......
......@@ -4,6 +4,8 @@ set -x
cd $CICD_MODULE_WORK_DIR/cookbook_test
source set_env_vars
cd /tmp/cookbook_tmp
source set_env_vars
cd $PEASOUP_HOME/examples/cpp-examples
./test_quick.sh
import os
# import and create a copy of the environment so we don't screw up anyone elses env.
# import and create a copy of the environment so we don't mess
# up anyone else's env.
Import('irdb_env')
myenv=irdb_env.Clone()
# set input files and output program name
files=Glob( Dir('.').srcnode().abspath+"/*.cpp")
files=Glob( Dir('.').srcnode().abspath+"/*.cpp" )
pgm_name="initialize_stack.exe"
# build, install and return the program.
# build, install and return the program by default.
pgm=irdb_env.Program(pgm_name, files)
install=myenv.Install("$INSTALL_PATH/", pgm)
Default(install)
#
# and we're done
#
Return('install')
env=Environment()
Export('env')
lib=SConscript("SConscript")
......@@ -24,29 +24,35 @@
#include <algorithm>
#include <math.h>
// todo: remove these lines
#define MIN_STACK_FRAME_SIZE 0
#define MAX_STACK_FRAME_SIZE 8000000
#define ALLOF(a) begin(a), end(a)
using namespace std;
using namespace IRDB_SDK;
using namespace InitStack;
/*
* constructor
*/
InitStack_t::InitStack_t(FileIR_t *p_variantIR, const string& p_functionsFilename, int p_initValue, bool p_verbose)
:
Transform(p_variantIR),
m_initValue(p_initValue),
Transform(p_variantIR), // initialize the Transform class so things like insertAssembly and getFileIR() can be used
m_initValue(p_initValue), // member variable inits
m_verbose(p_verbose),
m_numTransformed(0)
{
if (p_functionsFilename=="")
{
cout << "Auto-initialize all functions" << endl;
m_funcsToInit = getFileIR()->getFunctions();
m_funcsToInit = getFileIR()->getFunctions(); // use all functions from the IR
}
else
{
cout << "Auto-initialize functions specified in: " << p_functionsFilename << endl;
readFunctionsFromFile(p_functionsFilename);
readFunctionsFromFile(p_functionsFilename); // read functions from file
}
}
......@@ -57,40 +63,45 @@ InitStack_t::InitStack_t(FileIR_t *p_variantIR, const string& p_functionsFilenam
*/
void InitStack_t::readFunctionsFromFile(const string &p_filename)
{
ifstream functionsFile(p_filename);
const auto &all_funcs=getFileIR()->getFunctions();
ifstream functionsFile(p_filename); // can't use auto decl here because of lack of copy constructor in ifstream class
if (!functionsFile.is_open()) throw runtime_error("Cannot open "+p_filename);
auto line = string();
while(functionsFile >> line)
{
for(auto f : getFileIR()->getFunctions())
const auto func_it=find_if(ALLOF(all_funcs), [&](const Function_t* f)
{
return f->getName() == line;
});
if(func_it!=end(all_funcs))
{
if (f && f->getName() == line)
{
m_funcsToInit.insert(f);
cout <<"Adding " << line << " to function list" << endl;
}
};
auto f=*func_it;
cout <<"Adding " << f->getName() << " to function list" << endl;
m_funcsToInit.insert(f);
}
}
}
/*
* Execute the transform.
* Execute the transform by transforming all to-transform functions
*
* preconditions: the FileIR is read as from the IRDB. valid file listing functions to auto-initialize
* postcondition: instructions added to auto-initialize stack for each specified function
*
*/
int InitStack_t::execute()
bool InitStack_t::execute()
{
// transform all functions
for(auto f : m_funcsToInit)
{
if (f == nullptr ) continue;
// todo: remove this
if (f->getName().substr(0, 1) == ".") continue; /* anh: ??? */
initStack(f);
};
}
// #ATTRIBUTE is a convention used to help find useful information in log files
cout << "#ATTRIBUTE InitStack::numTransformed=" << m_numTransformed << endl;
return m_numTransformed>0; // true means success
......@@ -109,6 +120,7 @@ void InitStack_t::initStack(Function_t* f)
const auto frame_size = f->getStackFrameSize();
const auto num_locs = static_cast<uint64_t> (ceil(frame_size / 4.0));
// todo: remove this line
if (frame_size <= MIN_STACK_FRAME_SIZE || frame_size >= MAX_STACK_FRAME_SIZE) return;
/* debug output */
......@@ -118,21 +130,24 @@ void InitStack_t::initStack(Function_t* f)
const auto entry = f->getEntryPoint();
if (!entry) return;
// log what we are doing
cout << "Function: " << f->getName() << " auto-initialize " << dec << num_locs << " stack memory locations (4 bytes at a time) with value = " << hex << m_initValue << endl;
/* determine the registers to use on x86-32 or x86-64 */
const auto sp_reg= getFileIR()->getArchitectureBitWidth()==64 ? "rsp" : "esp";
const auto scratch_reg= getFileIR()->getArchitectureBitWidth()==64 ? "r11" : "ecx";
// assume: flags dead at function entry.
// and insert these instructions at the start of the function
auto i=entry;
insertAssemblyBefore (i, string()+"mov ["+sp_reg+"+"+to_string(-f->getStackFrameSize()-100)+"], "+scratch_reg);
i = insertAssemblyAfter (i, string()+"mov "+scratch_reg+", -" + to_string(num_locs));
const auto L1 = i = insertAssemblyAfter (i, string()+"mov dword ["+sp_reg+"+"+scratch_reg+"*4-4], " + to_string(m_initValue));
i = insertAssemblyAfter (i, string()+"inc "+scratch_reg);
i = insertAssemblyAfter (i, string()+"jnz 0", L1);
i = insertAssemblyAfter (i, string()+"mov "+scratch_reg+", ["+sp_reg+"+"+to_string(-f->getStackFrameSize()-100)+"] ");
// assume: flags and scratch_reg are dead at function entry.
// insert these instructions at the start of the function (to initialize the stack frame before the function runs)
auto tmp=entry;
//todo: anh to comment assembly and explain -100 constant.
insertAssemblyBefore (tmp, string()+"mov ["+sp_reg+"+"+to_string(-f->getStackFrameSize()-100)+"], "+scratch_reg);
tmp = insertAssemblyAfter (tmp, string()+"mov "+scratch_reg+", -" + to_string(num_locs));
const auto L1 = tmp = insertAssemblyAfter (tmp, string()+"mov dword ["+sp_reg+"+"+scratch_reg+"*4-4], " + to_string(m_initValue));
tmp = insertAssemblyAfter (tmp, string()+"inc "+scratch_reg);
tmp = insertAssemblyAfter (tmp, string()+"jnz 0", L1); // jnz to L1
tmp = insertAssemblyAfter (tmp, string()+"mov "+scratch_reg+", ["+sp_reg+"+"+to_string(-f->getStackFrameSize()-100)+"] ");
m_numTransformed++;
}
......@@ -24,34 +24,53 @@
#include <irdb-core>
#include <irdb-transform>
//
// Put the transform in its own namespace
// just to keep the header files easy to read.
// This is not an IRDB transform requirement.
//
namespace InitStack
{
using namespace std;
using namespace IRDB_SDK;
// the actual transform.
//
// This class handles initializing stack frames to a constant value
//
class InitStack_t : public Transform
{
public:
// construct an object
InitStack_t(
FileIR_t *p_variantIR,
const string& p_functionFilename,
int initValue = 0,
bool p_verbose = false
FileIR_t *p_variantIR, // the FileIR object to transform
const string& p_functionFilename, // the name of a file with functions to transform. "" -> no file and transform all functions
int initValue = 0, // the value to write when initializing the stack
bool p_verbose = false // use verbose logging?
);
int execute();
private:
// execute the transform
// input: m_funcsToInit the set of functions to transform, the fileIR to transform
// output: the transformed fileIR, with extra instructions to init stack frames
// return value: true -> success, false -> fail
bool execute();
private: // methods
// read in the given file full of function names to transform (called from constructor)
// input: the filename and FileIR to transform
// output: m_funcsToInit with the functions listed in the file
void readFunctionsFromFile(const string &p_filename);
void initStack(Function_t* f);
private:
set<Function_t*> m_funcsToInit;
// initialize the stack for a given function
// input: the fileIR to transform
// output: the transformed fileIR
void initStack(Function_t* f);
int m_initValue;
bool m_verbose;
int m_numTransformed;
private: // data
set<Function_t*> m_funcsToInit; // the functions whose stacks this object should initialize
int m_initValue; // the value with which to init the stack.
bool m_verbose; // do verbose logging
int m_numTransformed; // stats about how many functions that this object has transformed
};
}
......
/* fix copyright headers in all files */
/* fix variable name schema (camelcase? underscores? p_'s m_'s */
/*
* Copyright (c) 2016, 2017 - University of Virginia
*
......@@ -26,13 +31,13 @@ using namespace std;
using namespace IRDB_SDK;
using namespace InitStack;
void usage(char* name)
void usage(char* p_name)
{
cerr<<"Usage: "<<name<<" <variant_id>\n";
cerr<<"\t[--functions <file> | -f <file>] Read in the functions to auto-initialize"<<endl;
cerr<<"\t[--initvalue <value> | -i <value>] Specify stack initialization value (default=0)"<<endl;
cerr<<"\t[--verbose | -v] Verbose mode "<<endl;
cerr<<"[--help,--usage,-?,-h] Display this message "<<endl;
cerr << "Usage: " << p_name << " <variant_id>\n";
cerr << "\t[--functions <file> | -f <file>] Read in the functions to auto-initialize " << endl;
cerr << "\t[--initvalue <value> | -i <value>] Specify stack initialization value (default=0)" << endl;
cerr << "\t[--verbose | -v] Verbose mode " << endl;
cerr << "\t[--help,--usage,-?,-h] Display this message " << endl;
}
......@@ -45,16 +50,16 @@ int main(int argc, char **argv)
}
// constant parameters read from argv
const auto programName = string(argv[0]);
const auto variantID = atoi(argv[1]);
const auto program_name = string(argv[0]);
const auto variantID = atoi(argv[1]);
// initial values of parameters to parse
auto verbose = false;
auto funcsFilename= string();
auto initValue = 0;
auto verbose = false;
auto funcs_filename = string();
auto init_value = 0;
// Parse some options for the transform
// parse some options for the transform
const char* short_opts="f:i:v?h";
struct option long_options[] = {
{"functions", required_argument, 0, 'f'},
{"initvalue", required_argument, 0, 'i'},
......@@ -64,7 +69,6 @@ int main(int argc, char **argv)
{0,0,0,0}
};
const char* short_opts="f:i:v?h";
while(true)
{
int index = 0;
......@@ -74,12 +78,12 @@ int main(int argc, char **argv)
switch(c)
{
case 'f':
funcsFilename=optarg;
cout<<"Reading file with function specifiers: "<<funcsFilename<<endl;
funcs_filename=optarg;
cout << "Reading file with function specifiers: " << funcs_filename << endl;
break;
case 'i':
initValue=strtoll(optarg, NULL, 0);
cout<<" Stack initialization value: "<<hex<<initValue<<endl;
init_value=strtoll(optarg, NULL, 0);
cout << " Stack initialization value: " << hex << init_value << endl;
break;
case 'v':
verbose=true;
......@@ -94,54 +98,63 @@ int main(int argc, char **argv)
}
}
/* setup the interface to the sql server */
// setup the interface to the sql server
auto pqxx_interface=pqxxDB_t::factory();
BaseObj_t::setInterface(pqxx_interface.get());
// create and read a variant ID from the database
auto pidp=VariantID_t::factory(variantID);
assert(pidp->isRegistered()==true);
auto success = false;
// create and read the main file's IR from the datatbase
auto this_file = pidp->getMainFile();
auto firp = FileIR_t::factory(pidp.get(), this_file);
auto url = this_file->getURL();
cout<<"Transforming "<<this_file->getURL()<<endl;
assert(firp && pidp);
// declare for later so we can return the right value
auto success=false;
// now try to load the IR and execute a transform
try
{
InitStack_t is(firp.get(), funcsFilename, initValue, verbose);
// Create and download the file's IR.
auto firp = FileIR_t::factory(pidp.get(), this_file);
// sanity
assert(firp && pidp);
// log
cout << "Transforming " << this_file->getURL() << endl;
// create and invoke the transform
InitStack_t is(firp.get(), funcs_filename, init_value, verbose);
success=is.execute();
// conditionally write the IR back to the database on success
if (success)
{
cout<<"Writing changes for "<<this_file->getURL()<<endl;
cout << "Writing changes for " << url << endl;
firp->writeToDB();
pqxx_interface->commit();
}
else
{
cout<<"Skipping (no changes) "<<this_file->getURL()<<endl;
cout << "Skipping write back on failure. " << url << endl;
}
}
catch (DatabaseError_t pnide)
catch (DatabaseError_t db_error)
{
cerr << programName << ": Unexpected database error: " << pnide << "file url: " << this_file->getURL() << endl;
// log any databse errors that might come up in the transform process
cerr << program_name << ": Unexpected database error: " << db_error << "file url: " << url << endl;
}
catch (...)
{
cerr << programName << ": Unexpected error file url: " << this_file->getURL() << endl;
}
// if any transforms for any files succeeded, we commit
if (success)
{
cout<<"Commiting changes...\n";
pqxx_interface->commit();
// log any other errors
cerr << program_name << ": Unexpected error file url: " << url << endl;
}
// Return success code to driver. 0=success, 1=warnings, 2=errors.
//
// return success code to driver (as a shell-style return value). 0=success, 1=warnings, 2=errors
//
return success ? 0 : 2;
}
......@@ -4,13 +4,25 @@ Import('irdb_env')
# import and create a copy of the environment so we don't screw up anyone elses env.
myenv=irdb_env.Clone()
#
# set the files to build and the output file name
#
files=Glob( Dir('.').srcnode().abspath+"/*.cpp")
pgm="kill_deads.exe"
pgm="libkill_deads.so"
#
# override the default libs as we need more libraries for this transform
#
libs=Split("irdb-core irdb-transform irdb-deep irdb-util ")
pgm=myenv.Program(pgm, files, LIBS=libs)
# build and install the transform, by default
pgm=myenv.SharedLibrary(pgm, files, LIBS=libs)
install=myenv.Install("$INSTALL_PATH/", pgm)
Default(install)
#
# and we're done
#
Return('install')
env=Environment()
Export('env')
lib=SConscript("SConscript")
......@@ -24,34 +24,50 @@
using namespace IRDB_SDK;
using namespace std;
// constructor
KillDeads::KillDeads(FileIR_t *p_variantIR)
:
Transform(p_variantIR)
Transform(p_variantIR) // init transform class for insertAssembly and getFileIR
{
}
int KillDeads::execute()
bool KillDeads::execute()
{
// init statistics variables
auto killed_flags=0L;
auto killed_regs=0L;
// seed RNG and choose a random kill value.
srand(time(0));
int kill_val=rand();
// declare and construct a deep analysis engine
auto de=DeepAnalysis_t::factory(getFileIR());
auto reg_mapp=de->getDeadRegisters();
auto &reg_map=*reg_mapp;
cout<<"Using random_value: "<<dec<<kill_val<<endl;
// and get the dead regs
auto reg_map_ptr=de->getDeadRegisters();
// for syntactical convenience, we deref the pointer once and make a reference to it.
auto &reg_map=*reg_map_ptr;
// log
cout<<"Using random kill value: "<<dec<<kill_val<<endl;
for(auto &insn : getFileIR()->getInstructions())
// the insertAssembly family modifies what getInstructions(), and the range-based for loop
// may go crazy. Copy first so we only check the original instructions
const auto old_insn=getFileIR()->getInstructions();
// for each instruction
for(auto &insn : old_insn)
{
// find the dead registers for the instruction
const auto &regset=reg_map[insn];
// each register that's dead
for(auto reg : regset)
{
// if it's the flags, kill the flags with a cmp
if (reg==rn_EFLAGS)
{
// for flags, do a random compare to change them
......@@ -61,25 +77,35 @@ int KillDeads::execute()
insertAssemblyBefore(insn, buf);
killed_flags++;
}
// check if it's an integer register
if(is64bitRegister(reg) || is32bitRegister(reg) || is16bitRegister(reg) || is8bitRegister(reg))
{
// other integer registers can be killed with a mov
char buf[100];
sprintf(buf," mov %s, %d", registerToString(reg).c_str(), kill_val);
cout<<"Inserting '"<<buf<<"' before '"<<insn->getDisassembly()<<"'"<<endl;
insertAssemblyBefore(insn, buf);
killed_regs++;
}
// Future work: kill float registers