Create MCTargetOptions.
[oota-llvm.git] / lib / Target / X86 / AsmParser / X86AsmInstrumentation.cpp
1 //===-- 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"
14 #include "llvm/IR/Function.h"
15 #include "llvm/MC/MCContext.h"
16 #include "llvm/MC/MCInst.h"
17 #include "llvm/MC/MCInstBuilder.h"
18 #include "llvm/MC/MCParser/MCParsedAsmOperand.h"
19 #include "llvm/MC/MCStreamer.h"
20 #include "llvm/MC/MCSubtargetInfo.h"
21 #include "llvm/MC/MCTargetOptions.h"
22
23 namespace llvm {
24 namespace {
25
26 bool IsStackReg(unsigned Reg) {
27   return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
28 }
29
30 std::string FuncName(unsigned AccessSize, bool IsWrite) {
31   return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
32          (utostr(AccessSize));
33 }
34
35 class X86AddressSanitizer : public X86AsmInstrumentation {
36 public:
37   X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
38   virtual ~X86AddressSanitizer() {}
39
40   // X86AsmInstrumentation implementation:
41   virtual void InstrumentInstruction(
42       const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
43       MCContext &Ctx, MCStreamer &Out) override {
44     InstrumentMOV(Inst, Operands, Ctx, Out);
45   }
46
47   // Should be implemented differently in x86_32 and x86_64 subclasses.
48   virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
49                                         bool IsWrite, MCContext &Ctx,
50                                         MCStreamer &Out) = 0;
51
52   void InstrumentMemOperand(MCParsedAsmOperand *Op, unsigned AccessSize,
53                             bool IsWrite, MCContext &Ctx, MCStreamer &Out);
54   void InstrumentMOV(const MCInst &Inst,
55                      SmallVectorImpl<MCParsedAsmOperand *> &Operands,
56                      MCContext &Ctx, MCStreamer &Out);
57   void EmitInstruction(MCStreamer &Out, const MCInst &Inst) {
58     Out.EmitInstruction(Inst, STI);
59   }
60
61 protected:
62   const MCSubtargetInfo &STI;
63 };
64
65 void X86AddressSanitizer::InstrumentMemOperand(
66     MCParsedAsmOperand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
67     MCStreamer &Out) {
68   assert(Op && Op->isMem() && "Op should be a memory operand.");
69   assert((AccessSize & (AccessSize - 1)) == 0 && AccessSize <= 16 &&
70          "AccessSize should be a power of two, less or equal than 16.");
71
72   X86Operand *MemOp = static_cast<X86Operand *>(Op);
73   // FIXME: get rid of this limitation.
74   if (IsStackReg(MemOp->getMemBaseReg()) || IsStackReg(MemOp->getMemIndexReg()))
75     return;
76
77   InstrumentMemOperandImpl(MemOp, AccessSize, IsWrite, Ctx, Out);
78 }
79
80 void X86AddressSanitizer::InstrumentMOV(
81     const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
82     MCContext &Ctx, MCStreamer &Out) {
83   // Access size in bytes.
84   unsigned AccessSize = 0;
85   unsigned long OpIx = Operands.size();
86   switch (Inst.getOpcode()) {
87   case X86::MOV8mi:
88   case X86::MOV8mr:
89     AccessSize = 1;
90     OpIx = 2;
91     break;
92   case X86::MOV8rm:
93     AccessSize = 1;
94     OpIx = 1;
95     break;
96   case X86::MOV16mi:
97   case X86::MOV16mr:
98     AccessSize = 2;
99     OpIx = 2;
100     break;
101   case X86::MOV16rm:
102     AccessSize = 2;
103     OpIx = 1;
104     break;
105   case X86::MOV32mi:
106   case X86::MOV32mr:
107     AccessSize = 4;
108     OpIx = 2;
109     break;
110   case X86::MOV32rm:
111     AccessSize = 4;
112     OpIx = 1;
113     break;
114   case X86::MOV64mi32:
115   case X86::MOV64mr:
116     AccessSize = 8;
117     OpIx = 2;
118     break;
119   case X86::MOV64rm:
120     AccessSize = 8;
121     OpIx = 1;
122     break;
123   case X86::MOVAPDmr:
124   case X86::MOVAPSmr:
125     AccessSize = 16;
126     OpIx = 2;
127     break;
128   case X86::MOVAPDrm:
129   case X86::MOVAPSrm:
130     AccessSize = 16;
131     OpIx = 1;
132     break;
133   }
134   if (OpIx >= Operands.size())
135     return;
136
137   const bool IsWrite = (OpIx != 1);
138   InstrumentMemOperand(Operands[OpIx], AccessSize, IsWrite, Ctx, Out);
139 }
140
141 class X86AddressSanitizer32 : public X86AddressSanitizer {
142 public:
143   X86AddressSanitizer32(const MCSubtargetInfo &STI)
144       : X86AddressSanitizer(STI) {}
145   virtual ~X86AddressSanitizer32() {}
146
147   virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
148                                         bool IsWrite, MCContext &Ctx,
149                                         MCStreamer &Out) override;
150 };
151
152 void X86AddressSanitizer32::InstrumentMemOperandImpl(
153     X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
154     MCStreamer &Out) {
155   // FIXME: emit .cfi directives for correct stack unwinding.
156   EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
157   {
158     MCInst Inst;
159     Inst.setOpcode(X86::LEA32r);
160     Inst.addOperand(MCOperand::CreateReg(X86::EAX));
161     Op->addMemOperands(Inst, 5);
162     EmitInstruction(Out, Inst);
163   }
164   EmitInstruction(Out, MCInstBuilder(X86::PUSH32r).addReg(X86::EAX));
165   {
166     const std::string Func = FuncName(AccessSize, IsWrite);
167     const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
168     const MCSymbolRefExpr *FuncExpr =
169         MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
170     EmitInstruction(Out, MCInstBuilder(X86::CALLpcrel32).addExpr(FuncExpr));
171   }
172   EmitInstruction(Out, MCInstBuilder(X86::ADD32ri).addReg(X86::ESP)
173                            .addReg(X86::ESP).addImm(4));
174   EmitInstruction(Out, MCInstBuilder(X86::POP32r).addReg(X86::EAX));
175 }
176
177 class X86AddressSanitizer64 : public X86AddressSanitizer {
178 public:
179   X86AddressSanitizer64(const MCSubtargetInfo &STI)
180       : X86AddressSanitizer(STI) {}
181   virtual ~X86AddressSanitizer64() {}
182
183   virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
184                                         bool IsWrite, MCContext &Ctx,
185                                         MCStreamer &Out) override;
186 };
187
188 void X86AddressSanitizer64::InstrumentMemOperandImpl(
189     X86Operand *Op, unsigned AccessSize, bool IsWrite, MCContext &Ctx,
190     MCStreamer &Out) {
191   // FIXME: emit .cfi directives for correct stack unwinding.
192   // Set %rsp below current red zone (128 bytes wide)
193   EmitInstruction(Out, MCInstBuilder(X86::SUB64ri32).addReg(X86::RSP)
194                            .addReg(X86::RSP).addImm(128));
195   EmitInstruction(Out, MCInstBuilder(X86::PUSH64r).addReg(X86::RDI));
196   {
197     MCInst Inst;
198     Inst.setOpcode(X86::LEA64r);
199     Inst.addOperand(MCOperand::CreateReg(X86::RDI));
200     Op->addMemOperands(Inst, 5);
201     EmitInstruction(Out, Inst);
202   }
203   {
204     const std::string Func = FuncName(AccessSize, IsWrite);
205     const MCSymbol *FuncSym = Ctx.GetOrCreateSymbol(StringRef(Func));
206     const MCSymbolRefExpr *FuncExpr =
207         MCSymbolRefExpr::Create(FuncSym, MCSymbolRefExpr::VK_PLT, Ctx);
208     EmitInstruction(Out, MCInstBuilder(X86::CALL64pcrel32).addExpr(FuncExpr));
209   }
210   EmitInstruction(Out, MCInstBuilder(X86::POP64r).addReg(X86::RDI));
211   EmitInstruction(Out, MCInstBuilder(X86::ADD64ri32).addReg(X86::RSP)
212                            .addReg(X86::RSP).addImm(128));
213 }
214
215 } // End anonymous namespace
216
217 X86AsmInstrumentation::X86AsmInstrumentation() {}
218 X86AsmInstrumentation::~X86AsmInstrumentation() {}
219
220 void X86AsmInstrumentation::InstrumentInstruction(
221     const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
222     MCContext &Ctx, MCStreamer &Out) {}
223
224 X86AsmInstrumentation *
225 CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions, const MCContext &Ctx,
226                             const MCSubtargetInfo &STI) {
227   if (MCOptions.SanitizeAddress) {
228     if ((STI.getFeatureBits() & X86::Mode32Bit) != 0)
229       return new X86AddressSanitizer32(STI);
230     if ((STI.getFeatureBits() & X86::Mode64Bit) != 0)
231       return new X86AddressSanitizer64(STI);
232   }
233   return new X86AsmInstrumentation();
234 }
235
236 } // End llvm namespace