Skip to content
Snippets Groups Projects
ehwrite.cpp 42.77 KiB

#include <zipr_all.h>
#include <libIRDB-core.hpp>
#include <Rewrite_Utility.hpp>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <map>
#include <assert.h>
#include <sys/mman.h>
#include <ctype.h>
#include <iostream>   // std::cout
#include <string>     // std::string, std::to_string
#include <fstream>
#include <elf.h>

#include <zipr_dwarf2.hpp>

#include "elfio/elfio.hpp"
#include "elfio/elfio_dump.hpp"
#include "targ-config.h"

using namespace libIRDB;
using namespace std;
using namespace zipr;
using namespace ELFIO;

template < typename T > std::string to_hex_string( const T& n )
{
        std::ostringstream stm ;
        stm << std::hex<< "0x"<< n ;
        return stm.str() ;
}

template<int ptrsize>
void EhWriterImpl_t<ptrsize>::GenerateNewEhInfo()
{
	
	BuildFDEs();
	GenerateEhOutput();
	CompileEhOutput();
	ScoopifyEhOutput();

}

template <int ptrsize>
bool EhWriterImpl_t<ptrsize>::CIErepresentation_t::canSupport(Instruction_t* insn) const
{
	// if the insn is missing info, we can support it.
	if(insn==NULL)
		return true;
	if(insn->GetEhProgram()==NULL)
		return true;

	// all info here.


	// check that the program,CAF, DAF and RR match.  if not, can't support
	if(insn->GetEhProgram()->GetCIEProgram() != pgm || 
	   insn->GetEhProgram()->GetCodeAlignmentFactor() != code_alignment_factor || 
	   insn->GetEhProgram()->GetDataAlignmentFactor() != data_alignment_factor || 
	   insn->GetEhProgram()->GetReturnRegNumber() != (int64_t)return_reg 
	  )
		return false;

	auto personality_it=find_if(
		insn->GetEhProgram()->GetRelocations().begin(), 
		insn->GetEhProgram()->GetRelocations().end(),
		[](const Relocation_t* r) { return r->GetType()=="personality"; });

	// lastly, check for a compatible personality reloc.
	// if incoming has no personality, we better have no personality to match.
	if(personality_it==insn->GetEhProgram()->GetRelocations().end())
	{
		return personality_reloc==NULL;
	}

	// incomming has personality, but do we?
	if(personality_reloc==NULL) return false;

	// compare personalities.
	if(personality_reloc->GetWRT() != (*personality_it)->GetWRT()) return false;
	if(personality_reloc->GetAddend() != (*personality_it)->GetAddend()) return false;

	return true;
}

template <int ptrsize>
EhWriterImpl_t<ptrsize>::CIErepresentation_t::CIErepresentation_t(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw)
	: has_been_output(false)
{
	assert(insn && ehw && insn->GetEhProgram());

	pgm = insn->GetEhProgram()->GetCIEProgram();
	code_alignment_factor = insn->GetEhProgram()->GetCodeAlignmentFactor();
	data_alignment_factor = insn->GetEhProgram()->GetDataAlignmentFactor();
	return_reg = insn->GetEhProgram()->GetReturnRegNumber();

	auto personality_it=find_if(
		insn->GetEhProgram()->GetRelocations().begin(), 
		insn->GetEhProgram()->GetRelocations().end(),
		[](const Relocation_t* r) { return r->GetType()=="personality";});

	personality_reloc = (personality_it==insn->GetEhProgram()->GetRelocations().end())
		? (Relocation_t*)NULL
		: *personality_it;
}


template <int ptrsize>
void EhWriterImpl_t<ptrsize>::print_pers(Instruction_t* insn, EhWriterImpl_t<ptrsize>::CIErepresentation_t *cie)
{
	const auto pretty_print= [&](Relocation_t* pr)
		{
			if(pr==NULL)
			{
				cout<<"Found no personality reloc"<<endl;
				return;
			}
			const auto personality_scoop=dynamic_cast<DataScoop_t*>(pr->GetWRT());
			const auto personality_insn=dynamic_cast<Instruction_t*>(pr->GetWRT());

			if(pr->GetWRT()==NULL)
				cout<<"\tFound null personality"<<endl;
			else if(personality_scoop)
				cout<<"\tFound personlity scoop "<<personality_scoop->GetName()<<"+0x"<<hex<<pr->GetAddend()<<endl;
			else if(personality_insn)
				cout<<"\tFound personlity instruction "<<hex<<personality_insn->GetBaseID()<<dec<<":"<<hex<<personality_insn->getDisassembly()<<endl;
			else
				cout<<"\tFound reloc: unexpected type? "<<endl;
		};

	cout<<"  CIE-Personality addr= "<<hex<<cie->personality_reloc<<dec<<endl;
	pretty_print(cie->GetPersonalityReloc());
	const auto personality_it=find_if(
		insn->GetEhProgram()->GetRelocations().begin(), 
		insn->GetEhProgram()->GetRelocations().end(),
		[](const Relocation_t* r) { return r->GetType()=="personality"; });
	const auto pr = (personality_it==insn->GetEhProgram()->GetRelocations().end())
		? (Relocation_t*)NULL
		: *personality_it;
	cout<<"  insn personality addr= "<<hex<<pr<<dec<<endl;
	pretty_print(pr);


};


template <int ptrsize>
EhWriterImpl_t<ptrsize>::FDErepresentation_t::FDErepresentation_t(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw)
	: 
		lsda(insn),
		cie(NULL)
{
	auto cie_it=find_if( ehw->all_cies.begin(), ehw->all_cies.end(), [&](const CIErepresentation_t* candidate)
			{
				return candidate->canSupport(insn);
			});

	if(cie_it==ehw->all_cies.end())
	{
		cie=new CIErepresentation_t(insn,ehw);
		ehw->all_cies.push_back(cie);

		if(getenv("EH_VERBOSE")!=NULL)
			cout<<"Creating new CIE representation"<<endl;
	}
	else
	{
		cie=*cie_it;
		if(getenv("EH_VERBOSE")!=NULL)
		{
			cout<<"Re-using CIE representation"<<endl;
			print_pers(insn, cie);
		}
	}

	start_addr=ehw->zipr_obj.GetLocationMap()->at(insn);
	last_advance_addr=start_addr;
	end_addr=start_addr+insn->GetDataBits().size();
	pgm=EhProgramListingManip_t(insn->GetEhProgram()->GetFDEProgram());
}


template <int ptrsize>
int EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::getMergeIndex(const EhProgramListingManip_t &other)
{
	auto other_index=(size_t)0;
	for(const auto &this_ele : *this)
	{
		if(isAdvanceDirective(this_ele))
			continue;

		if(other_index >= other.size())
			return -1;

		if( this_ele!=other.at(other_index))
			return -1;
		other_index++;
	}

	return other_index;
}
template <int ptrsize>
bool EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::canExtend(const EhProgramListingManip_t &other)
{
	return getMergeIndex(other) != -1;
}

template <int ptrsize>
void EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::extend(const uint64_t inc_amt, const EhProgramListingManip_t &other)
{
	if(size() > 0 && isAdvanceDirective(at(size()-1)))
	{
		auto &last_insn=at(size()-1);
		auto old_inc_amt=(int)0;
		auto old_size=(int)0;
		switch(last_insn[0])
		{
			case DW_CFA_advance_loc1: old_size=1; break;
			case DW_CFA_advance_loc2: old_size=2; break;
			case DW_CFA_advance_loc4: old_size=4; break;
		}
		for(auto i=0;i<old_size;i++)
			((char*)(&old_inc_amt))[i]=last_insn[i+1];

		auto new_inc_amt=old_inc_amt+inc_amt;
		auto opcode=(char)0;
		auto new_size=(int)0;
		if(new_inc_amt<=255)
		{
			new_size=1;
			opcode=DW_CFA_advance_loc1;
		}
		else if(new_inc_amt<=65535)
		{
			new_size=2;
			opcode=DW_CFA_advance_loc2;
		}
		else
		{
			new_size=4;
			opcode=DW_CFA_advance_loc4;
		}
		last_insn.resize(1+new_size);
		last_insn[0]=opcode;
		for(auto i=0;i<new_size;i++)
			last_insn[i+1]=((const char*)(&new_inc_amt))[i];
	}
	else
	{	
		auto new_size=(int)0;
		auto opcode=(char)0;
		if(inc_amt<=255)
		{
			new_size=1;
			opcode=DW_CFA_advance_loc1;
		}
		else if(inc_amt<=65535)
		{
			new_size=2;
			opcode=DW_CFA_advance_loc2;
		}
		else
		{
			new_size=4;
			opcode=DW_CFA_advance_loc4;
		}
		// make an advance directive
		string ehinsn;
		ehinsn.resize(1+new_size);
		ehinsn[0]=opcode;
		for(auto i=0;i<new_size;i++)
			ehinsn[i+1]=((const char*)(&inc_amt))[i];

		// add it with this->push_back()
		this->push_back(ehinsn);
	}

	// add elements from other[merge_index]-other[other.size()]
	auto merge_index=getMergeIndex(other);
	assert(merge_index>=0);
	for_each(other.begin()+merge_index,other.end(), [&](const string& s)
	{
		this->push_back(s);
	});

	
}

template <int ptrsize>
bool EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::isAdvanceDirective(const string &s) const
{
	// make sure uint8_t is an unsigned char.       
	static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char");

	auto data=s.data();
	auto opcode=data[0];
	auto opcode_upper2=(uint8_t)(opcode >> 6);
	auto opcode_lower6=(uint8_t)(opcode & (0x3f));

	switch(opcode_upper2)
	{
		case 1:
		{
			return true;
		}
		case 0:
		{
			switch(opcode_lower6)
			{
				case DW_CFA_advance_loc1:
				case DW_CFA_advance_loc2:
				case DW_CFA_advance_loc4:
					return true;

			}
		}
	}
	return false;

}

// see https://en.wikipedia.org/wiki/LEB128
template <int ptrsize>
static bool read_uleb128
        ( uint64_t &result,
        uint32_t& position,
        const uint8_t* const data,
        const uint32_t max)
{
        result = 0;
        auto shift = 0;
        while( position < max )
        {
                auto byte = data[position];
                position++;
                result |= ( ( byte & 0x7f ) << shift);
                if ( ( byte & 0x80) == 0)
                        break;
                shift += 7;
        }
        return ( position > max );

}

// see https://en.wikipedia.org/wiki/LEB128
template <int ptrsize>
static bool read_sleb128 (
        int64_t &result,
        uint32_t & position,
        const uint8_t* const data,
        const uint32_t max)
{
        result = 0;
        auto shift = 0;
        auto size = 64;  // number of bits in signed integer;
        auto byte=uint8_t(0);
        do
        {
                byte = data [position];
                position++;
                result |= ((byte & 0x7f)<< shift);
                shift += 7;
        } while( (byte & 0x80) != 0);

        /* sign bit of byte is second high order bit (0x40) */
        if ((shift < size) && ( (byte & 0x40) !=0 /* sign bit of byte is set */))
                /* sign extend */
                result |= - (1 << shift);
        return ( position > max );

}




template <int ptrsize>
static void print_uleb_operand(
	stringstream &sout,
        uint32_t pos,
        const uint8_t* const data,
        const uint32_t max)
{
        auto uleb=uint64_t(0xdeadbeef);
        read_uleb128<ptrsize>(uleb, pos, data, max);
        sout<<" "<<dec<<uleb;
}

template <int ptrsize>
static void print_sleb_operand(
	stringstream &sout,
        uint32_t pos,
        const uint8_t* const data,
        const uint32_t max)
{
        auto leb=int64_t(0xdeadbeef);
        read_sleb128<ptrsize>(leb, pos, data, max);
        sout<<" "<<dec<<leb;
}



template <int ptrsize>
string EhWriterImpl_t<ptrsize>::EhProgramListingManip_t::getPrintableString(const string &s) const
{

	stringstream sout;
	// make sure uint8_t is an unsigned char.	
	static_assert(std::is_same<unsigned char, uint8_t>::value, "uint8_t is not unsigned char");

	auto data=s;
	auto opcode=(uint8_t)data[0];
	auto opcode_upper2=(uint8_t)(opcode >> 6);
	auto opcode_lower6=(uint8_t)(opcode & (0x3f));
	auto pos=uint32_t(1);
	auto max=data.size();
	switch(opcode_upper2)
	{
		case 1:
		{
			// case DW_CFA_advance_loc:
			sout<<"				cfa_advance_loc "<<dec<<+opcode_lower6<<" * caf";
			break;
		}
		case 2:
		{
			uint64_t uleb=0;
			sout<<"				cfa_offset "; 
			if(read_uleb128<ptrsize>(uleb, pos, (const uint8_t* const)data.data(), max))
				break;
			// case DW_CFA_offset:
			sout <<dec<<uleb;
			break;
		}
		case 3:
		{
			// case DW_CFA_restore (register #):
			sout<<"				cfa_restore";
			break;
		}
		case 0:
		{
			switch(opcode_lower6)
			{
			
				case DW_CFA_nop:
					sout<<"				nop" ;
					break;
				case DW_CFA_remember_state:
					sout<<"				remember_state" ;
					break;
				case DW_CFA_restore_state:
					sout<<"				restore_state" ;
					break;

				// takes single uleb128
				case DW_CFA_undefined:
					sout<<"				undefined" ;
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;
		
				case DW_CFA_same_value:
					sout<<"				same_value ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;
				case DW_CFA_restore_extended:
					sout<<"				restore_extended ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;
				case DW_CFA_def_cfa_register:
					sout<<"				def_cfa_register ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;
				case DW_CFA_GNU_args_size:
					sout<<"				GNU_arg_size ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;
				case DW_CFA_def_cfa_offset:
					sout<<"				def_cfa_offset "; 
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max); 
					break;

				case DW_CFA_set_loc:
				{
					auto arg=uintptr_t(0xDEADBEEF);
					switch(ptrsize)
					{
						case 4:
							arg=*(uint32_t*)&data.data()[pos]; break;
						case 8:
							arg=*(uint64_t*)&data.data()[pos]; break;
						default: 
							assert(0);
					}
					sout<<"				set_loc "<<hex<<arg;
					break;
				}
				case DW_CFA_advance_loc1:
				{
					auto loc=*(uint8_t*)(&data.data()[pos]);
					sout<<"				advance_loc1 "<<+loc<<" * caf " ;
					break;
				}

				case DW_CFA_advance_loc2:
				{
					auto loc=*(uint16_t*)(&data.data()[pos]);
					sout<<"				advance_loc2 "<<+loc<<" * caf " ;
					break;
				}

				case DW_CFA_advance_loc4:
				{
					auto loc=*(uint32_t*)(&data.data()[pos]);
					sout<<"				advance_loc4 "<<+loc<<" * caf " ;
					break;
				}
				case DW_CFA_offset_extended:
					sout<<"				offset_extended ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					break;
				case DW_CFA_register:
					sout<<"				register ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					break;
				case DW_CFA_def_cfa:
					sout<<"				def_cfa ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					break;
				case DW_CFA_def_cfa_sf:
					sout<<"				def_cfa_sf ";
					print_uleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					print_sleb_operand<ptrsize>(sout,pos,(const uint8_t* const)data.data(),max);
					break;

				case DW_CFA_def_cfa_expression:
				{
					auto uleb=uint64_t(0);
					sout<<"				def_cfa_expression "; 
					if(read_uleb128<ptrsize>(uleb, pos, (const uint8_t* const)data.data(), max))
						break;
					sout <<dec<<uleb;
					pos+=uleb;		// doing this old school for now, as we aren't printing the expression.
					sout <<" (not printing expression)";
					break;
				}
				case DW_CFA_expression:
				{
					auto uleb1=uint64_t(0);
					auto uleb2=uint64_t(0);
					sout<<"                              expression "; 
					if(read_uleb128<ptrsize>(uleb1, pos, (const uint8_t* const)data.data(), max))
						break;
					if(read_uleb128<ptrsize>(uleb2, pos, (const uint8_t* const)data.data(), max))
						break;
					sout<<dec<<uleb1<<" "<<uleb2;
					pos+=uleb2;
					break;
				}
				case DW_CFA_val_expression:
				{
					auto uleb1=uint64_t(0);
					auto uleb2=uint64_t(0);
					sout<<"                              val_expression "; 
					if(read_uleb128<ptrsize>(uleb1, pos, (const uint8_t* const)data.data(), max))
						break;
					if(read_uleb128<ptrsize>(uleb2, pos, (const uint8_t* const)data.data(), max))
						break;
					sout <<dec<<uleb1<<" "<<uleb2;
					pos+=uleb2;
					break;
				}
				case DW_CFA_def_cfa_offset_sf:
				{
					auto leb=int64_t(0);
					sout<<"					def_cfa_offset_sf "; 
					if(read_sleb128<ptrsize>(leb, pos, (const uint8_t* const)data.data(), max))
						break;
					sout <<dec<<leb;
					break;
				}
				case DW_CFA_offset_extended_sf:
				{
					auto uleb1=uint64_t(0);
					auto sleb2=int64_t(0);
					sout<<"                              offset_extended_sf "; 
					if(read_uleb128<ptrsize>(uleb1, pos, (const uint8_t* const)data.data(), max))
						break;
					if(read_sleb128<ptrsize>(sleb2, pos, (const uint8_t* const)data.data(), max))
						break;
					sout <<dec<<uleb1<<" "<<sleb2;
					break;
				}


				/* SGI/MIPS specific */
				case DW_CFA_MIPS_advance_loc8:

				/* GNU extensions */
				case DW_CFA_GNU_window_save:
				case DW_CFA_GNU_negative_offset_extended:
				default:
					sout<<"Unhandled opcode cannot print. opcode="<<opcode;
			}
			break;
		}
		default:
			assert(0);
	}

	return sout.str();
}

template <int ptrsize>
EhWriterImpl_t<ptrsize>::FDErepresentation_t::LSDArepresentation_t::LSDArepresentation_t(Instruction_t* insn)
	// if there are call sites, use the call site encoding.  if not, set to omit for initializer.
	//  extend/canExtend should be able to extend an omit to a non-omit.
	: tt_encoding( insn->GetEhCallSite() ? insn->GetEhCallSite()->GetTTEncoding() : 0xff)
{
		
	extend(insn);
}


static const auto RelocsEqual=[](const Relocation_t* a, const Relocation_t* b) -> bool
{
	if(a==NULL && b==NULL)
		return true;
	if(a==NULL || b==NULL)
		return false;
	return 
		forward_as_tuple(a->GetType(), a->GetOffset(), a->GetWRT(), a->GetAddend()) == 
		forward_as_tuple(b->GetType(), b->GetOffset(), b->GetWRT(), b->GetAddend());
};

template <int ptrsize>
bool EhWriterImpl_t<ptrsize>::FDErepresentation_t::LSDArepresentation_t::canExtend(Instruction_t* insn) const
{
	if(insn->GetEhCallSite() == NULL)
		return true;

	const auto insn_tt_encoding = insn->GetEhCallSite()->GetTTEncoding();

	// no type table
	if(tt_encoding==0xff || insn_tt_encoding==0xff) // DW_EH_PE_omit (0xff)
	{
		// no encoding issues.
	}
	// check if tt encodings match.
	else if(insn_tt_encoding!=tt_encoding)
		return true;

	assert((tt_encoding&0xf)==0x3 || 	// encoding contains DW_EH_PE_udata4 
	       (tt_encoding)==0xff || 		// or is exactly DW_EH_PE_omit
	       ((tt_encoding&0xf)==0x0 && ptrsize==4) || 		// or is exactly DW_EH_PE_absptr on 32-bit
 	       (tt_encoding&0xf)==0xb ); 	// or encoding contains DW_EH_PE_sdata4
	const auto tt_entry_size=4;

	const auto mismatch_tt_entry = find_if(
		insn->GetEhCallSite()->GetRelocations().begin(),
		insn->GetEhCallSite()->GetRelocations().end(),
		[&](const Relocation_t* candidate_reloc)
			{
				const auto tt_index=candidate_reloc->GetOffset()/tt_entry_size;
				if(tt_index>=(int64_t)type_table.size())
					return false;
				const auto &tt_entry=type_table.at(tt_index);
	
				if(tt_entry==NULL) // entry is empty, so no conflict
					return false;
				return !RelocsEqual(candidate_reloc, tt_entry);
			}
		);

	// return true if we found no mismatches
	return (mismatch_tt_entry == insn->GetEhCallSite()->GetRelocations().end());
}

template <int ptrsize>
void EhWriterImpl_t<ptrsize>::FDErepresentation_t::LSDArepresentation_t::extend(Instruction_t* insn)
{
	// if there's no call site info, the LSDA doesn't need an extension.
	if(insn->GetEhCallSite() == NULL)
		return;

	const auto insn_tt_encoding = insn->GetEhCallSite()->GetTTEncoding();

	// FIXME: optimization possibilty:  see if the last call site in the table
	// has the same set of catch-types + landing_pad and is "close enough" to this insn.
	// if so, combine.  

	cout<<"Creating call sites in LSDA for "<<hex<<insn->GetBaseID()<<":"<<insn->getDisassembly()<<endl;

	// just create a new entry in the CS table.. 
	auto cs=(call_site_t){0}; 

	cs.cs_insn_start=insn;
	cs.cs_insn_end=insn;
	cs.landing_pad=insn->GetEhCallSite()->GetLandingPad();

	if(tt_encoding == 0xff /* omit */)
	{
		/* existing is omit, use new encoding */
		tt_encoding=insn_tt_encoding;
	}
	else if(insn_tt_encoding == 0xff /* omit */)
	{
		/* new encoding is omit, use current tt encoding */
	}
	else if(tt_encoding == insn_tt_encoding)
	{
		/* encodings match, -- do nothing */
	}
	else
		assert(0); // canExtend failure?
	
		


	// go through the relocations on the eh call site and 
	// resolve each one by putting it into a set.
	// the set will be (non-duplicating) inserted as a "entry" (really multiple entries) 
	// into the action table,
	// Each reloc will also get a non-duplicating insert into the type table.
	for(const auto &reloc : insn->GetEhCallSite()->GetRelocations())
	{
		const auto wrt_scoop=dynamic_cast<DataScoop_t*>(reloc->GetWRT());
		if(reloc->GetWRT()==NULL)
			cout<<"\tFound reloc: NULL (catch all)"<<endl;
		else if(wrt_scoop)
			cout<<"\tFound reloc: scoop "<<wrt_scoop->GetName()<<"+0x"<<hex<<reloc->GetAddend()<<endl;
		else
			cout<<"\tFound reloc: unexpected type? "<<endl;

		// for now, this is the only supported reloc type on a EhCallSite 
		assert(reloc->GetType()=="type_table_entry");
		auto tt_it=find_if(type_table.begin(),type_table.end(), 
			[reloc](const Relocation_t* candidate) { return candidate!=NULL && RelocsEqual(candidate,reloc); });
		if(tt_it==type_table.end())
		{
			const auto tt_encoding = insn->GetEhCallSite()->GetTTEncoding();
			assert(
			       (tt_encoding&0xf)==0x3 ||  		// encoding contains DW_EH_PE_udata4
			       (tt_encoding&0xf)==0xb ||  		// encoding contains DW_EH_PE_sdata4
			       ((tt_encoding&0xf)==0x0 && ptrsize==4)  	// encoding contains DW_EH_PE_absptr && ptrsize==4
				);
			const auto tt_entry_size=4;
			const auto tt_index= reloc->GetOffset()/tt_entry_size;
			if(tt_index>=(int64_t)type_table.size())
				type_table.resize(tt_index+1);
			assert(type_table.at(tt_index)==NULL || RelocsEqual(type_table.at(tt_index),reloc));	
			type_table[tt_index]=reloc;	
		}
	}

	cs.actions=insn->GetEhCallSite()->GetTTOrderVector();

	auto at_it=find(action_table.begin(),action_table.end(), cs.actions);
	if(at_it==action_table.end())
	{
		// actions will be at the end of the action table.
		cs.action_table_index=action_table.size();

		// add to the action table
		action_table.push_back(cs.actions);
	}
	else
	{
		// calc which entry in the action table for the call site.
		cs.action_table_index=at_it-action_table.begin();
	}

	// the call site will index the action table at the end of the action table.
	callsite_table.push_back(cs);
}

template <int ptrsize>
bool EhWriterImpl_t<ptrsize>::FDErepresentation_t::canExtend(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw)
{
	const auto insn_addr=ehw->zipr_obj.GetLocationMap()->at(insn);
	const auto new_fde_thresh=100;

	if(insn_addr<start_addr)
		return false;

	if(end_addr + new_fde_thresh < insn_addr)
		return false;

	assert(cie);
	if(!cie->canSupport(insn))
		return false; // can't change the CIE.

	return pgm.canExtend(insn->GetEhProgram()->GetFDEProgram()) && 
		lsda.canExtend(insn);


}

template <int ptrsize>
void EhWriterImpl_t<ptrsize>::FDErepresentation_t::extend(Instruction_t* insn, EhWriterImpl_t<ptrsize>* ehw)
{
	const auto insn_addr=ehw->zipr_obj.GetLocationMap()->at(insn);
	const auto new_end_addr=insn_addr+insn->GetDataBits().size();
	const auto incr_amnt=insn_addr-last_advance_addr;
	last_advance_addr=insn_addr;

	// add appropriate instructions to the pgm.
	pgm.extend((incr_amnt)/cie->code_alignment_factor, insn->GetEhProgram()->GetFDEProgram());

	lsda.extend(insn);

	// extend the end 
	end_addr=new_end_addr;
	
}

template <int ptrsize>
void EhWriterImpl_t<ptrsize>::FDErepresentation_t::emitAssembly(ostream& out)
{
	out<<"Hello"<<endl;
}

template<int ptrsize>
void EhWriterImpl_t<ptrsize>::BuildFDEs()
{
	// build a map of the instructions in program order
	map<virtual_offset_t,Instruction_t*> insn_in_order;
	for(const auto& this_pair : *zipr_obj.GetLocationMap())
		insn_in_order[this_pair.second]=this_pair.first;


	// build the fdes (and cies/lsdas) for this insn, starting with a null fde in case none exist
	auto current_fde=(FDErepresentation_t*)NULL;
	auto insns_with_frame=0;

	// for_each instruction in program order
	for(const auto& this_pair : insn_in_order)
	{
		const auto &this_insn=this_pair.second;
		const auto &this_addr=this_pair.first;

		// no eh pgm or call site?  no worries, just ignore this insn
		if(this_insn->GetEhProgram()==NULL && this_insn->GetEhCallSite()==NULL)
			continue;

		insns_with_frame++;

		// if it has an unwinder and/or a call site, we will need an fde.

		// end this fde
		if(current_fde && !current_fde->canExtend(this_insn, this))
		{
			if(getenv("EH_VERBOSE")!=NULL)
				cout<<"Ending FDE because insn "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<<" doesn't fit at " << this_addr<< endl;
			current_fde=NULL;
		}


		// if we need to start a new fde, create one.
		if(current_fde==NULL)
		{
			if(getenv("EH_VERBOSE")!=NULL)
				cout<<"Creating new FDE for "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<< " at " << this_addr<<endl;
			current_fde=new FDErepresentation_t(this_insn,this);
			all_fdes.push_back(current_fde);
		}
		else
		{
			if(getenv("EH_VERBOSE")!=NULL)
			{
				cout<<"Extending new FDE for "<<hex<<this_insn->GetBaseID()<<":"<<this_insn->getDisassembly()<<" at " << this_addr <<endl;
				print_pers(this_insn,current_fde->cie);

			}
			current_fde->extend(this_insn,this);
		}
	}
	cout<<"# ATTRIBUTE ExceptionHandlerWrite::fdes_calculated="<<dec<<all_fdes.size()<<endl;
	cout<<"# ATTRIBUTE ExceptionHandlerWrite::cies_calculated="<<dec<<all_cies.size()<<endl;
	cout<<"# ATTRIBUTE ExceptionHandlerWrite::insns_with_eh_info="<<dec<<insns_with_frame<<endl;
	cout<<"# ATTRIBUTE ExceptionHandlerWrite::avg_insns_per_fde="<<dec<<insns_with_frame/(float)all_fdes.size()<<endl;
}

template<int ptrsize>
void EhWriterImpl_t<ptrsize>::GenerateEhOutput()
{

	auto output_program=[&](const EhProgramListingManip_t& p, ostream & out) 
	{
		auto flags=out.flags();//save flags
		for(auto i=0U; i < p.size() ; i ++ ) 
		{		
			const auto &s = p[i];
			if(i==p.size()-1 && p.isAdvanceDirective(s))	/* no need to output last insn if it's an advance */
				break;
			out<<"       .byte ";
			auto first=true;
			for(const auto &c : s)
			{
				if(!first)
				{
					out<<", ";
				}
				else
					first=false;
				out<<"0x"<<hex<<setfill('0')<<setw(2)<<((int)c&0xff);
			}
			out << " # " << p.getPrintableString(s)<<endl;
		}
		out.flags(flags); // restore flags
	};
	const auto output_lsda=[&](const FDErepresentation_t* fde, ostream& out, const uint32_t lsda_num) -> void
	{
		const auto lsda=&fde->lsda;
		out<<"LSDA"<<dec<<lsda_num<<":"<<endl;
		if(!lsda->exists())
		{
			return;
		}

		// the encoding of the landing pad is done in two parts:
		// landing_pad=landing_pad_base+landing_pad_offset.
		// typically, the landing_pad_base is omitted and the fde->start_addr is used instead.  
		// However, sometimes the fde->start_addr is equal to the landing_pad,
		// which would make the landing_pad_offset 0.
		// but a landing_pad offset of 0 indicates no landing pad.
		// To avoid this situation, we first detect it,
		// then arbitrarily pick (and encode) a landing_pad_base that's
		// not equal to any landing paad in the call site list.
		const auto calc_landing_pad_base=[&]() -> uint64_t
		{
			// look for a landing pad that happens to match the fde->start_addr
			const auto lp_base_conflict_it=find_if(
				lsda->callsite_table.begin(),
				lsda->callsite_table.end(),
				[&](const typename FDErepresentation_t::LSDArepresentation_t::call_site_t& candidate)
				{
					if(candidate.landing_pad==NULL)
						return false;
					const auto lp_addr=zipr_obj.GetLocationMap()->at(candidate.landing_pad);
					return (lp_addr==fde->start_addr);
				});

			// if not found, there's no need to adjust the landing pad base address.
			if(lp_base_conflict_it==lsda->callsite_table.end())
				return fde->start_addr;

			// we pick an arbitrary landing_pad base by taking the min of all
			// landing pads (and the fde_start addr), and subtracting 1.
			const auto min_cs_entry_it=min_element(
				lsda->callsite_table.begin(),
				lsda->callsite_table.end(),
				[&](const typename FDErepresentation_t::LSDArepresentation_t::call_site_t& a , const typename FDErepresentation_t::LSDArepresentation_t::call_site_t &b)
				{
					const auto lp_a=a.landing_pad;
					const auto lp_b=b.landing_pad;
					if(lp_a && lp_b)
					{
						const auto lp_addr_a=zipr_obj.GetLocationMap()->at(lp_a);
						const auto lp_addr_b=zipr_obj.GetLocationMap()->at(lp_b);
						return lp_addr_a<lp_addr_b;
					}
					if(!lp_a && lp_b)
						return false;
					if(!lp_b && lp_a)
						return true;
					return false;
				});
			const auto &min_cs_entry=*min_cs_entry_it;
			const auto min_lp_addr=zipr_obj.GetLocationMap()->at(min_cs_entry.landing_pad);
			const auto min_addr=min(min_lp_addr,fde->start_addr);
			return min_addr-1;
	
		};

		const auto landing_pad_base=calc_landing_pad_base();

		// how to output actions
		const auto output_action=[&](const libIRDB::TTOrderVector_t &act, const uint32_t act_num) -> void
		{
			const auto &ttov=act;
			const auto biggest_ttov_index=ttov.size()-1;
			auto act_entry_num=biggest_ttov_index;

			for(int i=act_entry_num; i>=0; i--)
			{
				out<<"LSDA"<<dec<<lsda_num<<"_act"<<act_num<<"_start_entry"<<act_entry_num<<""<<":"<<endl;
				out<<"	.sleb128 "<<dec<<ttov.at(act_entry_num)<<endl;        
				if(act_entry_num==biggest_ttov_index)
					out<<"	.sleb128 0 "<<endl;
				else
					out<<"	.sleb128  LSDA"<<lsda_num<<"_act"<<act_num<<"_start_entry"<<act_entry_num+1<<" - . "<<endl;
				act_entry_num--;
			}
		};


		const auto output_callsite=[&](const typename FDErepresentation_t::LSDArepresentation_t::call_site_t &cs, const uint32_t cs_num) -> void
		{
			const auto cs_start_addr=zipr_obj.GetLocationMap()->at(cs.cs_insn_start);
			const auto cs_end_addr=zipr_obj.GetLocationMap()->at(cs.cs_insn_start)+cs.cs_insn_start->GetDataBits().size();
			const auto cs_len=cs_end_addr-cs_start_addr;
			out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_entry"<<cs_num<<"_start:"<<endl;
        		out<<"	# 1) start of call site relative to FDE start addr (call site encoding)"<<endl;
        		out<<"	.sleb128 0x"<<hex<<cs_start_addr<<" - 0x"<<hex<<fde->start_addr<<endl;
        		out<<"	# 2) length of call site (call site encoding)"<<endl;
        		out<<"	.sleb128 "<<dec<<cs_len<<endl;
			if(cs.landing_pad)
			{
				const auto lp_addr=zipr_obj.GetLocationMap()->at(cs.landing_pad);
				out<<"	# 3) the landing pad, or 0 if none exists. (call site encoding)"<<endl;
				out<<"	.sleb128 0x"<<hex<<lp_addr<<" - 0x"<<hex<<landing_pad_base<<endl;
			}
			else
			{
				out<<"	# 3) the landing pad, or 0 if none exists. (call site encoding)"<<endl;
				out<<"	.sleb128 0"<<endl;
			}
			if(cs.actions.size() > 0 )
			{
				out<<"	# 4) index into action table + 1 -- 0 indicates unwind only (call site encoding)"<<endl;
				out<<"	.sleb128 1 + LSDA"<<dec<<lsda_num<<"_act"
				   <<cs.action_table_index<<"_start_entry0 - LSDA"<<dec<<lsda_num<<"_action_tab_start"<<endl;
			}
			else
			{
				out<<"	# 4) index into action table + 1 -- 0 indicates unwind only (always uleb)"<<endl;
				out<<"	.uleb128 0 # no actions!" << endl;
			}
			out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_entry"<<cs_num<<"_end:"<<endl;

		};

		const auto output_lsda_header=[&]()
		{
			if(landing_pad_base==fde->start_addr)
			{
				out<<"        # 1) encoding of next field "<<endl;
				out<<"        .byte 0xff # DW_EH_PE_omit (0xff)"<<endl;
				out<<""<<endl;
				out<<"        # 2) landing pad base, if omitted, use FDE start addr"<<endl;
				out<<"        # .<fdebasetype> <fdebase> -- omitted.  "<<endl;
			}
			else
			{
				out<<"        # 1) encoding of next field "<<endl;
				out<<"        .byte 0x1b # DW_EH_PE_pcrel (0x10) |sdata4 (0xb)"<<endl;
				out<<""<<endl;
				out<<"        # 2) landing pad base, if omitted, use FDE start addr"<<endl;
				out<<"        .int  0x"<<hex<<landing_pad_base<<"- . # as pcrel|sdata4 .  "<<endl;
			}
			out<<""<<endl;
			out<<"        # 3) encoding of type table entries"<<endl;
			out<<"        .byte 0x"<<hex<<lsda->tt_encoding<<"  # DW_EH_PE_udata4"<<endl;
			out<<""<<endl;
			out<<"        # 4) type table pointer -- always a uleb128"<<endl;
			if(lsda->tt_encoding==0xff) /* omit */
			{
				out<<"        # .uleb128 LSDAptr omitted"<< endl;
			}
			else
			{
				out<<"        .uleb128 LSDA"<<dec<<lsda_num<<"_type_table_end - LSDA"<<lsda_num<<"_tt_ptr_end"<<endl;
			}
			out<<"LSDA"<<dec<<lsda_num<<"_tt_ptr_end:"<<endl;
			out<<""<<endl;
			out<<"        # 5) call site table encoding"<<endl;
			out<<"        .byte 0x9 # DW_EH_PE_sleb128 "<<endl;
			out<<""<<endl;
			out<<"        # 6) the length of the call site table"<<endl;
			out<<"        .uleb128 LSDA"<<dec<<lsda_num<<"_cs_tab_end-LSDA"<<dec<<lsda_num<<"_cs_tab_start"<<endl;
			out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_start:"<<endl;
		};

		const auto output_call_site_table=[&]()
		{
			// output call site table
			auto cs_num=0;
			for(const auto & cs : lsda->callsite_table)
			{
				output_callsite(cs,cs_num++);
			}
			out<<"LSDA"<<dec<<lsda_num<<"_cs_tab_end:"<<endl;
		};
		const auto output_action_table=[&]()
		{
			// output action table
			out<<"LSDA"<<dec<<lsda_num<<"_action_tab_start:"<<endl;
			auto act_num=0;
			for(const auto & act : lsda->action_table)
			{
				output_action(act,act_num++);
			}
			out<<"LSDA"<<dec<<lsda_num<<"_action_tab_end:"<<endl;
		};

		const auto output_type_table=[&]()
		{
			out<<"LSDA"<<dec<<lsda_num<<"_type_table_start:"<<endl;
			for_each( lsda->type_table.rbegin(), lsda->type_table.rend(),  [&](const Relocation_t* reloc)
			{
				if(reloc==NULL)
				{
					// indicates a catch all or empty type table entry
					out<<"	.int 0x0 # not used!"<<endl;
				}
				else if(reloc->GetWRT()==NULL)
				{
					// indicates a catch all or empty type table entry
					out<<"	.int 0x0 # catch all "<<endl;
				}
				else
				{
					// indicates a catch of a paritcular type
					const auto scoop=dynamic_cast<DataScoop_t*>(reloc->GetWRT());
					assert(scoop);
					const auto final_addr=scoop->GetStart()->GetVirtualOffset() + reloc->GetAddend();
					if(((lsda->tt_encoding)&0x10) == 0x10) // if encoding contains pcrel (0x10).
						out<<"	.int 0x"<<hex<<final_addr<<" - . "<<endl;
					else
						out<<"	.int 0x"<<hex<<final_addr<<endl;
					
				}
			});
			out<<"LSDA"<<dec<<lsda_num<<"_type_table_end:"<<endl;
		};

		output_lsda_header();
		output_call_site_table();
		output_action_table();
		output_type_table();

	};
	const auto output_cie=[&](const CIErepresentation_t* cie, ostream& out) -> void
	{
		assert(cie);
		if(cie->has_been_output)
			return;

		const auto cie_pos_it=std::find(all_cies.begin(), all_cies.end(), cie);
		assert(cie_pos_it!=all_cies.end());

		const auto personality_scoop=cie->personality_reloc ? dynamic_cast<DataScoop_t*>  (cie->personality_reloc->GetWRT()) : (DataScoop_t*)NULL;
		const auto personality_insn =cie->personality_reloc ? dynamic_cast<Instruction_t*>(cie->personality_reloc->GetWRT()) : (Instruction_t*)NULL;
		const auto personality_addend=cie->personality_reloc ? cie->personality_reloc->GetAddend() : 0;

		const auto cie_pos=cie_pos_it-all_cies.begin();

		cie->has_been_output=true;
		out<<"# cie "<<dec<<cie_pos<<""<<endl;
		out<<"Lcie"<<cie_pos<<":"<<endl;
		out<<"	 .int Lcie"<<cie_pos<<"_end - Lcie"<<cie_pos<<" - 4 # length of this record. -4 because length doesn't include this field"<<endl;
		out<<"        .int 0                  # cie (not fde)"<<endl;
		out<<"        .byte 3                 # version"<<endl;
		out<<"        .asciz \"zPLR\"           # aug string."<<endl;
		out<<"        .uleb128 "<<dec<<cie->code_alignment_factor<<"              # code alignment factor"<<endl;
		out<<"        .sleb128 "<<dec<<cie->data_alignment_factor<<"             # data alignment factor"<<endl;
		out<<"        .uleb128 "<<dec<<cie->return_reg<<"             # return address reg."<<endl;
		out<<"        # encode the Z (length)"<<endl;
		out<<"        .sleb128 Lcie"<<cie_pos<<"_aug_data_end-Lcie"<<cie_pos<<"_aug_data_start # Z -- handle length field"<<endl;
		out<<"Lcie"<<cie_pos<<"_aug_data_start:"<<endl;
		out<<""<<endl;
		if(personality_scoop)
		{
			auto personality_value=personality_scoop->GetStart()->GetVirtualOffset()+personality_addend;
			out<<"        #encode the P (personality encoding + personality routine)"<<endl;
			out<<"        .byte 0x80 | 0x10 | 0x0B        #  personality pointer encoding DH_EH_PE_indirect (0x80) | pcrel | sdata4"<<endl;
			out<<"        .int "<<personality_value<<" - .               # actual personality routine, encoded as noted in prev line."<<endl;
		}
		else if(personality_insn)
		{
			const auto personality_insn_addr=zipr_obj.GetLocationMap()->at(personality_insn);
			const auto personality_value=personality_insn_addr+personality_addend;
			out<<"        #encode the P (personality encoding + personality routine)"<<endl;
			out<<"        .byte 0x10 | 0x0B        #  personality pointer encoding pcrel | sdata4"<<endl;
			out<<"        .int "<<personality_value<<" - .               # actual personality routine, encoded as noted in prev line."<<endl;
		}
		else
		{
			assert(cie->personality_reloc==NULL || cie->personality_reloc->GetWRT()==NULL);
			out<<"        #encode the P (personality encoding + personality routine)"<<endl;
			out<<"        .byte  0x0B        #  personality pointer encoding sdata4"<<endl;
			out<<"        .int 0               # actual personality routine, encoded as noted in prev line."<<endl;
		}
		out<<""<<endl;
		out<<"        # encode L (lsda encoding) "<<endl;
		out<<"        .byte  0x1b     # LSDA encoding (pcrel|sdata4)"<<endl;
		out<<""<<endl;
		out<<"        # encode R (FDE encoding) "<<endl;
		out<<"        .byte  0x10 | 0x0B      # FDE encoding (pcrel | sdata4)"<<endl;
		out<<"Lcie"<<cie_pos<<"_aug_data_end:"<<endl;
		out<<"       # CIE program"<<endl;
		output_program(cie->pgm,out);
		out<<""<<endl;
		out<<"       # pad with nops"<<endl;
		out<<"       .align 4, 0"<<endl;
		out<<"Lcie"<<cie_pos<<"_end:"<<endl;

	};
	auto output_fde=[&](const FDErepresentation_t* fde, ostream& out, const uint32_t fde_num) -> void
	{
		assert(fde && fde->cie);
		output_cie(fde->cie,out);


		auto cie_pos_it=std::find(all_cies.begin(), all_cies.end(), fde->cie);
		assert(cie_pos_it!=all_cies.end());
		auto cie_pos=cie_pos_it-all_cies.begin();

		out<<"#fde "<<dec<<fde_num<<""<<endl;
		out<<"Lfde"<<fde_num<<":"<<endl;
		out<<"        .int Lfde"<<fde_num<<"_end - Lfde"<<fde_num<<" - 4      # length of this record. -4 because "
		     "length doesn't include this field."<<endl;
		out<<"        .int . - Lcie"<<cie_pos<<"                  # this is an FDE (not a "
		     "cie), and it's cie is CIE"<<cie_pos<<".  byte offset from start of field."<<endl;
		out<<"        .int 0x"<<hex<<fde->start_addr<<dec<<" - .               # FDE start addr"<<endl;
		out<<"        .int "<<dec<<fde->end_addr-fde->start_addr<<"                     # fde range length (i.e., can calc the "
		     "fde_end_addr from this -- note that pcrel is ignored here!)"<<endl;
		out<<"        #encode Z (length)"<<endl;
		out<<"        .uleb128 Lfde"<<fde_num<<"_aug_data_end-Lfde"<<fde_num<<"_aug_data_start"<<endl;
		out<<"Lfde"<<fde_num<<"_aug_data_start:"<<endl;
		out<<"        #encode L (LSDA) "<<endl;
		if(fde->hasLsda())
			out<<"        .int LSDA"<<fde_num<<" - .    # LSDA hard coded here (as pcrel+sdata4)"<<endl;	 
		else
			out<<"        .int 0-.      # no LSDA, encoded with pcrel "<<endl;	 
		out<<"Lfde"<<fde_num<<"_aug_data_end:"<<endl;
		out<<""<<endl;
		out<<"        # FDE"<<fde_num<<" program"<<endl;
		output_program(fde->pgm,out);
		out<<"        .align 4, 0"<<endl;
		out<<"        Lfde"<<fde_num<<"_end:"<<endl;

	};
	auto generate_eh_frame_hdr=[&](ostream& out) -> void	
	{
		out<<".section eh_frame_hdr, \"a\", @progbits"<<endl;
		out<<"eh_frame_hdr_start:"<<endl;
		out<<"        .byte 1                 # version"<<endl;
		out<<"        .byte 0x10 | 0x0B       # encoding for pointer to eh-frame -- DH_EH_PE_pcrel (0x10) | DH_EH_PE_sdata4 (0x0B)"<<endl;
		out<<"        .byte 0x03              # encoding for ; of entries in eh-frame-hdr  -- BDH_EH_PE_udata4 (0x03)"<<endl;
		out<<"        .byte 0x30 | 0x0B       # encoding for pointers (to fdes) held in the eh-frame-hdr header  "
		     "-- DH_EH_PE_datarel (0x30) | DH_EH_PE_sdata4 (0x0b) " <<endl;

		out<<"        .int Lfde_table - .     # pointer to fde_table, encoded as an sdata4, pcrel"<<endl;
		out<<"        .int (eh_frame_table_end-eh_frame_table)/8     # number of FDEs in the header."<<endl;
		out<<"        .align 4"<<endl;
		out<<"eh_frame_table:"<<endl;
		out<<"        # fde pointers"<<endl;

		for(auto fde_num=0U; fde_num < all_fdes.size(); fde_num++)
		{
			const auto& fde=all_fdes[fde_num];
			out<<"        .int 0x"<<hex<<fde->start_addr<<" - eh_frame_hdr_start"<<endl;
			out<<"        .int Lfde"<<dec<<fde_num<<" - eh_frame_hdr_start"<<endl;
		}

		out<<"eh_frame_table_end:"<<endl;

	};
	auto generate_eh_frame=[&](ostream& out) -> void	
	{
		out<<".section eh_frame, \"a\", @progbits"<<endl;
		out<<"Lfde_table: # needed for xref to eh_frame_hdr" <<endl;

		auto fde_num=0;
		for(const auto& fde: all_fdes)
		{
			output_fde(fde,out, fde_num++);
		}
	};
	auto generate_gcc_except_table=[&](ostream& out) -> void	
	{
		out<<".section gcc_except_table, \"a\", @progbits"<<endl;
		auto lsda_num=0;
		for(const auto& fde: all_fdes)
		{
			output_lsda(fde,out,lsda_num++);
		}
	};

	ofstream fout(ehframe_s_filename, std::ofstream::out);
	if(!fout)
	{
		cerr<<"Fatal: cannot open "<<ehframe_s_filename<<"."<<endl;
		exit(2);
	}

	generate_eh_frame_hdr(fout);
	generate_eh_frame(fout);
	generate_gcc_except_table(fout);
}

template<int ptrsize>
void EhWriterImpl_t<ptrsize>::CompileEhOutput()
{
	auto page_round_up=[](const uintptr_t x) -> uintptr_t 
	{
		auto page_size=(uintptr_t)PAGE_SIZE;
		return  ( (((uintptr_t)(x)) + page_size-1)  & (~(page_size-1)) );
	};

	// find maximum used scoop address.
	const auto max_used_addr=std::max_element(
		zipr_obj.GetFileIR()->GetDataScoops().begin(),
		zipr_obj.GetFileIR()->GetDataScoops().end(),
		[&](const DataScoop_t* a, const DataScoop_t* b)
		{
			assert(a && b && a->GetEnd() && b->GetEnd()) ;
			return a->GetEnd()->GetVirtualOffset() < b->GetEnd()->GetVirtualOffset();
		}
		);

	// round it up and stringify it.
	const auto eh_frame_hdr_addr=page_round_up((*max_used_addr)->GetEnd()->GetVirtualOffset());
	const auto eh_frame_hdr_addr_str=to_hex_string(eh_frame_hdr_addr);

	// create and execute the command to build the ehframe.
	auto cmd=(string)"$PEASOUP_HOME/tools/eh_frame_tools/eh_to_bin.sh "+ehframe_s_filename+" "+eh_frame_hdr_addr_str+" "+ehframe_exe_filename;
	auto res=system(cmd.c_str());

	// err check.
	if( res==-1 || WEXITSTATUS(res)!=0 )
	{
		perror("Cannot compile eh_frame.");
		cerr<<"Exit code="<<res<<endl;
		cerr<<" for command="<<cmd<<endl;
		exit(2);
	}
}

template<int ptrsize>
void EhWriterImpl_t<ptrsize>::ScoopifyEhOutput()
{
        ELFIO::elfio ehframe_exe_elfio;
	ehframe_exe_elfio.load(ehframe_exe_filename);

	auto to_scoop=[&](const string &secname)->void
	{
		const auto &sec=ehframe_exe_elfio.sections[secname];

		// if sec is missing, don't scoopify.

		if(sec==NULL) return;
		const auto data=string(sec->get_data(), sec->get_size());
		const auto start_vo=sec->get_address();
		const auto start_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, BaseObj_t::NOT_IN_DATABASE, start_vo);
		const auto end_vo=sec->get_address()+sec->get_size()-1;
		const auto end_addr=new AddressID_t(BaseObj_t::NOT_IN_DATABASE, BaseObj_t::NOT_IN_DATABASE, end_vo);
		const auto new_scoop=new DataScoop_t(zipr_obj.GetFileIR()->GetMaxBaseID()+1, secname, start_addr,end_addr,NULL,4,false,data);

		zipr_obj.GetFileIR()->GetAddresses().insert(start_addr);
		zipr_obj.GetFileIR()->GetAddresses().insert(end_addr);
		zipr_obj.GetFileIR()->GetDataScoops().insert(new_scoop);
	};

	to_scoop(".eh_frame_hdr");	
	to_scoop(".eh_frame");	
	to_scoop(".gcc_except_table");	


}

template<int ptrsize>
EhWriterImpl_t<ptrsize>::~EhWriterImpl_t()
{
	for(const auto &i : all_fdes) delete i;
	for(const auto &i : all_cies) delete i;
}


/* make sure these get compiled */
namespace zipr
{
template class EhWriterImpl_t<8>;
template class EhWriterImpl_t<4>;
};