Newer
Older
// Loop through all basic blocks and emit profiling request annotations
// for those blocks that have unsafe memory writes in them.
list<SMPBasicBlock>::iterator CurrBlock;
this->SafeBlocks = 0;
this->UnsafeBlocks = 0;
for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
if (CurrBlock->MaybeAliasedWrite()) {
++(this->UnsafeBlocks);
clc5q
committed
#if SMP_OPTIMIZE_BLOCK_PROFILING
list<list<SMPInstr>::iterator>::iterator CurrInst;
CurrInst = CurrBlock->GetFirstInstr();
ea_t addr = (*CurrInst)->GetAddr();
qfprintf(AnnotFile, "%10x %6d BLOCK PROFILECOUNT %s\n", addr,
(*CurrInst)->GetCmd().size, (*CurrInst)->GetDisasm());
clc5q
committed
#endif
}
else {
++(this->SafeBlocks);
}
}
return;
} // end of SMPFunction::EmitAnnotations()
// Debug output dump.
void SMPFunction::Dump(void) {
list<SMPBasicBlock>::iterator CurrBlock;
msg("Debug dump for function: %s\n", this->GetFuncName());
msg("UseFP: %d LocalVarsAllocInstr: %x\n", this->UseFP,
this->LocalVarsAllocInstr);
for (size_t index = 0; index < this->IDom.size(); ++index) {
msg("IDOM for %d: %d\n", index, this->IDom.at(index));
}
for (size_t index = 0; index < this->DomTree.size(); ++index) {
msg("DomTree for %d: ", index);
list<int>::iterator DomIter;
for (DomIter = this->DomTree.at(index).second.begin();
DomIter != this->DomTree.at(index).second.end();
++DomIter) {
msg("%d ", *DomIter);
}
msg("\n");
}
msg("Global names: \n");
set<op_t, LessOp>::iterator NameIter;
for (NameIter = this->GlobalNames.begin(); NameIter != this->GlobalNames.end(); ++NameIter) {
msg("index: %d ", ExtractGlobalIndex(*NameIter));
PrintListOperand(*NameIter);
msg("\n");
}
msg("Blocks each name is defined in: \n");
for (size_t index = 0; index < this->BlocksDefinedIn.size(); ++index) {
msg("Name index: %d Blocks: ", index);
list<int>::iterator BlockIter;
for (BlockIter = this->BlocksDefinedIn.at(index).begin();
BlockIter != this->BlocksDefinedIn.at(index).end();
++BlockIter) {
msg("%d ", *BlockIter);
}
msg("\n");
}
for (CurrBlock = this->Blocks.begin(); CurrBlock != this->Blocks.end(); ++CurrBlock) {
// Dump out the function number and data flow sets before the instructions.
CurrBlock->Dump();
}
msg("End of debug dump for function: %s\n", this->GetFuncName());
return;
} // end of SMPFunction::Dump()
// Analyzes the function to see if the return address can be marked as safe
void SMPFunction::MarkFunctionSafe() {
msg(" Analyzing function %s and isLeaf = %d \n ", this->GetFuncName(), this->IsLeaf());
bool HasCallTargets = false;
clc5q
committed
bool HasStackPointerCopy = false;
bool HasStackPointerPush = false;
bool HasIndirectGlobalWrite = false;
bool WritesAboveLocalFrame = false; // Direct writes above local frame
bool WritesAboveLocalFrameIndirect = false; // Indirect writes above local frame
clc5q
committed
bool HasIndexedStackWrite = false;
bool HasIndirectWrite = false;
clc5q
committed
this->ReturnAddrStatus = FUNC_SAFE;
this->SafeFunc = true;
if (!this->AllCallTargets.empty()) {
HasCallTargets = true;
#if SMP_USE_SWITCH_TABLE_INFO
if (this->UnresolvedIndirectJumps) {
#else
msg("Function %s marked as unsafe due to indirect jumps\n", this->GetFuncName());
#endif
}
list<SMPInstr>::iterator Instructions;
clc5q
committed
// while processing the stack pointer writes the prologue code for
// saving frame register and allcating local variables needs to be
// handled
bool SaveEBP = false;
bool XferESPtoEBP = false;
for (Instructions = Instrs.begin(); Instructions != Instrs.end(); ++Instructions) {
#if SMP_USE_SSA_FNOP_MARKER
if (this->Instrs.begin() == Instructions)
continue; // skip marker instruction
#endif
4116
4117
4118
4119
4120
4121
4122
4123
4124
4125
4126
4127
4128
4129
4130
4131
4132
4133
4134
4135
4136
4137
4138
msg(" Total number of defs for this instruction %d\n", Instructions->NumDefs());
#endif
if (!SaveEBP) { // still looking for "push ebp"
if (Instructions->MDIsPushInstr() && Instructions->GetCmd().Operands[0].is_reg(R_bp)) {
SaveEBP = true;
continue;
}
}
else if (!XferESPtoEBP) { // found "push ebp", looking for "mov ebp,esp"
insn_t CurrCmd = Instructions->GetCmd();
if ((CurrCmd.itype == NN_mov)
&& (Instructions->GetFirstDef()->GetOp().is_reg(R_bp))
&& (Instructions->GetFirstUse()->GetOp().is_reg(R_sp))) {
XferESPtoEBP = true;
continue;
}
}
ea_t address = Instructions->GetAddr();
if (address == this->LocalVarsAllocInstr ||
address == this->LocalVarsDeallocInstr)
continue;
if (Instructions->MDIsStackPointerCopy(this->UseFP)) {
clc5q
committed
HasStackPointerCopy = true;
if (NN_lea == Instructions->GetCmd().itype) {
// If an lea instruction loads an address above
// the stack frame, we must assume that writes
// above the stack frame could occur.
if (this->WritesAboveLocalFrame(Instructions->GetCmd().Operands[1]))
WritesAboveLocalFrameIndirect = true;
}
msg(" Function %s marked as unsafe due to stack pointer copy \n ", this->GetFuncName());
msg("%s %x \n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
}
if (Instructions->MDIsPushInstr()) {
// not exactly sure how to handle this instruction
// for the moment if its a push on a esp or usefp & ebp
// mark as unsafe
if (Instructions->GetCmd().Operands[0].is_reg(R_sp) ||
(this->UseFP && Instructions->GetCmd().Operands[0].is_reg(R_bp))) {
clc5q
committed
HasStackPointerPush = true;
msg(" Function %s marked as unsafe due to push on ebp or esp outside of function header \n", this->GetFuncName());
msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
}
continue;
}
if (Instructions->MDIsPopInstr()) {
// ignore pops for the moment
continue;
}
set<DefOrUse, LessDefUse>::iterator setIterator;
for (setIterator = Instructions->GetFirstDef(); setIterator != Instructions->GetLastDef(); ++setIterator) {
op_t Operand = setIterator->GetOp();
clc5q
committed
int BaseReg;
int IndexReg;
ushort ScaleFactor;
ea_t offset;
// now o_mem can have sib byte as well, as
clc5q
committed
// reported by IDA. Check if the base reg is R_none
// and index reg is R_none. If they are, then this is
clc5q
committed
// a direct global write and can be marked safe.
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
clc5q
committed
// go onto next def
continue;
HasIndirectGlobalWrite = true;
}
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
bool FramePointerRelative = (this->UseFP && (BaseReg == R_bp));
bool StackPointerRelative = (BaseReg == R_sp);
if (StackPointerRelative || FramePointerRelative) {
clc5q
committed
if (IndexReg == R_none) {
bool tempWritesAboveLocalFrame = this->WritesAboveLocalFrame(Operand);
msg(" Function %s marked as unsafe due to direct write above loc "
"variables offset=%x loc=%x\n ", this->GetFuncName(),
offset, this->LocalVarsSize);
msg("Write above local frame in %s : offset: %d ",
this->GetFuncName(), offset);
msg("LocalVarsSize: %d OutgoingArgsSize: %d frsize: %d frregs: %d",
this->LocalVarsSize, this->OutgoingArgsSize,
this->FuncInfo.frsize, this->FuncInfo.frregs);
Instructions->Dump();
}
#endif
bool tempWritesAboveLocalFrameIndirect = this->IndexedWritesAboveLocalFrame(Operand);
/* seperate indirect writes to this frame from indirect writes to another frame */
WritesAboveLocalFrameIndirect = true;
msg(" Function %s marked as unsafe due to indexed stack write above "
"loc variable offset\n", this->GetFuncName());
msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
msg(" Function %s marked as unsafe due to indexed stack write\n",
this->GetFuncName());
msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
/* check whether there is profiler information for this indirect reference */
clc5q
committed
HasIndirectWrite = true;
}
else if (Operand.type == o_phrase) {
// so phrase is of the form [BASE_REG + IND ]
// if the index register is missing just make sure that
// the displacement is below stack frame top
clc5q
committed
MDExtractAddressFields(Operand, BaseReg, IndexReg, ScaleFactor, offset);
// check the base reg
// if index reg is used mark as unsafe
if ((BaseReg == R_sp || (this->UseFP && BaseReg == R_bp))) {
if (IndexReg == R_none) {
/* addressing mode is *esp or *ebp */
clc5q
committed
continue;
}
else {
HasIndexedStackWrite = true;
#if SMP_DEBUG_FUNC
msg(" Function %s marked as unsafe due to indexed stack write\n", this->GetFuncName());
clc5q
committed
msg("%s %x\n", (Instructions)->GetDisasm(), (Instructions)->GetAddr());
#endif
}
/* check whether there is profiler information for this indirect reference */
clc5q
committed
HasIndirectWrite = true;
// else not memory, and we don't care.
} // end for all DEFs in current instruction
} // end for all instructions
clc5q
committed
// For mmStrata bounds checking of the stack frame, we don't care
// about indirect writes unless they are to the stack.
bool Unsafe = (HasStackPointerCopy || HasStackPointerPush
|| HasIndexedStackWrite || this->SharedChunks
|| this->UnresolvedIndirectJumps || this->UnresolvedIndirectCalls);
this->SafeFunc = (!Unsafe);
bool SpecUnsafe = (HasStackPointerCopy || HasStackPointerPush
|| HasIndexedStackWrite || this->SharedChunks
|| this->UnresolvedIndirectJumps);
this->SpecSafeFunc = (!SpecUnsafe);
this->WritesAboveRA = WritesAboveLocalFrameIndirect;
this->SafeCallee = (!Unsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
this->SpecSafeCallee = (!SpecUnsafe) && (!WritesAboveLocalFrameIndirect) && this->AnalyzedSP;
this->SpecNeedsStackReferent = SpecUnsafe;
this->HasIndirectWrites = (HasIndexedStackWrite || HasIndirectWrite
|| WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite);
if (Unsafe || WritesAboveLocalFrame || WritesAboveLocalFrameIndirect || HasIndirectGlobalWrite
|| HasIndirectWrite || (!this->AnalyzedSP)) {
clc5q
committed
this->ReturnAddrStatus = FUNC_UNSAFE;
clc5q
committed
msg("UNSAFE function %s ", this->GetFuncName());
msg("StackPtrCopy: %d StackPtrPush: %d IndirectGlobal: %d ",
HasStackPointerCopy, HasStackPointerPush, HasIndirectGlobalWrite);
msg("WritesAboveFrame: %d IndirectStack: %d IndirectWrite: %d ",
WritesAboveLocalFrame, HasIndexedStackWrite, HasIndirectWrite);
msg("AnalyzedSP: %d UnresolvedCalls: %d UnresolvedJumps: %d SharedChunks: %d IsLeaf: %d\n",
this->AnalyzedSP, this->UnresolvedIndirectCalls, this->UnresolvedIndirectJumps,
clc5q
committed
this->SharedChunks, this->IsLeaf());
clc5q
committed
}
else if (HasCallTargets) {
clc5q
committed
this->ReturnAddrStatus = FUNC_UNKNOWN;
}
msg("Function %s is SAFE\n", GetFuncName());
msg("Function %s is UNSAFE\n", GetFuncName());
msg("Function %s is UNKNOWN\n", GetFuncName());
msg("Function %s is mmSAFE\n", GetFuncName());
else
msg("Function %s is mmUNSAFE\n", GetFuncName());
msg("Function %s is Speculatively mmSAFE\n", GetFuncName());
else
msg("Function %s is Speculatively mmUNSAFE\n", GetFuncName());
#endif
clc5q
committed
return;
} // end of SMPFunction::MarkFunctionSafe()