blob: 4829165892e676619c94474f36559625bf8a2881 [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 Stepanov0a951b72014-04-23 11:16:03 +000018#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000019#include "llvm/MC/MCStreamer.h"
20#include "llvm/MC/MCSubtargetInfo.h"
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000021#include "llvm/MC/MCTargetOptions.h"
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000022
23namespace llvm {
24namespace {
25
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000026bool IsStackReg(unsigned Reg) {
27 return Reg == X86::RSP || Reg == X86::ESP || Reg == X86::SP;
28}
29
30std::string FuncName(unsigned AccessSize, bool IsWrite) {
31 return std::string("__sanitizer_sanitize_") + (IsWrite ? "store" : "load") +
32 (utostr(AccessSize));
33}
34
35class X86AddressSanitizer : public X86AsmInstrumentation {
36public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000037 X86AddressSanitizer(const MCSubtargetInfo &STI) : STI(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000038 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
61protected:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +000062 const MCSubtargetInfo &STI;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000063};
64
65void 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
80void X86AddressSanitizer::InstrumentMOV(
81 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
82 MCContext &Ctx, MCStreamer &Out) {
83 // Access size in bytes.
84 unsigned AccessSize = 0;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000085
86 // FIXME: use MCInstrDesc to get proper value of IsWrite.
87 bool IsWrite = false;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000088 switch (Inst.getOpcode()) {
89 case X86::MOV8mi:
90 case X86::MOV8mr:
91 AccessSize = 1;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +000092 IsWrite = true;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000093 break;
94 case X86::MOV8rm:
95 AccessSize = 1;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +000096 break;
97 case X86::MOV16mi:
98 case X86::MOV16mr:
99 AccessSize = 2;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000100 IsWrite = true;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000101 break;
102 case X86::MOV16rm:
103 AccessSize = 2;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000104 break;
105 case X86::MOV32mi:
106 case X86::MOV32mr:
107 AccessSize = 4;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000108 IsWrite = true;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000109 break;
110 case X86::MOV32rm:
111 AccessSize = 4;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000112 break;
113 case X86::MOV64mi32:
114 case X86::MOV64mr:
115 AccessSize = 8;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000116 IsWrite = true;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000117 break;
118 case X86::MOV64rm:
119 AccessSize = 8;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000120 break;
121 case X86::MOVAPDmr:
122 case X86::MOVAPSmr:
123 AccessSize = 16;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000124 IsWrite = true;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000125 break;
126 case X86::MOVAPDrm:
127 case X86::MOVAPSrm:
128 AccessSize = 16;
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000129 break;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000130 default:
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000131 return;
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000132 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000133
Evgeniy Stepanovb6c47a52014-04-24 09:56:15 +0000134 for (unsigned Ix = 0; Ix < Operands.size(); ++Ix) {
135 MCParsedAsmOperand *Op = Operands[Ix];
136 if (Op && Op->isMem())
137 InstrumentMemOperand(Op, AccessSize, IsWrite, Ctx, Out);
138 }
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000139}
140
141class X86AddressSanitizer32 : public X86AddressSanitizer {
142public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000143 X86AddressSanitizer32(const MCSubtargetInfo &STI)
144 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000145 virtual ~X86AddressSanitizer32() {}
146
147 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
148 bool IsWrite, MCContext &Ctx,
149 MCStreamer &Out) override;
150};
151
152void 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
177class X86AddressSanitizer64 : public X86AddressSanitizer {
178public:
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000179 X86AddressSanitizer64(const MCSubtargetInfo &STI)
180 : X86AddressSanitizer(STI) {}
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000181 virtual ~X86AddressSanitizer64() {}
182
183 virtual void InstrumentMemOperandImpl(X86Operand *Op, unsigned AccessSize,
184 bool IsWrite, MCContext &Ctx,
185 MCStreamer &Out) override;
186};
187
188void 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
217X86AsmInstrumentation::X86AsmInstrumentation() {}
218X86AsmInstrumentation::~X86AsmInstrumentation() {}
219
220void X86AsmInstrumentation::InstrumentInstruction(
221 const MCInst &Inst, SmallVectorImpl<MCParsedAsmOperand *> &Operands,
222 MCContext &Ctx, MCStreamer &Out) {}
223
Evgeniy Stepanov0a951b72014-04-23 11:16:03 +0000224X86AsmInstrumentation *
225CreateX86AsmInstrumentation(const MCTargetOptions &MCOptions, const MCContext &Ctx,
226 const MCSubtargetInfo &STI) {
227 if (MCOptions.SanitizeAddress) {
Evgeniy Stepanov49e26252014-03-14 08:58:04 +0000228 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