From 92f9928044e00dacf1f287a00bb9f76af2297f93 Mon Sep 17 00:00:00 2001
From: an7s <an7s@git.zephyr-software.com>
Date: Tue, 29 Dec 2015 16:45:06 +0000
Subject: [PATCH] Support for ICFS off STARS annotation Support for
 module_complete and complete ICFS status field

Former-commit-id: fab0cbf0e7cc86c37ea4cab01bca621aab5c874d
---
 .gitattributes                               |  1 +
 libIRDB/include/core/icfs.hpp                | 41 +++++++++---
 libIRDB/src/core/fileir.cpp                  | 16 ++---
 libIRDB/src/core/icfs.cpp                    | 49 +++++++++++++--
 libIRDB/test/fill_in_indtargs.cpp            | 66 +++++++++++++++++---
 libIRDB/test/read_variantir.cpp              |  2 +-
 libIRDB/test/tests/ibtarget/Makefile         | 14 +++--
 libIRDB/test/tests/ibtarget/validate_ibts.sh | 38 +++++++++++
 tools/meds2pdb/meds2pdb.cpp                  | 33 +++++++---
 tools/transforms/Rewrite_Utility.cpp         |  2 +
 xform/rewriter.cpp                           | 34 +++++++---
 11 files changed, 239 insertions(+), 57 deletions(-)
 create mode 100755 libIRDB/test/tests/ibtarget/validate_ibts.sh

diff --git a/.gitattributes b/.gitattributes
index df19ed873..9303fa063 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -290,6 +290,7 @@ libIRDB/test/tests/ibtarget/jmp.shared.cpp -text
 libIRDB/test/tests/ibtarget/jmp1.cpp -text
 libIRDB/test/tests/ibtarget/jmp2.cpp -text
 libIRDB/test/tests/ibtarget/jmp2.shared.cpp -text
+libIRDB/test/tests/ibtarget/validate_ibts.sh -text
 libIRDB/test/unfix_calls.cpp -text
 libIRDB/test/unwind-pe.h -text
 libMEDSannotation/LICENSE.txt -text
diff --git a/libIRDB/include/core/icfs.hpp b/libIRDB/include/core/icfs.hpp
index 78b4f6c5a..bb9e1d5be 100644
--- a/libIRDB/include/core/icfs.hpp
+++ b/libIRDB/include/core/icfs.hpp
@@ -21,27 +21,50 @@
 class Instruction_t;
 typedef std::set<Instruction_t*> InstructionSet_t;
 
+typedef enum ICFS_Analysis_Status_t { ICFS_Analysis_Incomplete, ICFS_Analysis_Module_Complete, ICFS_Analysis_Complete } ICFS_Analysis_Status_t; 
+
+// these must match the allowed values for type icfs_analysis_result in Postgres DB
+#define ICFS_ANALYSIS_INCOMPLETE_STR "icfs_analysis_incomplete"
+#define ICFS_ANALYSIS_MODULE_COMPLETE_STR "icfs_analysis_module_complete"
+#define ICFS_ANALYSIS_COMPLETE_STR "icfs_analysis_complete"
+
 // Keep track of instruction control flow sets
 class ICFS_t : public InstructionSet_t, public BaseObj_t
 {
 	public:
-		ICFS_t(): BaseObj_t(NULL), is_complete(false) {}
-		ICFS_t(db_id_t set_id, bool p_is_complete = false) : BaseObj_t(NULL)
-		{
-			SetBaseID(set_id);
-			SetComplete(p_is_complete);	
-		}
+		ICFS_t(): BaseObj_t(NULL), m_icfs_analysis_status(ICFS_Analysis_Incomplete) {}
+		ICFS_t(db_id_t p_set_id, const ICFS_Analysis_Status_t p_status = ICFS_Analysis_Incomplete);
+		ICFS_t(db_id_t p_set_id, const std::string);
 		std::string WriteToDB(File_t *fid);
 		 
+		ICFS_t& operator=(const InstructionSet_t &p_other);
 		void SetTargets(const InstructionSet_t &other) 
 		{
 			InstructionSet_t::operator=(other);
 		}
-		void SetComplete(bool complete) { is_complete = complete; }
-		bool IsComplete() const { return is_complete; }			
+
+		bool IsIncomplete() const {
+			return GetAnalysisStatus() == ICFS_Analysis_Incomplete;
+		}
+
+		bool IsComplete() const {
+			return GetAnalysisStatus() == ICFS_Analysis_Complete;
+		}
+
+		bool IsModuleComplete() const {
+			return GetAnalysisStatus() == ICFS_Analysis_Module_Complete;
+		}
+
+		void SetAnalysisStatus(const ICFS_Analysis_Status_t p_status) {
+			m_icfs_analysis_status = p_status;
+		}
+
+		ICFS_Analysis_Status_t GetAnalysisStatus() const { 
+			return m_icfs_analysis_status;
+		}
 
 	private:
-		bool is_complete;
+		ICFS_Analysis_Status_t m_icfs_analysis_status;
 };
 
 typedef std::set<ICFS_t*> ICFSSet_t;
diff --git a/libIRDB/src/core/fileir.cpp b/libIRDB/src/core/fileir.cpp
index c11c14b8b..32c057c97 100644
--- a/libIRDB/src/core/fileir.cpp
+++ b/libIRDB/src/core/fileir.cpp
@@ -941,16 +941,9 @@ void FileIR_t::ReadAllICFSFromDB(std::map<db_id_t,Instruction_t*> &addr2instMap,
 	while(!dbintr->IsDone())
 	{
 		db_id_t icfs_id = atoi(dbintr->GetResultColumn("icfs_id").c_str());
-		bool isComplete=false;
-		string isCompleteString=dbintr->GetResultColumn("is_complete"); 
-		const char *isCompletestr=isCompleteString.c_str();
-		if (isCompleteString.size() > 0)
-		{
-			if (isCompletestr[0] == 't' || isCompletestr[0] == 'T' || isCompletestr[0] == '1' || isCompletestr[0] == 'y' || isCompletestr[0] == 'Y')
-				isComplete = true;
-		}
+		string statusString=dbintr->GetResultColumn("icfs_status"); 
 
-		ICFS_t* icfs = new ICFS_t(icfs_id, isComplete);		
+		ICFS_t* icfs = new ICFS_t(icfs_id, statusString);		
 		GetAllICFS().insert(icfs);
 
 		icfsMap[icfs_id] = icfs;
@@ -972,8 +965,11 @@ void FileIR_t::ReadAllICFSFromDB(std::map<db_id_t,Instruction_t*> &addr2instMap,
 		{
 			db_id_t address_id = atoi(dbintr->GetResultColumn("address_id").c_str());
 			Instruction_t* instruction = addr2instMap[address_id];
-			if (instruction)
+			if (instruction) 
+			{
 				icfs->insert(instruction);
+			}
+
 			// @todo: handle cross-file addresses
 			//        these are allowed by the DB schema but we don't yet handle them
 			// if we encounter an unresolved address, we should mark the ICFS
diff --git a/libIRDB/src/core/icfs.cpp b/libIRDB/src/core/icfs.cpp
index 9f72f37d1..a81b5469e 100644
--- a/libIRDB/src/core/icfs.cpp
+++ b/libIRDB/src/core/icfs.cpp
@@ -24,19 +24,60 @@
 using namespace libIRDB;
 using namespace std;
 
+static string getICFSAnalysisStatus(const ICFS_Analysis_Status_t p_status) {
+	// strings must match DB definition
+	switch (p_status) {
+		case ICFS_Analysis_Incomplete:
+			return string("icfs_analysis_incomplete");
+			break;
+		case ICFS_Analysis_Module_Complete:
+			return string("icfs_analysis_module_complete");
+			break;
+		case ICFS_Analysis_Complete:
+			return string("icfs_analysis_complete");
+			break;
+		default:
+			return string("icfs_analysis_incomplete");
+			break;
+	}
+
+	std::cerr << "error: unknown ICFS analysis status: " << p_status << std::endl;
+	assert(0);
+}
+
+ICFS_t::ICFS_t(db_id_t p_set_id, const ICFS_Analysis_Status_t p_status) : BaseObj_t(NULL)
+{
+	SetBaseID(p_set_id);
+	SetAnalysisStatus(p_status);	
+}
+
+ICFS_t::ICFS_t(db_id_t p_set_id, const string p_statusString) : BaseObj_t(NULL)
+{
+	SetBaseID(p_set_id);
+	if (p_statusString == "icfs_analysis_incomplete") {
+		SetAnalysisStatus(ICFS_Analysis_Incomplete);	
+	} else if (p_statusString == "icfs_analysis_module_complete") {
+		SetAnalysisStatus(ICFS_Analysis_Module_Complete);	
+	} else if (p_statusString == "icfs_analysis_complete") {
+		SetAnalysisStatus(ICFS_Analysis_Complete);	
+	} else {
+		std::cerr << "error: unknown ICFS analysis status string: " << p_statusString << std::endl;
+		assert(0);
+	}
+}
+
 string ICFS_t::WriteToDB(File_t *fid)
 {
 	assert(fid);
 
 	db_id_t icfs_id = GetBaseID();
 
-	// one of the many postgres encoding of boolean values
-	string complete = IsComplete() ? "t" : "f"; 
+	string analysis_status = getICFSAnalysisStatus(GetAnalysisStatus());
 
 	string q=string("insert into ") + fid->icfs_table_name + 
-		string(" (icfs_id, is_complete) VALUES (") + 
+		string(" (icfs_id, icfs_status) VALUES (") + 
 		string("'") + to_string(icfs_id) + string("', ") + 
-		string("'") + complete + string("'); ") ;
+		string("'") + analysis_status + string("'); ") ;
 
 	for (InstructionSet_t::const_iterator it = this->begin(); 
 		it != this->end(); ++it)
diff --git a/libIRDB/test/fill_in_indtargs.cpp b/libIRDB/test/fill_in_indtargs.cpp
index 1543dae19..a1c183f9c 100644
--- a/libIRDB/test/fill_in_indtargs.cpp
+++ b/libIRDB/test/fill_in_indtargs.cpp
@@ -29,12 +29,10 @@
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <regex.h>
-// #include <elf.h>
 #include <ctype.h>
 #include <list>
 #include <stdio.h>
 
-
 #include <exeio.h>
 #include "beaengine/BeaEngine.h"
 #include "check_thunks.hpp"
@@ -253,7 +251,7 @@ void mark_jmptables(FileIR_t *firp)
 
 		assert(instruction_targets.size() > 0);
 
-		ICFS_t* new_icfs = new ICFS_t(next_icfs_set_id++, true);
+		ICFS_t* new_icfs = new ICFS_t(next_icfs_set_id++, ICFS_Analysis_Complete);
 		new_icfs->SetTargets(instruction_targets);
 		firp->GetAllICFS().insert(new_icfs);
 
@@ -264,6 +262,57 @@ void mark_jmptables(FileIR_t *firp)
 	}
 }
 
+bool allTargetsIndirectlyCalledFunctions(Instruction_t *instr)
+{
+	if (!instr->GetIBTargets())
+		return false;
+
+	ICFS_t *targets = instr->GetIBTargets();
+	for(set<Instruction_t*>::const_iterator it=targets->begin();
+		it!=targets->end(); ++it)
+	{
+		Instruction_t *insn = *it;
+		if (!insn->GetFunction())
+			return false;
+		else if (!insn->GetFunction()->GetEntryPoint())
+			return false;
+		/* NB: current API assumes only 1 entry point per function */
+		else if (insn->GetFunction()->GetEntryPoint() != insn)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+	 pre: some ib targets may be incomplete 
+	post: all icfs are either module_complete or complete 
+*/
+void patch_icfs(FileIR_t *firp)
+{
+	for (set<Instruction_t*>::const_iterator it=firp->GetInstructions().begin();
+		it!=firp->GetInstructions().end(); 
+		++it)
+	{
+		Instruction_t* instr = *it;
+
+		if(instr->GetIBTargets() && !(
+			instr->GetIBTargets()->IsComplete() ||
+			instr->GetIBTargets()->IsModuleComplete()) )
+		{
+			assert(instr->GetIBTargets()->IsIncomplete());
+
+			if (allTargetsIndirectlyCalledFunctions(instr)) {
+				cerr << "ib targets for: " << instr->getDisassembly() << " reassigned to indirectcalls node" << endl;
+				instr->SetIBTargets(indirect_calls);
+			} else {
+				cerr << "ib targets for: " << instr->getDisassembly() << " reassigned to hellnode" << endl;
+				instr->SetIBTargets(hellnode_tgts);
+			}
+		}
+	}
+}
+
 void mark_targets(FileIR_t *firp)
 {
         for(
@@ -1431,8 +1480,6 @@ template <class T> T MAX(T a, T b)
 
 void icfs_init(FileIR_t* firp)
 {
-
-
 	assert(firp);
 	db_id_t max_id=0;
 	for(ICFSSet_t::iterator it=firp->GetAllICFS().begin(); it!=firp->GetAllICFS().end(); ++it)
@@ -1441,8 +1488,8 @@ void icfs_init(FileIR_t* firp)
 	}
 	next_icfs_set_id = max_id+1;
 	cerr<<"Found max ICFS id=="<<max_id<<endl;
-	hellnode_tgts = new ICFS_t(next_icfs_set_id++, false);
-	indirect_calls = new ICFS_t(next_icfs_set_id++, false); 
+	hellnode_tgts = new ICFS_t(next_icfs_set_id++, ICFS_Analysis_Module_Complete);
+	indirect_calls = new ICFS_t(next_icfs_set_id++, ICFS_Analysis_Module_Complete); 
 	firp->GetAllICFS().insert(hellnode_tgts);
 	firp->GetAllICFS().insert(indirect_calls);
 }
@@ -1496,7 +1543,6 @@ void check_for_ret(FileIR_t* const firp, Instruction_t* const insn)
 	if(strstr(d.Instruction.Mnemonic, "ret")==NULL)
 		return;
 
-
 	// already analysed by ida.
 	if(insn->GetIBTargets() && insn->GetIBTargets()->IsComplete())
 		return;
@@ -1704,12 +1750,14 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, std::list<virtual_offset_t>
 
 	mark_jmptables(firp);
 
+	patch_icfs(firp);
+
 	for(ICFSSet_t::const_iterator it=firp->GetAllICFS().begin();
 		it != firp->GetAllICFS().end();
 		++it)
 	{
 		ICFS_t *icfs = *it;
-		cout << dec << "icfs set id: " << icfs->GetBaseID() << "  #ibtargets: " << icfs->size() << endl;
+		cout << dec << "icfs set id: " << icfs->GetBaseID() << "  #ibtargets: " << icfs->size() << " analysis status: " << icfs->GetAnalysisStatus() << endl;
 	}
 }
 
diff --git a/libIRDB/test/read_variantir.cpp b/libIRDB/test/read_variantir.cpp
index 6248cbbe6..912ebee03 100644
--- a/libIRDB/test/read_variantir.cpp
+++ b/libIRDB/test/read_variantir.cpp
@@ -106,7 +106,7 @@ main(int argc, char* argv[])
 				++it)
 			{
 				ICFS_t *icfs = *it;
-				cout << "icfs set id: " << icfs->GetBaseID() << " complete: " << icfs->IsComplete() << "  #ibtargets: " << dec << icfs->size() << " | ";
+				cout << "icfs set id: " << dec << icfs->GetBaseID() << " analysis status: " << icfs->GetAnalysisStatus() << "  #ibtargets: " << icfs->size() << " | ";
 				int count = 0;
 				for(ICFS_t::const_iterator it2=icfs->begin(); 
 					it2!=icfs->end(); ++it2, ++count)
diff --git a/libIRDB/test/tests/ibtarget/Makefile b/libIRDB/test/tests/ibtarget/Makefile
index 4ed7b3e9b..7cc34a278 100644
--- a/libIRDB/test/tests/ibtarget/Makefile
+++ b/libIRDB/test/tests/ibtarget/Makefile
@@ -3,18 +3,20 @@ INCLUDES= -I../../../../include -I../../../include/ -I../../../../beaengine/incl
 #OPT=-fPIE -fPIC -O
 #OPT=-g -fPIE -fPIC
 OPT=-O
-.SUFFIXES: .exe .cpp .peasoup
+.SUFFIXES: .exe .cpp .protected
 
 PROGS=jmp1.exe jmp2.exe jmp.shared.exe icall.exe
-PEASOUP_PROGS=jmp1.peasoup jmp2.peasoup jmp.shared.peasoup icall.peasoup
+PEASOUP_PROGS=jmp1.protected jmp2.protected jmp.shared.protected icall.protected
 
 all: $(PROGS)
-peasoup: $(PEASOUP_PROGS)
+protected: $(PEASOUP_PROGS)
 
 $(PROGS): ../../../../lib/*
 
-.exe.peasoup: $<
-	LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." $(PEASOUP_HOME)/tools/ps_analyze.sh $< $@ --backend zipr --step meds_static=off
+.exe.protected: $<
+#	FIX_CALLS_FIX_ALL_CALLS=1 LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." $(PEASOUP_HOME)/tools/ps_analyze.sh $< $@ --backend zipr --step selective_cfi=on 
+	FIX_CALLS_FIX_ALL_CALLS=1 LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." $(PEASOUP_HOME)/tools/ps_analyze.sh $< $@ --backend zipr --step selective_cfi=on --step-option selective_cfi:--color
+#	LD_LIBRARY_PATH="$(LD_LIBRARY_PATH):." $(PEASOUP_HOME)/tools/ps_analyze.sh $< $@ --backend zipr --stop_after pdb_register
 
 .o.exe:  $< ../lib/libIRDB-core.a ../lib/libIRDB-cfg.a
 	g++ $< $(INCLUDES) $(LIBS) $(OPT)  -o $@
@@ -32,4 +34,4 @@ jmp.shared.exe: jmp.shared.so jmp.main.cpp
 	g++ jmp.main.o -L. -ljmp -o $@
 
 clean:
-	rm -fr $(PROGS) *.o *.so peasoup_executable* *.peasoup 
+	rm -fr $(PROGS) *.o *.so peasoup_executable* *.protected *.tmp.orig 
diff --git a/libIRDB/test/tests/ibtarget/validate_ibts.sh b/libIRDB/test/tests/ibtarget/validate_ibts.sh
new file mode 100755
index 000000000..f95b2cd9d
--- /dev/null
+++ b/libIRDB/test/tests/ibtarget/validate_ibts.sh
@@ -0,0 +1,38 @@
+# build original and protected test programs
+make clean all protected
+if [ ! $? -eq 0 ]; then
+	echo "failed to compile test programs"
+	exit 1
+fi
+
+export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:."
+
+ALL_PASS_STATUS=0
+# compare output
+for i in `ls *.exe`
+do
+	orig=$i
+	base=$(basename $orig .exe)
+	protected=${base}.protected
+
+	echo $orig $base $protected
+	./$orig 1 2 > $$.tmp.orig
+	./$protected 1 2 > $$.tmp.protected
+	diff $$.tmp.orig $$.tmp.protected
+	if [ ! $? -eq 0 ]; then
+		echo "FAIL: Protected program ${base}.protected does not match original program"
+		ALL_PASS_STATUS=1
+	else
+		echo "PASS: $orig vs. $protected"
+	fi
+
+	rm $$.tmp.orig $$.tmp.protected
+done
+
+echo
+if [ $ALL_PASS_STATUS -eq 0 ]; then
+	echo "PASS: all tests passed"
+else
+	echo "FAIL: one or more test failed"
+fi
+
diff --git a/tools/meds2pdb/meds2pdb.cpp b/tools/meds2pdb/meds2pdb.cpp
index 1c56ea279..a74510bf5 100644
--- a/tools/meds2pdb/meds2pdb.cpp
+++ b/tools/meds2pdb/meds2pdb.cpp
@@ -1,4 +1,3 @@
-char temp;
 /*
  * Copyright (c) 2014 - Zephyr Software LLC
  *
@@ -96,20 +95,25 @@ void insert_icfs(int fileID, const vector<wahoo::Instruction*>& instructions)
 
   	for (int i = 0; i < instructions.size(); i ++)
 	{
-      		wahoo::Instruction *instruction = instructions[i];
+     		wahoo::Instruction *instruction = instructions[i];
 		assert(instruction);
 
 		const std::set<Instruction*> &ibts=instruction->getIBTs();
 		
 		if(ibts.size()==0)
 			continue;
-		cerr<<"Found fromIB=="<<instruction->getAddress()<<endl;
+		cerr<<"Found fromIB=="<<hex<<instruction->getAddress()<<endl;
     
 		string query = "INSERT INTO " + icfsTable;
-    		query += " (icfs_id,is_complete) VALUES ";
+    		query += " (icfs_id,icfs_status) VALUES ";
       		query += "(";
       		query += txn.quote(next_icfs_id) + ",";
-      		query += txn.quote(instruction->isIbComplete());
+
+		if (instruction->isIbComplete())
+   	   		query += txn.quote(ICFS_ANALYSIS_COMPLETE_STR);
+		else
+   	   		query += txn.quote(ICFS_ANALYSIS_INCOMPLETE_STR);
+
 		query += ")";
 
 		string query2 = "INSERT INTO " + icfsMapTable;
@@ -117,7 +121,7 @@ void insert_icfs(int fileID, const vector<wahoo::Instruction*>& instructions)
 
 		for(set<Instruction*>::iterator it=ibts.begin(); it!=ibts.end(); it++)
 		{
-			cerr<<"  Found toIBT=="<<(*it)->getAddress()<<endl;
+			cerr<<"  Found toIBT=="<<hex<<(*it)->getAddress()<<endl;
 			if(it!=ibts.begin())
 				query2+=",";
 			int target_address_id=instruction_to_addressid_map[*it];
@@ -127,10 +131,22 @@ void insert_icfs(int fileID, const vector<wahoo::Instruction*>& instructions)
 			query2 += ")";
 			
 		}
-		
+
+		// update icfs_id entry in instruction
+		app_iaddr_t instruction_id = address_to_instructionid_map[instruction->getAddress()];
+		string query3 = "UPDATE " + instructionTable;
+    		query3 += " SET icfs_id=";
+			query3 += txn.quote(next_icfs_id);
+			query3 += " WHERE instruction_id=";
+			query3 += txn.quote(instruction_id);
+
 		query+=";";
 		query2+=";";
-    		txn.exec(query+query2);
+		query3+=";";
+
+    	txn.exec(query+query2+query3);
+
+		cerr<<query+query2+query3<<endl;
 		next_icfs_id++;
 	}
  	cerr<<"Finished inserting ICFS into IR."<<endl; 
@@ -571,6 +587,7 @@ int main(int argc, char **argv)
   	insert_functions(fileID, functions);
   	insert_instructions(fileID, instructions, functions);
   	update_functions(fileID, functions);
+
   	insert_icfs(fileID, instructions);
 
 	// add function prototype information to the IRDB
diff --git a/tools/transforms/Rewrite_Utility.cpp b/tools/transforms/Rewrite_Utility.cpp
index fac8f7cad..e162173be 100644
--- a/tools/transforms/Rewrite_Utility.cpp
+++ b/tools/transforms/Rewrite_Utility.cpp
@@ -45,6 +45,7 @@ Instruction_t* insertAssemblyBefore(FileIR_t* virp, Instruction_t* first, string
 	//"Null" out the original address (it should be as if the instruction was not in the database).
 	first->SetOriginalAddressID(BaseObj_t::NOT_IN_DATABASE);
 	first->GetRelocations().clear();
+	first->SetIBTargets(NULL);
 
 	virp->ChangeRegistryKey(first,next);
 	setInstructionAssembly(virp,first,assembly,next,target);
@@ -134,6 +135,7 @@ void copyInstruction(Instruction_t* src, Instruction_t* dest)
 	dest->SetCallback(src->GetCallback());
 	dest->SetFallthrough(src->GetFallthrough());
 	dest->SetTarget(src->GetTarget());
+	dest->SetIBTargets(src->GetIBTargets()); 
 	dest->GetRelocations()=src->GetRelocations();
 }
 
diff --git a/xform/rewriter.cpp b/xform/rewriter.cpp
index e659756f1..dac766a71 100644
--- a/xform/rewriter.cpp
+++ b/xform/rewriter.cpp
@@ -631,6 +631,7 @@ void Rewriter::readXrefsFile(char p_filename[])
 		addr_to_insn_map[instr->getAddress()]=instr;
 	}
 
+	set<app_iaddr_t> completeIBT;
 
         FILE* fin=fopen(p_filename, "r");
 
@@ -698,20 +699,25 @@ void Rewriter::readXrefsFile(char p_filename[])
 					from_instr->addIBT(instr);
 				}
 			}
-			else
-			{
-				wahoo::Instruction *instr = addr_to_insn_map[addr];
-				assert(instr);
-				instr->markIbComplete();
-			}
 		}
 		// check for instr xref fromib 	
 		else if(string("FROMIB")==string(ibt))
 		{
-			cerr<<"FROMIB line ignored for now."<<endl;
-		}
-
+			// annotations can come in any order so the COMPLETE annotation for IB targets
+			// can come before/after the targets themselves
+			// in this loop, just keep track of instructions w/ complete targets
+			// 4004b6      1 INSTR XREF FROMIB COMPLETE      1
+			char complete[200];
+			fscanf(fin, "%s", complete);
+
+			if(strcmp(complete,"COMPLETE")==0) 
+			{
+				completeIBT.insert(addr);
+			}
 
+			if(feof(fin))           // deal with blank lines at the EOF
+				break;
+		}
 		
 		char remainder[2000];
 		fgets(remainder, sizeof(remainder), fin);
@@ -719,9 +725,17 @@ void Rewriter::readXrefsFile(char p_filename[])
 	
 
 	} while(!feof(fin));
-	fclose(fin);
 
+	// let's backpatch all IB instructions with complete targets
+	set<app_iaddr_t>::const_iterator it;
+	for (it = completeIBT.begin(); it != completeIBT.end(); ++it)
+	{
+		wahoo::Instruction *instr = addr_to_insn_map[*it];
+		assert(instr);
+		instr->markIbComplete();
+	}
 
+	fclose(fin);
 }
 
 /*
-- 
GitLab