diff --git a/builtin_xforms/p1transform/P1_utility.cpp b/builtin_xforms/p1transform/P1_utility.cpp
index 6c2838a7351ae23048b7a9470d41d55ab3c75f2f..98894473898edeec289e242fce74fb8e64067c1d 100644
--- a/builtin_xforms/p1transform/P1_utility.cpp
+++ b/builtin_xforms/p1transform/P1_utility.cpp
@@ -78,23 +78,26 @@ Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, stri
         return newInsn;
 }
 
-
-#if 0
-Instruction_t* P1_copyInstruction(Instruction_t* instr)
+Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target)
 {
-	return IRDB_SDK::copyInstruction(instr);
+	Instruction_t* newInsn = IRDB_SDK::insertDataBitsBefore(virp, first, dataBits, target);
+	Function_t* func = newInsn->getFunction();
+	inserted_instr[func].insert(newInsn);
+        inserted_addr[func].insert(newInsn->getAddress());
+        return newInsn;
 }
 
-
-void P1_copyInstruction(Instruction_t* src, Instruction_t* dest)
+Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits)
 {
-	IRDB_SDK::copyInstruction(src, dest);
+	Instruction_t* newInsn = IRDB_SDK::insertDataBitsBefore(virp, first, dataBits);
+	Function_t* func = newInsn->getFunction();
+	inserted_instr[func].insert(newInsn);
+        inserted_addr[func].insert(newInsn->getAddress());
+        return newInsn;
 }
-#endif
 
 Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID, Function_t* func)
 {
-//	Instruction_t* newInsn = IRDB_SDK::allocateNewInstruction(virp, p_fileID, func);
 	auto newAddr=virp->addNewAddress(virp->getFile()->getBaseID(),0);
 	auto newInsn=virp->addNewInstruction(newAddr, func);
 
@@ -106,7 +109,6 @@ Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID,
 
 Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, Instruction_t *template_instr)
 {
-// 	Instruction_t* newInsn = IRDB_SDK::allocateNewInstruction(virp, template_instr);
 	auto fileId=virp->getFile()->getBaseID();
 	Function_t* func = template_instr->getFunction();
 	auto newInsn=P1_allocateNewInstruction(virp,fileId,func);
@@ -188,27 +190,27 @@ string getJecxzDataBits()
 Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitigation_policy policy, unsigned exit_code)
 {
 	auto handler_code=(Instruction_t *)nullptr;
+	static auto breadcrumb=(DataScoop_t *)nullptr;
+
 
 	if (policy == P_CONTROLLED_EXIT) 
 	{
-		string exit_code_str = 
-			virp->getArchitectureBitWidth()==64 ? 
+		const auto exit_code_str = virp->getArchitectureBitWidth()==64 ? 
 				"mov rdi, " + std::to_string(exit_code) : 
 				"mov ebx, " + std::to_string(exit_code);
 
 		handler_code = P1_allocateNewInstruction(virp,fallthrough);
 
 		P1_setInstructionAssembly(virp,handler_code,exit_code_str.c_str(), NULL,NULL);
-		Instruction_t* syscall_num = 
-			virp->getArchitectureBitWidth()==64 ? 
+		auto syscall_num = virp->getArchitectureBitWidth()==64 ? 
 				P1_insertAssemblyAfter(virp,handler_code,"mov rax, 60",NULL):  
 				P1_insertAssemblyAfter(virp,handler_code,"mov eax, 1",NULL);
-		Instruction_t* syscall_i = P1_insertAssemblyAfter(virp,syscall_num,"syscall",NULL);
+		auto syscall_i = P1_insertAssemblyAfter(virp,syscall_num,"syscall",NULL);
 		syscall_i->setFallthrough(fallthrough);
 	}
 	else if (policy == P_HARD_EXIT) 
 	{
-		handler_code= P1_allocateNewInstruction(virp,fallthrough);
+		handler_code = P1_allocateNewInstruction(virp,fallthrough);
 		P1_setInstructionAssembly(virp,handler_code,"hlt",NULL,NULL);
 		handler_code->setComment("hlt ; hard exit requested");
 		handler_code->setFallthrough(fallthrough);
@@ -221,6 +223,31 @@ Instruction_t* getHandlerCode(FileIR_t* virp, Instruction_t* fallthrough, mitiga
 		handler_code->setFallthrough(fallthrough);
 	}
 
+
+	// now that we've created some handler code, pre-pend the breadcrumbs as necessary
+	if(pn_options->getDoBreadcrumbs())
+	{
+		if(breadcrumb == nullptr)
+		{
+			auto sa=virp->addNewAddress(fallthrough->getAddress()->getFileID(), 0);
+			auto ea=virp->addNewAddress(fallthrough->getAddress()->getFileID(), 7);
+			auto contents=string(8,'\xff');
+			breadcrumb=virp->addNewDataScoop("p1_breadcrumb", sa, ea, nullptr, 6, false, contents );
+		}
+
+		const auto func_id       = fallthrough->getFunction()->getBaseID();
+		auto new_insn_bits_start = string{0x48, (int8_t)0xc7, 0x05, (int8_t)0xf5, (int8_t)0xff, (int8_t)0xff, (int8_t)0xff}; 
+		auto new_insn_bits       = new_insn_bits_start + string(reinterpret_cast<const char*>(&func_id), 4);
+
+		// note: updates handler_code to be the newly inserted instruction
+		P1_insertDataBitsBefore(virp, handler_code, new_insn_bits);
+		 
+		// add a pcrel reloc to the breadcrumb instruction, and link it to the breadcrumb scoop
+		(void)virp->addNewRelocation(handler_code, 0, "pcrel", breadcrumb);
+
+	}
+
+	/* note:  may be breadcrumb code */
 	return handler_code;
 }
 
diff --git a/builtin_xforms/p1transform/P1_utility.hpp b/builtin_xforms/p1transform/P1_utility.hpp
index 226b13e64d06c88d0f4da984f9313a748851b6ff..a9158f140acb8c2c6236de2c7cfd118e9736fc9c 100644
--- a/builtin_xforms/p1transform/P1_utility.hpp
+++ b/builtin_xforms/p1transform/P1_utility.hpp
@@ -32,6 +32,8 @@ Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, stri
 Instruction_t* P1_insertAssemblyAfter(FileIR_t* virp, Instruction_t* first, string assembly);
 Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target);
 Instruction_t* P1_insertDataBitsAfter(FileIR_t* virp, Instruction_t* first, string dataBits);
+Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits, Instruction_t *target);
+Instruction_t* P1_insertDataBitsBefore(FileIR_t* virp, Instruction_t* first, string dataBits);
 Instruction_t* P1_copyInstruction(Instruction_t* instr);
 void P1_copyInstruction(Instruction_t* src, Instruction_t* dest);
 Instruction_t* P1_allocateNewInstruction(FileIR_t* virp, DatabaseID_t p_fileID,Function_t* func);
diff --git a/builtin_xforms/p1transform/PNMain.cpp b/builtin_xforms/p1transform/PNMain.cpp
index 1f237bf37c09479e33ab81c5e10352a373a23291..e00ff885080dc07407dcd03c810c2ac69f18c3c6 100644
--- a/builtin_xforms/p1transform/PNMain.cpp
+++ b/builtin_xforms/p1transform/PNMain.cpp
@@ -63,6 +63,7 @@ enum
 	COVERAGE_FILE_OPTION,
 	PN_THRESHOLD_OPTION,
 	CANARIES_OPTION,
+	BREADCRUMBS_OPTION,
 	ONLY_VALIDATE_OPTION,
 	NO_P1_VALIDATE_OPTION,
 	ALIGN_STACK_OPTION,
@@ -92,6 +93,7 @@ static struct option const long_options[] =
 	{"coverage_file",required_argument, nullptr, COVERAGE_FILE_OPTION},
 	{"pn_threshold",required_argument, nullptr, PN_THRESHOLD_OPTION},
 	{"canaries", required_argument, nullptr, CANARIES_OPTION},
+	{"breadcrumbs", required_argument, nullptr, BREADCRUMBS_OPTION},
 	{"only_validate",required_argument, nullptr, ONLY_VALIDATE_OPTION},
 	{"no_p1_validate",no_argument,nullptr,NO_P1_VALIDATE_OPTION},
 	{"apriori_layout_file",required_argument, nullptr, APRIORI_OPTION},
@@ -320,6 +322,24 @@ int parseArgs(const vector<string> step_args)
 			}
 			break;
 		}
+		case BREADCRUMBS_OPTION:
+		{
+			if(strcasecmp("on",optarg)==0)
+			{
+				pn_options->setDoBreadcrumbs(true);
+			}
+			else if(strcasecmp("off",optarg)==0)
+			{
+				pn_options->setDoBreadcrumbs(false);
+			}
+			else
+			{
+				//TODO: print error message and usage
+				usage();
+				return 1;
+			}
+			break;
+		}
 		case ONLY_VALIDATE_OPTION:
 		{
 			only_validate=optarg;
diff --git a/builtin_xforms/p1transform/globals.h b/builtin_xforms/p1transform/globals.h
index f9bfd02f261707af0437b3fa4aae00a0e2618fab..973064c0a452ecd3108b37edaf2d081cf94cbba0 100644
--- a/builtin_xforms/p1transform/globals.h
+++ b/builtin_xforms/p1transform/globals.h
@@ -58,6 +58,7 @@ class PNOptions
 			recursive_min_stack_padding = 64;
 			recursive_max_stack_padding = recursive_min_stack_padding*2;
 			do_canaries = true;
+			do_breadcrumbs = false;
 			do_selective_canaries = false;
 			should_double_frame_size=true;
 			random_seed=getpid();
@@ -94,8 +95,11 @@ class PNOptions
 				return (rand()&0xffff) | (rand()<<16); 
 		}
 
-		void setDoCanaries(bool canaries) { do_canaries = canaries; }
-		bool getDoCanaries() const { return do_canaries; }
+		void setDoCanaries   (bool canaries   ) { do_canaries = canaries; }
+		void setDoBreadcrumbs(bool breadcrumbs) { do_breadcrumbs = breadcrumbs; }
+
+		bool getDoCanaries()    const { return do_canaries;    }
+		bool getDoBreadcrumbs() const { return do_breadcrumbs; }
 
 		void addSelectiveCanaryFunction(std::string func) { do_selective_canaries = true; canary_functions.insert(func);}
 		bool shouldCanaryFunction(std::string func) 
@@ -121,6 +125,7 @@ class PNOptions
 		int recursive_min_stack_padding;
 		int recursive_max_stack_padding;
 		bool do_canaries;
+		bool do_breadcrumbs;
 		bool do_selective_canaries;
 		bool should_double_frame_size;
 		int random_seed;