Skip to content

Commit 408b5e6

Browse files
committed
[MC] Add support for encoding CodeView variable definition ranges
CodeView, like most other debug formats, represents the live range of a variable so that debuggers might print them out. They use a variety of records to represent how a particular variable might be available (in a register, in a frame pointer, etc.) along with a set of ranges where this debug information is relevant. However, the format only allows us to use ranges which are limited to a maximum of 0xF000 in size. This means that we need to split our debug information into chunks of 0xF000. Because the layout of code is not known until *very* late, we must use a new fragment to record the information we need until we can know *exactly* what the range is. llvm-svn: 259868
1 parent adc2376 commit 408b5e6

16 files changed

+332
-13
lines changed

llvm/include/llvm/DebugInfo/CodeView/SymbolRecord.h

+2
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,8 @@ struct LocalVariableAddrGap {
123123
ulittle16_t Range;
124124
};
125125

126+
enum : uint16_t { MaxDefRange = 0xf000 };
127+
126128
// S_DEFRANGE
127129
struct DefRangeSym {
128130
ulittle32_t Program;

llvm/include/llvm/MC/MCAssembler.h

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ class MCAssembler {
191191
MCDwarfCallFrameFragment &DF);
192192
bool relaxCVInlineLineTable(MCAsmLayout &Layout,
193193
MCCVInlineLineTableFragment &DF);
194+
bool relaxCVDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &DF);
194195

195196
/// finishLayout - Finalize a layout, including fragment lowering.
196197
void finishLayout(MCAsmLayout &Layout);

llvm/include/llvm/MC/MCCodeView.h

+7
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ class CodeViewContext {
166166
void encodeInlineLineTable(MCAsmLayout &Layout,
167167
MCCVInlineLineTableFragment &F);
168168

169+
void
170+
emitDefRange(MCObjectStreamer &OS,
171+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
172+
StringRef FixedSizePortion);
173+
174+
void encodeDefRange(MCAsmLayout &Layout, MCCVDefRangeFragment &F);
175+
169176
/// Emits the string table substream.
170177
void emitStringTable(MCObjectStreamer &OS);
171178

llvm/include/llvm/MC/MCFragment.h

+35-4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class MCFragment : public ilist_node_with_parent<MCFragment, MCSection> {
4141
FT_LEB,
4242
FT_SafeSEH,
4343
FT_CVInlineLines,
44+
FT_CVDefRange,
4445
FT_Dummy
4546
};
4647

@@ -211,7 +212,8 @@ class MCEncodedFragmentWithFixups :
211212

212213
static bool classof(const MCFragment *F) {
213214
MCFragment::FragmentType Kind = F->getKind();
214-
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data;
215+
return Kind == MCFragment::FT_Relaxable || Kind == MCFragment::FT_Data ||
216+
Kind == MCFragment::FT_CVDefRange;
215217
}
216218
};
217219

@@ -509,9 +511,7 @@ class MCCVInlineLineTableFragment : public MCFragment {
509511
: MCFragment(FT_CVInlineLines, false, 0, Sec), SiteFuncId(SiteFuncId),
510512
StartFileId(StartFileId), StartLineNum(StartLineNum),
511513
FnStartSym(FnStartSym), FnEndSym(FnEndSym),
512-
SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {
513-
Contents.push_back(0);
514-
}
514+
SecondaryFuncs(SecondaryFuncs.begin(), SecondaryFuncs.end()) {}
515515

516516
/// \name Accessors
517517
/// @{
@@ -529,6 +529,37 @@ class MCCVInlineLineTableFragment : public MCFragment {
529529
}
530530
};
531531

532+
/// Fragment representing the .cv_def_range directive.
533+
class MCCVDefRangeFragment : public MCEncodedFragmentWithFixups<32, 4> {
534+
SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 2> Ranges;
535+
SmallString<32> FixedSizePortion;
536+
537+
/// CodeViewContext has the real knowledge about this format, so let it access
538+
/// our members.
539+
friend class CodeViewContext;
540+
541+
public:
542+
MCCVDefRangeFragment(
543+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
544+
StringRef FixedSizePortion, MCSection *Sec = nullptr)
545+
: MCEncodedFragmentWithFixups<32, 4>(FT_CVDefRange, false, Sec),
546+
Ranges(Ranges.begin(), Ranges.end()),
547+
FixedSizePortion(FixedSizePortion) {}
548+
549+
/// \name Accessors
550+
/// @{
551+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> getRanges() const {
552+
return Ranges;
553+
}
554+
555+
StringRef getFixedSizePortion() const { return FixedSizePortion; }
556+
/// @}
557+
558+
static bool classof(const MCFragment *F) {
559+
return F->getKind() == MCFragment::FT_CVDefRange;
560+
}
561+
};
562+
532563
} // end namespace llvm
533564

534565
#endif

llvm/include/llvm/MC/MCObjectStreamer.h

+3
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ class MCObjectStreamer : public MCStreamer {
131131
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
132132
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
133133
ArrayRef<unsigned> SecondaryFunctionIds) override;
134+
void EmitCVDefRangeDirective(
135+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
136+
StringRef FixedSizePortion) override;
134137
void EmitCVStringTableDirective() override;
135138
void EmitCVFileChecksumsDirective() override;
136139
void EmitGPRel32Value(const MCExpr *Value) override;

llvm/include/llvm/MC/MCStreamer.h

+6
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,12 @@ class MCStreamer {
662662
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
663663
ArrayRef<unsigned> SecondaryFunctionIds);
664664

665+
/// \brief This implements the CodeView '.cv_def_range' assembler
666+
/// directive.
667+
virtual void EmitCVDefRangeDirective(
668+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
669+
StringRef FixedSizePortion);
670+
665671
/// \brief This implements the CodeView '.cv_stringtable' assembler directive.
666672
virtual void EmitCVStringTableDirective() {}
667673

llvm/lib/MC/MCAsmStreamer.cpp

+19
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ class MCAsmStreamer final : public MCStreamer {
209209
unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
210210
const MCSymbol *FnStartSym, const MCSymbol *FnEndSym,
211211
ArrayRef<unsigned> SecondaryFunctionIds) override;
212+
void EmitCVDefRangeDirective(
213+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
214+
StringRef FixedSizePortion) override;
212215
void EmitCVStringTableDirective() override;
213216
void EmitCVFileChecksumsDirective() override;
214217

@@ -1038,6 +1041,22 @@ void MCAsmStreamer::EmitCVInlineLinetableDirective(
10381041
SecondaryFunctionIds);
10391042
}
10401043

1044+
void MCAsmStreamer::EmitCVDefRangeDirective(
1045+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
1046+
StringRef FixedSizePortion) {
1047+
OS << "\t.cv_def_range\t";
1048+
for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
1049+
OS << ' ';
1050+
Range.first->print(OS, MAI);
1051+
OS << ' ';
1052+
Range.second->print(OS, MAI);
1053+
}
1054+
OS << ", ";
1055+
PrintQuotedString(FixedSizePortion, OS);
1056+
EmitEOL();
1057+
this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion);
1058+
}
1059+
10411060
void MCAsmStreamer::EmitCVStringTableDirective() {
10421061
OS << "\t.cv_stringtable";
10431062
EmitEOL();

llvm/lib/MC/MCAssembler.cpp

+27-5
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout,
303303
return cast<MCDwarfCallFrameFragment>(F).getContents().size();
304304
case MCFragment::FT_CVInlineLines:
305305
return cast<MCCVInlineLineTableFragment>(F).getContents().size();
306+
case MCFragment::FT_CVDefRange:
307+
return cast<MCCVDefRangeFragment>(F).getContents().size();
306308
case MCFragment::FT_Dummy:
307309
llvm_unreachable("Should not have been added");
308310
}
@@ -545,6 +547,11 @@ static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout,
545547
OW->writeBytes(OF.getContents());
546548
break;
547549
}
550+
case MCFragment::FT_CVDefRange: {
551+
const auto &DRF = cast<MCCVDefRangeFragment>(F);
552+
OW->writeBytes(DRF.getContents());
553+
break;
554+
}
548555
case MCFragment::FT_Dummy:
549556
llvm_unreachable("Should not have been added");
550557
}
@@ -673,27 +680,32 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
673680
// Evaluate and apply the fixups, generating relocation entries as necessary.
674681
for (MCSection &Sec : *this) {
675682
for (MCFragment &Frag : Sec) {
676-
MCEncodedFragment *F = dyn_cast<MCEncodedFragment>(&Frag);
677683
// Data and relaxable fragments both have fixups. So only process
678684
// those here.
679685
// FIXME: Is there a better way to do this? MCEncodedFragmentWithFixups
680686
// being templated makes this tricky.
681-
if (!F || isa<MCCompactEncodedInstFragment>(F))
687+
if (isa<MCEncodedFragment>(&Frag) &&
688+
isa<MCCompactEncodedInstFragment>(&Frag))
689+
continue;
690+
if (!isa<MCEncodedFragment>(&Frag) && !isa<MCCVDefRangeFragment>(&Frag))
682691
continue;
683692
ArrayRef<MCFixup> Fixups;
684693
MutableArrayRef<char> Contents;
685-
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(F)) {
694+
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
695+
Fixups = FragWithFixups->getFixups();
696+
Contents = FragWithFixups->getContents();
697+
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
686698
Fixups = FragWithFixups->getFixups();
687699
Contents = FragWithFixups->getContents();
688-
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(F)) {
700+
} else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
689701
Fixups = FragWithFixups->getFixups();
690702
Contents = FragWithFixups->getContents();
691703
} else
692704
llvm_unreachable("Unknown fragment with fixups!");
693705
for (const MCFixup &Fixup : Fixups) {
694706
uint64_t FixedValue;
695707
bool IsPCRel;
696-
std::tie(FixedValue, IsPCRel) = handleFixup(Layout, *F, Fixup);
708+
std::tie(FixedValue, IsPCRel) = handleFixup(Layout, Frag, Fixup);
697709
getBackend().applyFixup(Fixup, Contents.data(),
698710
Contents.size(), FixedValue, IsPCRel);
699711
}
@@ -828,6 +840,13 @@ bool MCAssembler::relaxCVInlineLineTable(MCAsmLayout &Layout,
828840
return OldSize != F.getContents().size();
829841
}
830842

843+
bool MCAssembler::relaxCVDefRange(MCAsmLayout &Layout,
844+
MCCVDefRangeFragment &F) {
845+
unsigned OldSize = F.getContents().size();
846+
getContext().getCVContext().encodeDefRange(Layout, F);
847+
return OldSize != F.getContents().size();
848+
}
849+
831850
bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
832851
// Holds the first fragment which needed relaxing during this layout. It will
833852
// remain NULL if none were relaxed.
@@ -863,6 +882,9 @@ bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
863882
RelaxedFrag =
864883
relaxCVInlineLineTable(Layout, *cast<MCCVInlineLineTableFragment>(I));
865884
break;
885+
case MCFragment::FT_CVDefRange:
886+
RelaxedFrag = relaxCVDefRange(Layout, *cast<MCCVDefRangeFragment>(I));
887+
break;
866888
}
867889
if (RelaxedFrag && !FirstRelaxedFragment)
868890
FirstRelaxedFragment = &*I;

llvm/lib/MC/MCCodeView.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
2020
#include "llvm/MC/MCContext.h"
2121
#include "llvm/MC/MCObjectStreamer.h"
22+
#include "llvm/MC/MCValue.h"
2223
#include "llvm/Support/COFF.h"
2324

2425
using namespace llvm;
@@ -236,6 +237,16 @@ void CodeViewContext::emitInlineLineTableForFunction(
236237
SecondaryFunctionIds, OS.getCurrentSectionOnly());
237238
}
238239

240+
void CodeViewContext::emitDefRange(
241+
MCObjectStreamer &OS,
242+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
243+
StringRef FixedSizePortion) {
244+
// Create and insert a fragment into the current section that will be encoded
245+
// later.
246+
new MCCVDefRangeFragment(Ranges, FixedSizePortion,
247+
OS.getCurrentSectionOnly());
248+
}
249+
239250
static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin,
240251
const MCSymbol *End) {
241252
MCContext &Ctx = Layout.getAssembler().getContext();
@@ -352,6 +363,58 @@ void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
352363
compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
353364
}
354365

366+
void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
367+
MCCVDefRangeFragment &Frag) {
368+
MCContext &Ctx = Layout.getAssembler().getContext();
369+
SmallVectorImpl<char> &Contents = Frag.getContents();
370+
Contents.clear();
371+
SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
372+
Fixups.clear();
373+
raw_svector_ostream OS(Contents);
374+
375+
// Write down each range where the variable is defined.
376+
for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
377+
unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
378+
unsigned Bias = 0;
379+
// We must split the range into chunks of MaxDefRange, this is a fundamental
380+
// limitation of the file format.
381+
do {
382+
uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
383+
384+
const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Range.first, Ctx);
385+
const MCBinaryExpr *BE =
386+
MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
387+
MCValue Res;
388+
BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr);
389+
390+
// Each record begins with a 2-byte number indicating how large the record
391+
// is.
392+
StringRef FixedSizePortion = Frag.getFixedSizePortion();
393+
// Our record is a fixed sized prefix and a LocalVariableAddrRange that we
394+
// are artificially constructing.
395+
size_t RecordSize =
396+
FixedSizePortion.size() + sizeof(LocalVariableAddrRange);
397+
// Write out the recrod size.
398+
support::endian::Writer<support::little>(OS).write<uint16_t>(RecordSize);
399+
// Write out the fixed size prefix.
400+
OS << FixedSizePortion;
401+
// Make space for a fixup that will eventually have a section relative
402+
// relocation pointing at the offset where the variable becomes live.
403+
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
404+
Contents.resize(Contents.size() + 4); // Fixup for code start.
405+
// Make space for a fixup that will record the section index for the code.
406+
Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
407+
Contents.resize(Contents.size() + 2); // Fixup for section index.
408+
// Write down the range's extent.
409+
support::endian::Writer<support::little>(OS).write<uint16_t>(Chunk);
410+
411+
// Move on to the next range.
412+
Bias += Chunk;
413+
RangeSize -= Chunk;
414+
} while (RangeSize > 0);
415+
}
416+
}
417+
355418
//
356419
// This is called when an instruction is assembled into the specified section
357420
// and if there is information from the last .cv_loc directive that has yet to have

llvm/lib/MC/MCFragment.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,9 @@ void MCFragment::destroy() {
292292
case FT_CVInlineLines:
293293
delete cast<MCCVInlineLineTableFragment>(this);
294294
return;
295+
case FT_CVDefRange:
296+
delete cast<MCCVDefRangeFragment>(this);
297+
return;
295298
case FT_Dummy:
296299
delete cast<MCDummyFragment>(this);
297300
return;
@@ -331,6 +334,7 @@ LLVM_DUMP_METHOD void MCFragment::dump() {
331334
case MCFragment::FT_LEB: OS << "MCLEBFragment"; break;
332335
case MCFragment::FT_SafeSEH: OS << "MCSafeSEHFragment"; break;
333336
case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break;
337+
case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break;
334338
case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break;
335339
}
336340

@@ -435,6 +439,16 @@ LLVM_DUMP_METHOD void MCFragment::dump() {
435439
OS << " Sym:" << *F->getFnStartSym();
436440
break;
437441
}
442+
case MCFragment::FT_CVDefRange: {
443+
const auto *F = cast<MCCVDefRangeFragment>(this);
444+
OS << "\n ";
445+
for (std::pair<const MCSymbol *, const MCSymbol *> RangeStartEnd :
446+
F->getRanges()) {
447+
OS << " RangeStart:" << RangeStartEnd.first;
448+
OS << " RangeEnd:" << RangeStartEnd.second;
449+
}
450+
break;
451+
}
438452
case MCFragment::FT_Dummy:
439453
break;
440454
}

llvm/lib/MC/MCObjectStreamer.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,13 @@ void MCObjectStreamer::EmitCVInlineLinetableDirective(
396396
SecondaryFunctionIds);
397397
}
398398

399+
void MCObjectStreamer::EmitCVDefRangeDirective(
400+
ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
401+
StringRef FixedSizePortion) {
402+
getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion);
403+
this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion);
404+
}
405+
399406
void MCObjectStreamer::EmitCVStringTableDirective() {
400407
getContext().getCVContext().emitStringTable(*this);
401408
}

0 commit comments

Comments
 (0)