Skip to content
Snippets Groups Projects
fileir.cpp 60.9 KiB
Newer Older
jdh8d's avatar
jdh8d committed

/*
 * Copyright (c) 2014 - Zephyr Software LLC
 *
 * This file may be used and modified for non-commercial purposes as long as
 * all copyright, permission, and nonwarranty notices are preserved.
 * Redistribution is prohibited without prior written consent from Zephyr
 * Software.
 *
 * Please contact the authors for restrictions applying to commercial use.
 *
 * THIS SOURCE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * Author: Zephyr Software
 * e-mail: jwd@zephyr-software.com
 * URL   : http://www.zephyr-software.com/
 *
 */

jdh8d's avatar
jdh8d committed
#include <all.hpp>
#include <irdb-util>
jdh8d's avatar
jdh8d committed
#include <map>
jdh8d's avatar
 
jdh8d committed
#include <elf.h>
#include <algorithm>
jdh8d's avatar
jdh8d committed
#include <iomanip>
#include <irdb-util>
Jason Hiser's avatar
Jason Hiser committed
#include <endian.h>
jdh8d's avatar
jdh8d committed
using namespace libIRDB;
using namespace std;


#define SCOOP_CHUNK_SIZE (10*1024*1024)  /* 10 mb  */
#define ALLOF(a) begin(a),end(a)
jdh8d's avatar
 
jdh8d committed
#undef EIP

int command_to_stream(const string& command, ostream& stream)
{
Jason Hiser's avatar
Jason Hiser committed
	cout << "Issuing command: " << command << endl;
	const auto res = command_to_string(command);
	stream << res.first << endl;
	return res.second;
jdh8d's avatar
jdh8d committed

static void UpdateEntryPoints(
	const std::map<db_id_t,Instruction_t*> 	&insnMap,
	const map<Function_t*,db_id_t>& entry_points)
jdh8d's avatar
jdh8d committed
{
	/* for each function, look up the instruction that's the entry point */
	for(	map<Function_t*,db_id_t>::const_iterator it=entry_points.begin();
jdh8d's avatar
jdh8d committed
		it!=entry_points.end();
		++it
	   )
	{
		Function_t* func=(*it).first;
		db_id_t func_entry_id=(*it).second;

		assert(func_entry_id==-1 || insnMap.at(func_entry_id));
		func->setEntryPoint(insnMap.at(func_entry_id));
//		cout<<"Function named "<<func->getName()<< " getting entry point set to "<<insnMap[func_entry_id]->getComment()<<"."<<endl;
jdh8d's avatar
jdh8d committed
	}
		
}

static void UpdateUnresolvedEhCallSites(
	const std::map<db_id_t,Instruction_t*> 	&insnMap,
	const std::map<EhCallSite_t*,db_id_t> & unresolvedEhcss)
{
	for(const auto &i : unresolvedEhcss)
	{
		const auto& ehcs=i.first; 
		const auto& insnid=i.second;
		const auto& insn=insnMap.at(insnid);
		assert(insn);
		ehcs->setLandingPad(insn);
	}
}

static virtual_offset_t strtovo(std::string s)
an7s's avatar
an7s committed
{
        return IRDB_SDK::strtoint<virtual_offset_t>(s);
jdh8d's avatar
jdh8d committed
// Create a Variant from the database
Matthew McGill's avatar
Matthew McGill committed
FileIR_t::FileIR_t(const VariantID_t &newprogid, File_t* fid) 
			: BaseObj_t(NULL), progid((VariantID_t&) newprogid)
jdh8d's avatar
jdh8d committed
	
jdh8d's avatar
jdh8d committed
{
	orig_variant_ir_p=NULL;

	if(fid==NULL)
		fileptr=dynamic_cast<File_t*>(newprogid.getMainFile());
jdh8d's avatar
jdh8d committed
	else
		fileptr=fid;

	if(progid.isRegistered())
jdh8d's avatar
 
jdh8d committed
	{
jdh8d's avatar
jdh8d committed
		ReadFromDB();
		setArchitecture();
jdh8d's avatar
 
jdh8d committed
	}
jdh8d's avatar
jdh8d committed

}
	for(auto i : funcs ) delete i;
	for(auto i : insns ) delete i;
	for(auto i : addrs ) delete i;
	for(auto i : relocs) delete i;
	for(auto i : types ) delete i;
an7s's avatar
an7s committed

	// @todo: clear icfs_t
jdh8d's avatar
jdh8d committed
  
// DB operations
void FileIR_t::ReadFromDB()
{
jdh8d's avatar
jdh8d committed
    	ReadIRDB_start = clock();


	auto entry_points=map<Function_t*,db_id_t>();
	auto unresolvedICFS=std::map<Instruction_t*, db_id_t>();
	auto unresolvedEhCallSites=std::map<EhCallSite_t*,db_id_t>();
	auto objMap=std::map<db_id_t,BaseObj_t*>();
	auto addressToInstructionMap=std::map<db_id_t,Instruction_t*>();
jdh8d's avatar
jdh8d committed

	auto ehpgmMap 	= ReadEhPgmsFromDB(); 
	auto ehcsMap 	= ReadEhCallSitesFromDB(unresolvedEhCallSites); 
	auto typesMap 	= ReadTypesFromDB(types); 
	auto addrMap	= ReadAddrsFromDB();
	auto funcMap	= ReadFuncsFromDB(addrMap, typesMap,entry_points);
	auto scoopMap	= ReadScoopsFromDB(addrMap, typesMap);
	auto insnMap	= ReadInsnsFromDB(funcMap,addrMap,ehpgmMap,ehcsMap,addressToInstructionMap, unresolvedICFS);
an7s's avatar
an7s committed

an7s's avatar
an7s committed
	ReadAllICFSFromDB(addressToInstructionMap, unresolvedICFS);
	// put the scoops, instructions, ehpgms, eh call sites into the object map.
	// if relocs end up on other objects, we'll need to add them to.  for now only these things.
	objMap.insert(insnMap.begin(), insnMap.end());
	objMap.insert(scoopMap.begin(), scoopMap.end());
	objMap.insert(ehcsMap.begin(), ehcsMap.end());
	objMap.insert(ehpgmMap.begin(), ehpgmMap.end());
jdh8d's avatar
jdh8d committed

	UpdateEntryPoints(insnMap,entry_points);
	UpdateUnresolvedEhCallSites(insnMap,unresolvedEhCallSites);
jdh8d's avatar
jdh8d committed

	ReadIRDB_end = clock();


void  FileIR_t::changeRegistryKey(IRDB_SDK::Instruction_t *p_orig, IRDB_SDK::Instruction_t *p_updated)
	auto orig=dynamic_cast<libIRDB::Instruction_t*>(p_orig);
	auto updated=dynamic_cast<libIRDB::Instruction_t*>(p_updated);

	if(assembly_registry.find(orig) != assembly_registry.end())
	{
		assembly_registry[updated] = assembly_registry[orig];

		assembly_registry.erase(orig);
	}
}

void FileIR_t::assembleRegistry()
{
	if(assembly_registry.size() == 0)
		return;

	string assemblyFile = "tmp.asm";
	string binaryOutputFile = "tmp.bin";
	string command = "rm -f " + assemblyFile + " " + binaryOutputFile;
	auto actual_exit = command_to_stream(command, cout); // system(command.c_str());
	
	ofstream asmFile;
	asmFile.open(assemblyFile.c_str());
	if(!asmFile.is_open())
		assert(false);

	asmFile<<"BITS "<<std::dec<<getArchitectureBitWidth()<<endl; 
	for(auto it : assembly_registry)
		asmFile<<it.second<<endl;
	command = string("nasm ") + assemblyFile + string(" -o ") + binaryOutputFile;
	actual_exit = command_to_stream(command,cout); // system(command.c_str());
	ifstream binreader;
	unsigned int filesize;
	binreader.open(binaryOutputFile.c_str(),ifstream::in|ifstream::binary);


	binreader.seekg(0,ios::end);
	filesize = binreader.tellg();
	binreader.seekg(0,ios::beg);

	unsigned char *binary_stream = new unsigned char[filesize];

	binreader.read((char*)binary_stream,filesize);
	binreader.close();

	unsigned int index = 0;
	registry_type::iterator reg_val =  assembly_registry.begin();

		//the number of registered instructions should not be exceeded
		assert(reg_val != assembly_registry.end());
		Instruction_t *instr = reg_val->first;

		// disasm.EIP =  (UIntPtr)&binary_stream[index];
		// int instr_len = Disasm(&disasm);

		const auto p_disasm=DecodedInstruction_t::factory
			(
				/* fake start addr doesn't matter */0x1000, 
				(void*)&binary_stream[index], 
				(void*)&binary_stream[filesize]
			);
		const auto& disasm=*p_disasm;

		assert(disasm.valid());
		const auto instr_len=disasm.length();

		string rawBits;
		rawBits.resize(instr_len);
		for(auto i=0U;i<instr_len;i++,index++)
		instr->setDataBits(rawBits);
//		*verbose_logging << "doing instruction:" << ((Instruction_t*)instr)->getDisassembly() << " comment: " << ((Instruction_t*)instr)->getComment() << endl;
	assert(reg_val == assembly_registry.end());
void FileIR_t::registerAssembly(IRDB_SDK::Instruction_t *p_instr, string assembly)
	auto instr=dynamic_cast<Instruction_t*>(p_instr);
	assert(instr);
	assembly_registry[instr] = assembly;
}

void FileIR_t::unregisterAssembly(IRDB_SDK::Instruction_t *p_instr)
	auto instr=dynamic_cast<Instruction_t*>(p_instr);
	assert(instr);
	assembly_registry.erase(instr);
}

std::string FileIR_t::lookupAssembly(IRDB_SDK::Instruction_t *p_instr)
an7s's avatar
an7s committed
{
	auto instr=dynamic_cast<Instruction_t*>(p_instr);
	assert(instr);
an7s's avatar
an7s committed
	if (assembly_registry.find(instr) != assembly_registry.end())
		return assembly_registry[instr];
	else
		return std::string();
}
jdh8d's avatar
jdh8d committed
std::map<db_id_t,Function_t*> FileIR_t::ReadFuncsFromDB
	(
        	std::map<db_id_t,AddressID_t*> &addrMap,
		std::map<db_id_t,Type_t*> &typesMap,
		map<Function_t*,db_id_t> &entry_points
jdh8d's avatar
jdh8d committed
	)
{
	auto idMap=std::map<db_id_t,Function_t*> ();
jdh8d's avatar
jdh8d committed

	auto q=std::string("select * from ") + fileptr->function_table_name + " ; ";
jdh8d's avatar
jdh8d committed

	dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed

	while(!dbintr->isDone())
jdh8d's avatar
jdh8d committed
	{
// function_id | file_id | name | stack_frame_size | out_args_region_size | use_frame_pointer | is_safe | doip_id
jdh8d's avatar
jdh8d committed

		db_id_t fid=atoi(dbintr->getResultColumn("function_id").c_str());
		db_id_t entry_point_id=atoi(dbintr->getResultColumn("entry_point_id").c_str());
		std::string name=dbintr->getResultColumn("name");
		int sfsize=atoi(dbintr->getResultColumn("stack_frame_size").c_str());
		int oasize=atoi(dbintr->getResultColumn("out_args_region_size").c_str());
		db_id_t function_type_id=atoi(dbintr->getResultColumn("type_id").c_str());
jdh8d's avatar
jdh8d committed
// postgresql encoding of boolean can be 'true', '1', 'T', 'y'
		bool useFP=false;
		bool isSafe=false;
		string useFPString=dbintr->getResultColumn("use_frame_pointer"); 
		string isSafeString=dbintr->getResultColumn("is_safe"); 
		const char *useFPstr=useFPString.c_str();
		const char *isSafestr=isSafeString.c_str();
		if (strlen(useFPstr) > 0)
jdh8d's avatar
jdh8d committed
		{
			if (useFPstr[0] == 't' || useFPstr[0] == 'T' || useFPstr[0] == '1' || useFPstr[0] == 'y' || useFPstr[0] == 'Y')
				useFP = true;
		}

		if (strlen(isSafestr) > 0)
		{
			if (isSafestr[0] == 't' || isSafestr[0] == 'T' || isSafestr[0] == '1' || isSafestr[0] == 'y' || isSafestr[0] == 'Y')
				isSafe = true;
		}

		// handle later?
		//db_id_t doipid=atoi(dbintr->getResultColumn("doip_id").c_str());
jdh8d's avatar
jdh8d committed

		FuncType_t* fnType = NULL;
		if (typesMap.count(function_type_id) > 0)
			fnType = dynamic_cast<FuncType_t*>(typesMap[function_type_id]);
		Function_t *newfunc=new Function_t(fid,name,sfsize,oasize,useFP,isSafe,fnType, NULL); 
		assert(newfunc);
jdh8d's avatar
jdh8d committed
		entry_points[newfunc]=entry_point_id;
		
//std::cout<<"Found function "<<name<<"."<<std::endl;

		idMap[fid]=newfunc;

		funcs.insert(newfunc);

		dbintr->moveToNextRow();
jdh8d's avatar
jdh8d committed
	}

	return idMap;
}


std::map<db_id_t,EhCallSite_t*> FileIR_t::ReadEhCallSitesFromDB
	(
		map<EhCallSite_t*,db_id_t> &unresolvedEhCssLandingPads // output arg.
	)
{
	auto ehcsMap=std::map<db_id_t,EhCallSite_t*>();

	std::string q= "select * from " + fileptr->getEhCallSiteTableName() + " ; ";
	for(dbintr->issueQuery(q); !dbintr->isDone(); dbintr->moveToNextRow())
		const auto string_to_vec=[&](const string& str ) ->  vector<int>
		{
			auto out=vector<int>();
			istringstream s(str);
			auto in=(int)0;
			while ( s >> in)
				out.push_back(in);
			return out;
		};
		/* 
		 * ehcs_id         integer,        -- id of this object.
		 * tt_encoding     integer,        -- the encoding of the type table.
		 * lp_insn_id      integer         -- the landing pad instruction's id.
		 */


		const auto eh_cs_id=atoi(dbintr->getResultColumn("ehcs_id").c_str());
		const auto tt_encoding=atoi(dbintr->getResultColumn("tt_encoding").c_str());
		const auto &ttov=string(dbintr->getResultColumn("ttov").c_str());
		const auto lp_insn_id=atoi(dbintr->getResultColumn("lp_insn_id").c_str());
		auto newEhCs=new EhCallSite_t(eh_cs_id,tt_encoding,NULL); // create the call site with an unresolved LP
		newEhCs->GetTTOrderVector()=string_to_vec(ttov);
		eh_css.insert(newEhCs);					  // record that it exists.
		ehcsMap[eh_cs_id]=newEhCs;				  // record the map for when we read instructions.
		if(lp_insn_id != BaseObj_t::NOT_IN_DATABASE)
			unresolvedEhCssLandingPads[newEhCs]=lp_insn_id;		  // note that the LP is unresolved
	}

	return ehcsMap;
}

std::map<db_id_t,EhProgram_t*> FileIR_t::ReadEhPgmsFromDB()
{
	auto idMap = std::map<db_id_t,EhProgram_t*>();

	auto q=std::string("select * from ") + fileptr->ehpgm_table_name + " ; ";
	dbintr->issueQuery(q);

	auto decode_pgm=[](const string& encoded_pgm, EhProgramListing_t& decoded_pgm)
	{

		auto split=[](const string& str, const string& delim, EhProgramListing_t& tokens) -> void
		{
			auto prev = size_t(0);
			auto pos = size_t(0);
			do
			{
				pos = str.find(delim, prev);
				if (pos == string::npos) pos = str.length();
				string token = str.substr(prev, pos-prev);
				if (!token.empty()) tokens.push_back(token);
				prev = pos + delim.length();
			}
			while (pos < str.length() && prev < str.length());
		};

		auto decode_in_place=[](string& to_decode) -> void
		{
			auto charToHex=[](uint8_t value) -> uint8_t
			{
				if (value >= '0' && value <= '9') return value - '0';
				else if (value >= 'A' && value <= 'F') return value - 'A' + 10;
				else if (value >= 'a' && value <= 'f') return value - 'a' + 10;
				assert(false);
			};


			auto out=string("");
			while(to_decode.size() > 0)
			{
				// to-decode should have pairs of characters that represent individual bytes.
				assert(to_decode.size() >= 2);
				auto val =  uint8_t ( charToHex(to_decode[0])*16  + charToHex(to_decode[1]) ); 
				out += val;
				to_decode.erase(0,2);
			}

			to_decode=out;
		};

		split(encoded_pgm, ",", decoded_pgm);

		// decode each one
		for(auto& i : decoded_pgm)
			decode_in_place(i);
		
		
	};

	while(!dbintr->isDone())
	{
		/* 
		 * eh_pgm_id       integer,
		 * caf             integer,
		 * daf             integer,
		 * ptrsize         integer,
		 * cie_program     text,
		 * fde_program     text
		 */


		const auto eh_pgm_id=atoi(dbintr->getResultColumn("eh_pgm_id").c_str());
		const auto caf=atoi(dbintr->getResultColumn("caf").c_str());
		const auto daf=atoi(dbintr->getResultColumn("daf").c_str());
		const auto rr=atoi(dbintr->getResultColumn("return_register").c_str());
		const auto ptrsize=atoi(dbintr->getResultColumn("ptrsize").c_str());
		const auto& encoded_cie_program = dbintr->getResultColumn("cie_program");
		const auto& encoded_fde_program = dbintr->getResultColumn("fde_program");
		auto new_ehpgm=new EhProgram_t(eh_pgm_id, caf, daf, rr, ptrsize, {}, {});
		decode_pgm(encoded_cie_program, new_ehpgm->GetCIEProgram());
		decode_pgm(encoded_fde_program, new_ehpgm->GetFDEProgram());

		idMap[eh_pgm_id]=new_ehpgm;
		eh_pgms.insert(new_ehpgm);
		dbintr->moveToNextRow();
jdh8d's avatar
jdh8d committed
std::map<db_id_t,AddressID_t*> FileIR_t::ReadAddrsFromDB  
	(
	) 
{
	std::map<db_id_t,AddressID_t*> idMap;

	std::string q= "select * from " + fileptr->address_table_name + " ; ";


	dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed

	while(!dbintr->isDone())
jdh8d's avatar
jdh8d committed
	{
//   address_id            integer PRIMARY KEY,
//  file_id               integer REFERENCES file_info,
an7s's avatar
an7s committed
//  vaddress_offset       bigint,
jdh8d's avatar
jdh8d committed
//  doip_id               integer DEFAULT -1


		db_id_t aid=atoi(dbintr->getResultColumn("address_id").c_str());
		db_id_t file_id=atoi(dbintr->getResultColumn("file_id").c_str());
		virtual_offset_t vaddr=strtovo(dbintr->getResultColumn("vaddress_offset"));
		//db_id_t doipid=atoi(dbintr->getResultColumn("doip_id").c_str());
jdh8d's avatar
jdh8d committed

		AddressID_t *newaddr=new AddressID_t(aid,file_id,vaddr);

//std::cout<<"Found address "<<aid<<"."<<std::endl;

		idMap[aid]=newaddr;

		addrs.insert(newaddr);

		dbintr->moveToNextRow();
jdh8d's avatar
jdh8d committed
	}

	return idMap;
}


jdh8d's avatar
jdh8d committed
static string encoded_to_raw_string(string encoded)
{
	int len = encoded.length();
	std::string raw;
	for(int i=0; i< len; i+=2)
	{
	    string byte = encoded.substr(i,2);
	    char chr = (char) (int)strtol(byte.c_str(), nullptr, 16);
	    raw.push_back(chr);
	}
	return raw;
}

jdh8d's avatar
jdh8d committed
std::map<db_id_t,Instruction_t*> FileIR_t::ReadInsnsFromDB 
	(      
        const std::map<db_id_t,Function_t*> &funcMap,
        const std::map<db_id_t,AddressID_t*> &addrMap,
        const std::map<db_id_t,EhProgram_t*> &ehpgmMap,
        const std::map<db_id_t,EhCallSite_t*> &ehcsMap,
	std::map<db_id_t,Instruction_t*> &addressToInstructionMap,
	std::map<Instruction_t*, db_id_t> &unresolvedICFS
jdh8d's avatar
jdh8d committed
        ) 
{
	std::map<db_id_t,Instruction_t*> idMap;
	std::map<db_id_t,db_id_t> fallthroughs;
	std::map<db_id_t,db_id_t> targets;

	std::string q= "select * from " + fileptr->instruction_table_name + " ; ";


	dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed

	while(!dbintr->isDone())
jdh8d's avatar
jdh8d committed
	{

//  address_id                integer REFERENCES #PROGNAME#_address,
//  parent_function_id        integer,
//  orig_address_id           integer REFERENCES #PROGNAME#_address,
//  fallthrough_address_id    integer,
//  target_address_id         integer,
an7s's avatar
an7s committed
//  icfs_id                   integer,
jdh8d's avatar
jdh8d committed
//  data                      bytea,
//  callback                  text,
//  comment                   text,
//  doip_id                   integer DEFAULT -1


		db_id_t instruction_id=atoi(dbintr->getResultColumn("instruction_id").c_str());
		db_id_t aid=atoi(dbintr->getResultColumn("address_id").c_str());
		db_id_t parent_func_id=atoi(dbintr->getResultColumn("parent_function_id").c_str());
		db_id_t orig_address_id=atoi(dbintr->getResultColumn("orig_address_id").c_str());
		db_id_t fallthrough_address_id=atoi(dbintr->getResultColumn("fallthrough_address_id").c_str());
		db_id_t targ_address_id=atoi(dbintr->getResultColumn("target_address_id").c_str());
		db_id_t icfs_id=atoi(dbintr->getResultColumn("icfs_id").c_str());
		db_id_t eh_pgm_id=atoi(dbintr->getResultColumn("ehpgm_id").c_str());
		db_id_t eh_cs_id=atoi(dbintr->getResultColumn("ehcss_id").c_str());
		std::string encoded_data=(dbintr->getResultColumn("data"));
jdh8d's avatar
jdh8d committed
		std::string data=encoded_to_raw_string(encoded_data);
		std::string callback=(dbintr->getResultColumn("callback"));
		std::string comment=(dbintr->getResultColumn("comment"));
		db_id_t indirect_branch_target_address_id = atoi(dbintr->getResultColumn("ind_target_address_id").c_str());
		db_id_t doipid=atoi(dbintr->getResultColumn("doip_id").c_str());
jdh8d's avatar
jdh8d committed

		std::string isIndStr=(dbintr->getResultColumn("ind_target_address_id"));
jdh8d's avatar
jdh8d committed

jdh8d's avatar
jdh8d committed
		if (indirect_branch_target_address_id != NOT_IN_DATABASE) 
			indTarg = addrMap.at(indirect_branch_target_address_id);

		auto parent_func=(Function_t*)NULL;
		if(parent_func_id!= NOT_IN_DATABASE) parent_func=funcMap.at(parent_func_id);
jdh8d's avatar
jdh8d committed

		Instruction_t *newinsn=new Instruction_t(instruction_id,
jdh8d's avatar
jdh8d committed
			orig_address_id,
			data, callback, comment, indTarg, doipid);
		if(eh_pgm_id != NOT_IN_DATABASE) newinsn->setEhProgram(ehpgmMap.at(eh_pgm_id));
		if(eh_cs_id != NOT_IN_DATABASE) newinsn->setEhCallSite(ehcsMap.at(eh_cs_id));
jdh8d's avatar
jdh8d committed
	
jdh8d's avatar
jdh8d committed
		{
			parent_func->GetInstructions().insert(newinsn);
			newinsn->setFunction(funcMap.at(parent_func_id));
jdh8d's avatar
jdh8d committed
		}
jdh8d's avatar
jdh8d committed

//std::cout<<"Found address "<<aid<<"."<<std::endl;

		idMap[instruction_id]=newinsn;
		fallthroughs[instruction_id]=fallthrough_address_id;
		targets[instruction_id]=targ_address_id;

an7s's avatar
an7s committed
		addressToInstructionMap[aid] = newinsn;
jdh8d's avatar
jdh8d committed
		insns.insert(newinsn);

an7s's avatar
an7s committed
		if (icfs_id == NOT_IN_DATABASE)
		{
			newinsn->setIBTargets(NULL);
an7s's avatar
an7s committed
		}
		else
		{
			// keep track of instructions for which we have not yet
			// resolved the ICFS
			unresolvedICFS[newinsn] = icfs_id;
		}

		dbintr->moveToNextRow();
jdh8d's avatar
jdh8d committed
	}

	for(std::map<db_id_t,Instruction_t*>::const_iterator i=idMap.begin(); i!=idMap.end(); ++i)
	{
		Instruction_t *instr=(*i).second;
		db_id_t fallthroughid=fallthroughs[instr->getBaseID()];
jdh8d's avatar
jdh8d committed
		if(idMap[fallthroughid])	
			instr->setFallthrough(idMap[fallthroughid]);
		db_id_t targetid=targets[instr->getBaseID()];
jdh8d's avatar
jdh8d committed
		if(idMap[targetid])	
			instr->setTarget(idMap[targetid]);
jdh8d's avatar
jdh8d committed
	}


	return idMap;
}

void FileIR_t::ReadRelocsFromDB
	(
		std::map<db_id_t,BaseObj_t*> 	&objMap
	)
{
	std::string q= "select * from " + fileptr->relocs_table_name + " ; ";
	dbintr->issueQuery(q);
	while(!dbintr->isDone())
                db_id_t reloc_id=atoi(dbintr->getResultColumn("reloc_id").c_str());
                int reloc_offset=atoi(dbintr->getResultColumn("reloc_offset").c_str());
                std::string reloc_type=(dbintr->getResultColumn("reloc_type"));
                db_id_t instruction_id=atoi(dbintr->getResultColumn("instruction_id").c_str());
                //db_id_t doipid=atoi(dbintr->getResultColumn("doip_id").c_str());
                db_id_t wrt_id=atoi(dbintr->getResultColumn("wrt_id").c_str());
                uint32_t addend=atoi(dbintr->getResultColumn("addend").c_str());
jdh8d's avatar
jdh8d committed
		BaseObj_t* wrt_obj=objMap[wrt_id];	 // might be null.
jdh8d's avatar
jdh8d committed
		Relocation_t *reloc=new Relocation_t(reloc_id,reloc_offset,reloc_type,wrt_obj,addend);
		assert(objMap[instruction_id]!=NULL);
		objMap[instruction_id]->GetRelocations().insert(reloc);
		relocs.insert(reloc);

		dbintr->moveToNextRow();
void FileIR_t::writeToDB(ostream *verbose_logging)
jdh8d's avatar
jdh8d committed
{
//     	const auto WriteIRDB_start = clock();
jdh8d's avatar
jdh8d committed

	const auto pqIntr=dynamic_cast<pqxxDB_t*>(dbintr);
	assert(pqIntr);

	//Resolve (assemble) any instructions in the registry.
	assembleRegistry();
jdh8d's avatar
jdh8d committed
	/* assign each item a unique ID */
	setBaseIDS();
jdh8d's avatar
jdh8d committed

jdh8d's avatar
jdh8d committed
	db_id_t j=-1;

	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->instruction_table_name 	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->icfs_table_name 		+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->icfs_map_table_name 	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->function_table_name    	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->address_table_name     	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->relocs_table_name     	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->types_table_name     	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->scoop_table_name     	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->scoop_table_name+"_part2"+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->ehpgm_table_name     	+ string(" cascade;"));
	dbintr->issueQuery(string("TRUNCATE TABLE ")+ fileptr->ehcss_table_name     	+ string(" cascade;"));
jdh8d's avatar
jdh8d committed

	/* and now that everything has an ID, let's write to the DB */
jdh8d's avatar
jdh8d committed
// write out the types
	string q=string("");
	for(auto t=types.begin(); t!=types.end(); ++t)
		auto real_t=dynamic_cast<Type_t*>(*t);
		assert(real_t);
		q+=real_t->WriteToDB(fileptr,j); // @TODO: wtf is j?
		if(q.size()>1024*1024)
		{
			dbintr->issueQuery(q);
	dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed
// write out functions 
	auto withHeader=true;
	for(auto f=funcs.begin(); f!=funcs.end(); ++f)
jdh8d's avatar
jdh8d committed
	{
		auto real_f=dynamic_cast<Function_t*>(*f);
		assert(real_f);
		q+=real_f->WriteToDB(fileptr,j);
jdh8d's avatar
jdh8d committed
		if(q.size()>1024*1024)
		{
			dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed
			q=string("");
		}
	}
	dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed

jdh8d's avatar
jdh8d committed

// write out addresses
	pqxx::tablewriter W_addrs(pqIntr->getTransaction(),fileptr->address_table_name);
jdh8d's avatar
jdh8d committed
	for(const auto &a : addrs)
jdh8d's avatar
jdh8d committed
	{
		auto real_a=dynamic_cast<AddressID_t*>(a);
		assert(real_a);
		W_addrs << real_a->WriteToDB(fileptr,j,withHeader);
jdh8d's avatar
jdh8d committed
	}
jdh8d's avatar
jdh8d committed
	W_addrs.complete();
jdh8d's avatar
jdh8d committed

jdh8d's avatar
jdh8d committed
// write out instructions

	pqxx::tablewriter W(pqIntr->getTransaction(),fileptr->instruction_table_name);
	for(auto i=insns.begin(); i!=insns.end(); ++i)
jdh8d's avatar
jdh8d committed
	{	
		auto insnp=dynamic_cast<Instruction_t*>(*i);
		//DISASM disasm;
		//Disassemble(insnp,disasm);
		const auto p_disasm=DecodedInstruction_t::factory(insnp);
		const auto& disasm=*p_disasm;
jdh8d's avatar
 
jdh8d committed

		if(insnp->getOriginalAddressID() == NOT_IN_DATABASE)
jdh8d's avatar
 
jdh8d committed
		{

			// if(insnp->getFallthrough()==NULL && disasm.Instruction.BranchType!=RetType && disasm.Instruction.BranchType!=JmpType )
			if(insnp->getFallthrough()==NULL && !disasm.isReturn() && !disasm.isUnconditionalBranch())
jdh8d's avatar
 
jdh8d committed
			{
				// instructions that fall through are required to either specify a fallthrough that's
				// in the IRDB, or have an associated "old" instruction.  
				// without these bits of information, the new instruction can't possibly execute correctly.
				// and we won't have the information necessary to emit spri.
				*verbose_logging << "NULL fallthrough: offending instruction:" << ((Instruction_t*)insnp)->getDisassembly() << " comment: " << ((Instruction_t*)insnp)->getComment() << endl;
jdh8d's avatar
 
jdh8d committed
				assert(0);
				abort();
			}
			//if(insnp->getTarget()==NULL && disasm.Instruction.BranchType!=0 && 
			//	disasm.Instruction.BranchType!=RetType &&
			//	// not an indirect branch
			//	((disasm.Instruction.BranchType!=JmpType && disasm.Instruction.BranchType!=CallType) ||
			//	 disasm.Argument1.ArgType&CONSTANT_TYPE))

			if(insnp->getTarget()==NULL && disasm.isBranch() && !disasm.isReturn() &&
				// not an indirect branch
				( (!disasm.isUnconditionalBranch() && !disasm.isCall()) || disasm.getOperand(0)->isConstant())
jdh8d's avatar
 
jdh8d committed
			{
				// direct branches are required to either specify a target that's
jdh8d's avatar
 
jdh8d committed
				// in the IRDB, or have an associated "old" instruction.  
				// without these bits of information, the new instruction can't possibly execute correctly.
				// and we won't have the information necessary to emit spri.
				*verbose_logging << "Call must have a target; offending instruction:" << ((Instruction_t*)insnp)->getDisassembly() << " comment: " << ((Instruction_t*)insnp)->getComment() << endl;
jdh8d's avatar
 
jdh8d committed
				assert(0);
				abort();
			}
		}

		const auto &insn_values=insnp->WriteToDB(fileptr,j);
jdh8d's avatar
jdh8d committed
		W << insn_values;

jdh8d's avatar
jdh8d committed
	W.complete();


// icfs 
	for (auto it = GetAllICFS().begin(); it != GetAllICFS().end(); ++it)
		ICFS_t* icfs = dynamic_cast<ICFS_t*>(*it);
		assert(icfs);
		string q = icfs->WriteToDB(fileptr);
		dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed

// scoops
	for(auto it=scoops.begin(); it!=scoops.end(); ++it)
jdh8d's avatar
 
jdh8d committed
	{
		DataScoop_t* scoop = dynamic_cast<DataScoop_t*>(*it);
jdh8d's avatar
 
jdh8d committed
		assert(scoop);
		string q = scoop->WriteToDB(fileptr,j);
		dbintr->issueQuery(q);
jdh8d's avatar
 
jdh8d committed
	}
jdh8d's avatar
jdh8d committed

// ehpgms 
	pqxx::tablewriter W_eh(pqIntr->getTransaction(),fileptr->ehpgm_table_name);
jdh8d's avatar
jdh8d committed
	{
		W_eh << dynamic_cast<EhProgram_t*>(i)->WriteToDB(fileptr);
jdh8d's avatar
jdh8d committed
	}
	W_eh.complete();

// eh css
	for(const auto& i : eh_css)
		string q = dynamic_cast<EhCallSite_t*>(i)->WriteToDB(fileptr);
		dbintr->issueQuery(q);
jdh8d's avatar
jdh8d committed
	}
jdh8d's avatar
jdh8d committed

// all relocs
	pqxx::tablewriter W_reloc(pqIntr->getTransaction(),fileptr->relocs_table_name);
jdh8d's avatar
jdh8d committed

// eh css relocs
	for(const auto& i : eh_css)
	{
		const auto &relocs=i->getRelocations();
			W_reloc << dynamic_cast<Relocation_t*>(reloc)->WriteToDB(fileptr,dynamic_cast<BaseObj_t*>(i));
jdh8d's avatar
jdh8d committed

// eh pgms relocs
	for(const auto& i : eh_pgms)
		const auto &relocs=i->getRelocations();
			W_reloc << dynamic_cast<Relocation_t*>(reloc)->WriteToDB(fileptr,dynamic_cast<BaseObj_t*>(i));
jdh8d's avatar
jdh8d committed
// scoops relocs
	for(const auto& i : scoops)
	{
		const auto &relocs=i->getRelocations();
			W_reloc << dynamic_cast<Relocation_t*>(reloc)->WriteToDB(fileptr,dynamic_cast<BaseObj_t*>(i));
jdh8d's avatar
jdh8d committed
	}
// write out instruction's relocs
	for(const auto& i : insns)
	{
		const auto &relocs=i->getRelocations();
			W_reloc << dynamic_cast<Relocation_t*>(reloc)->WriteToDB(fileptr,dynamic_cast<BaseObj_t*>(i));
jdh8d's avatar
jdh8d committed
	}
	W_reloc.complete();

db_id_t FileIR_t::getMaxBaseID() const
jdh8d's avatar
jdh8d committed
{
#define MAX(a,b) (((a)>(b)) ? (a) : (b))

	/* find the highest database ID */
	db_id_t j=0;
	for(auto i=funcs.begin(); i!=funcs.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=addrs.begin(); i!=addrs.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=insns.begin(); i!=insns.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=relocs.begin(); i!=relocs.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=types.begin(); i!=types.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=scoops.begin(); i!=scoops.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=icfs_set.begin(); i!=icfs_set.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=eh_pgms.begin(); i!=eh_pgms.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
	for(auto i=eh_css.begin(); i!=eh_css.end(); ++i)
		j=MAX(j,(*i)->getBaseID());
jdh8d's avatar
jdh8d committed

	return j+1;	 // easy to off-by-one this so we do it for a user just in case.
}

void FileIR_t::setBaseIDS()
	auto j=getMaxBaseID();
jdh8d's avatar
jdh8d committed
	/* increment past the max ID so we don't duplicate */
	j++;
	/* for anything that's not yet in the DB, assign an ID to it */
	for(auto i=funcs.begin(); i!=funcs.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=addrs.begin(); i!=addrs.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=insns.begin(); i!=insns.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=relocs.begin(); i!=relocs.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=types.begin(); i!=types.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=scoops.begin(); i!=scoops.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=icfs_set.begin(); i!=icfs_set.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=eh_pgms.begin(); i!=eh_pgms.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
	for(auto i=eh_css.begin(); i!=eh_css.end(); ++i)
		if((*i)->getBaseID()==NOT_IN_DATABASE)
			(*i)->setBaseID(j++);
jdh8d's avatar
jdh8d committed
}
jdh8d's avatar
 
jdh8d committed

const  IRDB_SDK::ArchitectureDescription_t* IRDB_SDK::FileIR_t::getArchitecture() 
{ 
		return libIRDB::FileIR_t::archdesc; 
}

uint32_t IRDB_SDK::FileIR_t::getArchitectureBitWidth()
jdh8d's avatar
 
jdh8d committed
{
	return libIRDB::FileIR_t::archdesc->getBitWidth();
jdh8d's avatar
 
jdh8d committed
}

void FileIR_t::setArchitecture(const int width, const ADMachineType_t mt) 
{
	if(archdesc==NULL)
		archdesc=new ArchitectureDescription_t;
	archdesc->setBitWidth(width); 
Jason Hiser's avatar
Jason Hiser committed
	archdesc->setMachineType(mt); 

	archdesc->setFileBase(0);	// maybe not rght for PE files?
void FileIR_t::setArchitecture()
jdh8d's avatar
 
jdh8d committed
{

	/* the first 16 bytes of an ELF file define the magic number and ELF Class. */
Jason Hiser's avatar
Jason Hiser committed
    	// unsigned char e_ident[16];
	union 
	{
		Elf32_Ehdr ehdr32;
		Elf64_Ehdr ehdr64;
	} hdr_union;
jdh8d's avatar
 
jdh8d committed

Jason Hiser's avatar
Jason Hiser committed
	auto myinter=BaseObj_t::GetInterface();
	auto *mypqxxintr=dynamic_cast<pqxxDB_t*>(myinter);
jdh8d's avatar
 
jdh8d committed

	const auto elfoid=getFile()->getELFOID();
        pqxx::largeobjectaccess loa(mypqxxintr->getTransaction(), elfoid, PGSTD::ios::in);
jdh8d's avatar
 
jdh8d committed


Jason Hiser's avatar
Jason Hiser committed
        loa.cread((char*)&hdr_union, sizeof(hdr_union));

	const auto e_ident=hdr_union.ehdr32.e_ident;
jdh8d's avatar
 
jdh8d committed

	libIRDB::FileIR_t::archdesc=new ArchitectureDescription_t;
an7s's avatar
an7s committed

Jason Hiser's avatar
Jason Hiser committed
	auto is_elf=false;
	auto is_pe=false;

an7s's avatar
an7s committed
	if((e_ident[EI_MAG0]==ELFMAG0) && 
	   (e_ident[EI_MAG1]==ELFMAG1) &&