From fec69afb1d639cd28a5d77adc0fed1e2574c262a Mon Sep 17 00:00:00 2001
From: jdh8d <jdh8d@git.zephyr-software.com>
Date: Mon, 22 Aug 2016 18:09:29 +0000
Subject: [PATCH] updates (all over the place) for CFI with multimodule
 support.

Former-commit-id: 2bad6a3f6f42c8d3652ececdd4a2f48beec33344
---
 .gitattributes                                |  4 +
 tools/ret_shadow_stack/rss_instrument.cpp     |  4 +-
 tools/selective_cfi/SConscript                |  3 +
 tools/selective_cfi/scfi_instr.cpp            | 79 +++++++++++++------
 .../zest_cfi_runtime/SConscript32             | 34 ++++++++
 .../zest_cfi_runtime/SConscript64             | 35 ++++++++
 .../selective_cfi/zest_cfi_runtime/SConstruct |  7 ++
 .../zest_cfi_runtime/zest_dispatch64.s        | 47 +++++++++++
 tools/simple_cdi/scdi_instr.cpp               |  5 +-
 tools/transforms/Rewrite_Utility.cpp          | 39 +++++++++
 tools/transforms/Rewrite_Utility.hpp          |  4 +
 11 files changed, 233 insertions(+), 28 deletions(-)
 create mode 100644 tools/selective_cfi/zest_cfi_runtime/SConscript32
 create mode 100644 tools/selective_cfi/zest_cfi_runtime/SConscript64
 create mode 100644 tools/selective_cfi/zest_cfi_runtime/SConstruct
 create mode 100644 tools/selective_cfi/zest_cfi_runtime/zest_dispatch64.s

diff --git a/.gitattributes b/.gitattributes
index 059005660..99cae336e 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1134,6 +1134,10 @@ tools/selective_cfi/color_map.hpp -text
 tools/selective_cfi/scfi_driver.cpp -text
 tools/selective_cfi/scfi_instr.cpp -text
 tools/selective_cfi/scfi_instr.hpp -text
+tools/selective_cfi/zest_cfi_runtime/SConscript32 -text
+tools/selective_cfi/zest_cfi_runtime/SConscript64 -text
+tools/selective_cfi/zest_cfi_runtime/SConstruct -text
+tools/selective_cfi/zest_cfi_runtime/zest_dispatch64.s -text
 tools/simple_cdi/Makefile.in -text
 tools/simple_cdi/SConscript -text
 tools/simple_cdi/SConstruct -text
diff --git a/tools/ret_shadow_stack/rss_instrument.cpp b/tools/ret_shadow_stack/rss_instrument.cpp
index 401a500e7..c8ee2a972 100644
--- a/tools/ret_shadow_stack/rss_instrument.cpp
+++ b/tools/ret_shadow_stack/rss_instrument.cpp
@@ -69,7 +69,8 @@ virtual_offset_t getAvailableAddress(FileIR_t *p_virp)
 
 
 
-
+#if 0
+// moved to Rewrite_Utility.cpp
 static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm)
 {
         Instruction_t* newinstr;
@@ -88,6 +89,7 @@ static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, str
 
         return newinstr;
 }
+#endif
 
 
 static Instruction_t* registerCallbackHandler64(FileIR_t* firp, Instruction_t *p_orig, string p_callbackHandler, int p_numArgs)
diff --git a/tools/selective_cfi/SConscript b/tools/selective_cfi/SConscript
index 1f4a127f3..8f1007abc 100644
--- a/tools/selective_cfi/SConscript
+++ b/tools/selective_cfi/SConscript
@@ -31,3 +31,6 @@ Default(install)
 
 	
 	
+#lib32=SConscript("zest_cfi_runtime/SConscript", variant_dir="build32")
+SConscript("zest_cfi_runtime/SConscript") # , variant_dir="build64")
+
diff --git a/tools/selective_cfi/scfi_instr.cpp b/tools/selective_cfi/scfi_instr.cpp
index ab420e6eb..de49eceef 100644
--- a/tools/selective_cfi/scfi_instr.cpp
+++ b/tools/selective_cfi/scfi_instr.cpp
@@ -48,6 +48,8 @@ virtual_offset_t getAvailableAddress(FileIR_t *p_virp)
 
 
 
+#if 0
+// moved to Rewrite_Utility.cpp
 static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm)
 {
         Instruction_t* newinstr;
@@ -66,7 +68,6 @@ static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, str
 
         return newinstr;
 }
-
 static Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits)
 {
         Instruction_t* newinstr;
@@ -85,6 +86,7 @@ static Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, str
 
         return newinstr;
 }
+#endif
 
 
 static Instruction_t* registerCallbackHandler64(FileIR_t* firp, Instruction_t *p_orig, string p_callbackHandler, int p_numArgs)
@@ -595,13 +597,11 @@ void SCFI_Instrument::AddReturnCFIForExeNonce(Instruction_t* insn, ColoredSlotVa
 	ret -> jmp shared
 
 	shared: 
+		and [rsp], 0x7ffffffff
 		mov reg <- [ rsp ] 
 		cmp [reg], exe_nonce_value
-		jne ret_slow
+		jne slow
 		ret
-	ret_slow:	
-		pop ecx
-		jmp slow  // with cfi_slow-path nonce.
 
 #endif
 
@@ -1039,22 +1039,25 @@ static unsigned int  add_to_scoop(const string &str, DataScoop_t* scoop)
 	return oldend+1;
 };
 
-
 template<int ptrsize>
-static unsigned int prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t* firp) 
+static void insert_into_scoop_at(const string &str, DataScoop_t* scoop, FileIR_t* firp, const unsigned int at) 
 {
 	// assert that this scoop is unpinned.  may need to enable --step move_globals --step-option move_globals:--cfi
 	assert(scoop->GetStart()->GetVirtualOffset()==0);
 	int len=str.length();
-	scoop->SetContents(str+scoop->GetContents());
+	string new_scoop_contents=scoop->GetContents();
+	new_scoop_contents.insert(at,str);
+	scoop->SetContents(new_scoop_contents);
+
 	virtual_offset_t oldend=scoop->GetEnd()->GetVirtualOffset();
 	virtual_offset_t newend=oldend+len;
 	scoop->GetEnd()->SetVirtualOffset(newend);
 
 	// update each reloc to point to the new location.
-	for_each(scoop->GetRelocations().begin(), scoop->GetRelocations().end(), [str](Relocation_t* reloc)
+	for_each(scoop->GetRelocations().begin(), scoop->GetRelocations().end(), [str,at](Relocation_t* reloc)
 	{
-		reloc->SetOffset(reloc->GetOffset()+str.size());
+		if(reloc->GetOffset()>=at)
+			reloc->SetOffset(reloc->GetOffset()+str.size());
 		
 	});
 
@@ -1068,10 +1071,10 @@ static unsigned int prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t
 	});
 
 	// for each scoop
-	for_each(firp->GetDataScoops().begin(), firp->GetDataScoops().end(), [&str,scoop,firp](DataScoop_t* scoop_to_update)
+	for_each(firp->GetDataScoops().begin(), firp->GetDataScoops().end(), [&str,scoop,firp,at](DataScoop_t* scoop_to_update)
 	{
 		// for each relocation for that scoop
-		for_each(scoop_to_update->GetRelocations().begin(), scoop_to_update->GetRelocations().end(), [&str,scoop,firp,scoop_to_update](Relocation_t* reloc)
+		for_each(scoop_to_update->GetRelocations().begin(), scoop_to_update->GetRelocations().end(), [&str,scoop,firp,scoop_to_update,at](Relocation_t* reloc)
 		{
 			// if it's a reloc that's wrt scoop
 			DataScoop_t* wrt=dynamic_cast<DataScoop_t*>(reloc->GetWRT());
@@ -1088,7 +1091,8 @@ static unsigned int prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t
 						case 4:
 						{
 							unsigned int val=*((unsigned int*)&contents.c_str()[reloc->GetOffset()]); 
-							val +=str.size();
+							if(val>=at)
+								val +=str.size();
 							contents.replace(reloc->GetOffset(), ptrsize, (const char*)&val, ptrsize);
 							break;
 						
@@ -1096,7 +1100,8 @@ static unsigned int prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t
 						case 8:
 						{
 							unsigned long long val=*((long long*)&contents.c_str()[reloc->GetOffset()]); 
-							val +=str.size();
+							if(val>=at)
+								val +=str.size();
 							contents.replace(reloc->GetOffset(), ptrsize, (const char*)&val, ptrsize);
 							break;
 
@@ -1111,8 +1116,12 @@ static unsigned int prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t
 		});
 		
 	});
+};
 
-	return oldend+1;
+template<int ptrsize>
+static void prefix_scoop(const string &str, DataScoop_t* scoop, FileIR_t* firp) 
+{
+	insert_into_scoop_at<ptrsize>(str,scoop,firp,0);
 };
 
 
@@ -1166,7 +1175,7 @@ void SCFI_Instrument::add_got_entry(const std::string& name)
 	AddressID_t* start_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, firp->GetFile()->GetBaseID(), 0);
 	AddressID_t* end_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, firp->GetFile()->GetBaseID(), ptrsize-1);
 	DataScoop_t* external_func_addr_scoop=new DataScoop_t(BaseObj_t::NOT_IN_DATABASE,
-		"zest_cfi_added_"+name, start_addr,end_addr, NULL, 6, true, new_got_entry_str);
+		name, start_addr,end_addr, NULL, 6, true, new_got_entry_str);
 
 	firp->GetAddresses().insert(start_addr);
 	firp->GetAddresses().insert(end_addr);
@@ -1183,14 +1192,30 @@ void SCFI_Instrument::add_got_entry(const std::string& name)
 	string dl_sym_str((const char*)&dl_sym, sizeof(T_Elf_Sym));
 	unsigned int dl_pos=add_to_scoop(dl_sym_str,dynsym_scoop);
 
-	// add reloc to binary
+	// find the rela count.  can't insert before that.
+	int rela_count=0;
+	for(int i=0;i+sizeof(T_Elf_Dyn)<dynamic_scoop->GetSize(); i+=sizeof(T_Elf_Dyn))
+	{
+		T_Elf_Dyn &dyn_entry=*(T_Elf_Dyn*)&dynamic_scoop->GetContents().c_str()[i];
+		if(dyn_entry.d_tag==DT_RELACOUNT)	 // diff than rela size.
+		{
+			// add to the size
+			rela_count=dyn_entry.d_un.d_val;
+			break;
+		}
+	}
+
+	// create the new reloc 
 	T_Elf_Rela dl_rel;
 	memset(&dl_rel,0,sizeof(dl_rel));
 	dl_rel.r_info= ((dl_pos/sizeof(T_Elf_Sym))<<rela_shift) | reloc_type;
 	string dl_rel_str((const char*)&dl_rel, sizeof(dl_rel));
-	unsigned dl_rel_pos=prefix_scoop<ptrsize>(dl_rel_str, relscoop, firp);
 
-	Relocation_t* dl_reloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE,  0+((uintptr_t)&dl_rel.r_offset -(uintptr_t)&dl_rel), "dataptr_to_scoop", external_func_addr_scoop);
+// need to fixup relocs
+	unsigned int at=rela_count*sizeof(T_Elf_Rela);
+	insert_into_scoop_at<ptrsize>(dl_rel_str, relscoop, firp, at);
+
+	Relocation_t* dl_reloc=new Relocation_t(BaseObj_t::NOT_IN_DATABASE,  at+((uintptr_t)&dl_rel.r_offset -(uintptr_t)&dl_rel), "dataptr_to_scoop", external_func_addr_scoop);
 	relscoop->GetRelocations().insert(dl_reloc);
 	firp->GetRelocations().insert(dl_reloc);
 
@@ -1202,9 +1227,13 @@ void SCFI_Instrument::add_got_entry(const std::string& name)
 		if(dyn_entry.d_tag==DT_RELASZ)
 			// add to the size
 			dyn_entry.d_un.d_val+=sizeof(T_Elf_Rela);
-		if(dyn_entry.d_tag==DT_RELA)
+
+		// we insert the zest_cfi_dispatch symbol after the relative relocs.
+		// but we need to adjust the start if there are no relative relocs.
+		if(at == 0  && dyn_entry.d_tag==DT_RELA)
 			// subtract from the start.
 			dyn_entry.d_un.d_val-=sizeof(T_Elf_Rela);
+
 	}
 }
 
@@ -1226,10 +1255,10 @@ bool SCFI_Instrument::add_got_entries()
 
 
 	// add necessary GOT entries.
-	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("printf");
-	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("dladdr");
-	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("dlopen");
-	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("dlsym");
+	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("zest_cfi_dispatch");
+//	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("dlopen");
+//	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("printf");
+//	add_got_entry<T_Elf_Sym,T_Elf_Rela,T_Elf_Dyn,reloc_type,rela_shift,ptrsize>("dlsym");
 
 
 	// also add a zest cfi "function" that's exported so dlsym can find it.
@@ -1294,7 +1323,7 @@ bool SCFI_Instrument::add_libdl_as_needed_support()
 	assert(relaplt_scoop != NULL || relplt_scoop!=NULL); // can't have neither
 
 
-	auto libld_str_pos=add_to_scoop(string("libdl.so")+'\0', dynstr_scoop);
+	auto libld_str_pos=add_to_scoop(string("libzestcfi.so")+'\0', dynstr_scoop);
 
 
 	// a new dt_needed entry for libdl.so
diff --git a/tools/selective_cfi/zest_cfi_runtime/SConscript32 b/tools/selective_cfi/zest_cfi_runtime/SConscript32
new file mode 100644
index 000000000..705492944
--- /dev/null
+++ b/tools/selective_cfi/zest_cfi_runtime/SConscript32
@@ -0,0 +1,34 @@
+import os
+
+
+Import('env')
+myenv=env.Clone()
+myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME'])
+myenv.Replace(ZEST_RUNTIME=os.environ['ZEST_RUNTIME'])
+
+cpppath=''' 
+	'''
+
+
+cfiles=Glob( Dir('.').srcnode().abspath+"/*.cpp")
+nasmfiles32=Glob( Dir('.').srcnode().abspath+"/*32.s")
+
+CXXFLAGS = " -nostdlib -nostdinc -fno-exceptions -Wall "
+CFLAGS = " -nostdlib -nostdinc -fno-exceptions -Wall "
+LDFLAGS = " -nostdlib -nostdinc -fno-exceptions -Wall "
+AS = "nasm"
+
+myenv.Replace(AS = AS)
+myenv.Append(CPPPATH=Split(cpppath))
+
+myenv.Replace(ASFLAGS = " -felf32 " )
+myenv.Append(CXXFLAGS = CXXFLAGS+" -m32 ")
+myenv.Append(CFLAGS = CFLAGS+" -m32 ")
+myenv.Append(LINKFLAGS = LDFLAGS+" -m32 ")
+
+
+so32=myenv.SharedLibrary("libzestcfi32.so",  cfiles+nasmfiles32)
+install32=myenv.Install("$ZEST_RUNTIME/lib32/", so32)
+Default(install32)
+
+	
diff --git a/tools/selective_cfi/zest_cfi_runtime/SConscript64 b/tools/selective_cfi/zest_cfi_runtime/SConscript64
new file mode 100644
index 000000000..35add780f
--- /dev/null
+++ b/tools/selective_cfi/zest_cfi_runtime/SConscript64
@@ -0,0 +1,35 @@
+import os
+
+
+Import('env')
+myenv=env.Clone()
+myenv.Replace(SECURITY_TRANSFORMS_HOME=os.environ['SECURITY_TRANSFORMS_HOME'])
+myenv.Replace(ZEST_RUNTIME=os.environ['ZEST_RUNTIME'])
+
+cpppath=''' 
+	'''
+
+
+cfiles=Glob( Dir('.').srcnode().abspath+"/*.cpp")+Glob( Dir('.').srcnode().abspath+"/*.c")
+nasmfiles64=Glob( Dir('.').srcnode().abspath+"/*64.s")
+
+CXXFLAGS = " -nostdlib -fno-exceptions -Wall -fPIC -g "
+CFLAGS = " -nostdlib -fno-exceptions -Wall -fPIC -g "
+LDFLAGS = " -nostdlib -fno-exceptions -Wall -fPIC -g "
+AS = "nasm"
+
+myenv.Replace(AS = AS)
+myenv.Append(CPPPATH=Split(cpppath))
+
+myenv.Replace(ASFLAGS = " -felf64 ")
+myenv.Append(CXXFLAGS = CXXFLAGS +" -m64 ")
+myenv.Append(CFLAGS = CFLAGS +" -m64 ")
+myenv.Append(LINKFLAGS = LDFLAGS +" -m64 ")
+
+
+so64=myenv.SharedLibrary("libzestcfi.so",  cfiles+nasmfiles64)
+install64=myenv.Install("$ZEST_RUNTIME/lib64/", so64)
+Default(install64)
+
+	
+	
diff --git a/tools/selective_cfi/zest_cfi_runtime/SConstruct b/tools/selective_cfi/zest_cfi_runtime/SConstruct
new file mode 100644
index 000000000..e47f36c51
--- /dev/null
+++ b/tools/selective_cfi/zest_cfi_runtime/SConstruct
@@ -0,0 +1,7 @@
+
+
+
+env=Environment()
+Export('env')
+#env.SConscript('SConscript32', variant_dir='/tmp/build32')
+env.SConscript('SConscript64', variant_dir='/tmp/build64')
diff --git a/tools/selective_cfi/zest_cfi_runtime/zest_dispatch64.s b/tools/selective_cfi/zest_cfi_runtime/zest_dispatch64.s
new file mode 100644
index 000000000..4b75848d6
--- /dev/null
+++ b/tools/selective_cfi/zest_cfi_runtime/zest_dispatch64.s
@@ -0,0 +1,47 @@
+BITS 64
+
+default rel
+
+extern zest_cfi_dispatch_c
+
+section .text
+global zest_cfi_dispatch:function
+zest_cfi_dispatch:
+
+	lea rsp, [rsp-128]
+	pushf
+	push rax
+	push rbx
+	push rcx
+	push rdx
+	push rsi
+	push rdi
+	push rbp
+	push r8
+	push r9
+	push r10
+	push r11
+	push r12
+	push r13
+	push r14
+	push r15
+	mov rdi, r11	; r11 is the cfi reg for x86-64, copy it to rdi for C-calling convention.
+	call zest_cfi_dispatch_c wrt ..plt
+	pop r15
+	pop r14
+	pop r13
+	pop r12
+	pop r11
+	pop r10
+	pop r9
+	pop r8
+	pop rbp
+	pop rdi
+	pop rsi
+	pop rdx
+	pop rcx
+	pop rbx
+	pop rax
+	popf
+	lea rsp, [rsp+128]
+	ret
diff --git a/tools/simple_cdi/scdi_instr.cpp b/tools/simple_cdi/scdi_instr.cpp
index cc64ecc18..e8765e58f 100644
--- a/tools/simple_cdi/scdi_instr.cpp
+++ b/tools/simple_cdi/scdi_instr.cpp
@@ -48,7 +48,8 @@ std::string int_to_hex_string( T i )
 
 
 
-
+#if 0
+// moved to Rewrite_Utility.cpp
 static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm)
 {
         Instruction_t* newinstr;
@@ -67,7 +68,7 @@ static Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, str
 
         return newinstr;
 }
-
+#endif
 
 static Instruction_t* registerCallbackHandler64(FileIR_t* firp, Instruction_t *p_orig, string p_callbackHandler, int p_numArgs)
 {
diff --git a/tools/transforms/Rewrite_Utility.cpp b/tools/transforms/Rewrite_Utility.cpp
index e162173be..ccbdbb9b5 100644
--- a/tools/transforms/Rewrite_Utility.cpp
+++ b/tools/transforms/Rewrite_Utility.cpp
@@ -158,6 +158,45 @@ Instruction_t* allocateNewInstruction(FileIR_t* virp, db_id_t p_fileID,Function_
 	return instr;
 }
 
+Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm)
+{
+        Instruction_t* newinstr;
+        if (p_instr)
+                newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction());
+        else
+                newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL);
+
+        firp->RegisterAssembly(newinstr, p_asm);
+
+        if (p_instr)
+        {
+                newinstr->SetFallthrough(p_instr->GetFallthrough());
+                p_instr->SetFallthrough(newinstr);
+        }
+
+        return newinstr;
+}
+
+Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits)
+{
+        Instruction_t* newinstr;
+        if (p_instr)
+                newinstr = allocateNewInstruction(firp,p_instr->GetAddress()->GetFileID(), p_instr->GetFunction());
+        else
+                newinstr = allocateNewInstruction(firp,BaseObj_t::NOT_IN_DATABASE, NULL);
+
+        newinstr->SetDataBits(p_bits);
+
+        if (p_instr)
+        {
+                newinstr->SetFallthrough(p_instr->GetFallthrough());
+                p_instr->SetFallthrough(newinstr);
+        }
+
+        return newinstr;
+}
+
+
 Instruction_t* allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr)
 {
 	Function_t *func = template_instr->GetFunction();
diff --git a/tools/transforms/Rewrite_Utility.hpp b/tools/transforms/Rewrite_Utility.hpp
index c8a7b572f..b4b115c46 100644
--- a/tools/transforms/Rewrite_Utility.hpp
+++ b/tools/transforms/Rewrite_Utility.hpp
@@ -46,6 +46,10 @@ Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string
 Instruction_t* insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly);
 Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target);
 Instruction_t* insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits);
+Instruction_t* addNewDatabits(FileIR_t* firp, Instruction_t *p_instr, string p_bits);
+Instruction_t* addNewAssembly(FileIR_t* firp, Instruction_t *p_instr, string p_asm);
+
+
 
 //Does not insert into any variant, just copies data about the instruction itself, see the copyInstruction(src,dest) to see what is copied. 
 Instruction_t* copyInstruction(Instruction_t* instr);
-- 
GitLab