blob: 030778af7e1a27c3719cd74ff4201bac16810be8 [file] [log] [blame]
Evgeniy Stepanov49e26252014-03-14 08:58:04 +00001//===-- X86AsmInstrumentation.cpp - Instrument X86 inline assembly C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "MCTargetDesc/X86BaseInfo.h"
11#include "X86AsmInstrumentation.h"
12#include "X86Operand.h"
13#include "llvm/ADT/StringExtras.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000014#include "llvm/IR/Function.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000015#include "llvm/MC/MCContext.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/MC/MCInstBuilder.h"
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000018#include "llvm/MC/MCInstrInfo.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000019#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000020#include "llvm/MC/MCStreamer.h"
21#include "llvm/MC/MCSubtargetInfo.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000022#include "llvm/MC/MCTargetOptions.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000023
24namespace llvm {
25namespace {
26
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000027bool IsStackReg(unsigned Reg) {
28 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
29}
30
31std::string FuncName(unsigned AccessSize, bool IsWrite) {
32 return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
33 (utostr(AccessSize));
34}
35
36class X86AddressSanitizer : public X86AsmInstrumentation {
37public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000038 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000039 virtual ~X86AddressSanitizer() {}
40
41 // X86AsmInstrumentation implementation:
42 virtual void InstrumentInstruction(
43 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000044 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) override {
45 InstrumentMOV(Inst, Operands, Ctx, MII, Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000046 }
47
48 // Should be implemented differently in x86_32 and x86_64 subclasses.
49 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
50 bool IsWrite, MCContext &Ctx,
51 MCStreamer &Out) = 0;
52
53 void InstrumentMemOperand(MCParsedAsmOperand *Op, unsigned AccessSize,
54 bool IsWrite, MCContext &Ctx, MCStreamer &Out);
55 void InstrumentMOV(const MCInst &Inst,
56 SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000057 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out);
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000058 void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
59 Out.EmitInstruction(Inst, STI);
60 }
61
62protected:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000063 const MCSubtargetInfo &STI;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000064};
65
66void X86AddressSanitizer::InstrumentMemOperand(
67 MCParsedAsmOperand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
68 MCStreamer &Out) {
69 assert(Op && Op->isMem() && "Op should be a memory operand.");
70 assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
71 "AccessSize should be a power of two, less or equal than 16.");
72
73 X86Operand *MemOp = static_cast<X86Operand *>(Op);
74 // FIXME: get rid of this limitation.
75 if (IsStackReg(MemOp->getMemBaseReg()) || IsStackReg(MemOp->getMemIndexReg()))
76 return;
77
78 InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
79}
80
81void X86AddressSanitizer::InstrumentMOV(
82 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +000083 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000084 // Access size in bytes.
85 unsigned AccessSize = 0;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000086
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000087 switch (Inst.getOpcode()) {
88 case X86::MOV8mi:
89 case X86::MOV8mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000090 case X86::MOV8rm:
91 AccessSize = 1;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000092 break;
93 case X86::MOV16mi:
94 case X86::MOV16mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000095 case X86::MOV16rm:
96 AccessSize = 2;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000097 break;
98 case X86::MOV32mi:
99 case X86::MOV32mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000100 case X86::MOV32rm:
101 AccessSize = 4;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000102 break;
103 case X86::MOV64mi32:
104 case X86::MOV64mr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000105 case X86::MOV64rm:
106 AccessSize = 8;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000107 break;
108 case X86::MOVAPDmr:
109 case X86::MOVAPSmr:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000110 case X86::MOVAPDrm:
111 case X86::MOVAPSrm:
112 AccessSize = 16;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000113 break;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000114 default:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000115 return;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000116 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000117
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000118 const bool IsWrite = MII.get(Inst.getOpcode()).mayStore();
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000119 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
120 MCParsedAsmOperand *Op = Operands[Ix];
121 if (Op && Op->isMem())
122 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
123 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000124}
125
126class X86AddressSanitizer32 : public X86AddressSanitizer {
127public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000128 X86AddressSanitizer32(const MCSubtargetInfo &STI)
129 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000130 virtual ~X86AddressSanitizer32() {}
131
132 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
133 bool IsWrite, MCContext &Ctx,
134 MCStreamer &Out) override;
135};
136
137void X86AddressSanitizer32::InstrumentMemOperandImpl(
138 X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
139 MCStreamer &Out) {
140 // FIXME: emit .cfi directives for correct stack unwinding.
141 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
142 {
143 MCInst Inst;
144 Inst.setOpcode(X86::LEA32r);
145 Inst.addOperand(MCOperand::CreateReg(X86::EAX));
146 Op->addMemOperands(Inst, 5);
147 EmitInstruction(Out, Inst);
148 }
149 EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
150 {
151 const std::string Func = FuncName(AccessSize, IsWrite);
152 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
153 const MCSymbolRefExpr *FuncExpr =
154 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
155 EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
156 }
157 EmitInstruction(Out, MCInstBuilder(X86::ADD32ri).addReg(X86::ESP)
158 .addReg(X86::ESP).addImm(4));
159 EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
160}
161
162class X86AddressSanitizer64 : public X86AddressSanitizer {
163public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000164 X86AddressSanitizer64(const MCSubtargetInfo &STI)
165 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000166 virtual ~X86AddressSanitizer64() {}
167
168 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
169 bool IsWrite, MCContext &Ctx,
170 MCStreamer &Out) override;
171};
172
173void X86AddressSanitizer64::InstrumentMemOperandImpl(
174 X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
175 MCStreamer &Out) {
176 // FIXME: emit .cfi directives for correct stack unwinding.
177 // Set %rsp below current red zone (128 bytes wide)
178 EmitInstruction(Out, MCInstBuilder(X86::SUB64ri32).addReg(X86::RSP)
179 .addReg(X86::RSP).addImm(128));
180 EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
181 {
182 MCInst Inst;
183 Inst.setOpcode(X86::LEA64r);
184 Inst.addOperand(MCOperand::CreateReg(X86::RDI));
185 Op->addMemOperands(Inst, 5);
186 EmitInstruction(Out, Inst);
187 }
188 {
189 const std::string Func = FuncName(AccessSize, IsWrite);
190 const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
191 const MCSymbolRefExpr *FuncExpr =
192 MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
193 EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
194 }
195 EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
196 EmitInstruction(Out, MCInstBuilder(X86::ADD64ri32).addReg(X86::RSP)
197 .addReg(X86::RSP).addImm(128));
198}
199
200} // End anonymous namespace
201
202X86AsmInstrumentation::X86AsmInstrumentation() {}
203X86AsmInstrumentation::~X86AsmInstrumentation() {}
204
205void X86AsmInstrumentation::InstrumentInstruction(
206 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
Evgeniy Stepanovf4a36992014-04-24 13:29:34 +0000207 MCContext &Ctx, const MCInstrInfo &MII, MCStreamer &Out) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000208
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000209X86AsmInstrumentation *
210CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions, const MCContext &Ctx,
211 const MCSubtargetInfo &STI) {
212 if (MCOptions.SanitizeAddress) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000213 if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
214 return new X86AddressSanitizer32(STI);
215 if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
216 return new X86AddressSanitizer64(STI);
217 }
218 return new X86AsmInstrumentation();
219}
220
221} // End llvm namespace