From fe6516bc392095472e0e236206713558bbbc396a Mon Sep 17 00:00:00 2001
From: jdh8d <jdh8d@git.zephyr-software.com>
Date: Thu, 8 Feb 2018 16:03:52 +0000
Subject: [PATCH] fixed switch detected for type3 switches so unpinner works!

Former-commit-id: b366f999f806b73b3bdb3b5035b03a3b4af8e32c
---
 libIRDB/test/fill_in_indtargs.cpp | 124 +++++++++++++++++++++---------
 libIRDB/test/fill_in_indtargs.hpp |  52 +++++++++++++
 2 files changed, 138 insertions(+), 38 deletions(-)

diff --git a/libIRDB/test/fill_in_indtargs.cpp b/libIRDB/test/fill_in_indtargs.cpp
index 6df80cfdd..c3c1f6d4e 100644
--- a/libIRDB/test/fill_in_indtargs.cpp
+++ b/libIRDB/test/fill_in_indtargs.cpp
@@ -80,6 +80,9 @@ map< Instruction_t*, fii_icfs > jmptables;
 // a map of virtual offset -> instruction for quick access.
 map<virtual_offset_t,Instruction_t*> lookupInstructionMap;
 
+// the set of things that are partially unpinned already.
+set<Instruction_t*> already_unpinned;
+
 static long total_unpins=0;
 
 
@@ -152,9 +155,9 @@ bool possible_target(virtual_offset_t p, virtual_offset_t from_addr, ibt_provena
 		if(getenv("IB_VERBOSE")!=NULL)
 		{
 			if(from_addr!=0)
-				cout<<"Found IB target address 0x"<<std::hex<<p<<" at 0x"<<from_addr<<std::dec<<endl;
+				cout<<"Found IB target address 0x"<<std::hex<<p<<" at 0x"<<from_addr<<std::dec<<", prov="<<prov<<endl;
 			else
-				cout<<"Found IB target address 0x"<<std::hex<<p<<" from unknown location"<<endl;
+				cout<<"Found IB target address 0x"<<std::hex<<p<<" from unknown location, prov="<<prov<<endl;
 		}
 		targets[p].add(prov);
 		return true;
@@ -981,12 +984,21 @@ static void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* in
 	if(table_base==0)
 		return;
 
-
 	// find the section with the data table
 	EXEIO::section *pSec=find_section(table_base,elfiop);
 	if(!pSec)
 		return;
 
+	auto table_max=-1;
+	auto cmp_insn=(Instruction_t*)NULL;
+	if(backup_until("cmp ", cmp_insn, insn))
+	{
+		assert(cmp_insn);
+		const auto cmp_decode=DecodedInstruction_t(cmp_insn);
+		table_max=cmp_decode.getImmediate();
+	}
+	
+
 	// if the section has no data, abort 
 	const char* secdata=pSec->get_data();
 	if(!secdata)
@@ -1078,11 +1090,7 @@ static void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* in
 				if(ibtarget)
 				{
 					jmptables[I5].insert(ibtarget);
-#ifdef CGC
-					jmptables[I5].SetAnalysisStatus(ICFS_Analysis_Complete);
-#else
 					jmptables[I5].SetAnalysisStatus(ICFS_Analysis_Module_Complete);
-#endif
 					possible_target(table_entry,table_base+0*ptrsize, ibt_provenance_t::ibtp_gotplt);
 					if(getenv("IB_VERBOSE")!=0)
 						cout<<hex<<"Found  plt dispatch ("<<disasm.getDisassembly()<<"') at "<<I5->GetAddress()->GetVirtualOffset()<< endl;
@@ -1123,7 +1131,16 @@ static void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* in
 		// finished the loop.
 		for(i=0;true;i++)
 		{
-			if(offset+i*ptrsize+ptrsize > pSec->get_size())
+			if(i>table_max)
+			{
+				if(getenv("IB_VERBOSE")!=0)
+				{
+					cout<<hex<<"Switch dispatch at "<<I5->GetAddress()->GetVirtualOffset()<< " with table_base="
+					    <<table_base<<" is complete!"<<endl;
+				}
+				jmptables[insn].SetAnalysisStatus(ICFS_Analysis_Complete);
+			}
+			if(offset+i*ptrsize+ptrsize > pSec->get_size() || i > table_max)
 				return;
 
 			const void *table_entry_ptr=(const int*)&(secdata[offset+i*ptrsize]);
@@ -1148,9 +1165,8 @@ static void check_for_PIC_switch_table32_type3(FileIR_t* firp, Instruction_t* in
 				cout<<"Found switch table (thunk-relative) entry["<<dec<<i<<"], "<<hex<<table_entry<<endl;
 
 			// make table bigger.
-			jmptables[insn].SetTableSize(i);
+			jmptables[insn].SetTableSize(i+1);/* 0 index, and this index is determined valid. */
 			jmptables[insn].insert(ibt);
-			jmptables[insn].SetAnalysisStatus(ICFS_Analysis_Complete);
 		}
 	}
 	else
@@ -2352,32 +2368,43 @@ void unpin_elf_tables(FileIR_t *firp, int64_t do_unpin_opt)
 				  )
 				{
 					total_unpins++;
+					auto allow_unpin=true;
 					if(do_unpin_opt != -1)
 					{
 						if(total_unpins > do_unpin_opt) 
 						{
+						/*
 							cout<<"Aborting unpin process mid elf table."<<endl;
 							return;
+						*/
+							allow_unpin=false;
 						}
-						cout<<"Attempting unpin #"<<total_unpins<<"."<<endl;
 					}
 
 					// when/if they fail, convert to if and guard the reloc creation.
 					if(getenv("UNPIN_VERBOSE")!=0)
-						cout<<"Unpinning "<<scoop->GetName()<<" entry at offset "<<dec<<i<<". vo="<<hex<<vo<<endl;
-
+					{
+						if(allow_unpin)
+							cout<<"Attempting unpin #"<<total_unpins<<"."<<endl;
+						else
+							cout<<"Eliding unpin #"<<total_unpins<<"."<<endl;
+					}
 
-					unpin_counts[scoop->GetName()]++;
+					if(allow_unpin || already_unpinned.find(insn)!=already_unpinned.end())
+					{
+						already_unpinned.insert(insn);
+						unpin_counts[scoop->GetName()]++;
 
-					Relocation_t* nr=new Relocation_t();
-					assert(nr);
-					nr->SetType("data_to_insn_ptr");
-					nr->SetOffset(i);
-					nr->SetWRT(insn);
+						Relocation_t* nr=new Relocation_t();
+						assert(nr);
+						nr->SetType("data_to_insn_ptr");
+						nr->SetOffset(i);
+						nr->SetWRT(insn);
 
-					// add reloc to IR.
-					firp->GetRelocations().insert(nr);
-					scoop->GetRelocations().insert(nr);
+						// add reloc to IR.
+						firp->GetRelocations().insert(nr);
+						scoop->GetRelocations().insert(nr);
+					}
 				}
 				else
 				{
@@ -2543,7 +2570,10 @@ void unpin_type3_switchtable(FileIR_t* firp,Instruction_t* insn,DataScoop_t* sco
 	set<Instruction_t*> switch_targs;
 
 	if(getenv("UNPIN_VERBOSE"))
-		cout<<"Unpinning type3 switch, dispatch is "<<hex<<insn->GetAddress()->GetVirtualOffset()<<":"<<insn->getDisassembly()<<endl; 
+	{
+		cout<<"Unpinning type3 switch, dispatch is "<<hex<<insn->GetAddress()->GetVirtualOffset()<<":"
+		    <<insn->getDisassembly()<<" with tabSz="<<jmptables[insn].GetTableSize()<<endl; 
+	}
 
 
 	// switch check
@@ -2590,29 +2620,44 @@ void unpin_type3_switchtable(FileIR_t* firp,Instruction_t* insn,DataScoop_t* sco
 			// which isn't otherwise addressed.
 			if(targets[table_entry].areOnlyTheseSet(prov))
 			{
+				auto allow_new_unpins=true;
 				total_unpins++;
 				if(do_unpin_opt != -1 && total_unpins > do_unpin_opt) 
 				{
-					cout<<"Aborting unpin process mid switch table."<<endl;
-					return;
+					allow_new_unpins=false;
+					
+					// don't abort early as we need to fully unpin the IBT once we've started.
+					//cout<<"Aborting unpin process mid switch table."<<endl;
+					// return;
 				}
 
-				if(getenv("UNPIN_VERBOSE"))
-					cout<<"Unpinning switch for ibt="<<hex<<table_entry<<", scoop_off="<<scoop_off<<endl;
+				// if we are out of unpins, and we haven't unpinned this instruction yet, skip unpinning it.
+				if(!allow_new_unpins && already_unpinned.find(ibt)==already_unpinned.end())
+				{
+					if(getenv("UNPIN_VERBOSE"))
+						cout<<"Eliding switch unpin for entry["<<dec<<i<<"] ibt="<<hex<<table_entry<<", scoop_off="<<scoop_off<<endl;
 
+					// do nothing
+				}
+				else
+				{
+					if(getenv("UNPIN_VERBOSE"))
+						cout<<"Unpinning switch entry ["<<dec<<i<<"] for ibt="<<hex<<table_entry<<", scoop_off="<<scoop_off<<endl;
+					already_unpinned.insert(ibt);
 
-				Relocation_t* nr=new Relocation_t();
-				assert(nr);
-				nr->SetType("data_to_insn_ptr");
-				nr->SetOffset(scoop_off);
-				nr->SetWRT(ibt);
-				// add reloc to IR.
-				firp->GetRelocations().insert(nr);
-				scoop->GetRelocations().insert(nr);
+					Relocation_t* nr=new Relocation_t();
+					assert(nr);
+					nr->SetType("data_to_insn_ptr");
+					nr->SetOffset(scoop_off);
+					nr->SetWRT(ibt);
+					// add reloc to IR.
+					firp->GetRelocations().insert(nr);
+					scoop->GetRelocations().insert(nr);
 
-				// remove rodata reference for hell nodes.
-				targets[table_entry]=newprov;
-				switch_targs.insert(ibt);
+					// remove rodata reference for hell nodes.
+					targets[table_entry]=newprov;
+					switch_targs.insert(ibt);
+				}
 			}
 		}
 		scoop_off+=ptrsize;
@@ -2661,11 +2706,13 @@ void unpin_switches(FileIR_t *firp, int do_unpin_opt)
 		{
 			unpin_type3_switchtable(firp,insn,scoop, do_unpin_opt);
 		}
+		/* don't do this as it breaks binary--search of unpinning 
 		if(do_unpin_opt != -1 && total_unpins > do_unpin_opt) 
 		{
 			cout<<"Aborting unpin after switch table."<<endl;
 			return;
 		}
+		*/
 		
         }
 	cout<<"#ATTRIBUTE switch_type3_pins="<<dec<<type3_pins<<endl;
@@ -2724,6 +2771,7 @@ void fill_in_indtargs(FileIR_t* firp, exeio* elfiop, std::list<virtual_offset_t>
 	ranges.clear();
 	targets.clear();
 	jmptables.clear();
+	already_unpinned.clear();
 	lookupInstruction_init(firp);
 
 	calc_preds(firp);
diff --git a/libIRDB/test/fill_in_indtargs.hpp b/libIRDB/test/fill_in_indtargs.hpp
index d474f91be..d8fcd0c99 100644
--- a/libIRDB/test/fill_in_indtargs.hpp
+++ b/libIRDB/test/fill_in_indtargs.hpp
@@ -55,6 +55,10 @@ using namespace EXEIO;
 // data structures
 //
 
+
+class ibt_provenance_t; 
+static inline std::ostream& operator<<(std::ostream& out, const ibt_provenance_t& prov);
+
 class ibt_provenance_t
 {
 	public:
@@ -107,12 +111,60 @@ class ibt_provenance_t
 		bool areOnlyTheseSet(const ibt_provenance_t t) const { return (value&~t.value) == 0; }
 		bool isEmpty() const { return value==0; }
 
+
 	private:
 
 		provtype_t value;
+		friend ostream& operator<<(ostream& out, const ibt_provenance_t& prov);
 		
 };
 
+static inline std::ostream& operator<<(std::ostream& out, const ibt_provenance_t& prov)
+{
+#define print_prov(a) 						\
+{						 		\
+	if(prov.value&(ibt_provenance_t::a))			\
+	{ 							\
+		const auto foo=std::string(#a);			\
+		out<<foo.substr(4,foo.length())<<",";		\
+	}							\
+}		
+	print_prov(ibtp_eh_frame);
+	print_prov(ibtp_user);
+	print_prov(ibtp_gotplt);
+	print_prov(ibtp_initarray);
+	print_prov(ibtp_finiarray);
+	print_prov(ibtp_entrypoint);
+	print_prov(ibtp_data);
+	print_prov(ibtp_text);
+	print_prov(ibtp_texttoprintf);
+	print_prov(ibtp_dynsym);
+	print_prov(ibtp_symtab);
+	print_prov(ibtp_stars_ret);
+	print_prov(ibtp_stars_switch);
+	print_prov(ibtp_stars_data);
+	print_prov(ibtp_stars_unknown);
+	print_prov(ibtp_stars_addressed);
+	print_prov(ibtp_stars_unreachable);
+	print_prov(ibtp_switchtable_type1);
+	print_prov(ibtp_switchtable_type2);
+	print_prov(ibtp_switchtable_type3);
+	print_prov(ibtp_switchtable_type4);
+	print_prov(ibtp_switchtable_type5);
+	print_prov(ibtp_switchtable_type6);
+	print_prov(ibtp_switchtable_type7);
+	print_prov(ibtp_switchtable_type8);
+	print_prov(ibtp_switchtable_type9);
+	print_prov(ibtp_switchtable_type10);
+	print_prov(ibtp_rodata);
+	print_prov(ibtp_unknown);
+	print_prov(ibtp_got);
+	print_prov(ibtp_ret);
+#undef print_prov
+
+	return out;
+}
+
 
 /*
  * Forward prototypes 
-- 
GitLab