Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/Target/X86/MCTargetDesc/X86WinCOFFTargetStreamer.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- X86WinCOFFTargetStreamer.cpp ----------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "X86MCTargetDesc.h"
10
#include "X86TargetStreamer.h"
11
#include "llvm/DebugInfo/CodeView/CodeView.h"
12
#include "llvm/MC/MCCodeView.h"
13
#include "llvm/MC/MCContext.h"
14
#include "llvm/MC/MCInstPrinter.h"
15
#include "llvm/MC/MCRegisterInfo.h"
16
#include "llvm/MC/MCSubtargetInfo.h"
17
#include "llvm/Support/FormattedStream.h"
18
19
using namespace llvm;
20
using namespace llvm::codeview;
21
22
namespace {
23
/// Implements Windows x86-only directives for assembly emission.
24
class X86WinCOFFAsmTargetStreamer : public X86TargetStreamer {
25
  formatted_raw_ostream &OS;
26
  MCInstPrinter &InstPrinter;
27
28
public:
29
  X86WinCOFFAsmTargetStreamer(MCStreamer &S, formatted_raw_ostream &OS,
30
                              MCInstPrinter &InstPrinter)
31
8.35k
      : X86TargetStreamer(S), OS(OS), InstPrinter(InstPrinter) {}
32
33
  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
34
                   SMLoc L) override;
35
  bool emitFPOEndPrologue(SMLoc L) override;
36
  bool emitFPOEndProc(SMLoc L) override;
37
  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
38
  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
39
  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
40
  bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
41
  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
42
};
43
44
/// Represents a single FPO directive.
45
struct FPOInstruction {
46
  MCSymbol *Label;
47
  enum Operation {
48
    PushReg,
49
    StackAlloc,
50
    StackAlign,
51
    SetFrame,
52
  } Op;
53
  unsigned RegOrOffset;
54
};
55
56
struct FPOData {
57
  const MCSymbol *Function = nullptr;
58
  MCSymbol *Begin = nullptr;
59
  MCSymbol *PrologueEnd = nullptr;
60
  MCSymbol *End = nullptr;
61
  unsigned ParamsSize = 0;
62
63
  SmallVector<FPOInstruction, 5> Instructions;
64
};
65
66
/// Implements Windows x86-only directives for object emission.
67
class X86WinCOFFTargetStreamer : public X86TargetStreamer {
68
  /// Map from function symbol to its FPO data.
69
  DenseMap<const MCSymbol *, std::unique_ptr<FPOData>> AllFPOData;
70
71
  /// Current FPO data created by .cv_fpo_proc.
72
  std::unique_ptr<FPOData> CurFPOData;
73
74
377
  bool haveOpenFPOData() { return !!CurFPOData; }
75
76
  /// Diagnoses an error at L if we are not in an FPO prologue. Return true on
77
  /// error.
78
  bool checkInFPOPrologue(SMLoc L);
79
80
  MCSymbol *emitFPOLabel();
81
82
377
  MCContext &getContext() { return getStreamer().getContext(); }
83
84
public:
85
533
  X86WinCOFFTargetStreamer(MCStreamer &S) : X86TargetStreamer(S) {}
86
87
  bool emitFPOProc(const MCSymbol *ProcSym, unsigned ParamsSize,
88
                   SMLoc L) override;
89
  bool emitFPOEndPrologue(SMLoc L) override;
90
  bool emitFPOEndProc(SMLoc L) override;
91
  bool emitFPOData(const MCSymbol *ProcSym, SMLoc L) override;
92
  bool emitFPOPushReg(unsigned Reg, SMLoc L) override;
93
  bool emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) override;
94
  bool emitFPOStackAlign(unsigned Align, SMLoc L) override;
95
  bool emitFPOSetFrame(unsigned Reg, SMLoc L) override;
96
};
97
} // end namespace
98
99
bool X86WinCOFFAsmTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
100
90
                                              unsigned ParamsSize, SMLoc L) {
101
90
  OS << "\t.cv_fpo_proc\t";
102
90
  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
103
90
  OS << ' ' << ParamsSize << '\n';
104
90
  return false;
105
90
}
106
107
58
bool X86WinCOFFAsmTargetStreamer::emitFPOEndPrologue(SMLoc L) {
108
58
  OS << "\t.cv_fpo_endprologue\n";
109
58
  return false;
110
58
}
111
112
90
bool X86WinCOFFAsmTargetStreamer::emitFPOEndProc(SMLoc L) {
113
90
  OS << "\t.cv_fpo_endproc\n";
114
90
  return false;
115
90
}
116
117
bool X86WinCOFFAsmTargetStreamer::emitFPOData(const MCSymbol *ProcSym,
118
0
                                              SMLoc L) {
119
0
  OS << "\t.cv_fpo_data\t";
120
0
  ProcSym->print(OS, getStreamer().getContext().getAsmInfo());
121
0
  OS << '\n';
122
0
  return false;
123
0
}
124
125
71
bool X86WinCOFFAsmTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
126
71
  OS << "\t.cv_fpo_pushreg\t";
127
71
  InstPrinter.printRegName(OS, Reg);
128
71
  OS << '\n';
129
71
  return false;
130
71
}
131
132
bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc,
133
43
                                                    SMLoc L) {
134
43
  OS << "\t.cv_fpo_stackalloc\t" << StackAlloc << '\n';
135
43
  return false;
136
43
}
137
138
3
bool X86WinCOFFAsmTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
139
3
  OS << "\t.cv_fpo_stackalign\t" << Align << '\n';
140
3
  return false;
141
3
}
142
143
34
bool X86WinCOFFAsmTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
144
34
  OS << "\t.cv_fpo_setframe\t";
145
34
  InstPrinter.printRegName(OS, Reg);
146
34
  OS << '\n';
147
34
  return false;
148
34
}
149
150
207
bool X86WinCOFFTargetStreamer::checkInFPOPrologue(SMLoc L) {
151
207
  if (!haveOpenFPOData() || CurFPOData->PrologueEnd) {
152
0
    getContext().reportError(
153
0
        L,
154
0
        "directive must appear between .cv_fpo_proc and .cv_fpo_endprologue");
155
0
    return true;
156
0
  }
157
207
  return false;
158
207
}
159
160
377
MCSymbol *X86WinCOFFTargetStreamer::emitFPOLabel() {
161
377
  MCSymbol *Label = getContext().createTempSymbol("cfi", true);
162
377
  getStreamer().EmitLabel(Label);
163
377
  return Label;
164
377
}
165
166
bool X86WinCOFFTargetStreamer::emitFPOProc(const MCSymbol *ProcSym,
167
85
                                           unsigned ParamsSize, SMLoc L) {
168
85
  if (haveOpenFPOData()) {
169
0
    getContext().reportError(
170
0
        L, "opening new .cv_fpo_proc before closing previous frame");
171
0
    return true;
172
0
  }
173
85
  CurFPOData = llvm::make_unique<FPOData>();
174
85
  CurFPOData->Function = ProcSym;
175
85
  CurFPOData->Begin = emitFPOLabel();
176
85
  CurFPOData->ParamsSize = ParamsSize;
177
85
  return false;
178
85
}
179
180
85
bool X86WinCOFFTargetStreamer::emitFPOEndProc(SMLoc L) {
181
85
  if (!haveOpenFPOData()) {
182
0
    getContext().reportError(L, ".cv_fpo_endproc must appear after .cv_proc");
183
0
    return true;
184
0
  }
185
85
  if (!CurFPOData->PrologueEnd) {
186
33
    // Complain if there were prologue setup instructions but no end prologue.
187
33
    if (!CurFPOData->Instructions.empty()) {
188
0
      getContext().reportError(L, "missing .cv_fpo_endprologue");
189
0
      CurFPOData->Instructions.clear();
190
0
    }
191
33
192
33
    // Claim there is a zero-length prologue to make the label math work out
193
33
    // later.
194
33
    CurFPOData->PrologueEnd = CurFPOData->Begin;
195
33
  }
196
85
197
85
  CurFPOData->End = emitFPOLabel();
198
85
  const MCSymbol *Fn = CurFPOData->Function;
199
85
  AllFPOData.insert({Fn, std::move(CurFPOData)});
200
85
  return false;
201
85
}
202
203
35
bool X86WinCOFFTargetStreamer::emitFPOSetFrame(unsigned Reg, SMLoc L) {
204
35
  if (checkInFPOPrologue(L))
205
0
    return true;
206
35
  FPOInstruction Inst;
207
35
  Inst.Label = emitFPOLabel();
208
35
  Inst.Op = FPOInstruction::SetFrame;
209
35
  Inst.RegOrOffset = Reg;
210
35
  CurFPOData->Instructions.push_back(Inst);
211
35
  return false;
212
35
}
213
214
75
bool X86WinCOFFTargetStreamer::emitFPOPushReg(unsigned Reg, SMLoc L) {
215
75
  if (checkInFPOPrologue(L))
216
0
    return true;
217
75
  FPOInstruction Inst;
218
75
  Inst.Label = emitFPOLabel();
219
75
  Inst.Op = FPOInstruction::PushReg;
220
75
  Inst.RegOrOffset = Reg;
221
75
  CurFPOData->Instructions.push_back(Inst);
222
75
  return false;
223
75
}
224
225
40
bool X86WinCOFFTargetStreamer::emitFPOStackAlloc(unsigned StackAlloc, SMLoc L) {
226
40
  if (checkInFPOPrologue(L))
227
0
    return true;
228
40
  FPOInstruction Inst;
229
40
  Inst.Label = emitFPOLabel();
230
40
  Inst.Op = FPOInstruction::StackAlloc;
231
40
  Inst.RegOrOffset = StackAlloc;
232
40
  CurFPOData->Instructions.push_back(Inst);
233
40
  return false;
234
40
}
235
236
5
bool X86WinCOFFTargetStreamer::emitFPOStackAlign(unsigned Align, SMLoc L) {
237
5
  if (checkInFPOPrologue(L))
238
0
    return true;
239
10
  
if (5
!llvm::any_of(CurFPOData->Instructions, [](const FPOInstruction &Inst) 5
{
240
10
        return Inst.Op == FPOInstruction::SetFrame;
241
10
      })) {
242
0
    getContext().reportError(
243
0
        L, "a frame register must be established before aligning the stack");
244
0
    return true;
245
0
  }
246
5
  FPOInstruction Inst;
247
5
  Inst.Label = emitFPOLabel();
248
5
  Inst.Op = FPOInstruction::StackAlign;
249
5
  Inst.RegOrOffset = Align;
250
5
  CurFPOData->Instructions.push_back(Inst);
251
5
  return false;
252
5
}
253
254
52
bool X86WinCOFFTargetStreamer::emitFPOEndPrologue(SMLoc L) {
255
52
  if (checkInFPOPrologue(L))
256
0
    return true;
257
52
  CurFPOData->PrologueEnd = emitFPOLabel();
258
52
  return false;
259
52
}
260
261
namespace {
262
struct RegSaveOffset {
263
73
  RegSaveOffset(unsigned Reg, unsigned Offset) : Reg(Reg), Offset(Offset) {}
264
265
  unsigned Reg = 0;
266
  unsigned Offset = 0;
267
};
268
269
struct FPOStateMachine {
270
82
  explicit FPOStateMachine(const FPOData *FPO) : FPO(FPO) {}
271
272
  const FPOData *FPO = nullptr;
273
  unsigned FrameReg = 0;
274
  unsigned FrameRegOff = 0;
275
  unsigned CurOffset = 0;
276
  unsigned LocalSize = 0;
277
  unsigned SavedRegSize = 0;
278
  unsigned StackOffsetBeforeAlign = 0;
279
  unsigned StackAlign = 0;
280
  unsigned Flags = 0; // FIXME: Set HasSEH / HasEH.
281
282
  SmallString<128> FrameFunc;
283
284
  SmallVector<RegSaveOffset, 4> RegSaveOffsets;
285
286
  void emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label);
287
};
288
} // end namespace
289
290
234
static Printable printFPOReg(const MCRegisterInfo *MRI, unsigned LLVMReg) {
291
234
  return Printable([MRI, LLVMReg](raw_ostream &OS) {
292
234
    switch (LLVMReg) {
293
234
    // MSVC only seems to emit symbolic register names for EIP, EBP, and ESP,
294
234
    // but the format seems to support more than that, so we emit them.
295
234
    
case X86::EAX: OS << "$eax"; break0
;
296
234
    
case X86::EBX: OS << "$ebx"; break30
;
297
234
    
case X86::ECX: OS << "$ecx"; break0
;
298
234
    
case X86::EDX: OS << "$edx"; break0
;
299
234
    
case X86::EDI: OS << "$edi"; break26
;
300
234
    
case X86::ESI: OS << "$esi"; break23
;
301
234
    
case X86::ESP: OS << "$esp"; break0
;
302
234
    
case X86::EBP: OS << "$ebp"; break155
;
303
234
    
case X86::EIP: OS << "$eip"; break0
;
304
234
    // Otherwise, get the codeview register number and print $N.
305
234
    default:
306
0
      OS << '$' << MRI->getCodeViewRegNum(LLVMReg);
307
0
      break;
308
234
    }
309
234
  });
310
234
}
311
312
205
void FPOStateMachine::emitFrameDataRecord(MCStreamer &OS, MCSymbol *Label) {
313
205
  unsigned CurFlags = Flags;
314
205
  if (Label == FPO->Begin)
315
82
    CurFlags |= FrameData::IsFunctionStart;
316
205
317
205
  // Compute the new FrameFunc string.
318
205
  FrameFunc.clear();
319
205
  raw_svector_ostream FuncOS(FrameFunc);
320
205
  const MCRegisterInfo *MRI = OS.getContext().getRegisterInfo();
321
205
  assert((StackAlign == 0 || FrameReg != 0) &&
322
205
         "cannot align stack without frame reg");
323
205
  StringRef CFAVar = StackAlign == 0 ? 
"$T0"200
:
"$T1"5
;
324
205
325
205
  if (FrameReg) {
326
54
    // CFA is FrameReg + FrameRegOff.
327
54
    FuncOS << CFAVar << ' ' << printFPOReg(MRI, FrameReg) << ' ' << FrameRegOff
328
54
           << " + = ";
329
54
330
54
    // Assign $T0, the VFRAME register, the value of ESP after it is aligned.
331
54
    // Starting from the CFA, we subtract the size of all pushed registers, and
332
54
    // align the result. While we don't store any CSRs in this area, $T0 is used
333
54
    // by S_DEFRANGE_FRAMEPOINTER_REL records to find local variables.
334
54
    if (StackAlign) {
335
5
      FuncOS << "$T0 " << CFAVar << ' ' << StackOffsetBeforeAlign << " - "
336
5
             << StackAlign << " @ = ";
337
5
    }
338
151
  } else {
339
151
    // The address of return address is ESP + CurOffset, but we use .raSearch to
340
151
    // match MSVC. This seems to ask the debugger to subtract some combination
341
151
    // of LocalSize and SavedRegSize from ESP and grovel around in that memory
342
151
    // to find the address of a plausible return address.
343
151
    FuncOS << CFAVar << " .raSearch = ";
344
151
  }
345
205
346
205
  // Caller's $eip should be dereferenced CFA, and $esp should be CFA plus 4.
347
205
  FuncOS << "$eip " << CFAVar << " ^ = ";
348
205
  FuncOS << "$esp " << CFAVar << " 4 + = ";
349
205
350
205
  // Each saved register is stored at an unchanging negative CFA offset.
351
205
  for (RegSaveOffset RO : RegSaveOffsets)
352
180
    FuncOS << printFPOReg(MRI, RO.Reg) << ' ' << CFAVar << ' ' << RO.Offset
353
180
           << " - ^ = ";
354
205
355
205
  // Add it to the CV string table.
356
205
  CodeViewContext &CVCtx = OS.getContext().getCVContext();
357
205
  unsigned FrameFuncStrTabOff = CVCtx.addToStringTable(FuncOS.str()).second;
358
205
359
205
  // MSVC has only ever been observed to emit a MaxStackSize of zero.
360
205
  unsigned MaxStackSize = 0;
361
205
362
205
  // The FrameData record format is:
363
205
  //   ulittle32_t RvaStart;
364
205
  //   ulittle32_t CodeSize;
365
205
  //   ulittle32_t LocalSize;
366
205
  //   ulittle32_t ParamsSize;
367
205
  //   ulittle32_t MaxStackSize;
368
205
  //   ulittle32_t FrameFunc; // String table offset
369
205
  //   ulittle16_t PrologSize;
370
205
  //   ulittle16_t SavedRegsSize;
371
205
  //   ulittle32_t Flags;
372
205
373
205
  OS.emitAbsoluteSymbolDiff(Label, FPO->Begin, 4); // RvaStart
374
205
  OS.emitAbsoluteSymbolDiff(FPO->End, Label, 4);   // CodeSize
375
205
  OS.EmitIntValue(LocalSize, 4);
376
205
  OS.EmitIntValue(FPO->ParamsSize, 4);
377
205
  OS.EmitIntValue(MaxStackSize, 4);
378
205
  OS.EmitIntValue(FrameFuncStrTabOff, 4); // FrameFunc
379
205
  OS.emitAbsoluteSymbolDiff(FPO->PrologueEnd, Label, 2);
380
205
  OS.EmitIntValue(SavedRegSize, 2);
381
205
  OS.EmitIntValue(CurFlags, 4);
382
205
}
383
384
/// Compute and emit the real CodeView FrameData subsection.
385
82
bool X86WinCOFFTargetStreamer::emitFPOData(const MCSymbol *ProcSym, SMLoc L) {
386
82
  MCStreamer &OS = getStreamer();
387
82
  MCContext &Ctx = OS.getContext();
388
82
389
82
  auto I = AllFPOData.find(ProcSym);
390
82
  if (I == AllFPOData.end()) {
391
0
    Ctx.reportError(L, Twine("no FPO data found for symbol ") +
392
0
                           ProcSym->getName());
393
0
    return true;
394
0
  }
395
82
  const FPOData *FPO = I->second.get();
396
82
  assert(FPO->Begin && FPO->End && FPO->PrologueEnd && "missing FPO label");
397
82
398
82
  MCSymbol *FrameBegin = Ctx.createTempSymbol(),
399
82
           *FrameEnd = Ctx.createTempSymbol();
400
82
401
82
  OS.EmitIntValue(unsigned(DebugSubsectionKind::FrameData), 4);
402
82
  OS.emitAbsoluteSymbolDiff(FrameEnd, FrameBegin, 4);
403
82
  OS.EmitLabel(FrameBegin);
404
82
405
82
  // Start with the RVA of the function in question.
406
82
  OS.EmitValue(MCSymbolRefExpr::create(FPO->Function,
407
82
                                       MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx),
408
82
               4);
409
82
410
82
  // Emit a sequence of FrameData records.
411
82
  FPOStateMachine FSM(FPO);
412
82
413
82
  FSM.emitFrameDataRecord(OS, FPO->Begin);
414
149
  for (const FPOInstruction &Inst : FPO->Instructions) {
415
149
    switch (Inst.Op) {
416
149
    case FPOInstruction::PushReg:
417
73
      FSM.CurOffset += 4;
418
73
      FSM.SavedRegSize += 4;
419
73
      FSM.RegSaveOffsets.push_back({Inst.RegOrOffset, FSM.CurOffset});
420
73
      break;
421
149
    case FPOInstruction::SetFrame:
422
33
      FSM.FrameReg = Inst.RegOrOffset;
423
33
      FSM.FrameRegOff = FSM.CurOffset;
424
33
      break;
425
149
    case FPOInstruction::StackAlign:
426
5
      FSM.StackOffsetBeforeAlign = FSM.CurOffset;
427
5
      FSM.StackAlign = Inst.RegOrOffset;
428
5
      break;
429
149
    case FPOInstruction::StackAlloc:
430
38
      FSM.CurOffset += Inst.RegOrOffset;
431
38
      FSM.LocalSize += Inst.RegOrOffset;
432
38
      // No need to emit FrameData for stack allocations with a frame pointer.
433
38
      if (FSM.FrameReg)
434
26
        continue;
435
12
      break;
436
123
    }
437
123
    FSM.emitFrameDataRecord(OS, Inst.Label);
438
123
  }
439
82
440
82
  OS.EmitValueToAlignment(4, 0);
441
82
  OS.EmitLabel(FrameEnd);
442
82
  return false;
443
82
}
444
445
MCTargetStreamer *llvm::createX86AsmTargetStreamer(MCStreamer &S,
446
                                                   formatted_raw_ostream &OS,
447
                                                   MCInstPrinter *InstPrinter,
448
8.35k
                                                   bool IsVerboseAsm) {
449
8.35k
  // FIXME: This makes it so we textually assemble COFF directives on ELF.
450
8.35k
  // That's kind of nonsensical.
451
8.35k
  return new X86WinCOFFAsmTargetStreamer(S, OS, *InstPrinter);
452
8.35k
}
453
454
MCTargetStreamer *
455
6.93k
llvm::createX86ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
456
6.93k
  // No need to register a target streamer.
457
6.93k
  if (!STI.getTargetTriple().isOSBinFormatCOFF())
458
6.40k
    return nullptr;
459
531
  // Registers itself to the MCStreamer.
460
531
  return new X86WinCOFFTargetStreamer(S);
461
531
}