[NativePDB] Add support for S_CONSTANT records.
clang-cl does not emit these, but MSVC does, so we need to be able to
handle them.
Because clang-cl does not generate them, it was a bit hard to write a
test. So what I had to do was get an PDB file with some S_CONSTANT
records in using cl and link, dump it using llvm-pdbutil dump -globals
-sym-data to get the bytes of the records, generate the same object file
using clang-cl but with -S to emit an assembly file, and replace all the
S_LDATA32 records with the bytes of the S_CONSTANT records. This way, we
can compile the file using llvm-mc and link it with lld-link.
Differential Revision: https://reviews.llvm.org/D54452
llvm-svn: 346787
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 7224cbd..174c0c4 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -253,6 +253,29 @@
}
}
+static bool IsSimpleTypeSignedInteger(SimpleTypeKind kind) {
+ switch (kind) {
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::Float128:
+ case SimpleTypeKind::Float80:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ case SimpleTypeKind::SByte:
+ return true;
+ default:
+ return false;
+ }
+}
+
static size_t GetTypeSizeForSimpleKind(SimpleTypeKind kind) {
switch (kind) {
case SimpleTypeKind::Boolean128:
@@ -303,6 +326,35 @@
}
}
+std::pair<size_t, bool> GetIntegralTypeInfo(TypeIndex ti, TpiStream &tpi) {
+ if (ti.isSimple()) {
+ SimpleTypeKind stk = ti.getSimpleKind();
+ return {GetTypeSizeForSimpleKind(stk), IsSimpleTypeSignedInteger(stk)};
+ }
+
+ CVType cvt = tpi.getType(ti);
+ switch (cvt.kind()) {
+ case LF_MODIFIER: {
+ ModifierRecord mfr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<ModifierRecord>(cvt, mfr));
+ return GetIntegralTypeInfo(mfr.ModifiedType, tpi);
+ }
+ case LF_POINTER: {
+ PointerRecord pr;
+ llvm::cantFail(TypeDeserializer::deserializeAs<PointerRecord>(cvt, pr));
+ return GetIntegralTypeInfo(pr.ReferentType, tpi);
+ }
+ case LF_ENUM: {
+ EnumRecord er;
+ llvm::cantFail(TypeDeserializer::deserializeAs<EnumRecord>(cvt, er));
+ return GetIntegralTypeInfo(er.UnderlyingType, tpi);
+ }
+ default:
+ assert(false && "Type is not integral!");
+ return {0, false};
+ }
+}
+
static llvm::StringRef GetSimpleTypeName(SimpleTypeKind kind) {
switch (kind) {
case SimpleTypeKind::Boolean128:
@@ -557,10 +609,15 @@
if (Record.Type.isSimple())
return llvm::None;
+ CVType cvt = tpi.getType(Record.Type);
+
+ if (!IsTagRecord(cvt))
+ return llvm::None;
+
// If it's an inner definition, then treat whatever name we have here as a
// single component of a mangled name. So we can inject it into the parent's
// mangled name to see if it matches.
- CVTagRecord child = CVTagRecord::create(tpi.getType(Record.Type));
+ CVTagRecord child = CVTagRecord::create(cvt);
std::string qname = parent.asTag().getUniqueName();
if (qname.size() < 4 || child.asTag().getUniqueName().size() < 4)
return llvm::None;
@@ -971,15 +1028,17 @@
lldb::TypeSP SymbolFileNativePDB::CreateTagType(PdbSymUid type_uid,
const EnumRecord &er) {
- llvm::StringRef name = DropNameScope(er.getName());
-
- clang::DeclContext *decl_context = m_clang->GetTranslationUnitDecl();
+ const PdbTypeSymId &tid = type_uid.asTypeSym();
+ TypeIndex ti(tid.index);
+ clang::DeclContext *decl_context = nullptr;
+ std::string uname;
+ std::tie(decl_context, uname) = CreateDeclInfoForType(er, ti);
Declaration decl;
TypeSP underlying_type = GetOrCreateType(er.UnderlyingType);
CompilerType enum_ct = m_clang->CreateEnumerationType(
- name.str().c_str(), decl_context, decl,
- underlying_type->GetFullCompilerType(), er.isScoped());
+ uname.c_str(), decl_context, decl, underlying_type->GetFullCompilerType(),
+ er.isScoped());
ClangASTContext::StartTagDeclarationDefinition(enum_ct);
ClangASTContext::SetHasExternalStorage(enum_ct.GetOpaqueQualType(), true);
@@ -987,7 +1046,7 @@
// We're just going to forward resolve this for now. We'll complete
// it only if the user requests.
return std::make_shared<lldb_private::Type>(
- type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(name),
+ type_uid.toOpaqueId(), m_clang->GetSymbolFile(), ConstString(uname),
underlying_type->GetByteSize(), nullptr, LLDB_INVALID_UID,
lldb_private::Type::eEncodingIsUID, decl, enum_ct,
lldb_private::Type::eResolveStateForward);
@@ -1184,6 +1243,39 @@
return CreateAndCacheType(type_uid);
}
+static DWARFExpression
+MakeConstantLocationExpression(TypeIndex underlying_ti, TpiStream &tpi,
+ const ConstantSym &constant, ModuleSP module) {
+ const ArchSpec &architecture = module->GetArchitecture();
+ uint32_t address_size = architecture.GetAddressByteSize();
+
+ size_t size = 0;
+ bool is_signed = false;
+ std::tie(size, is_signed) = GetIntegralTypeInfo(underlying_ti, tpi);
+
+ union {
+ llvm::support::little64_t I;
+ llvm::support::ulittle64_t U;
+ } Value;
+
+ std::shared_ptr<DataBufferHeap> buffer = std::make_shared<DataBufferHeap>();
+ buffer->SetByteSize(size);
+
+ llvm::ArrayRef<uint8_t> bytes;
+ if (is_signed) {
+ Value.I = constant.Value.getSExtValue();
+ } else {
+ Value.U = constant.Value.getZExtValue();
+ }
+
+ bytes = llvm::makeArrayRef(reinterpret_cast<const uint8_t *>(&Value), 8)
+ .take_front(size);
+ buffer->CopyData(bytes.data(), size);
+ DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
+ DWARFExpression result(nullptr, extractor, nullptr, 0, size);
+ return result;
+}
+
static DWARFExpression MakeGlobalLocationExpression(uint16_t section,
uint32_t offset,
ModuleSP module) {
@@ -1227,6 +1319,9 @@
const PdbCuSymId &cu_sym = var_uid.asCuSym();
lldbassert(cu_sym.global);
CVSymbol sym = m_index->symrecords().readRecord(cu_sym.offset);
+ if (sym.kind() == S_CONSTANT)
+ return CreateConstantSymbol(var_uid, sym);
+
lldb::ValueType scope = eValueTypeInvalid;
TypeIndex ti;
llvm::StringRef name;
@@ -1298,6 +1393,34 @@
return var_sp;
}
+lldb::VariableSP
+SymbolFileNativePDB::CreateConstantSymbol(PdbSymUid var_uid,
+ const CVSymbol &cvs) {
+ TpiStream &tpi = m_index->tpi();
+ ConstantSym constant(cvs.kind());
+
+ llvm::cantFail(SymbolDeserializer::deserializeAs<ConstantSym>(cvs, constant));
+ std::string global_name("::");
+ global_name += constant.Name;
+ PDB_SymType pdbst = GetPdbSymType(tpi, constant.Type);
+ PdbSymUid tuid = PdbSymUid::makeTypeSymId(pdbst, constant.Type, false);
+ SymbolFileTypeSP type_sp =
+ std::make_shared<SymbolFileType>(*this, tuid.toOpaqueId());
+
+ Declaration decl;
+ Variable::RangeList ranges;
+ ModuleSP module = GetObjectFile()->GetModule();
+ DWARFExpression location =
+ MakeConstantLocationExpression(constant.Type, tpi, constant, module);
+
+ VariableSP var_sp = std::make_shared<Variable>(
+ var_uid.toOpaqueId(), constant.Name.str().c_str(), global_name.c_str(),
+ type_sp, eValueTypeVariableGlobal, module.get(), ranges, &decl, location,
+ false, false, false);
+ var_sp->SetLocationIsConstantValueData(true);
+ return var_sp;
+}
+
VariableSP SymbolFileNativePDB::GetOrCreateGlobalVariable(PdbSymUid var_uid) {
lldbassert(var_uid.isGlobalVariable());
@@ -1587,7 +1710,8 @@
case SymbolKind::S_GDATA32:
case SymbolKind::S_LDATA32:
case SymbolKind::S_GTHREAD32:
- case SymbolKind::S_LTHREAD32: {
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_CONSTANT: {
PdbSymUid uid = PdbSymUid::makeGlobalVariableUid(result.first);
var = GetOrCreateGlobalVariable(uid);
variables.AddVariable(var);