summaryrefslogtreecommitdiff
path: root/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/CodeGen/AsmPrinter/CodeViewDebug.cpp')
-rw-r--r--lib/CodeGen/AsmPrinter/CodeViewDebug.cpp539
1 files changed, 347 insertions, 192 deletions
diff --git a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index a81d56e9618b..1d0a003dc50a 100644
--- a/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "CodeViewDebug.h"
+#include "DwarfExpression.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
@@ -19,9 +20,9 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Triple.h"
@@ -34,9 +35,14 @@
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/CodeGen/TargetFrameLowering.h"
+#include "llvm/CodeGen/TargetLoweringObjectFile.h"
+#include "llvm/CodeGen/TargetRegisterInfo.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
#include "llvm/DebugInfo/CodeView/Line.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
@@ -61,17 +67,15 @@
#include "llvm/Support/BinaryByteStream.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/SMLoc.h"
-#include "llvm/Target/TargetFrameLowering.h"
-#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Target/TargetMachine.h"
-#include "llvm/Target/TargetRegisterInfo.h"
-#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
#include <cassert>
#include <cctype>
@@ -86,6 +90,9 @@
using namespace llvm;
using namespace llvm::codeview;
+static cl::opt<bool> EmitDebugGlobalHashes("emit-codeview-ghash-section",
+ cl::ReallyHidden, cl::init(false));
+
CodeViewDebug::CodeViewDebug(AsmPrinter *AP)
: DebugHandlerBase(AP), OS(*Asm->OutStreamer), TypeTable(Allocator) {
// If module doesn't have named metadata anchors or COFF debug section
@@ -153,12 +160,19 @@ StringRef CodeViewDebug::getFullFilepath(const DIFile *File) {
}
unsigned CodeViewDebug::maybeRecordFile(const DIFile *F) {
+ StringRef FullPath = getFullFilepath(F);
unsigned NextId = FileIdMap.size() + 1;
- auto Insertion = FileIdMap.insert(std::make_pair(F, NextId));
+ auto Insertion = FileIdMap.insert(std::make_pair(FullPath, NextId));
if (Insertion.second) {
// We have to compute the full filepath and emit a .cv_file directive.
- StringRef FullPath = getFullFilepath(F);
- bool Success = OS.EmitCVFileDirective(NextId, FullPath);
+ std::string Checksum = fromHex(F->getChecksum());
+ void *CKMem = OS.getContext().allocate(Checksum.size(), 1);
+ memcpy(CKMem, Checksum.data(), Checksum.size());
+ ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem),
+ Checksum.size());
+ DIFile::ChecksumKind ChecksumKind = F->getChecksumKind();
+ bool Success = OS.EmitCVFileDirective(NextId, FullPath, ChecksumAsBytes,
+ static_cast<unsigned>(ChecksumKind));
(void)Success;
assert(Success && ".cv_file directive failed");
}
@@ -270,7 +284,7 @@ TypeIndex CodeViewDebug::getScopeIndex(const DIScope *Scope) {
// Build the fully qualified name of the scope.
std::string ScopeName = getFullyQualifiedName(Scope);
StringIdRecord SID(TypeIndex(), ScopeName);
- auto TI = TypeTable.writeKnownType(SID);
+ auto TI = TypeTable.writeLeafType(SID);
return recordTypeIndexForDINode(Scope, TI);
}
@@ -295,12 +309,12 @@ TypeIndex CodeViewDebug::getFuncIdForSubprogram(const DISubprogram *SP) {
TypeIndex ClassType = getTypeIndex(Class);
MemberFuncIdRecord MFuncId(ClassType, getMemberFunctionType(SP, Class),
DisplayName);
- TI = TypeTable.writeKnownType(MFuncId);
+ TI = TypeTable.writeLeafType(MFuncId);
} else {
// Otherwise, this must be a free function.
TypeIndex ParentScope = getScopeIndex(Scope);
FuncIdRecord FuncId(ParentScope, getTypeIndex(SP->getType()), DisplayName);
- TI = TypeTable.writeKnownType(FuncId);
+ TI = TypeTable.writeLeafType(FuncId);
}
return recordTypeIndexForDINode(SP, TI);
@@ -324,8 +338,9 @@ TypeIndex CodeViewDebug::getMemberFunctionType(const DISubprogram *SP,
// function type, as the complete class type is likely to reference this
// member function type.
TypeLoweringScope S(*this);
- TypeIndex TI =
- lowerTypeMemberFunction(SP->getType(), Class, SP->getThisAdjustment());
+ const bool IsStaticMethod = (SP->getFlags() & DINode::FlagStaticMember) != 0;
+ TypeIndex TI = lowerTypeMemberFunction(
+ SP->getType(), Class, SP->getThisAdjustment(), IsStaticMethod);
return recordTypeIndexForDINode(SP, TI, Class);
}
@@ -476,10 +491,13 @@ void CodeViewDebug::endModule() {
OS.AddComment("String table");
OS.EmitCVStringTableDirective();
- // Emit type information last, so that any types we translate while emitting
- // function info are included.
+ // Emit type information and hashes last, so that any types we translate while
+ // emitting function info are included.
emitTypeInformation();
+ if (EmitDebugGlobalHashes)
+ emitTypeGlobalHashes();
+
clear();
}
@@ -496,11 +514,6 @@ static void emitNullTerminatedSymbolName(MCStreamer &OS, StringRef S) {
}
void CodeViewDebug::emitTypeInformation() {
- // Do nothing if we have no debug info or if no non-trivial types were emitted
- // to TypeTable during codegen.
- NamedMDNode *CU_Nodes = MMI->getModule()->getNamedMetadata("llvm.dbg.cu");
- if (!CU_Nodes)
- return;
if (TypeTable.empty())
return;
@@ -545,7 +558,39 @@ void CodeViewDebug::emitTypeInformation() {
}
}
-namespace {
+void CodeViewDebug::emitTypeGlobalHashes() {
+ if (TypeTable.empty())
+ return;
+
+ // Start the .debug$H section with the version and hash algorithm, currently
+ // hardcoded to version 0, SHA1.
+ OS.SwitchSection(Asm->getObjFileLowering().getCOFFGlobalTypeHashesSection());
+
+ OS.EmitValueToAlignment(4);
+ OS.AddComment("Magic");
+ OS.EmitIntValue(COFF::DEBUG_HASHES_SECTION_MAGIC, 4);
+ OS.AddComment("Section Version");
+ OS.EmitIntValue(0, 2);
+ OS.AddComment("Hash Algorithm");
+ OS.EmitIntValue(uint16_t(GlobalTypeHashAlg::SHA1), 2);
+
+ TypeIndex TI(TypeIndex::FirstNonSimpleIndex);
+ for (const auto &GHR : TypeTable.hashes()) {
+ if (OS.isVerboseAsm()) {
+ // Emit an EOL-comment describing which TypeIndex this hash corresponds
+ // to, as well as the stringified SHA1 hash.
+ SmallString<32> Comment;
+ raw_svector_ostream CommentOS(Comment);
+ CommentOS << formatv("{0:X+} [{1}]", TI.getIndex(), GHR);
+ OS.AddComment(Comment);
+ ++TI;
+ }
+ assert(GHR.Hash.size() % 20 == 0);
+ StringRef S(reinterpret_cast<const char *>(GHR.Hash.data()),
+ GHR.Hash.size());
+ OS.EmitBinaryData(S);
+ }
+}
static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
switch (DWLang) {
@@ -572,6 +617,8 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
return SourceLanguage::Cobol;
case dwarf::DW_LANG_Java:
return SourceLanguage::Java;
+ case dwarf::DW_LANG_D:
+ return SourceLanguage::D;
default:
// There's no CodeView representation for this language, and CV doesn't
// have an "unknown" option for the language field, so we'll use MASM,
@@ -580,9 +627,11 @@ static SourceLanguage MapDWLangToCVLang(unsigned DWLang) {
}
}
+namespace {
struct Version {
int Part[4];
};
+} // end anonymous namespace
// Takes a StringRef like "clang 4.0.0.0 (other nonsense 123)" and parses out
// the version number.
@@ -605,20 +654,19 @@ static Version parseVersion(StringRef Name) {
static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
switch (Type) {
- case Triple::ArchType::x86:
- return CPUType::Pentium3;
- case Triple::ArchType::x86_64:
- return CPUType::X64;
- case Triple::ArchType::thumb:
- return CPUType::Thumb;
- default:
- report_fatal_error("target architecture doesn't map to a CodeView "
- "CPUType");
+ case Triple::ArchType::x86:
+ return CPUType::Pentium3;
+ case Triple::ArchType::x86_64:
+ return CPUType::X64;
+ case Triple::ArchType::thumb:
+ return CPUType::Thumb;
+ case Triple::ArchType::aarch64:
+ return CPUType::ARM64;
+ default:
+ report_fatal_error("target architecture doesn't map to a CodeView CPUType");
}
}
-} // end anonymous namespace
-
void CodeViewDebug::emitCompilerInformation() {
MCContext &Context = MMI->getContext();
MCSymbol *CompilerBegin = Context.createTempSymbol(),
@@ -678,8 +726,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
OS.AddComment("Inlinee lines subsection");
MCSymbol *InlineEnd = beginCVSubsection(DebugSubsectionKind::InlineeLines);
- // We don't provide any extra file info.
- // FIXME: Find out if debuggers use this info.
+ // We emit the checksum info for files. This is used by debuggers to
+ // determine if a pdb matches the source before loading it. Visual Studio,
+ // for instance, will display a warning that the breakpoints are not valid if
+ // the pdb does not match the source.
OS.AddComment("Inlinee lines signature");
OS.EmitIntValue(unsigned(InlineeLinesSignature::Normal), 4);
@@ -692,13 +742,10 @@ void CodeViewDebug::emitInlineeLinesSubsection() {
OS.AddComment("Inlined function " + SP->getName() + " starts at " +
SP->getFilename() + Twine(':') + Twine(SP->getLine()));
OS.AddBlankLine();
- // The filechecksum table uses 8 byte entries for now, and file ids start at
- // 1.
- unsigned FileOffset = (FileId - 1) * 8;
OS.AddComment("Type index of inlined function");
OS.EmitIntValue(InlineeIdx.getIndex(), 4);
OS.AddComment("Offset into filechecksum table");
- OS.EmitIntValue(FileOffset, 4);
+ OS.EmitCVFileChecksumOffsetDirective(FileId);
OS.AddComment("Starting line number");
OS.EmitIntValue(SP->getLine(), 4);
}
@@ -799,6 +846,10 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
if (FuncName.empty())
FuncName = GlobalValue::dropLLVMManglingEscape(GV->getName());
+ // Emit FPO data, but only on 32-bit x86. No other platforms use it.
+ if (Triple(MMI->getModule()->getTargetTriple()).getArch() == Triple::x86)
+ OS.EmitCVFPOData(Fn);
+
// Emit a symbol subsection, required by VS2012+ to find function boundaries.
OS.AddComment("Symbol subsection for " + Twine(FuncName));
MCSymbol *SymbolsEnd = beginCVSubsection(DebugSubsectionKind::Symbols);
@@ -858,6 +909,30 @@ void CodeViewDebug::emitDebugInfoForFunction(const Function *GV,
emitInlinedCallSite(FI, InlinedAt, I->second);
}
+ for (auto Annot : FI.Annotations) {
+ MCSymbol *Label = Annot.first;
+ MDTuple *Strs = cast<MDTuple>(Annot.second);
+ MCSymbol *AnnotBegin = MMI->getContext().createTempSymbol(),
+ *AnnotEnd = MMI->getContext().createTempSymbol();
+ OS.AddComment("Record length");
+ OS.emitAbsoluteSymbolDiff(AnnotEnd, AnnotBegin, 2);
+ OS.EmitLabel(AnnotBegin);
+ OS.AddComment("Record kind: S_ANNOTATION");
+ OS.EmitIntValue(SymbolKind::S_ANNOTATION, 2);
+ OS.EmitCOFFSecRel32(Label, /*Offset=*/0);
+ // FIXME: Make sure we don't overflow the max record size.
+ OS.EmitCOFFSectionIndex(Label);
+ OS.EmitIntValue(Strs->getNumOperands(), 2);
+ for (Metadata *MD : Strs->operands()) {
+ // MDStrings are null terminated, so we can do EmitBytes and get the
+ // nice .asciz directive.
+ StringRef Str = cast<MDString>(MD)->getString();
+ assert(Str.data()[Str.size()] == '\0' && "non-nullterminated MDString");
+ OS.EmitBytes(StringRef(Str.data(), Str.size() + 1));
+ }
+ OS.EmitLabel(AnnotEnd);
+ }
+
if (SP != nullptr)
emitDebugInfoForUDTs(LocalUDTs);
@@ -947,13 +1022,110 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
}
}
+static bool canUseReferenceType(const DbgVariableLocation &Loc) {
+ return !Loc.LoadChain.empty() && Loc.LoadChain.back() == 0;
+}
+
+static bool needsReferenceType(const DbgVariableLocation &Loc) {
+ return Loc.LoadChain.size() == 2 && Loc.LoadChain.back() == 0;
+}
+
+void CodeViewDebug::calculateRanges(
+ LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) {
+ const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
+
+ // Calculate the definition ranges.
+ for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+ const InsnRange &Range = *I;
+ const MachineInstr *DVInst = Range.first;
+ assert(DVInst->isDebugValue() && "Invalid History entry");
+ // FIXME: Find a way to represent constant variables, since they are
+ // relatively common.
+ Optional<DbgVariableLocation> Location =
+ DbgVariableLocation::extractFromMachineInstruction(*DVInst);
+ if (!Location)
+ continue;
+
+ // CodeView can only express variables in register and variables in memory
+ // at a constant offset from a register. However, for variables passed
+ // indirectly by pointer, it is common for that pointer to be spilled to a
+ // stack location. For the special case of one offseted load followed by a
+ // zero offset load (a pointer spilled to the stack), we change the type of
+ // the local variable from a value type to a reference type. This tricks the
+ // debugger into doing the load for us.
+ if (Var.UseReferenceType) {
+ // We're using a reference type. Drop the last zero offset load.
+ if (canUseReferenceType(*Location))
+ Location->LoadChain.pop_back();
+ else
+ continue;
+ } else if (needsReferenceType(*Location)) {
+ // This location can't be expressed without switching to a reference type.
+ // Start over using that.
+ Var.UseReferenceType = true;
+ Var.DefRanges.clear();
+ calculateRanges(Var, Ranges);
+ return;
+ }
+
+ // We can only handle a register or an offseted load of a register.
+ if (Location->Register == 0 || Location->LoadChain.size() > 1)
+ continue;
+ {
+ LocalVarDefRange DR;
+ DR.CVRegister = TRI->getCodeViewRegNum(Location->Register);
+ DR.InMemory = !Location->LoadChain.empty();
+ DR.DataOffset =
+ !Location->LoadChain.empty() ? Location->LoadChain.back() : 0;
+ if (Location->FragmentInfo) {
+ DR.IsSubfield = true;
+ DR.StructOffset = Location->FragmentInfo->OffsetInBits / 8;
+ } else {
+ DR.IsSubfield = false;
+ DR.StructOffset = 0;
+ }
+
+ if (Var.DefRanges.empty() ||
+ Var.DefRanges.back().isDifferentLocation(DR)) {
+ Var.DefRanges.emplace_back(std::move(DR));
+ }
+ }
+
+ // Compute the label range.
+ const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
+ const MCSymbol *End = getLabelAfterInsn(Range.second);
+ if (!End) {
+ // This range is valid until the next overlapping bitpiece. In the
+ // common case, ranges will not be bitpieces, so they will overlap.
+ auto J = std::next(I);
+ const DIExpression *DIExpr = DVInst->getDebugExpression();
+ while (J != E &&
+ !fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
+ ++J;
+ if (J != E)
+ End = getLabelBeforeInsn(J->first);
+ else
+ End = Asm->getFunctionEnd();
+ }
+
+ // If the last range end is our begin, just extend the last range.
+ // Otherwise make a new range.
+ SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &R =
+ Var.DefRanges.back().Ranges;
+ if (!R.empty() && R.back().second == Begin)
+ R.back().second = End;
+ else
+ R.emplace_back(Begin, End);
+
+ // FIXME: Do more range combining.
+ }
+}
+
void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
DenseSet<InlinedVariable> Processed;
// Grab the variable info that was squirreled away in the MMI side-table.
collectVariableInfoFromMFTable(Processed);
- const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
-
for (const auto &I : DbgValues) {
InlinedVariable IV = I.first;
if (Processed.count(IV))
@@ -976,87 +1148,15 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
LocalVariable Var;
Var.DIVar = DIVar;
- // Calculate the definition ranges.
- for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
- const InsnRange &Range = *I;
- const MachineInstr *DVInst = Range.first;
- assert(DVInst->isDebugValue() && "Invalid History entry");
- const DIExpression *DIExpr = DVInst->getDebugExpression();
- bool IsSubfield = false;
- unsigned StructOffset = 0;
-
- // Handle fragments.
- auto Fragment = DIExpr->getFragmentInfo();
- if (Fragment) {
- IsSubfield = true;
- StructOffset = Fragment->OffsetInBits / 8;
- } else if (DIExpr->getNumElements() > 0) {
- continue; // Ignore unrecognized exprs.
- }
-
- // Bail if operand 0 is not a valid register. This means the variable is a
- // simple constant, or is described by a complex expression.
- // FIXME: Find a way to represent constant variables, since they are
- // relatively common.
- unsigned Reg =
- DVInst->getOperand(0).isReg() ? DVInst->getOperand(0).getReg() : 0;
- if (Reg == 0)
- continue;
-
- // Handle the two cases we can handle: indirect in memory and in register.
- unsigned CVReg = TRI->getCodeViewRegNum(Reg);
- bool InMemory = DVInst->getOperand(1).isImm();
- int Offset = InMemory ? DVInst->getOperand(1).getImm() : 0;
- {
- LocalVarDefRange DR;
- DR.CVRegister = CVReg;
- DR.InMemory = InMemory;
- DR.DataOffset = Offset;
- DR.IsSubfield = IsSubfield;
- DR.StructOffset = StructOffset;
-
- if (Var.DefRanges.empty() ||
- Var.DefRanges.back().isDifferentLocation(DR)) {
- Var.DefRanges.emplace_back(std::move(DR));
- }
- }
-
- // Compute the label range.
- const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
- const MCSymbol *End = getLabelAfterInsn(Range.second);
- if (!End) {
- // This range is valid until the next overlapping bitpiece. In the
- // common case, ranges will not be bitpieces, so they will overlap.
- auto J = std::next(I);
- while (J != E &&
- !fragmentsOverlap(DIExpr, J->first->getDebugExpression()))
- ++J;
- if (J != E)
- End = getLabelBeforeInsn(J->first);
- else
- End = Asm->getFunctionEnd();
- }
-
- // If the last range end is our begin, just extend the last range.
- // Otherwise make a new range.
- SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges =
- Var.DefRanges.back().Ranges;
- if (!Ranges.empty() && Ranges.back().second == Begin)
- Ranges.back().second = End;
- else
- Ranges.emplace_back(Begin, End);
-
- // FIXME: Do more range combining.
- }
-
+ calculateRanges(Var, Ranges);
recordLocalVariable(std::move(Var), InlinedAt);
}
}
void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
- const Function *GV = MF->getFunction();
- assert(FnDebugInfo.count(GV) == false);
- CurFn = &FnDebugInfo[GV];
+ const Function &GV = MF->getFunction();
+ assert(FnDebugInfo.count(&GV) == false);
+ CurFn = &FnDebugInfo[&GV];
CurFn->FuncId = NextFuncId++;
CurFn->Begin = Asm->getFunctionBegin();
@@ -1087,10 +1187,40 @@ void CodeViewDebug::beginFunctionImpl(const MachineFunction *MF) {
}
}
-void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) {
+static bool shouldEmitUdt(const DIType *T) {
+ if (!T)
+ return false;
+
+ // MSVC does not emit UDTs for typedefs that are scoped to classes.
+ if (T->getTag() == dwarf::DW_TAG_typedef) {
+ if (DIScope *Scope = T->getScope().resolve()) {
+ switch (Scope->getTag()) {
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_union_type:
+ return false;
+ }
+ }
+ }
+
+ while (true) {
+ if (!T || T->isForwardDecl())
+ return false;
+
+ const DIDerivedType *DT = dyn_cast<DIDerivedType>(T);
+ if (!DT)
+ return true;
+ T = DT->getBaseType().resolve();
+ }
+ return true;
+}
+
+void CodeViewDebug::addToUDTs(const DIType *Ty) {
// Don't record empty UDTs.
if (Ty->getName().empty())
return;
+ if (!shouldEmitUdt(Ty))
+ return;
SmallVector<StringRef, 5> QualifiedNameComponents;
const DISubprogram *ClosestSubprogram = getQualifiedNameComponents(
@@ -1099,10 +1229,11 @@ void CodeViewDebug::addToUDTs(const DIType *Ty, TypeIndex TI) {
std::string FullyQualifiedName =
getQualifiedName(QualifiedNameComponents, getPrettyScopeName(Ty));
- if (ClosestSubprogram == nullptr)
- GlobalUDTs.emplace_back(std::move(FullyQualifiedName), TI);
- else if (ClosestSubprogram == CurrentSubprogram)
- LocalUDTs.emplace_back(std::move(FullyQualifiedName), TI);
+ if (ClosestSubprogram == nullptr) {
+ GlobalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);
+ } else if (ClosestSubprogram == CurrentSubprogram) {
+ LocalUDTs.emplace_back(std::move(FullyQualifiedName), Ty);
+ }
// TODO: What if the ClosestSubprogram is neither null or the current
// subprogram? Currently, the UDT just gets dropped on the floor.
@@ -1139,7 +1270,8 @@ TypeIndex CodeViewDebug::lowerType(const DIType *Ty, const DIType *ClassTy) {
// The member function type of a member function pointer has no
// ThisAdjustment.
return lowerTypeMemberFunction(cast<DISubroutineType>(Ty), ClassTy,
- /*ThisAdjustment=*/0);
+ /*ThisAdjustment=*/0,
+ /*IsStaticMethod=*/false);
}
return lowerTypeFunction(cast<DISubroutineType>(Ty));
case dwarf::DW_TAG_enumeration_type:
@@ -1160,7 +1292,7 @@ TypeIndex CodeViewDebug::lowerTypeAlias(const DIDerivedType *Ty) {
TypeIndex UnderlyingTypeIndex = getTypeIndex(UnderlyingTypeRef);
StringRef TypeName = Ty->getName();
- addToUDTs(Ty, UnderlyingTypeIndex);
+ addToUDTs(Ty);
if (UnderlyingTypeIndex == TypeIndex(SimpleTypeKind::Int32Long) &&
TypeName == "HRESULT")
@@ -1193,11 +1325,12 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
"codeview doesn't support subranges with lower bounds");
int64_t Count = Subrange->getCount();
- // Variable Length Array (VLA) has Count equal to '-1'.
- // Replace with Count '1', assume it is the minimum VLA length.
- // FIXME: Make front-end support VLA subrange and emit LF_DIMVARLU.
+ // Forward declarations of arrays without a size and VLAs use a count of -1.
+ // Emit a count of zero in these cases to match what MSVC does for arrays
+ // without a size. MSVC doesn't support VLAs, so it's not clear what we
+ // should do for them even if we could distinguish them.
if (Count == -1)
- Count = 1;
+ Count = 0;
// Update the element size and element type index for subsequent subranges.
ElementSize *= Count;
@@ -1209,7 +1342,7 @@ TypeIndex CodeViewDebug::lowerTypeArray(const DICompositeType *Ty) {
StringRef Name = (i == 0) ? Ty->getName() : "";
ArrayRecord AR(ElementTypeIndex, IndexType, ArraySize, Name);
- ElementTypeIndex = TypeTable.writeKnownType(AR);
+ ElementTypeIndex = TypeTable.writeLeafType(AR);
}
return ElementTypeIndex;
@@ -1342,7 +1475,7 @@ TypeIndex CodeViewDebug::lowerTypePointer(const DIDerivedType *Ty) {
// do.
PointerOptions PO = PointerOptions::None;
PointerRecord PR(PointeeTI, PK, PM, PO, Ty->getSizeInBits() / 8);
- return TypeTable.writeKnownType(PR);
+ return TypeTable.writeLeafType(PR);
}
static PointerToMemberRepresentation
@@ -1393,7 +1526,7 @@ TypeIndex CodeViewDebug::lowerTypeMemberPointer(const DIDerivedType *Ty) {
MemberPointerInfo MPI(
ClassTI, translatePtrToMemberRep(SizeInBytes, IsPMF, Ty->getFlags()));
PointerRecord PR(PointeeTI, PK, PM, PO, SizeInBytes, MPI);
- return TypeTable.writeKnownType(PR);
+ return TypeTable.writeLeafType(PR);
}
/// Given a DWARF calling convention, get the CodeView equivalent. If we don't
@@ -1432,7 +1565,7 @@ TypeIndex CodeViewDebug::lowerTypeModifier(const DIDerivedType *Ty) {
}
TypeIndex ModifiedTI = getTypeIndex(BaseTy);
ModifierRecord MR(ModifiedTI, Mods);
- return TypeTable.writeKnownType(MR);
+ return TypeTable.writeLeafType(MR);
}
TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
@@ -1449,18 +1582,19 @@ TypeIndex CodeViewDebug::lowerTypeFunction(const DISubroutineType *Ty) {
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
- TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
+ TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
ProcedureRecord Procedure(ReturnTypeIndex, CC, FunctionOptions::None,
ArgTypeIndices.size(), ArgListIndex);
- return TypeTable.writeKnownType(Procedure);
+ return TypeTable.writeLeafType(Procedure);
}
TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
const DIType *ClassTy,
- int ThisAdjustment) {
+ int ThisAdjustment,
+ bool IsStaticMethod) {
// Lower the containing class type.
TypeIndex ClassType = getTypeIndex(ClassTy);
@@ -1475,26 +1609,22 @@ TypeIndex CodeViewDebug::lowerTypeMemberFunction(const DISubroutineType *Ty,
ReturnTypeIndex = ReturnAndArgTypesRef.front();
ArgTypeIndices = ReturnAndArgTypesRef.drop_front();
}
- TypeIndex ThisTypeIndex = TypeIndex::Void();
- if (!ArgTypeIndices.empty()) {
+ TypeIndex ThisTypeIndex;
+ if (!IsStaticMethod && !ArgTypeIndices.empty()) {
ThisTypeIndex = ArgTypeIndices.front();
ArgTypeIndices = ArgTypeIndices.drop_front();
}
ArgListRecord ArgListRec(TypeRecordKind::ArgList, ArgTypeIndices);
- TypeIndex ArgListIndex = TypeTable.writeKnownType(ArgListRec);
+ TypeIndex ArgListIndex = TypeTable.writeLeafType(ArgListRec);
CallingConvention CC = dwarfCCToCodeView(Ty->getCC());
- // TODO: Need to use the correct values for:
- // FunctionOptions
- // ThisPointerAdjustment.
+ // TODO: Need to use the correct values for FunctionOptions.
MemberFunctionRecord MFR(ReturnTypeIndex, ClassType, ThisTypeIndex, CC,
FunctionOptions::None, ArgTypeIndices.size(),
ArgListIndex, ThisAdjustment);
- TypeIndex TI = TypeTable.writeKnownType(MFR);
-
- return TI;
+ return TypeTable.writeLeafType(MFR);
}
TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
@@ -1503,7 +1633,7 @@ TypeIndex CodeViewDebug::lowerTypeVFTableShape(const DIDerivedType *Ty) {
SmallVector<VFTableSlotKind, 4> Slots(VSlotCount, VFTableSlotKind::Near);
VFTableShapeRecord VFTSR(Slots);
- return TypeTable.writeKnownType(VFTSR);
+ return TypeTable.writeLeafType(VFTSR);
}
static MemberAccess translateAccessFlags(unsigned RecordTag, unsigned Flags) {
@@ -1530,6 +1660,9 @@ static MethodOptions translateMethodOptionFlags(const DISubprogram *SP) {
static MethodKind translateMethodKindFlags(const DISubprogram *SP,
bool Introduced) {
+ if (SP->getFlags() & DINode::FlagStaticMember)
+ return MethodKind::Static;
+
switch (SP->getVirtuality()) {
case dwarf::DW_VIRTUALITY_none:
break;
@@ -1542,8 +1675,6 @@ static MethodKind translateMethodKindFlags(const DISubprogram *SP,
llvm_unreachable("unhandled virtuality case");
}
- // FIXME: Get Clang to mark DISubprogram as static and do something with it.
-
return MethodKind::Vanilla;
}
@@ -1593,9 +1724,8 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
if (Ty->isForwardDecl()) {
CO |= ClassOptions::ForwardReference;
} else {
- FieldListRecordBuilder FLRB(TypeTable);
-
- FLRB.begin();
+ ContinuationRecordBuilder ContinuationBuilder;
+ ContinuationBuilder.begin(ContinuationRecordKind::FieldList);
for (const DINode *Element : Ty->getElements()) {
// We assume that the frontend provides all members in source declaration
// order, which is what MSVC does.
@@ -1603,18 +1733,18 @@ TypeIndex CodeViewDebug::lowerTypeEnum(const DICompositeType *Ty) {
EnumeratorRecord ER(MemberAccess::Public,
APSInt::getUnsigned(Enumerator->getValue()),
Enumerator->getName());
- FLRB.writeMemberType(ER);
+ ContinuationBuilder.writeMemberType(ER);
EnumeratorCount++;
}
}
- FTI = FLRB.end(true);
+ FTI = TypeTable.insertRecord(ContinuationBuilder);
}
std::string FullName = getFullyQualifiedName(Ty);
EnumRecord ER(EnumeratorCount, CO, FTI, FullName, Ty->getIdentifier(),
getTypeIndex(Ty->getBaseType()));
- return TypeTable.writeKnownType(ER);
+ return TypeTable.writeLeafType(ER);
}
//===----------------------------------------------------------------------===//
@@ -1643,7 +1773,7 @@ struct llvm::ClassInfo {
TypeIndex VShapeTI;
- std::vector<const DICompositeType *> NestedClasses;
+ std::vector<const DIType *> NestedTypes;
};
void CodeViewDebug::clear() {
@@ -1694,12 +1824,14 @@ ClassInfo CodeViewDebug::collectClassInfo(const DICompositeType *Ty) {
} else if (DDTy->getTag() == dwarf::DW_TAG_pointer_type &&
DDTy->getName() == "__vtbl_ptr_type") {
Info.VShapeTI = getTypeIndex(DDTy);
+ } else if (DDTy->getTag() == dwarf::DW_TAG_typedef) {
+ Info.NestedTypes.push_back(DDTy);
} else if (DDTy->getTag() == dwarf::DW_TAG_friend) {
// Ignore friend members. It appears that MSVC emitted info about
// friends in the past, but modern versions do not.
}
} else if (auto *Composite = dyn_cast<DICompositeType>(Element)) {
- Info.NestedClasses.push_back(Composite);
+ Info.NestedTypes.push_back(Composite);
}
// Skip other unrecognized kinds of elements.
}
@@ -1715,7 +1847,7 @@ TypeIndex CodeViewDebug::lowerTypeClass(const DICompositeType *Ty) {
std::string FullName = getFullyQualifiedName(Ty);
ClassRecord CR(Kind, 0, CO, TypeIndex(), TypeIndex(), TypeIndex(), 0,
FullName, Ty->getIdentifier());
- TypeIndex FwdDeclTI = TypeTable.writeKnownType(CR);
+ TypeIndex FwdDeclTI = TypeTable.writeLeafType(CR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
@@ -1741,16 +1873,17 @@ TypeIndex CodeViewDebug::lowerCompleteTypeClass(const DICompositeType *Ty) {
ClassRecord CR(Kind, FieldCount, CO, FieldTI, TypeIndex(), VShapeTI,
SizeInBytes, FullName, Ty->getIdentifier());
- TypeIndex ClassTI = TypeTable.writeKnownType(CR);
+ TypeIndex ClassTI = TypeTable.writeLeafType(CR);
if (const auto *File = Ty->getFile()) {
StringIdRecord SIDR(TypeIndex(0x0), getFullFilepath(File));
- TypeIndex SIDI = TypeTable.writeKnownType(SIDR);
+ TypeIndex SIDI = TypeTable.writeLeafType(SIDR);
+
UdtSourceLineRecord USLR(ClassTI, SIDI, Ty->getLine());
- TypeTable.writeKnownType(USLR);
+ TypeTable.writeLeafType(USLR);
}
- addToUDTs(Ty, ClassTI);
+ addToUDTs(Ty);
return ClassTI;
}
@@ -1760,7 +1893,7 @@ TypeIndex CodeViewDebug::lowerTypeUnion(const DICompositeType *Ty) {
ClassOptions::ForwardReference | getCommonClassOptions(Ty);
std::string FullName = getFullyQualifiedName(Ty);
UnionRecord UR(0, CO, TypeIndex(), 0, FullName, Ty->getIdentifier());
- TypeIndex FwdDeclTI = TypeTable.writeKnownType(UR);
+ TypeIndex FwdDeclTI = TypeTable.writeLeafType(UR);
if (!Ty->isForwardDecl())
DeferredCompleteTypes.push_back(Ty);
return FwdDeclTI;
@@ -1782,14 +1915,15 @@ TypeIndex CodeViewDebug::lowerCompleteTypeUnion(const DICompositeType *Ty) {
UnionRecord UR(FieldCount, CO, FieldTI, SizeInBytes, FullName,
Ty->getIdentifier());
- TypeIndex UnionTI = TypeTable.writeKnownType(UR);
+ TypeIndex UnionTI = TypeTable.writeLeafType(UR);
StringIdRecord SIR(TypeIndex(0x0), getFullFilepath(Ty->getFile()));
- TypeIndex SIRI = TypeTable.writeKnownType(SIR);
+ TypeIndex SIRI = TypeTable.writeLeafType(SIR);
+
UdtSourceLineRecord USLR(UnionTI, SIRI, Ty->getLine());
- TypeTable.writeKnownType(USLR);
+ TypeTable.writeLeafType(USLR);
- addToUDTs(Ty, UnionTI);
+ addToUDTs(Ty);
return UnionTI;
}
@@ -1802,8 +1936,8 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
// list record.
unsigned MemberCount = 0;
ClassInfo Info = collectClassInfo(Ty);
- FieldListRecordBuilder FLBR(TypeTable);
- FLBR.begin();
+ ContinuationRecordBuilder ContinuationBuilder;
+ ContinuationBuilder.begin(ContinuationRecordKind::FieldList);
// Create base classes.
for (const DIDerivedType *I : Info.Inheritance) {
@@ -1821,14 +1955,14 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
getTypeIndex(I->getBaseType()), getVBPTypeIndex(), VBPtrOffset,
VBTableIndex);
- FLBR.writeMemberType(VBCR);
+ ContinuationBuilder.writeMemberType(VBCR);
} else {
assert(I->getOffsetInBits() % 8 == 0 &&
"bases must be on byte boundaries");
BaseClassRecord BCR(translateAccessFlags(Ty->getTag(), I->getFlags()),
getTypeIndex(I->getBaseType()),
I->getOffsetInBits() / 8);
- FLBR.writeMemberType(BCR);
+ ContinuationBuilder.writeMemberType(BCR);
}
}
@@ -1842,7 +1976,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
if (Member->isStaticMember()) {
StaticDataMemberRecord SDMR(Access, MemberBaseType, MemberName);
- FLBR.writeMemberType(SDMR);
+ ContinuationBuilder.writeMemberType(SDMR);
MemberCount++;
continue;
}
@@ -1851,7 +1985,7 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
if ((Member->getFlags() & DINode::FlagArtificial) &&
Member->getName().startswith("_vptr$")) {
VFPtrRecord VFPR(getTypeIndex(Member->getBaseType()));
- FLBR.writeMemberType(VFPR);
+ ContinuationBuilder.writeMemberType(VFPR);
MemberCount++;
continue;
}
@@ -1868,12 +2002,12 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
StartBitOffset -= MemberOffsetInBits;
BitFieldRecord BFR(MemberBaseType, Member->getSizeInBits(),
StartBitOffset);
- MemberBaseType = TypeTable.writeKnownType(BFR);
+ MemberBaseType = TypeTable.writeLeafType(BFR);
}
uint64_t MemberOffsetInBytes = MemberOffsetInBits / 8;
DataMemberRecord DMR(Access, MemberBaseType, MemberOffsetInBytes,
MemberName);
- FLBR.writeMemberType(DMR);
+ ContinuationBuilder.writeMemberType(DMR);
MemberCount++;
}
@@ -1898,40 +2032,42 @@ CodeViewDebug::lowerRecordFieldList(const DICompositeType *Ty) {
}
assert(!Methods.empty() && "Empty methods map entry");
if (Methods.size() == 1)
- FLBR.writeMemberType(Methods[0]);
+ ContinuationBuilder.writeMemberType(Methods[0]);
else {
+ // FIXME: Make this use its own ContinuationBuilder so that
+ // MethodOverloadList can be split correctly.
MethodOverloadListRecord MOLR(Methods);
- TypeIndex MethodList = TypeTable.writeKnownType(MOLR);
+ TypeIndex MethodList = TypeTable.writeLeafType(MOLR);
+
OverloadedMethodRecord OMR(Methods.size(), MethodList, Name);
- FLBR.writeMemberType(OMR);
+ ContinuationBuilder.writeMemberType(OMR);
}
}
// Create nested classes.
- for (const DICompositeType *Nested : Info.NestedClasses) {
+ for (const DIType *Nested : Info.NestedTypes) {
NestedTypeRecord R(getTypeIndex(DITypeRef(Nested)), Nested->getName());
- FLBR.writeMemberType(R);
+ ContinuationBuilder.writeMemberType(R);
MemberCount++;
}
- TypeIndex FieldTI = FLBR.end(true);
+ TypeIndex FieldTI = TypeTable.insertRecord(ContinuationBuilder);
return std::make_tuple(FieldTI, Info.VShapeTI, MemberCount,
- !Info.NestedClasses.empty());
+ !Info.NestedTypes.empty());
}
TypeIndex CodeViewDebug::getVBPTypeIndex() {
if (!VBPType.getIndex()) {
// Make a 'const int *' type.
ModifierRecord MR(TypeIndex::Int32(), ModifierOptions::Const);
- TypeIndex ModifiedTI = TypeTable.writeKnownType(MR);
+ TypeIndex ModifiedTI = TypeTable.writeLeafType(MR);
PointerKind PK = getPointerSizeInBytes() == 8 ? PointerKind::Near64
: PointerKind::Near32;
PointerMode PM = PointerMode::Pointer;
PointerOptions PO = PointerOptions::None;
PointerRecord PR(ModifiedTI, PK, PM, PO, getPointerSizeInBytes());
-
- VBPType = TypeTable.writeKnownType(PR);
+ VBPType = TypeTable.writeLeafType(PR);
}
return VBPType;
@@ -1957,6 +2093,16 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) {
return recordTypeIndexForDINode(Ty, TI, ClassTy);
}
+TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) {
+ DIType *Ty = TypeRef.resolve();
+ PointerRecord PR(getTypeIndex(Ty),
+ getPointerSizeInBytes() == 8 ? PointerKind::Near64
+ : PointerKind::Near32,
+ PointerMode::LValueReference, PointerOptions::None,
+ Ty->getSizeInBits() / 8);
+ return TypeTable.writeLeafType(PR);
+}
+
TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) {
const DIType *Ty = TypeRef.resolve();
@@ -2064,7 +2210,9 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
Flags |= LocalSymFlags::IsOptimizedOut;
OS.AddComment("TypeIndex");
- TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType());
+ TypeIndex TI = Var.UseReferenceType
+ ? getTypeIndexForReferenceTo(Var.DIVar->getType())
+ : getCompleteTypeIndex(Var.DIVar->getType());
OS.EmitIntValue(TI.getIndex(), 4);
OS.AddComment("Flags");
OS.EmitIntValue(static_cast<uint16_t>(Flags), 2);
@@ -2125,19 +2273,21 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
}
void CodeViewDebug::endFunctionImpl(const MachineFunction *MF) {
- const Function *GV = MF->getFunction();
- assert(FnDebugInfo.count(GV));
- assert(CurFn == &FnDebugInfo[GV]);
+ const Function &GV = MF->getFunction();
+ assert(FnDebugInfo.count(&GV));
+ assert(CurFn == &FnDebugInfo[&GV]);
- collectVariableInfo(GV->getSubprogram());
+ collectVariableInfo(GV.getSubprogram());
// Don't emit anything if we don't have any line tables.
if (!CurFn->HaveLineInfo) {
- FnDebugInfo.erase(GV);
+ FnDebugInfo.erase(&GV);
CurFn = nullptr;
return;
}
+ CurFn->Annotations = MF->getCodeViewAnnotations();
+
CurFn->End = Asm->getFunctionEnd();
CurFn = nullptr;
@@ -2156,6 +2306,8 @@ void CodeViewDebug::beginInstruction(const MachineInstr *MI) {
DebugLoc DL = MI->getDebugLoc();
if (!DL && MI->getParent() != PrevInstBB) {
for (const auto &NextMI : *MI->getParent()) {
+ if (NextMI.isDebugValue())
+ continue;
DL = NextMI.getDebugLoc();
if (DL)
break;
@@ -2187,8 +2339,11 @@ void CodeViewDebug::endCVSubsection(MCSymbol *EndLabel) {
}
void CodeViewDebug::emitDebugInfoForUDTs(
- ArrayRef<std::pair<std::string, TypeIndex>> UDTs) {
- for (const std::pair<std::string, codeview::TypeIndex> &UDT : UDTs) {
+ ArrayRef<std::pair<std::string, const DIType *>> UDTs) {
+ for (const auto &UDT : UDTs) {
+ const DIType *T = UDT.second;
+ assert(shouldEmitUdt(T));
+
MCSymbol *UDTRecordBegin = MMI->getContext().createTempSymbol(),
*UDTRecordEnd = MMI->getContext().createTempSymbol();
OS.AddComment("Record length");
@@ -2199,7 +2354,7 @@ void CodeViewDebug::emitDebugInfoForUDTs(
OS.EmitIntValue(unsigned(SymbolKind::S_UDT), 2);
OS.AddComment("Type");
- OS.EmitIntValue(UDT.second.getIndex(), 4);
+ OS.EmitIntValue(getCompleteTypeIndex(T).getIndex(), 4);
emitNullTerminatedSymbolName(OS, UDT.first);
OS.EmitLabel(UDTRecordEnd);