1 //===-- TypeTableBuilder.cpp ----------------------------------------------===// 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 "llvm/DebugInfo/CodeView/TypeTableBuilder.h" 11 #include "llvm/DebugInfo/CodeView/FieldListRecordBuilder.h" 12 #include "llvm/DebugInfo/CodeView/MethodListRecordBuilder.h" 13 #include "llvm/DebugInfo/CodeView/TypeIndex.h" 14 #include "llvm/DebugInfo/CodeView/TypeRecordBuilder.h" 15 #include "llvm/Support/raw_ostream.h" 16 17 using namespace llvm; 18 using namespace codeview; 19 TypeTableBuilder()20TypeTableBuilder::TypeTableBuilder() {} 21 ~TypeTableBuilder()22TypeTableBuilder::~TypeTableBuilder() {} 23 writeModifier(const ModifierRecord & Record)24TypeIndex TypeTableBuilder::writeModifier(const ModifierRecord &Record) { 25 TypeRecordBuilder Builder(Record.getKind()); 26 27 Builder.writeTypeIndex(Record.getModifiedType()); 28 Builder.writeUInt16(static_cast<uint16_t>(Record.getModifiers())); 29 30 return writeRecord(Builder); 31 } 32 writeProcedure(const ProcedureRecord & Record)33TypeIndex TypeTableBuilder::writeProcedure(const ProcedureRecord &Record) { 34 TypeRecordBuilder Builder(Record.getKind()); 35 36 Builder.writeTypeIndex(Record.getReturnType()); 37 Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); 38 Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); 39 Builder.writeUInt16(Record.getParameterCount()); 40 Builder.writeTypeIndex(Record.getArgumentList()); 41 42 return writeRecord(Builder); 43 } 44 45 TypeIndex writeMemberFunction(const MemberFunctionRecord & Record)46TypeTableBuilder::writeMemberFunction(const MemberFunctionRecord &Record) { 47 TypeRecordBuilder Builder(Record.getKind()); 48 49 Builder.writeTypeIndex(Record.getReturnType()); 50 Builder.writeTypeIndex(Record.getClassType()); 51 Builder.writeTypeIndex(Record.getThisType()); 52 Builder.writeUInt8(static_cast<uint8_t>(Record.getCallConv())); 53 Builder.writeUInt8(static_cast<uint8_t>(Record.getOptions())); 54 Builder.writeUInt16(Record.getParameterCount()); 55 Builder.writeTypeIndex(Record.getArgumentList()); 56 Builder.writeInt32(Record.getThisPointerAdjustment()); 57 58 return writeRecord(Builder); 59 } 60 writeArgList(const ArgListRecord & Record)61TypeIndex TypeTableBuilder::writeArgList(const ArgListRecord &Record) { 62 TypeRecordBuilder Builder(Record.getKind()); 63 64 Builder.writeUInt32(Record.getIndices().size()); 65 for (TypeIndex TI : Record.getIndices()) { 66 Builder.writeTypeIndex(TI); 67 } 68 69 return writeRecord(Builder); 70 } 71 writePointer(const PointerRecord & Record)72TypeIndex TypeTableBuilder::writePointer(const PointerRecord &Record) { 73 TypeRecordBuilder Builder(Record.getKind()); 74 75 Builder.writeTypeIndex(Record.getReferentType()); 76 uint32_t flags = static_cast<uint32_t>(Record.getOptions()) | 77 (Record.getSize() << PointerRecord::PointerSizeShift) | 78 (static_cast<uint32_t>(Record.getMode()) 79 << PointerRecord::PointerModeShift) | 80 (static_cast<uint32_t>(Record.getPointerKind()) 81 << PointerRecord::PointerKindShift); 82 Builder.writeUInt32(flags); 83 84 if (Record.isPointerToMember()) { 85 const MemberPointerInfo &M = Record.getMemberInfo(); 86 Builder.writeTypeIndex(M.getContainingType()); 87 Builder.writeUInt16(static_cast<uint16_t>(M.getRepresentation())); 88 } 89 90 return writeRecord(Builder); 91 } 92 writeArray(const ArrayRecord & Record)93TypeIndex TypeTableBuilder::writeArray(const ArrayRecord &Record) { 94 TypeRecordBuilder Builder(Record.getKind()); 95 96 Builder.writeTypeIndex(Record.getElementType()); 97 Builder.writeTypeIndex(Record.getIndexType()); 98 Builder.writeEncodedUnsignedInteger(Record.getSize()); 99 Builder.writeNullTerminatedString(Record.getName()); 100 101 return writeRecord(Builder); 102 } 103 writeClass(const ClassRecord & Record)104TypeIndex TypeTableBuilder::writeClass(const ClassRecord &Record) { 105 assert((Record.getKind() == TypeRecordKind::Struct) || 106 (Record.getKind() == TypeRecordKind::Class) || 107 (Record.getKind() == TypeRecordKind::Interface)); 108 109 TypeRecordBuilder Builder(Record.getKind()); 110 111 Builder.writeUInt16(Record.getMemberCount()); 112 uint16_t Flags = 113 static_cast<uint16_t>(Record.getOptions()) | 114 (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift) | 115 (static_cast<uint16_t>(Record.getWinRTKind()) 116 << ClassRecord::WinRTKindShift); 117 Builder.writeUInt16(Flags); 118 Builder.writeTypeIndex(Record.getFieldList()); 119 Builder.writeTypeIndex(Record.getDerivationList()); 120 Builder.writeTypeIndex(Record.getVTableShape()); 121 Builder.writeEncodedUnsignedInteger(Record.getSize()); 122 Builder.writeNullTerminatedString(Record.getName()); 123 if ((Record.getOptions() & ClassOptions::HasUniqueName) != 124 ClassOptions::None) { 125 Builder.writeNullTerminatedString(Record.getUniqueName()); 126 } 127 128 return writeRecord(Builder); 129 } 130 writeUnion(const UnionRecord & Record)131TypeIndex TypeTableBuilder::writeUnion(const UnionRecord &Record) { 132 TypeRecordBuilder Builder(TypeRecordKind::Union); 133 Builder.writeUInt16(Record.getMemberCount()); 134 uint16_t Flags = 135 static_cast<uint16_t>(Record.getOptions()) | 136 (static_cast<uint16_t>(Record.getHfa()) << ClassRecord::HfaKindShift); 137 Builder.writeUInt16(Flags); 138 Builder.writeTypeIndex(Record.getFieldList()); 139 Builder.writeEncodedUnsignedInteger(Record.getSize()); 140 Builder.writeNullTerminatedString(Record.getName()); 141 if ((Record.getOptions() & ClassOptions::HasUniqueName) != 142 ClassOptions::None) { 143 Builder.writeNullTerminatedString(Record.getUniqueName()); 144 } 145 return writeRecord(Builder); 146 } 147 writeEnum(const EnumRecord & Record)148TypeIndex TypeTableBuilder::writeEnum(const EnumRecord &Record) { 149 TypeRecordBuilder Builder(Record.getKind()); 150 151 Builder.writeUInt16(Record.getMemberCount()); 152 Builder.writeUInt16(static_cast<uint16_t>(Record.getOptions())); 153 Builder.writeTypeIndex(Record.getUnderlyingType()); 154 Builder.writeTypeIndex(Record.getFieldList()); 155 Builder.writeNullTerminatedString(Record.getName()); 156 if ((Record.getOptions() & ClassOptions::HasUniqueName) != 157 ClassOptions::None) { 158 Builder.writeNullTerminatedString(Record.getUniqueName()); 159 } 160 161 return writeRecord(Builder); 162 } 163 writeBitField(const BitFieldRecord & Record)164TypeIndex TypeTableBuilder::writeBitField(const BitFieldRecord &Record) { 165 TypeRecordBuilder Builder(Record.getKind()); 166 167 Builder.writeTypeIndex(Record.getType()); 168 Builder.writeUInt8(Record.getBitSize()); 169 Builder.writeUInt8(Record.getBitOffset()); 170 171 return writeRecord(Builder); 172 } 173 174 TypeIndex writeVFTableShape(const VFTableShapeRecord & Record)175TypeTableBuilder::writeVFTableShape(const VFTableShapeRecord &Record) { 176 TypeRecordBuilder Builder(Record.getKind()); 177 178 ArrayRef<VFTableSlotKind> Slots = Record.getSlots(); 179 180 Builder.writeUInt16(Slots.size()); 181 for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) { 182 uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4; 183 if ((SlotIndex + 1) < Slots.size()) { 184 Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]); 185 } 186 Builder.writeUInt8(Byte); 187 } 188 189 return writeRecord(Builder); 190 } 191 192 TypeIndex writeVFTable(const VFTableRecord & Record)193TypeTableBuilder::writeVFTable(const VFTableRecord &Record) { 194 TypeRecordBuilder Builder(Record.getKind()); 195 Builder.writeTypeIndex(Record.getCompleteClass()); 196 Builder.writeTypeIndex(Record.getOverriddenVTable()); 197 Builder.writeUInt32(Record.getVFPtrOffset()); 198 199 // Sum up the lengths of the null-terminated names. 200 size_t NamesLen = Record.getName().size() + 1; 201 for (StringRef MethodName : Record.getMethodNames()) 202 NamesLen += MethodName.size() + 1; 203 204 Builder.writeUInt32(NamesLen); 205 Builder.writeNullTerminatedString(Record.getName()); 206 for (StringRef MethodName : Record.getMethodNames()) 207 Builder.writeNullTerminatedString(MethodName); 208 209 return writeRecord(Builder); 210 } 211 writeStringId(const StringIdRecord & Record)212TypeIndex TypeTableBuilder::writeStringId(const StringIdRecord &Record) { 213 TypeRecordBuilder Builder(TypeRecordKind::StringId); 214 Builder.writeTypeIndex(Record.getId()); 215 Builder.writeNullTerminatedString(Record.getString()); 216 return writeRecord(Builder); 217 } 218 219 TypeIndex writeUdtSourceLine(const UdtSourceLineRecord & Record)220TypeTableBuilder::writeUdtSourceLine(const UdtSourceLineRecord &Record) { 221 TypeRecordBuilder Builder(Record.getKind()); 222 Builder.writeTypeIndex(Record.getUDT()); 223 Builder.writeTypeIndex(Record.getSourceFile()); 224 Builder.writeUInt32(Record.getLineNumber()); 225 return writeRecord(Builder); 226 } 227 228 TypeIndex writeUdtModSourceLine(const UdtModSourceLineRecord & Record)229TypeTableBuilder::writeUdtModSourceLine(const UdtModSourceLineRecord &Record) { 230 TypeRecordBuilder Builder(Record.getKind()); 231 Builder.writeTypeIndex(Record.getUDT()); 232 Builder.writeTypeIndex(Record.getSourceFile()); 233 Builder.writeUInt32(Record.getLineNumber()); 234 Builder.writeUInt16(Record.getModule()); 235 return writeRecord(Builder); 236 } 237 writeFuncId(const FuncIdRecord & Record)238TypeIndex TypeTableBuilder::writeFuncId(const FuncIdRecord &Record) { 239 TypeRecordBuilder Builder(Record.getKind()); 240 Builder.writeTypeIndex(Record.getParentScope()); 241 Builder.writeTypeIndex(Record.getFunctionType()); 242 Builder.writeNullTerminatedString(Record.getName()); 243 return writeRecord(Builder); 244 } 245 246 TypeIndex writeMemberFuncId(const MemberFuncIdRecord & Record)247TypeTableBuilder::writeMemberFuncId(const MemberFuncIdRecord &Record) { 248 TypeRecordBuilder Builder(Record.getKind()); 249 Builder.writeTypeIndex(Record.getClassType()); 250 Builder.writeTypeIndex(Record.getFunctionType()); 251 Builder.writeNullTerminatedString(Record.getName()); 252 return writeRecord(Builder); 253 } 254 255 TypeIndex writeBuildInfo(const BuildInfoRecord & Record)256TypeTableBuilder::writeBuildInfo(const BuildInfoRecord &Record) { 257 TypeRecordBuilder Builder(Record.getKind()); 258 assert(Record.getArgs().size() <= UINT16_MAX); 259 Builder.writeUInt16(Record.getArgs().size()); 260 for (TypeIndex Arg : Record.getArgs()) 261 Builder.writeTypeIndex(Arg); 262 return writeRecord(Builder); 263 } 264 writeRecord(TypeRecordBuilder & Builder)265TypeIndex TypeTableBuilder::writeRecord(TypeRecordBuilder &Builder) { 266 return writeRecord(Builder.str()); 267 } 268 writeFieldList(FieldListRecordBuilder & FieldList)269TypeIndex TypeTableBuilder::writeFieldList(FieldListRecordBuilder &FieldList) { 270 return FieldList.writeListRecord(*this); 271 } 272 writeMethodOverloadList(const MethodOverloadListRecord & Record)273TypeIndex TypeTableBuilder::writeMethodOverloadList( 274 const MethodOverloadListRecord &Record) { 275 TypeRecordBuilder Builder(Record.getKind()); 276 for (const OneMethodRecord &Method : Record.getMethods()) { 277 uint16_t Flags = static_cast<uint16_t>(Method.getAccess()); 278 Flags |= static_cast<uint16_t>(Method.getKind()) 279 << MemberAttributes::MethodKindShift; 280 Flags |= static_cast<uint16_t>(Method.getOptions()); 281 Builder.writeUInt16(Flags); 282 Builder.writeUInt16(0); // padding 283 Builder.writeTypeIndex(Method.getType()); 284 if (Method.isIntroducingVirtual()) { 285 assert(Method.getVFTableOffset() >= 0); 286 Builder.writeInt32(Method.getVFTableOffset()); 287 } else { 288 assert(Method.getVFTableOffset() == -1); 289 } 290 } 291 292 // TODO: Split the list into multiple records if it's longer than 64KB, using 293 // a subrecord of TypeRecordKind::Index to chain the records together. 294 return writeRecord(Builder); 295 } 296 writeTypeServer2(const TypeServer2Record & Record)297TypeIndex TypeTableBuilder::writeTypeServer2(const TypeServer2Record &Record) { 298 TypeRecordBuilder Builder(Record.getKind()); 299 Builder.writeGuid(Record.getGuid()); 300 Builder.writeUInt32(Record.getAge()); 301 Builder.writeNullTerminatedString(Record.getName()); 302 return writeRecord(Builder); 303 } 304