Expand Up
@@ -37,8 +37,8 @@ bool IsStackReg(unsigned Reg) {
}
std::string FuncName (unsigned AccessSize, bool IsWrite) {
return std::string (" __sanitizer_sanitize_ " ) + (IsWrite ? " store" : " load" ) +
( utostr (AccessSize) );
return std::string (" __asan_report_ " ) + (IsWrite ? " store" : " load" ) +
utostr (AccessSize);
}
class X86AddressSanitizer : public X86AsmInstrumentation {
Expand All
@@ -47,17 +47,19 @@ class X86AddressSanitizer : public X86AsmInstrumentation {
virtual ~X86AddressSanitizer () {}
// X86AsmInstrumentation implementation:
virtual void InstrumentInstruction (const MCInst &Inst,
OperandVector &Operands, MCContext &Ctx,
const MCInstrInfo &MII,
MCStreamer &Out) override {
virtual void InstrumentInstruction (
const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
const MCInstrInfo &MII, MCStreamer &Out) override {
InstrumentMOV (Inst, Operands, Ctx, MII, Out);
}
// Should be implemented differently in x86_32 and x86_64 subclasses.
virtual void InstrumentMemOperandImpl (X86Operand &Op, unsigned AccessSize,
bool IsWrite, MCContext &Ctx,
MCStreamer &Out) = 0;
virtual void InstrumentMemOperandSmallImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) = 0;
virtual void InstrumentMemOperandLargeImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) = 0;
void InstrumentMemOperand (MCParsedAsmOperand &Op, unsigned AccessSize,
bool IsWrite, MCContext &Ctx, MCStreamer &Out);
Expand All
@@ -67,14 +69,15 @@ class X86AddressSanitizer : public X86AsmInstrumentation {
Out.EmitInstruction (Inst, STI);
}
void EmitLabel (MCStreamer &Out, MCSymbol *Label) { Out.EmitLabel (Label); }
protected:
const MCSubtargetInfo &STI;
};
void X86AddressSanitizer::InstrumentMemOperand (MCParsedAsmOperand &Op,
unsigned AccessSize,
bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
void X86AddressSanitizer::InstrumentMemOperand (
MCParsedAsmOperand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
assert (Op.isMem () && " Op should be a memory operand." );
assert ((AccessSize & (AccessSize - 1 )) == 0 && AccessSize <= 16 &&
" AccessSize should be a power of two, less or equal than 16." );
Expand All
@@ -84,13 +87,16 @@ void X86AddressSanitizer::InstrumentMemOperand(MCParsedAsmOperand &Op,
if (IsStackReg (MemOp.getMemBaseReg ()) || IsStackReg (MemOp.getMemIndexReg ()))
return ;
InstrumentMemOperandImpl (MemOp, AccessSize, IsWrite, Ctx, Out);
// FIXME: take into account load/store alignment.
if (AccessSize < 8 )
InstrumentMemOperandSmallImpl (MemOp, AccessSize, IsWrite, Ctx, Out);
else
InstrumentMemOperandLargeImpl (MemOp, AccessSize, IsWrite, Ctx, Out);
}
void X86AddressSanitizer::InstrumentMOV (const MCInst &Inst,
OperandVector &Operands, MCContext &Ctx,
const MCInstrInfo &MII,
MCStreamer &Out) {
void X86AddressSanitizer::InstrumentMOV (
const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
const MCInstrInfo &MII, MCStreamer &Out) {
// Access size in bytes.
unsigned AccessSize = 0 ;
Expand Down
Expand Up
@@ -136,113 +142,352 @@ void X86AddressSanitizer::InstrumentMOV(const MCInst &Inst,
class X86AddressSanitizer32 : public X86AddressSanitizer {
public:
static const long kShadowOffset = 0x20000000 ;
X86AddressSanitizer32 (const MCSubtargetInfo &STI)
: X86AddressSanitizer(STI) {}
virtual ~X86AddressSanitizer32 () {}
virtual void InstrumentMemOperandImpl (X86Operand &Op, unsigned AccessSize,
bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
virtual void InstrumentMemOperandSmallImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
virtual void InstrumentMemOperandLargeImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
private:
void EmitCallAsanReport (MCContext &Ctx, MCStreamer &Out, unsigned AccessSize,
bool IsWrite, unsigned AddressReg) {
EmitInstruction (Out, MCInstBuilder (X86::CLD));
EmitInstruction (Out, MCInstBuilder (X86::MMX_EMMS));
EmitInstruction (Out, MCInstBuilder (X86::AND64ri8).addReg (X86::ESP)
.addReg (X86::ESP).addImm (-16 ));
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (AddressReg));
const std::string& Fn = FuncName (AccessSize, IsWrite);
MCSymbol *FnSym = Ctx.GetOrCreateSymbol (StringRef (Fn));
const MCSymbolRefExpr *FnExpr =
MCSymbolRefExpr::Create (FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::CALLpcrel32).addExpr (FnExpr));
}
};
void X86AddressSanitizer32::InstrumentMemOperandImpl (X86Operand &Op,
unsigned AccessSize,
bool IsWrite,
MCContext &Ctx,
MCStreamer &Out) {
// FIXME: emit .cfi directives for correct stack unwinding.
void X86AddressSanitizer32::InstrumentMemOperandSmallImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::ECX));
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::EDX));
EmitInstruction (Out, MCInstBuilder (X86::PUSHF32));
{
MCInst Inst;
Inst.setOpcode (X86::LEA32r);
Inst.addOperand (MCOperand::CreateReg (X86::EAX));
Op.addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::EAX));
EmitInstruction (
Out, MCInstBuilder (X86::MOV32rr).addReg (X86::ECX).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::SHR32ri).addReg (X86::ECX)
.addReg (X86::ECX).addImm (3 ));
{
const std::string Func = FuncName (AccessSize, IsWrite);
const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol (StringRef (Func));
const MCSymbolRefExpr *FuncExpr =
MCSymbolRefExpr::Create (FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::CALLpcrel32).addExpr (FuncExpr));
MCInst Inst;
Inst.setOpcode (X86::MOV8rm);
Inst.addOperand (MCOperand::CreateReg (X86::CL));
const MCExpr *Disp = MCConstantExpr::Create (kShadowOffset , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::ECX, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (Out,
MCInstBuilder (X86::TEST8rr).addReg (X86::CL).addReg (X86::CL));
MCSymbol *DoneSym = Ctx.CreateTempSymbol ();
const MCExpr *DoneExpr = MCSymbolRefExpr::Create (DoneSym, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::JE_4).addExpr (DoneExpr));
EmitInstruction (
Out, MCInstBuilder (X86::MOV32rr).addReg (X86::EDX).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::AND32ri).addReg (X86::EDX)
.addReg (X86::EDX).addImm (7 ));
switch (AccessSize) {
case 1 :
break ;
case 2 : {
MCInst Inst;
Inst.setOpcode (X86::LEA32r);
Inst.addOperand (MCOperand::CreateReg (X86::EDX));
const MCExpr *Disp = MCConstantExpr::Create (1 , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::EDX, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
break ;
}
case 4 :
EmitInstruction (Out, MCInstBuilder (X86::ADD32ri8).addReg (X86::EDX)
.addReg (X86::EDX).addImm (3 ));
break ;
default :
assert (false && " Incorrect access size" );
break ;
}
EmitInstruction (
Out, MCInstBuilder (X86::MOVSX32rr8).addReg (X86::ECX).addReg (X86::CL));
EmitInstruction (
Out, MCInstBuilder (X86::CMP32rr).addReg (X86::EDX).addReg (X86::ECX));
EmitInstruction (Out, MCInstBuilder (X86::JL_4).addExpr (DoneExpr));
EmitCallAsanReport (Ctx, Out, AccessSize, IsWrite, X86::EAX);
EmitLabel (Out, DoneSym);
EmitInstruction (Out, MCInstBuilder (X86::POPF32));
EmitInstruction (Out, MCInstBuilder (X86::POP32r).addReg (X86::EDX));
EmitInstruction (Out, MCInstBuilder (X86::POP32r).addReg (X86::ECX));
EmitInstruction (Out, MCInstBuilder (X86::POP32r).addReg (X86::EAX));
}
void X86AddressSanitizer32::InstrumentMemOperandLargeImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::PUSH32r).addReg (X86::ECX));
EmitInstruction (Out, MCInstBuilder (X86::PUSHF32));
{
MCInst Inst;
Inst.setOpcode (X86::LEA32r);
Inst.addOperand (MCOperand::CreateReg (X86::EAX));
Op.addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (
Out, MCInstBuilder (X86::MOV32rr).addReg (X86::ECX).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::SHR32ri).addReg (X86::ECX)
.addReg (X86::ECX).addImm (3 ));
{
MCInst Inst;
switch (AccessSize) {
case 8 :
Inst.setOpcode (X86::CMP8mi);
break ;
case 16 :
Inst.setOpcode (X86::CMP16mi);
break ;
default :
assert (false && " Incorrect access size" );
break ;
}
const MCExpr *Disp = MCConstantExpr::Create (kShadowOffset , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::ECX, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
Inst.addOperand (MCOperand::CreateImm (0 ));
EmitInstruction (Out, Inst);
}
MCSymbol *DoneSym = Ctx.CreateTempSymbol ();
const MCExpr *DoneExpr = MCSymbolRefExpr::Create (DoneSym, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::JE_4).addExpr (DoneExpr));
EmitCallAsanReport (Ctx, Out, AccessSize, IsWrite, X86::EAX);
EmitLabel (Out, DoneSym);
EmitInstruction (Out, MCInstBuilder (X86::POPF32));
EmitInstruction (Out, MCInstBuilder (X86::POP32r).addReg (X86::ECX));
EmitInstruction (Out, MCInstBuilder (X86::POP32r).addReg (X86::EAX));
}
class X86AddressSanitizer64 : public X86AddressSanitizer {
public:
static const long kShadowOffset = 0x7fff8000 ;
X86AddressSanitizer64 (const MCSubtargetInfo &STI)
: X86AddressSanitizer(STI) {}
virtual ~X86AddressSanitizer64 () {}
virtual void InstrumentMemOperandImpl (X86Operand &Op, unsigned AccessSize,
bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
};
void X86AddressSanitizer64::InstrumentMemOperandImpl (X86Operand &Op,
unsigned AccessSize,
bool IsWrite,
MCContext &Ctx,
MCStreamer &Out) {
// FIXME: emit .cfi directives for correct stack unwinding.
virtual void InstrumentMemOperandSmallImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
virtual void InstrumentMemOperandLargeImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) override ;
// Set %rsp below current red zone (128 bytes wide) using LEA instruction to
// preserve flags.
{
private:
void EmitAdjustRSP (MCContext &Ctx, MCStreamer &Out, long Offset) {
MCInst Inst;
Inst.setOpcode (X86::LEA64r);
Inst.addOperand (MCOperand::CreateReg (X86::RSP));
const MCExpr *Disp = MCConstantExpr::Create (- 128 , Ctx);
const MCExpr *Disp = MCConstantExpr::Create (Offset , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::RSP, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
void EmitCallAsanReport (MCContext &Ctx, MCStreamer &Out, unsigned AccessSize,
bool IsWrite) {
EmitInstruction (Out, MCInstBuilder (X86::CLD));
EmitInstruction (Out, MCInstBuilder (X86::MMX_EMMS));
EmitInstruction (Out, MCInstBuilder (X86::AND64ri8).addReg (X86::RSP)
.addReg (X86::RSP).addImm (-16 ));
const std::string& Fn = FuncName (AccessSize, IsWrite);
MCSymbol *FnSym = Ctx.GetOrCreateSymbol (StringRef (Fn));
const MCSymbolRefExpr *FnExpr =
MCSymbolRefExpr::Create (FnSym, MCSymbolRefExpr::VK_PLT, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::CALL64pcrel32).addExpr (FnExpr));
}
};
void X86AddressSanitizer64::InstrumentMemOperandSmallImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
EmitAdjustRSP (Ctx, Out, -128 );
EmitInstruction (Out, MCInstBuilder (X86::PUSH64r).addReg (X86::RAX));
EmitInstruction (Out, MCInstBuilder (X86::PUSH64r).addReg (X86::RCX));
EmitInstruction (Out, MCInstBuilder (X86::PUSH64r).addReg (X86::RDI));
EmitInstruction (Out, MCInstBuilder (X86::PUSHF64));
{
MCInst Inst;
Inst.setOpcode (X86::LEA64r);
Inst.addOperand (MCOperand::CreateReg (X86::RDI));
Op.addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (
Out, MCInstBuilder (X86::MOV64rr).addReg (X86::RAX).addReg (X86::RDI));
EmitInstruction (Out, MCInstBuilder (X86::SHR64ri).addReg (X86::RAX)
.addReg (X86::RAX).addImm (3 ));
{
const std::string Func = FuncName (AccessSize, IsWrite);
const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol (StringRef (Func));
const MCSymbolRefExpr *FuncExpr =
MCSymbolRefExpr::Create (FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::CALL64pcrel32).addExpr (FuncExpr));
MCInst Inst;
Inst.setOpcode (X86::MOV8rm);
Inst.addOperand (MCOperand::CreateReg (X86::AL));
const MCExpr *Disp = MCConstantExpr::Create (kShadowOffset , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::RAX, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (Out,
MCInstBuilder (X86::TEST8rr).addReg (X86::AL).addReg (X86::AL));
MCSymbol *DoneSym = Ctx.CreateTempSymbol ();
const MCExpr *DoneExpr = MCSymbolRefExpr::Create (DoneSym, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::JE_4).addExpr (DoneExpr));
EmitInstruction (
Out, MCInstBuilder (X86::MOV32rr).addReg (X86::ECX).addReg (X86::EDI));
EmitInstruction (Out, MCInstBuilder (X86::AND32ri).addReg (X86::ECX)
.addReg (X86::ECX).addImm (7 ));
switch (AccessSize) {
case 1 :
break ;
case 2 : {
MCInst Inst;
Inst.setOpcode (X86::LEA32r);
Inst.addOperand (MCOperand::CreateReg (X86::ECX));
const MCExpr *Disp = MCConstantExpr::Create (1 , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::ECX, 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
break ;
}
case 4 :
EmitInstruction (Out, MCInstBuilder (X86::ADD32ri8).addReg (X86::ECX)
.addReg (X86::ECX).addImm (3 ));
break ;
default :
assert (false && " Incorrect access size" );
break ;
}
EmitInstruction (
Out, MCInstBuilder (X86::MOVSX32rr8).addReg (X86::EAX).addReg (X86::AL));
EmitInstruction (
Out, MCInstBuilder (X86::CMP32rr).addReg (X86::ECX).addReg (X86::EAX));
EmitInstruction (Out, MCInstBuilder (X86::JL_4).addExpr (DoneExpr));
EmitCallAsanReport (Ctx, Out, AccessSize, IsWrite);
EmitLabel (Out, DoneSym);
EmitInstruction (Out, MCInstBuilder (X86::POPF64));
EmitInstruction (Out, MCInstBuilder (X86::POP64r).addReg (X86::RDI));
EmitInstruction (Out, MCInstBuilder (X86::POP64r).addReg (X86::RCX));
EmitInstruction (Out, MCInstBuilder (X86::POP64r).addReg (X86::RAX));
EmitAdjustRSP (Ctx, Out, 128 );
}
void X86AddressSanitizer64::InstrumentMemOperandLargeImpl (
X86Operand &Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
MCStreamer &Out) {
EmitAdjustRSP (Ctx, Out, -128 );
EmitInstruction (Out, MCInstBuilder (X86::PUSH64r).addReg (X86::RAX));
EmitInstruction (Out, MCInstBuilder (X86::PUSHF64));
// Restore old %rsp value.
{
MCInst Inst;
Inst.setOpcode (X86::LEA64r);
Inst.addOperand (MCOperand::CreateReg (X86::RSP));
const MCExpr *Disp = MCConstantExpr::Create (128 , Ctx);
Inst.addOperand (MCOperand::CreateReg (X86::RAX));
Op.addMemOperands (Inst, 5 );
EmitInstruction (Out, Inst);
}
EmitInstruction (Out, MCInstBuilder (X86::SHR64ri).addReg (X86::RAX)
.addReg (X86::RAX).addImm (3 ));
{
MCInst Inst;
switch (AccessSize) {
case 8 :
Inst.setOpcode (X86::CMP8mi);
break ;
case 16 :
Inst.setOpcode (X86::CMP16mi);
break ;
default :
assert (false && " Incorrect access size" );
break ;
}
const MCExpr *Disp = MCConstantExpr::Create (kShadowOffset , Ctx);
std::unique_ptr<X86Operand> Op (
X86Operand::CreateMem (0 , Disp, X86::RSP , 0 , 1 , SMLoc (), SMLoc ()));
X86Operand::CreateMem (0 , Disp, X86::RAX , 0 , 1 , SMLoc (), SMLoc ()));
Op->addMemOperands (Inst, 5 );
Inst.addOperand (MCOperand::CreateImm (0 ));
EmitInstruction (Out, Inst);
}
MCSymbol *DoneSym = Ctx.CreateTempSymbol ();
const MCExpr *DoneExpr = MCSymbolRefExpr::Create (DoneSym, Ctx);
EmitInstruction (Out, MCInstBuilder (X86::JE_4).addExpr (DoneExpr));
EmitCallAsanReport (Ctx, Out, AccessSize, IsWrite);
EmitLabel (Out, DoneSym);
EmitInstruction (Out, MCInstBuilder (X86::POPF64));
EmitInstruction (Out, MCInstBuilder (X86::POP64r).addReg (X86::RAX));
EmitAdjustRSP (Ctx, Out, 128 );
}
} // End anonymous namespace
X86AsmInstrumentation::X86AsmInstrumentation () {}
X86AsmInstrumentation::~X86AsmInstrumentation () {}
void X86AsmInstrumentation::InstrumentInstruction (const MCInst &Inst,
OperandVector &Operands,
MCContext &Ctx,
const MCInstrInfo &MII,
MCStreamer &Out) {}
void X86AsmInstrumentation::InstrumentInstruction (
const MCInst &Inst, OperandVector &Operands, MCContext &Ctx,
const MCInstrInfo &MII, MCStreamer &Out) {}
X86AsmInstrumentation *
CreateX86AsmInstrumentation (const MCTargetOptions &MCOptions,
Expand Down