diff --git a/libtransform/include/integertransform64.hpp b/libtransform/include/integertransform64.hpp index 9e6a0af3324606cedd3e883fbfbdbb2d59e73a79..7f2b2c20ec9e96297bf567324de644150614fe29 100644 --- a/libtransform/include/integertransform64.hpp +++ b/libtransform/include/integertransform64.hpp @@ -25,4 +25,7 @@ class IntegerTransform64 : public IntegerTransform } // end namespace +#define OVERFLOW_DETECTOR_64 "overflow_detector_64" +#define UNDERFLOW_DETECTOR_64 "underflow_detector_64" + #endif diff --git a/libtransform/include/transform.hpp b/libtransform/include/transform.hpp index 03be88e4dae7b82b6cc72373ef9b65ac88534426..079b6e6caff1a8830859d1002c96d5b5abbfb8ea 100644 --- a/libtransform/include/transform.hpp +++ b/libtransform/include/transform.hpp @@ -24,8 +24,10 @@ class Transform { protected: void setAssembly(Instruction_t *p_instr, string p_asm); + Instruction_t* addNewAssembly(string p_asm); Instruction_t* addNewAssembly(Instruction_t *p_instr, string p_asm); - Instruction_t* addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs); + Instruction_t* registerCallbackHandler64(string p_callbackHandler, int p_numArgs); + void addCallbackHandler64(Instruction_t *p_instr, string p_callbackHandler, int p_numArgs); void addInstruction(Instruction_t *p_instr, string p_dataBits, Instruction_t *p_fallThrough, Instruction_t *p_target); Instruction_t* carefullyInsertBefore(Instruction_t* &p_target, Instruction_t* &p_new); @@ -59,7 +61,7 @@ class Transform { void addMulRegisterConstant(Instruction_t *p_instr, Register::RegisterName p_regTgt, int p_constantValue, Instruction_t *p_fallThrough); void addMovRegisters(Instruction_t *p_instr, Register::RegisterName p_regTgt, Register::RegisterName p_regSrc, Instruction_t *p_fallThrough); - Instruction_t* allocateNewInstruction(db_id_t p_fileID, Function_t* p_func); + Instruction_t* allocateNewInstruction(db_id_t p_fileID=BaseObj_t::NOT_IN_DATABASE, Function_t* p_func=NULL); virtual_offset_t getAvailableAddress(); @@ -88,6 +90,7 @@ class Transform { VariantID_t *m_variantID; FileIR_t *m_fileIR; set<std::string> *m_filteredFunctions; + std::map<std::string, Instruction_t*> m_handlerMap; }; // make sure these match values in detector_handlers.h in the strata library diff --git a/libtransform/src/integertransform64.cpp b/libtransform/src/integertransform64.cpp index 5fd5ae163941aa95d4d6253c6ea893468dc40e72..8bc5c8ce52df3563ab36e107fbe1105a19f1fc90 100644 --- a/libtransform/src/integertransform64.cpp +++ b/libtransform/src/integertransform64.cpp @@ -5,12 +5,25 @@ using namespace libTransform; /** * 64 bit implementation status of the integer transform +* 20140228 64-bit overflows on multiply, signed/unsigned add/sub +* 20140422 callback handlers added * -* 20140228 64-bit overflows on multiply, signed/unsigned add/sub, halt policy -* +* 64-bit signed unsigned unknown +* -------- ------ -------- ------- +* add, sub of c of,c +* mul of of of +* lea @todo @todo @todo +* +* 32-bit signed unsigned unknown +* -------- ------ -------- ------- +* add, sub @todo @todo @todo +* mul @todo @todo @todo +* lea @todo @todo @todo + * @todo: +* - test unknown +* - test warnings only mode * - handle LEA instructions -* - callback handler for diagnostics * **/ @@ -154,15 +167,14 @@ void IntegerTransform64::handleUnderflowCheck(Instruction_t *p_instruction, cons // mul a, b ; <instruction to instrument> // jno <OrigNext> ; if no overflows, jump to original fallthrough instruction // mov a, MIN/MAX ; policy = min-saturate (underflow) / max-saturate (overflow) +// of64/uf64 handler ; call the callback handler (handle diagnostics) // OrigNext: <nextInstruction> ; original fallthrugh // void IntegerTransform64::addOverflowUnderflowCheck(Instruction_t *p_instruction, const MEDS_InstructionCheckAnnotation& p_annotation, int p_policy) { - Instruction_t* jncond_i = NULL; - Instruction_t* policy_i = NULL; + char tmpbuf[1024]; assert(getFileIR() && p_instruction && p_instruction->GetFallthrough()); - Register::RegisterName targetReg = getTargetRegister(p_instruction); if (targetReg == Register::UNKNOWN) { @@ -172,42 +184,66 @@ void IntegerTransform64::addOverflowUnderflowCheck(Instruction_t *p_instruction, logMessage(__func__, p_annotation, "debug"); - jncond_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); - policy_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + Instruction_t* jncond_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + Instruction_t* lea_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + Instruction_t* policy_i; Instruction_t* next_i = p_instruction->GetFallthrough(); p_instruction->SetFallthrough(jncond_i); - if (p_annotation.isUnsigned()) + if (p_policy == POLICY_CONTINUE_SATURATING_ARITHMETIC) + policy_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + else + policy_i = lea_i; + + if (p_annotation.isSigned() || isMultiplyInstruction(p_instruction)) { - addJnc(jncond_i, policy_i, next_i); + addJno(jncond_i, policy_i, next_i); } - else if (p_annotation.isSigned()) + if (p_annotation.isUnsigned()) { - addJno(jncond_i, policy_i, next_i); + addJnc(jncond_i, policy_i, next_i); } else { // unknown sign - addJno(jncond_i, policy_i, next_i); + Instruction_t* jnc_i = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + addJno(jncond_i, policy_i, jnc_i); + addJnc(jnc_i, policy_i, next_i); } if (p_policy == POLICY_CONTINUE_SATURATING_ARITHMETIC) { if (p_annotation.isUnderflow()) - { - addMinSaturation(policy_i, targetReg, p_annotation, next_i); - } + addMinSaturation(policy_i, targetReg, p_annotation, lea_i); else - { - addMaxSaturation(policy_i, targetReg, p_annotation, next_i); - } - - // add callback handler here for diagnostics + addMaxSaturation(policy_i, targetReg, p_annotation, lea_i); } + + setAssembly(lea_i, "lea rsp, [rsp-128]"); // red zone + + // add callback handler here for diagnostics + // pass in PC of instrumented instruction + // pass in p_policy + sprintf(tmpbuf,"push 0x%08x", p_policy); + Instruction_t* instr = addNewAssembly(lea_i, tmpbuf); + sprintf(tmpbuf,"push 0x%08x", p_instruction->GetAddress()->GetVirtualOffset()); + instr = addNewAssembly(instr, tmpbuf); + + Instruction_t* call = allocateNewInstruction(p_instruction->GetAddress()->GetFileID(), p_instruction->GetFunction()); + instr->SetFallthrough(call); +// setAssembly(call, "db 0xe8, 00, 00, 00, 00"); + setAssembly(call, "call 0"); + + if (p_annotation.isOverflow()) + addCallbackHandler64(call, OVERFLOW_DETECTOR_64, 2); // 2 args for now else - { - addHlt(policy_i, next_i); - } + addCallbackHandler64(call, UNDERFLOW_DETECTOR_64, 2); // 2 args for now + + assert(call->GetTarget()); + + instr = addNewAssembly(call, "lea rsp, [rsp+128+16]"); + call->SetFallthrough(instr); + instr->SetFallthrough(next_i); if (p_annotation.isUnderflow()) m_numUnderflows++; diff --git a/libtransform/src/transform.cpp b/libtransform/src/transform.cpp index c8ee073b08bbab177a50b4a239e0f5ebe161a788..898453d6547befd288f2f8e4b3858f2831a6b39a 100644 --- a/libtransform/src/transform.cpp +++ b/libtransform/src/transform.cpp @@ -78,6 +78,14 @@ Instruction_t* Transform::carefullyInsertBefore(Instruction_t* &p_instrumented, return dupInstr; } +void Transform::addPushf(Instruction_t *p_pushf_i, Instruction_t *p_fallThrough) +{ + string dataBits; + dataBits.resize(1); + dataBits[0] = 0x9c; + addInstruction(p_pushf_i, dataBits, p_fallThrough, NULL); +} + void Transform::addPushRegister(Instruction_t *p_instr, Register::RegisterName p_reg, Instruction_t *p_fallThrough) { string dataBits; @@ -282,7 +290,7 @@ void Transform::addNop(Instruction_t *p_nop_i, Instruction_t *p_fallThrough) Instruction_t* Transform::allocateNewInstruction(db_id_t p_fileID, Function_t* p_func) { Instruction_t *instr = new Instruction_t(); - AddressID_t *a =new AddressID_t(); + AddressID_t *a = new AddressID_t(); a->SetFileID(p_fileID); @@ -1242,14 +1250,6 @@ void Transform::addMinSaturation(Instruction_t *p_instruction, Register::Registe } } -void Transform::addPushf(Instruction_t *p_pushf_i, Instruction_t *p_fallThrough) -{ - string dataBits; - dataBits.resize(1); - dataBits[0] = 0x9c; - addInstruction(p_pushf_i, dataBits, p_fallThrough, NULL); -} - void Transform::setAssembly(Instruction_t *p_instr, string p_asm) { m_fileIR->RegisterAssembly(p_instr, p_asm); @@ -1257,125 +1257,149 @@ void Transform::setAssembly(Instruction_t *p_instr, string p_asm) // // Allocate and add new instruction given its assembly form +// If <p_instr> not NULL, then set fallthrough appropriately +// // Returns the newly added instruction // +// <p_instr> defined: // <p_instr> <p_instr> -// <fallthrough> ==> <p_asm> +// <fallthrough> ==> <newinstr>(<p_asm>) // <fallthrough> // +// <p_instr> is NULL: +// ==> <newinstr>(<p_asm>) +// Instruction_t* Transform::addNewAssembly(Instruction_t *p_instr, string p_asm) { - Instruction_t* newinstr = allocateNewInstruction(p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); + Instruction_t* newinstr; + if (p_instr) + newinstr = allocateNewInstruction(p_instr->GetAddress()->GetFileID(), p_instr->GetFunction()); + else + newinstr = allocateNewInstruction(BaseObj_t::NOT_IN_DATABASE, NULL); + m_fileIR->RegisterAssembly(newinstr, p_asm); - newinstr->SetFallthrough(p_instr->GetFallthrough()); - p_instr->SetFallthrough(newinstr); + + if (p_instr) + { + newinstr->SetFallthrough(p_instr->GetFallthrough()); + p_instr->SetFallthrough(newinstr); + } + return newinstr; } +// register instruction in IRDB +// 20140421 +Instruction_t* Transform::addNewAssembly(string p_asm) +{ + return addNewAssembly(NULL, p_asm); +} + +// x86-64 +// 20140421 +void Transform::addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs) +{ + // nb: if first time, register and cache callback handler sequence + if (m_handlerMap.count(p_callbackHandler) == 0) + { + m_handlerMap[p_callbackHandler] = registerCallbackHandler64(p_callbackHandler, p_numArgs); + } + + if (p_orig) + p_orig->SetTarget(m_handlerMap[p_callbackHandler]); +} // x86-64 -// add callback handler sequence to <p_orig> +// register callback handler sequence // 20140416 -Instruction_t* Transform::addCallbackHandler64(Instruction_t *p_orig, string p_callbackHandler, int p_numArgs) +Instruction_t* Transform::registerCallbackHandler64(string p_callbackHandler, int p_numArgs) { Instruction_t *instr; + Instruction_t *first; char tmpbuf[1024]; - // save flags and registers - instr = addNewAssembly(p_orig, "pushf"); - instr = addNewAssembly(instr, "push rax"); - instr = addNewAssembly(instr, "push rbx"); - instr = addNewAssembly(instr, "push rcx"); - instr = addNewAssembly(instr, "push rdx"); - instr = addNewAssembly(instr, "push rsi"); - instr = addNewAssembly(instr, "push rdi"); - instr = addNewAssembly(instr, "push rbp"); - instr = addNewAssembly(instr, "push rsp"); - instr = addNewAssembly(instr, "push r8"); - instr = addNewAssembly(instr, "push r9"); - instr = addNewAssembly(instr, "push r10"); - instr = addNewAssembly(instr, "push r11"); - instr = addNewAssembly(instr, "push r12"); - instr = addNewAssembly(instr, "push r13"); - instr = addNewAssembly(instr, "push r14"); - instr = addNewAssembly(instr, "push r15"); - - // handle the arguments (if any) - // rdi, rsi, rdx, rcx, r8, r9 - for (int i = p_numArgs, paramCount = 1; i >= 1; --i, paramCount++) - { - // pushf 16 regs param - // ----- -------- ----- - int offset = 8 + (16 * 8) + (i*8); - string paramReg; - switch(paramCount) - { - case 1: - paramReg = "rdi"; - break; - case 2: - paramReg = "rsi"; - break; - case 3: - paramReg = "rdx"; - break; - case 4: - paramReg = "rcx"; - break; - case 5: - paramReg = "r8"; - break; - case 6: - paramReg = "r9"; - break; - default: - assert(0); // only handle up to 6 args - break; - } - - // e.g.: mov rdi, [rsp+offset] - sprintf(tmpbuf, "[rsp+%d]", offset); - - instr = addNewAssembly(instr, "mov " + paramReg + ", " + tmpbuf); - } + // save flags and 16 registers (136 bytes) + // call pushes 8 bytes + // Total: 8 * 18 = 144 + first = instr = addNewAssembly("push rsp"); + instr = addNewAssembly(instr, "push rbp"); + instr = addNewAssembly(instr, "push rdi"); + instr = addNewAssembly(instr, "push rsi"); + instr = addNewAssembly(instr, "push rdx"); + instr = addNewAssembly(instr, "push rcx"); + instr = addNewAssembly(instr, "push rbx"); + instr = addNewAssembly(instr, "push rax"); + instr = addNewAssembly(instr, "push r8"); + instr = addNewAssembly(instr, "push r9"); + instr = addNewAssembly(instr, "push r10"); + instr = addNewAssembly(instr, "push r11"); + instr = addNewAssembly(instr, "push r12"); + instr = addNewAssembly(instr, "push r13"); + instr = addNewAssembly(instr, "push r14"); + instr = addNewAssembly(instr, "push r15"); + instr = addNewAssembly(instr, "pushf"); + + instr = addNewAssembly(instr, "mov rdi, rsp"); + + // handle the arguments (if any): rdi, rsi, rdx, rcx, r8, r9 + // first arg starts at byte +144 + if (p_numArgs >= 1) + instr = addNewAssembly(instr, "mov rsi, [rsp+144]"); + if (p_numArgs >= 2) + instr = addNewAssembly(instr, "mov rdx, [rsp+152]"); + if (p_numArgs >= 3) + instr = addNewAssembly(instr, "mov rcx, [rsp+160]"); + if (p_numArgs >= 4) + instr = addNewAssembly(instr, "mov r8, [rsp+168]"); + if (p_numArgs > 4) + assert(0); // only handle up to 5 args // pin the instruction that follows the callback handler - Instruction_t* postCallback = allocateNewInstruction(p_orig->GetAddress()->GetFileID(), p_orig->GetFunction()); + Instruction_t* postCallback = allocateNewInstruction(); virtual_offset_t postCallbackReturn = getAvailableAddress(); postCallback->GetAddress()->SetVirtualOffset(postCallbackReturn); // push the address to return to once the callback handler is invoked - sprintf(tmpbuf,"push 0x%x", postCallbackReturn); + sprintf(tmpbuf,"mov rax, 0x%x", postCallbackReturn); instr = addNewAssembly(instr, tmpbuf); + instr = addNewAssembly(instr, "push rax"); + // use a nop instruction for the actual callback instr = addNewAssembly(instr, "nop"); - instr->SetComment(" -- callback to " + p_callbackHandler + " orig: " + p_orig->GetComment()) ; + instr->SetComment(" -- callback: " + p_callbackHandler); instr->SetCallback(p_callbackHandler); instr->SetFallthrough(postCallback); + // need to make sure the post callback address is pinned + // (so that ILR and other transforms do not relocate it) + AddressID_t *indTarg =new AddressID_t(); + m_fileIR->GetAddresses().insert(indTarg); + indTarg->SetVirtualOffset(postCallback->GetAddress()->GetVirtualOffset()); + indTarg->SetFileID(BaseObj_t::NOT_IN_DATABASE); // SPRI global namespace + postCallback->SetIndirectBranchTargetAddress(indTarg); + // restore registers - setAssembly(postCallback, "pop r15"); - instr = addNewAssembly(postCallback, "pop r14"); + setAssembly(postCallback, "popf"); + instr = addNewAssembly(postCallback, "pop r15"); + instr = addNewAssembly(instr, "pop r14"); instr = addNewAssembly(instr, "pop r13"); instr = addNewAssembly(instr, "pop r12"); instr = addNewAssembly(instr, "pop r11"); instr = addNewAssembly(instr, "pop r10"); instr = addNewAssembly(instr, "pop r9"); instr = addNewAssembly(instr, "pop r8"); - instr = addNewAssembly(instr, "pop rsp"); - instr = addNewAssembly(instr, "pop rbp"); - instr = addNewAssembly(instr, "pop rdi"); - instr = addNewAssembly(instr, "pop rsi"); - instr = addNewAssembly(instr, "pop rdx"); - instr = addNewAssembly(instr, "pop rcx"); - instr = addNewAssembly(instr, "pop rbx"); instr = addNewAssembly(instr, "pop rax"); + instr = addNewAssembly(instr, "pop rbx"); + instr = addNewAssembly(instr, "pop rcx"); + instr = addNewAssembly(instr, "pop rdx"); + instr = addNewAssembly(instr, "pop rsi"); + instr = addNewAssembly(instr, "pop rdi"); + instr = addNewAssembly(instr, "pop rbp"); + instr = addNewAssembly(instr, "lea rsp, [rsp+8]"); - // restore flags - instr = addNewAssembly(instr, "popf"); instr = addNewAssembly(instr, "ret"); - return instr; + // return first instruction in the callback handler chain + return first; } - diff --git a/libtransform/tests/Makefile b/libtransform/tests/Makefile index 1675a65dd11e69dda64487fdee05f8351d01f164..162467a40000acd7cd2f53195366b1f3df510009 100644 --- a/libtransform/tests/Makefile +++ b/libtransform/tests/Makefile @@ -12,7 +12,7 @@ LD=DO_NOT_USE #exes=signed_add.exe #exes=simpletest.exe #exes=dummy.exe -exes=unsigned_mul.exe +exes=unsigned_mul.exe signed_add.exe signed_mul.exe all: env_check ${exes}