| 1 | //===-- LVCodeViewReader.cpp ----------------------------------------------===// |
| 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 | // This implements the LVCodeViewReader class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h" |
| 14 | #include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h" |
| 15 | #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h" |
| 16 | #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" |
| 17 | #include "llvm/DebugInfo/CodeView/SymbolDeserializer.h" |
| 18 | #include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h" |
| 19 | #include "llvm/DebugInfo/LogicalView/Core/LVLine.h" |
| 20 | #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" |
| 21 | #include "llvm/DebugInfo/PDB/Native/DbiStream.h" |
| 22 | #include "llvm/DebugInfo/PDB/Native/GlobalsStream.h" |
| 23 | #include "llvm/DebugInfo/PDB/Native/InfoStream.h" |
| 24 | #include "llvm/DebugInfo/PDB/Native/LinePrinter.h" |
| 25 | #include "llvm/DebugInfo/PDB/Native/PDBFile.h" |
| 26 | #include "llvm/DebugInfo/PDB/Native/RawConstants.h" |
| 27 | #include "llvm/DebugInfo/PDB/Native/SymbolStream.h" |
| 28 | #include "llvm/DebugInfo/PDB/Native/TpiStream.h" |
| 29 | #include "llvm/Object/COFF.h" |
| 30 | #include "llvm/Support/Errc.h" |
| 31 | #include "llvm/Support/Error.h" |
| 32 | #include "llvm/Support/FormatAdapters.h" |
| 33 | #include "llvm/Support/FormatVariadic.h" |
| 34 | #include "llvm/Support/WithColor.h" |
| 35 | |
| 36 | using namespace llvm; |
| 37 | using namespace llvm::codeview; |
| 38 | using namespace llvm::logicalview; |
| 39 | using namespace llvm::msf; |
| 40 | using namespace llvm::object; |
| 41 | using namespace llvm::pdb; |
| 42 | |
| 43 | #define DEBUG_TYPE "CodeViewReader" |
| 44 | |
| 45 | StringRef LVCodeViewReader::getSymbolKindName(SymbolKind Kind) { |
| 46 | switch (Kind) { |
| 47 | #define SYMBOL_RECORD(EnumName, EnumVal, Name) \ |
| 48 | case EnumName: \ |
| 49 | return #EnumName; |
| 50 | #include "llvm/DebugInfo/CodeView/CodeViewSymbols.def" |
| 51 | default: |
| 52 | return "UnknownSym" ; |
| 53 | } |
| 54 | llvm_unreachable("Unknown SymbolKind::Kind" ); |
| 55 | } |
| 56 | |
| 57 | std::string LVCodeViewReader::formatRegisterId(RegisterId Register, |
| 58 | CPUType CPU) { |
| 59 | #define RETURN_CASE(Enum, X, Ret) \ |
| 60 | case Enum::X: \ |
| 61 | return Ret; |
| 62 | |
| 63 | if (CPU == CPUType::ARMNT) { |
| 64 | switch (Register) { |
| 65 | #define CV_REGISTERS_ARM |
| 66 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
| 67 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
| 68 | #undef CV_REGISTER |
| 69 | #undef CV_REGISTERS_ARM |
| 70 | |
| 71 | default: |
| 72 | break; |
| 73 | } |
| 74 | } else if (CPU == CPUType::ARM64) { |
| 75 | switch (Register) { |
| 76 | #define CV_REGISTERS_ARM64 |
| 77 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
| 78 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
| 79 | #undef CV_REGISTER |
| 80 | #undef CV_REGISTERS_ARM64 |
| 81 | |
| 82 | default: |
| 83 | break; |
| 84 | } |
| 85 | } else { |
| 86 | switch (Register) { |
| 87 | #define CV_REGISTERS_X86 |
| 88 | #define CV_REGISTER(name, val) RETURN_CASE(RegisterId, name, #name) |
| 89 | #include "llvm/DebugInfo/CodeView/CodeViewRegisters.def" |
| 90 | #undef CV_REGISTER |
| 91 | #undef CV_REGISTERS_X86 |
| 92 | |
| 93 | default: |
| 94 | break; |
| 95 | } |
| 96 | } |
| 97 | return "formatUnknownEnum(Id)" ; |
| 98 | } |
| 99 | |
| 100 | void LVCodeViewReader::printRelocatedField(StringRef Label, |
| 101 | const coff_section *CoffSection, |
| 102 | uint32_t RelocOffset, |
| 103 | uint32_t Offset, |
| 104 | StringRef *RelocSym) { |
| 105 | StringRef SymStorage; |
| 106 | StringRef &Symbol = RelocSym ? *RelocSym : SymStorage; |
| 107 | if (!resolveSymbolName(CoffSection, Offset: RelocOffset, Name&: Symbol)) |
| 108 | W.printSymbolOffset(Label, Symbol, Value: Offset); |
| 109 | else |
| 110 | W.printHex(Label, Value: RelocOffset); |
| 111 | } |
| 112 | |
| 113 | void LVCodeViewReader::getLinkageName(const coff_section *CoffSection, |
| 114 | uint32_t RelocOffset, uint32_t Offset, |
| 115 | StringRef *RelocSym) { |
| 116 | StringRef SymStorage; |
| 117 | StringRef &Symbol = RelocSym ? *RelocSym : SymStorage; |
| 118 | if (resolveSymbolName(CoffSection, Offset: RelocOffset, Name&: Symbol)) |
| 119 | Symbol = "" ; |
| 120 | } |
| 121 | |
| 122 | Expected<StringRef> |
| 123 | LVCodeViewReader::getFileNameForFileOffset(uint32_t FileOffset, |
| 124 | const SymbolGroup *SG) { |
| 125 | if (SG) { |
| 126 | Expected<StringRef> Filename = SG->getNameFromChecksums(Offset: FileOffset); |
| 127 | if (!Filename) { |
| 128 | consumeError(Err: Filename.takeError()); |
| 129 | return StringRef("" ); |
| 130 | } |
| 131 | return *Filename; |
| 132 | } |
| 133 | |
| 134 | // The file checksum subsection should precede all references to it. |
| 135 | if (!CVFileChecksumTable.valid() || !CVStringTable.valid()) |
| 136 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 137 | |
| 138 | VarStreamArray<FileChecksumEntry>::Iterator Iter = |
| 139 | CVFileChecksumTable.getArray().at(Offset: FileOffset); |
| 140 | |
| 141 | // Check if the file checksum table offset is valid. |
| 142 | if (Iter == CVFileChecksumTable.end()) |
| 143 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 144 | |
| 145 | Expected<StringRef> NameOrErr = CVStringTable.getString(Offset: Iter->FileNameOffset); |
| 146 | if (!NameOrErr) |
| 147 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 148 | return *NameOrErr; |
| 149 | } |
| 150 | |
| 151 | Error LVCodeViewReader::printFileNameForOffset(StringRef Label, |
| 152 | uint32_t FileOffset, |
| 153 | const SymbolGroup *SG) { |
| 154 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG); |
| 155 | if (!NameOrErr) |
| 156 | return NameOrErr.takeError(); |
| 157 | W.printHex(Label, Str: *NameOrErr, Value: FileOffset); |
| 158 | return Error::success(); |
| 159 | } |
| 160 | |
| 161 | void LVCodeViewReader::cacheRelocations() { |
| 162 | for (const SectionRef &Section : getObj().sections()) { |
| 163 | const coff_section *CoffSection = getObj().getCOFFSection(Section); |
| 164 | |
| 165 | auto &RM = RelocMap[CoffSection]; |
| 166 | llvm::append_range(C&: RM, R: Section.relocations()); |
| 167 | |
| 168 | // Sort relocations by address. |
| 169 | llvm::sort(C&: RM, Comp: [](RelocationRef L, RelocationRef R) { |
| 170 | return L.getOffset() < R.getOffset(); |
| 171 | }); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | // Given a section and an offset into this section the function returns the |
| 176 | // symbol used for the relocation at the offset. |
| 177 | Error LVCodeViewReader::resolveSymbol(const coff_section *CoffSection, |
| 178 | uint64_t Offset, SymbolRef &Sym) { |
| 179 | const auto &Relocations = RelocMap[CoffSection]; |
| 180 | basic_symbol_iterator SymI = getObj().symbol_end(); |
| 181 | for (const RelocationRef &Relocation : Relocations) { |
| 182 | uint64_t RelocationOffset = Relocation.getOffset(); |
| 183 | |
| 184 | if (RelocationOffset == Offset) { |
| 185 | SymI = Relocation.getSymbol(); |
| 186 | break; |
| 187 | } |
| 188 | } |
| 189 | if (SymI == getObj().symbol_end()) |
| 190 | return make_error<StringError>(Args: "Unknown Symbol" , Args: inconvertibleErrorCode()); |
| 191 | Sym = *SymI; |
| 192 | return ErrorSuccess(); |
| 193 | } |
| 194 | |
| 195 | // Given a section and an offset into this section the function returns the |
| 196 | // name of the symbol used for the relocation at the offset. |
| 197 | Error LVCodeViewReader::resolveSymbolName(const coff_section *CoffSection, |
| 198 | uint64_t Offset, StringRef &Name) { |
| 199 | SymbolRef Symbol; |
| 200 | if (Error E = resolveSymbol(CoffSection, Offset, Sym&: Symbol)) |
| 201 | return E; |
| 202 | Expected<StringRef> NameOrErr = Symbol.getName(); |
| 203 | if (!NameOrErr) |
| 204 | return NameOrErr.takeError(); |
| 205 | Name = *NameOrErr; |
| 206 | return ErrorSuccess(); |
| 207 | } |
| 208 | |
| 209 | // CodeView and DWARF can have references to compiler generated elements, |
| 210 | // used for initialization. The MSVC includes in the PDBs, internal compile |
| 211 | // units, associated with the MS runtime support. We mark them as 'system' |
| 212 | // and they are printed only if the command line option 'internal=system'. |
| 213 | bool LVCodeViewReader::isSystemEntry(LVElement *Element, StringRef Name) const { |
| 214 | Name = Name.empty() ? Element->getName() : Name; |
| 215 | auto Find = [=](const char *String) -> bool { return Name.contains(Other: String); }; |
| 216 | auto Starts = [=](const char *Pattern) -> bool { |
| 217 | return Name.starts_with(Prefix: Pattern); |
| 218 | }; |
| 219 | auto CheckExclude = [&]() -> bool { |
| 220 | if (Starts("__" ) || Starts("_PMD" ) || Starts("_PMFN" )) |
| 221 | return true; |
| 222 | if (Find("_s__" )) |
| 223 | return true; |
| 224 | if (Find("_CatchableType" ) || Find("_TypeDescriptor" )) |
| 225 | return true; |
| 226 | if (Find("Intermediate\\vctools" )) |
| 227 | return true; |
| 228 | if (Find("$initializer$" ) || Find("dynamic initializer" )) |
| 229 | return true; |
| 230 | if (Find("`vftable'" ) || Find("_GLOBAL__sub" )) |
| 231 | return true; |
| 232 | return false; |
| 233 | }; |
| 234 | bool Excluded = CheckExclude(); |
| 235 | if (Excluded) |
| 236 | Element->setIsSystem(); |
| 237 | |
| 238 | return Excluded; |
| 239 | } |
| 240 | |
| 241 | Error LVCodeViewReader::collectInlineeInfo( |
| 242 | DebugInlineeLinesSubsectionRef &Lines, const llvm::pdb::SymbolGroup *SG) { |
| 243 | for (const InlineeSourceLine &Line : Lines) { |
| 244 | TypeIndex TIInlinee = Line.Header->Inlinee; |
| 245 | uint32_t LineNumber = Line.Header->SourceLineNum; |
| 246 | uint32_t FileOffset = Line.Header->FileID; |
| 247 | LLVM_DEBUG({ |
| 248 | DictScope S(W, "InlineeSourceLine" ); |
| 249 | LogicalVisitor.printTypeIndex("Inlinee" , TIInlinee, StreamTPI); |
| 250 | if (Error Err = printFileNameForOffset("FileID" , FileOffset, SG)) |
| 251 | return Err; |
| 252 | W.printNumber("SourceLineNum" , LineNumber); |
| 253 | |
| 254 | if (Lines.hasExtraFiles()) { |
| 255 | W.printNumber("ExtraFileCount" , Line.ExtraFiles.size()); |
| 256 | ListScope ExtraFiles(W, "ExtraFiles" ); |
| 257 | for (const ulittle32_t &FID : Line.ExtraFiles) |
| 258 | if (Error Err = printFileNameForOffset("FileID" , FID, SG)) |
| 259 | return Err; |
| 260 | } |
| 261 | }); |
| 262 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset, SG); |
| 263 | if (!NameOrErr) |
| 264 | return NameOrErr.takeError(); |
| 265 | LogicalVisitor.addInlineeInfo(TI: TIInlinee, LineNumber, Filename: *NameOrErr); |
| 266 | } |
| 267 | |
| 268 | return Error::success(); |
| 269 | } |
| 270 | |
| 271 | Error LVCodeViewReader::traverseInlineeLines(StringRef Subsection) { |
| 272 | BinaryStreamReader SR(Subsection, llvm::endianness::little); |
| 273 | DebugInlineeLinesSubsectionRef Lines; |
| 274 | if (Error E = Lines.initialize(Reader: SR)) |
| 275 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 276 | |
| 277 | return collectInlineeInfo(Lines); |
| 278 | } |
| 279 | |
| 280 | Error LVCodeViewReader::createLines( |
| 281 | const FixedStreamArray<LineNumberEntry> &LineNumbers, LVAddress Addendum, |
| 282 | uint32_t Segment, uint32_t Begin, uint32_t Size, uint32_t NameIndex, |
| 283 | const SymbolGroup *SG) { |
| 284 | LLVM_DEBUG({ |
| 285 | uint32_t End = Begin + Size; |
| 286 | W.getOStream() << formatv("{0:x-4}:{1:x-8}-{2:x-8}\n" , Segment, Begin, End); |
| 287 | }); |
| 288 | |
| 289 | for (const LineNumberEntry &Line : LineNumbers) { |
| 290 | if (Line.Offset >= Size) |
| 291 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 292 | |
| 293 | LineInfo LI(Line.Flags); |
| 294 | |
| 295 | LLVM_DEBUG({ |
| 296 | W.getOStream() << formatv( |
| 297 | "{0} {1:x-8}\n" , utostr(LI.getStartLine()), |
| 298 | fmt_align(Begin + Line.Offset, AlignStyle::Right, 8, '0')); |
| 299 | }); |
| 300 | |
| 301 | // The 'processLines()' function will move each created logical line |
| 302 | // to its enclosing logical scope, using the debug ranges information |
| 303 | // and they will be released when its scope parent is deleted. |
| 304 | LVLineDebug *LineDebug = createLineDebug(); |
| 305 | CULines.push_back(Elt: LineDebug); |
| 306 | LVAddress Address = linearAddress(Segment, Offset: Begin + Line.Offset); |
| 307 | LineDebug->setAddress(Address + Addendum); |
| 308 | |
| 309 | if (LI.isAlwaysStepInto()) |
| 310 | LineDebug->setIsAlwaysStepInto(); |
| 311 | else if (LI.isNeverStepInto()) |
| 312 | LineDebug->setIsNeverStepInto(); |
| 313 | else |
| 314 | LineDebug->setLineNumber(LI.getStartLine()); |
| 315 | |
| 316 | if (LI.isStatement()) |
| 317 | LineDebug->setIsNewStatement(); |
| 318 | |
| 319 | Expected<StringRef> NameOrErr = getFileNameForFileOffset(FileOffset: NameIndex, SG); |
| 320 | if (!NameOrErr) |
| 321 | return NameOrErr.takeError(); |
| 322 | LineDebug->setFilename(*NameOrErr); |
| 323 | } |
| 324 | |
| 325 | return Error::success(); |
| 326 | } |
| 327 | |
| 328 | Error LVCodeViewReader::initializeFileAndStringTables( |
| 329 | BinaryStreamReader &Reader) { |
| 330 | while (Reader.bytesRemaining() > 0 && |
| 331 | (!CVFileChecksumTable.valid() || !CVStringTable.valid())) { |
| 332 | // The section consists of a number of subsection in the following format: |
| 333 | // |SubSectionType|SubSectionSize|Contents...| |
| 334 | uint32_t SubType, SubSectionSize; |
| 335 | |
| 336 | if (Error E = Reader.readInteger(Dest&: SubType)) |
| 337 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 338 | if (Error E = Reader.readInteger(Dest&: SubSectionSize)) |
| 339 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 340 | |
| 341 | StringRef Contents; |
| 342 | if (Error E = Reader.readFixedString(Dest&: Contents, Length: SubSectionSize)) |
| 343 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 344 | |
| 345 | BinaryStreamRef ST(Contents, llvm::endianness::little); |
| 346 | switch (DebugSubsectionKind(SubType)) { |
| 347 | case DebugSubsectionKind::FileChecksums: |
| 348 | if (Error E = CVFileChecksumTable.initialize(Stream: ST)) |
| 349 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 350 | break; |
| 351 | case DebugSubsectionKind::StringTable: |
| 352 | if (Error E = CVStringTable.initialize(Contents: ST)) |
| 353 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 354 | break; |
| 355 | default: |
| 356 | break; |
| 357 | } |
| 358 | |
| 359 | uint32_t PaddedSize = alignTo(Value: SubSectionSize, Align: 4); |
| 360 | if (Error E = Reader.skip(Amount: PaddedSize - SubSectionSize)) |
| 361 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 362 | } |
| 363 | |
| 364 | return Error::success(); |
| 365 | } |
| 366 | |
| 367 | Error LVCodeViewReader::loadTypeServer(TypeServer2Record &TS) { |
| 368 | LLVM_DEBUG({ |
| 369 | W.printString("Guid" , formatv("{0}" , TS.getGuid()).str()); |
| 370 | W.printNumber("Age" , TS.getAge()); |
| 371 | W.printString("Name" , TS.getName()); |
| 372 | }); |
| 373 | |
| 374 | SmallString<128> ServerName(TS.getName()); |
| 375 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
| 376 | if (BuffOrErr.getError()) { |
| 377 | // The server name does not exist. Try in the same directory as the |
| 378 | // input file. |
| 379 | ServerName = createAlternativePath(From: ServerName); |
| 380 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
| 381 | if (BuffOrErr.getError()) { |
| 382 | // For the error message, use the original type server name. |
| 383 | return createStringError(EC: errc::bad_file_descriptor, |
| 384 | Fmt: "File '%s' does not exist." , |
| 385 | Vals: TS.getName().str().c_str()); |
| 386 | } |
| 387 | } |
| 388 | MemBuffer = std::move(BuffOrErr.get()); |
| 389 | |
| 390 | // Check if the buffer corresponds to a PDB file. |
| 391 | assert(identify_magic((*MemBuffer).getBuffer()) == file_magic::pdb && |
| 392 | "Invalid PDB file." ); |
| 393 | |
| 394 | if (Error Err = loadDataForPDB(Type: PDB_ReaderType::Native, Path: ServerName, Session)) |
| 395 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), Fmt: "%s" , |
| 396 | Vals: ServerName.c_str()); |
| 397 | |
| 398 | PdbSession.reset(p: static_cast<NativeSession *>(Session.release())); |
| 399 | PDBFile &Pdb = PdbSession->getPDBFile(); |
| 400 | |
| 401 | // Just because a file with a matching name was found and it was an actual |
| 402 | // PDB file doesn't mean it matches. For it to match the InfoStream's GUID |
| 403 | // must match the GUID specified in the TypeServer2 record. |
| 404 | Expected<InfoStream &> expectedInfo = Pdb.getPDBInfoStream(); |
| 405 | if (!expectedInfo || expectedInfo->getGuid() != TS.getGuid()) |
| 406 | return createStringError(EC: errc::invalid_argument, S: "signature_out_of_date" ); |
| 407 | |
| 408 | // The reader needs to switch to a type server, to process the types from |
| 409 | // the server. We need to keep the original input source, as reading other |
| 410 | // sections will require the input associated with the loaded object file. |
| 411 | TypeServer = std::make_shared<InputFile>(args: &Pdb); |
| 412 | LogicalVisitor.setInput(TypeServer); |
| 413 | |
| 414 | LazyRandomTypeCollection &Types = types(); |
| 415 | LazyRandomTypeCollection &Ids = ids(); |
| 416 | if (Error Err = traverseTypes(Pdb, Types, Ids)) |
| 417 | return Err; |
| 418 | |
| 419 | return Error::success(); |
| 420 | } |
| 421 | |
| 422 | Error LVCodeViewReader::loadPrecompiledObject(PrecompRecord &Precomp, |
| 423 | CVTypeArray &CVTypesObj) { |
| 424 | LLVM_DEBUG({ |
| 425 | W.printHex("Count" , Precomp.getTypesCount()); |
| 426 | W.printHex("Signature" , Precomp.getSignature()); |
| 427 | W.printString("PrecompFile" , Precomp.getPrecompFilePath()); |
| 428 | }); |
| 429 | |
| 430 | SmallString<128> ServerName(Precomp.getPrecompFilePath()); |
| 431 | BuffOrErr = MemoryBuffer::getFile(Filename: ServerName); |
| 432 | if (BuffOrErr.getError()) { |
| 433 | // The server name does not exist. Try in the directory as the input file. |
| 434 | ServerName = createAlternativePath(From: ServerName); |
| 435 | if (BuffOrErr.getError()) { |
| 436 | // For the error message, use the original type server name. |
| 437 | return createStringError(EC: errc::bad_file_descriptor, |
| 438 | Fmt: "File '%s' does not exist." , |
| 439 | Vals: Precomp.getPrecompFilePath().str().c_str()); |
| 440 | } |
| 441 | } |
| 442 | MemBuffer = std::move(BuffOrErr.get()); |
| 443 | |
| 444 | Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Source: *MemBuffer); |
| 445 | if (errorToErrorCode(Err: BinOrErr.takeError())) |
| 446 | return createStringError(EC: errc::not_supported, |
| 447 | Fmt: "Binary object format in '%s' is not supported." , |
| 448 | Vals: ServerName.c_str()); |
| 449 | |
| 450 | Binary &BinaryObj = *BinOrErr.get(); |
| 451 | if (!BinaryObj.isCOFF()) |
| 452 | return createStringError(EC: errc::not_supported, Fmt: "'%s' is not a COFF object." , |
| 453 | Vals: ServerName.c_str()); |
| 454 | |
| 455 | Builder = std::make_unique<AppendingTypeTableBuilder>(args&: BuilderAllocator); |
| 456 | |
| 457 | // The MSVC precompiled header object file, should contain just a single |
| 458 | // ".debug$P" section. |
| 459 | COFFObjectFile &Obj = *cast<COFFObjectFile>(Val: &BinaryObj); |
| 460 | for (const SectionRef &Section : Obj.sections()) { |
| 461 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
| 462 | if (!SectionNameOrErr) |
| 463 | return SectionNameOrErr.takeError(); |
| 464 | if (*SectionNameOrErr == ".debug$P" ) { |
| 465 | Expected<StringRef> DataOrErr = Section.getContents(); |
| 466 | if (!DataOrErr) |
| 467 | return DataOrErr.takeError(); |
| 468 | uint32_t Magic; |
| 469 | if (Error Err = consume(Data&: *DataOrErr, Item&: Magic)) |
| 470 | return Err; |
| 471 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
| 472 | return errorCodeToError(EC: object_error::parse_failed); |
| 473 | |
| 474 | ReaderPrecomp = std::make_unique<BinaryStreamReader>( |
| 475 | args&: *DataOrErr, args: llvm::endianness::little); |
| 476 | cantFail( |
| 477 | Err: ReaderPrecomp->readArray(Array&: CVTypesPrecomp, Size: ReaderPrecomp->getLength())); |
| 478 | |
| 479 | // Append all the type records up to the LF_ENDPRECOMP marker and |
| 480 | // check if the signatures match. |
| 481 | for (const CVType &Type : CVTypesPrecomp) { |
| 482 | ArrayRef<uint8_t> TypeData = Type.data(); |
| 483 | if (Type.kind() == LF_ENDPRECOMP) { |
| 484 | EndPrecompRecord EndPrecomp = cantFail( |
| 485 | ValOrErr: TypeDeserializer::deserializeAs<EndPrecompRecord>(Data: TypeData)); |
| 486 | if (Precomp.getSignature() != EndPrecomp.getSignature()) |
| 487 | return createStringError(EC: errc::invalid_argument, S: "no matching pch" ); |
| 488 | break; |
| 489 | } |
| 490 | Builder->insertRecordBytes(Record&: TypeData); |
| 491 | } |
| 492 | // Done processing .debug$P, break out of section loop. |
| 493 | break; |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | // Append all the type records, skipping the first record which is the |
| 498 | // reference to the precompiled header object information. |
| 499 | for (const CVType &Type : CVTypesObj) { |
| 500 | ArrayRef<uint8_t> TypeData = Type.data(); |
| 501 | if (Type.kind() != LF_PRECOMP) |
| 502 | Builder->insertRecordBytes(Record&: TypeData); |
| 503 | } |
| 504 | |
| 505 | // Set up a type stream that refers to the added type records. |
| 506 | Builder->ForEachRecord( |
| 507 | Func: [&](TypeIndex TI, const CVType &Type) { TypeArray.push_back(x: Type); }); |
| 508 | |
| 509 | ItemStream = |
| 510 | std::make_unique<BinaryItemStream<CVType>>(args: llvm::endianness::little); |
| 511 | ItemStream->setItems(TypeArray); |
| 512 | TypeStream.setUnderlyingStream(NewStream: *ItemStream); |
| 513 | |
| 514 | PrecompHeader = |
| 515 | std::make_shared<LazyRandomTypeCollection>(args&: TypeStream, args: TypeArray.size()); |
| 516 | |
| 517 | // Change the original input source to use the collected type records. |
| 518 | LogicalVisitor.setInput(PrecompHeader); |
| 519 | |
| 520 | LazyRandomTypeCollection &Types = types(); |
| 521 | LazyRandomTypeCollection &Ids = ids(); |
| 522 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI, |
| 523 | LogicalVisitor.getShared()); |
| 524 | return visitTypeStream(Types, Callbacks&: TDV); |
| 525 | } |
| 526 | |
| 527 | Error LVCodeViewReader::traverseTypeSection(StringRef SectionName, |
| 528 | const SectionRef &Section) { |
| 529 | LLVM_DEBUG({ |
| 530 | ListScope D(W, "CodeViewTypes" ); |
| 531 | W.printNumber("Section" , SectionName, getObj().getSectionID(Section)); |
| 532 | }); |
| 533 | |
| 534 | Expected<StringRef> DataOrErr = Section.getContents(); |
| 535 | if (!DataOrErr) |
| 536 | return DataOrErr.takeError(); |
| 537 | uint32_t Magic; |
| 538 | if (Error Err = consume(Data&: *DataOrErr, Item&: Magic)) |
| 539 | return Err; |
| 540 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
| 541 | return errorCodeToError(EC: object_error::parse_failed); |
| 542 | |
| 543 | // Get the first type record. It will indicate if this object uses a type |
| 544 | // server (/Zi) or a PCH file (/Yu). |
| 545 | CVTypeArray CVTypes; |
| 546 | BinaryStreamReader Reader(*DataOrErr, llvm::endianness::little); |
| 547 | cantFail(Err: Reader.readArray(Array&: CVTypes, Size: Reader.getLength())); |
| 548 | CVTypeArray::Iterator FirstType = CVTypes.begin(); |
| 549 | |
| 550 | // The object was compiled with /Zi. It uses types from a type server PDB. |
| 551 | if (FirstType->kind() == LF_TYPESERVER2) { |
| 552 | TypeServer2Record TS = cantFail( |
| 553 | ValOrErr: TypeDeserializer::deserializeAs<TypeServer2Record>(Data: FirstType->data())); |
| 554 | return loadTypeServer(TS); |
| 555 | } |
| 556 | |
| 557 | // The object was compiled with /Yc or /Yu. It uses types from another |
| 558 | // object file with a matching signature. |
| 559 | if (FirstType->kind() == LF_PRECOMP) { |
| 560 | PrecompRecord Precomp = cantFail( |
| 561 | ValOrErr: TypeDeserializer::deserializeAs<PrecompRecord>(Data: FirstType->data())); |
| 562 | return loadPrecompiledObject(Precomp, CVTypesObj&: CVTypes); |
| 563 | } |
| 564 | |
| 565 | LazyRandomTypeCollection &Types = types(); |
| 566 | LazyRandomTypeCollection &Ids = ids(); |
| 567 | Types.reset(Data: *DataOrErr, RecordCountHint: 100); |
| 568 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamTPI, |
| 569 | LogicalVisitor.getShared()); |
| 570 | return visitTypeStream(Types, Callbacks&: TDV); |
| 571 | } |
| 572 | |
| 573 | Error LVCodeViewReader::traverseTypes(PDBFile &Pdb, |
| 574 | LazyRandomTypeCollection &Types, |
| 575 | LazyRandomTypeCollection &Ids) { |
| 576 | // Traverse types (TPI and IPI). |
| 577 | auto VisitTypes = [&](LazyRandomTypeCollection &Types, |
| 578 | LazyRandomTypeCollection &Ids, |
| 579 | SpecialStream StreamIdx) -> Error { |
| 580 | LVTypeVisitor TDV(W, &LogicalVisitor, Types, Ids, StreamIdx, |
| 581 | LogicalVisitor.getShared()); |
| 582 | return visitTypeStream(Types, Callbacks&: TDV); |
| 583 | }; |
| 584 | |
| 585 | Expected<TpiStream &> StreamTpiOrErr = Pdb.getPDBTpiStream(); |
| 586 | if (!StreamTpiOrErr) |
| 587 | return StreamTpiOrErr.takeError(); |
| 588 | TpiStream &StreamTpi = *StreamTpiOrErr; |
| 589 | StreamTpi.buildHashMap(); |
| 590 | LLVM_DEBUG({ |
| 591 | W.getOStream() << formatv("Showing {0:N} TPI records\n" , |
| 592 | StreamTpi.getNumTypeRecords()); |
| 593 | }); |
| 594 | if (Error Err = VisitTypes(Types, Ids, StreamTPI)) |
| 595 | return Err; |
| 596 | |
| 597 | Expected<TpiStream &> StreamIpiOrErr = Pdb.getPDBIpiStream(); |
| 598 | if (!StreamIpiOrErr) |
| 599 | return StreamIpiOrErr.takeError(); |
| 600 | TpiStream &StreamIpi = *StreamIpiOrErr; |
| 601 | StreamIpi.buildHashMap(); |
| 602 | LLVM_DEBUG({ |
| 603 | W.getOStream() << formatv("Showing {0:N} IPI records\n" , |
| 604 | StreamIpi.getNumTypeRecords()); |
| 605 | }); |
| 606 | return VisitTypes(Ids, Ids, StreamIPI); |
| 607 | } |
| 608 | |
| 609 | Error LVCodeViewReader::traverseSymbolsSubsection(StringRef Subsection, |
| 610 | const SectionRef &Section, |
| 611 | StringRef SectionContents) { |
| 612 | ArrayRef<uint8_t> BinaryData(Subsection.bytes_begin(), |
| 613 | Subsection.bytes_end()); |
| 614 | LVSymbolVisitorDelegate VisitorDelegate(this, Section, &getObj(), |
| 615 | SectionContents); |
| 616 | CVSymbolArray Symbols; |
| 617 | BinaryStreamReader Reader(BinaryData, llvm::endianness::little); |
| 618 | if (Error E = Reader.readArray(Array&: Symbols, Size: Reader.getLength())) |
| 619 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 620 | |
| 621 | LazyRandomTypeCollection &Types = types(); |
| 622 | LazyRandomTypeCollection &Ids = ids(); |
| 623 | SymbolVisitorCallbackPipeline Pipeline; |
| 624 | SymbolDeserializer Deserializer(&VisitorDelegate, |
| 625 | CodeViewContainer::ObjectFile); |
| 626 | // As we are processing a COFF format, use TPI as IPI, so the generic code |
| 627 | // to process the CodeView format does not contain any additional checks. |
| 628 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, |
| 629 | &VisitorDelegate, LogicalVisitor.getShared()); |
| 630 | |
| 631 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
| 632 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
| 633 | CVSymbolVisitor Visitor(Pipeline); |
| 634 | return Visitor.visitSymbolStream(Symbols); |
| 635 | } |
| 636 | |
| 637 | Error LVCodeViewReader::traverseSymbolSection(StringRef SectionName, |
| 638 | const SectionRef &Section) { |
| 639 | LLVM_DEBUG({ |
| 640 | ListScope D(W, "CodeViewDebugInfo" ); |
| 641 | W.printNumber("Section" , SectionName, getObj().getSectionID(Section)); |
| 642 | }); |
| 643 | |
| 644 | Expected<StringRef> SectionOrErr = Section.getContents(); |
| 645 | if (!SectionOrErr) |
| 646 | return SectionOrErr.takeError(); |
| 647 | StringRef SectionContents = *SectionOrErr; |
| 648 | StringRef Data = SectionContents; |
| 649 | |
| 650 | SmallVector<StringRef, 10> SymbolNames; |
| 651 | StringMap<StringRef> FunctionLineTables; |
| 652 | |
| 653 | uint32_t Magic; |
| 654 | if (Error E = consume(Data, Item&: Magic)) |
| 655 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 656 | |
| 657 | if (Magic != COFF::DEBUG_SECTION_MAGIC) |
| 658 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 659 | |
| 660 | BinaryStreamReader FSReader(Data, llvm::endianness::little); |
| 661 | if (Error Err = initializeFileAndStringTables(Reader&: FSReader)) |
| 662 | return Err; |
| 663 | |
| 664 | while (!Data.empty()) { |
| 665 | // The section consists of a number of subsection in the following format: |
| 666 | // |SubSectionType|SubSectionSize|Contents...| |
| 667 | uint32_t SubType, SubSectionSize; |
| 668 | if (Error E = consume(Data, Item&: SubType)) |
| 669 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 670 | if (Error E = consume(Data, Item&: SubSectionSize)) |
| 671 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 672 | |
| 673 | // Process the subsection as normal even if the ignore bit is set. |
| 674 | SubType &= ~SubsectionIgnoreFlag; |
| 675 | |
| 676 | // Get the contents of the subsection. |
| 677 | if (SubSectionSize > Data.size()) |
| 678 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 679 | StringRef Contents = Data.substr(Start: 0, N: SubSectionSize); |
| 680 | |
| 681 | // Add SubSectionSize to the current offset and align that offset |
| 682 | // to find the next subsection. |
| 683 | size_t SectionOffset = Data.data() - SectionContents.data(); |
| 684 | size_t NextOffset = SectionOffset + SubSectionSize; |
| 685 | NextOffset = alignTo(Value: NextOffset, Align: 4); |
| 686 | if (NextOffset > SectionContents.size()) |
| 687 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 688 | Data = SectionContents.drop_front(N: NextOffset); |
| 689 | |
| 690 | switch (DebugSubsectionKind(SubType)) { |
| 691 | case DebugSubsectionKind::Symbols: |
| 692 | if (Error Err = |
| 693 | traverseSymbolsSubsection(Subsection: Contents, Section, SectionContents)) |
| 694 | return Err; |
| 695 | break; |
| 696 | |
| 697 | case DebugSubsectionKind::InlineeLines: |
| 698 | if (Error Err = traverseInlineeLines(Subsection: Contents)) |
| 699 | return Err; |
| 700 | break; |
| 701 | |
| 702 | case DebugSubsectionKind::Lines: |
| 703 | // Holds a PC to file:line table. Some data to parse this subsection |
| 704 | // is stored in the other subsections, so just check sanity and store |
| 705 | // the pointers for deferred processing. |
| 706 | |
| 707 | // Collect function and ranges only if we need to print logical lines. |
| 708 | if (options().getGeneralCollectRanges()) { |
| 709 | |
| 710 | if (SubSectionSize < 12) { |
| 711 | // There should be at least three words to store two function |
| 712 | // relocations and size of the code. |
| 713 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 714 | } |
| 715 | |
| 716 | StringRef SymbolName; |
| 717 | if (Error Err = resolveSymbolName(CoffSection: getObj().getCOFFSection(Section), |
| 718 | Offset: SectionOffset, Name&: SymbolName)) |
| 719 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
| 720 | S: getFileName()); |
| 721 | |
| 722 | LLVM_DEBUG({ W.printString("Symbol Name" , SymbolName); }); |
| 723 | if (!FunctionLineTables.try_emplace(Key: SymbolName, Args&: Contents).second) { |
| 724 | // Saw debug info for this function already? |
| 725 | return createStringError(EC: object_error::parse_failed, S: getFileName()); |
| 726 | } |
| 727 | |
| 728 | SymbolNames.push_back(Elt: SymbolName); |
| 729 | } |
| 730 | break; |
| 731 | |
| 732 | // Do nothing for unrecognized subsections. |
| 733 | default: |
| 734 | break; |
| 735 | } |
| 736 | W.flush(); |
| 737 | } |
| 738 | |
| 739 | // Traverse the line tables now that we've read all the subsections and |
| 740 | // know all the required information. |
| 741 | for (StringRef SymbolName : SymbolNames) { |
| 742 | LLVM_DEBUG({ |
| 743 | ListScope S(W, "FunctionLineTable" ); |
| 744 | W.printString("Symbol Name" , SymbolName); |
| 745 | }); |
| 746 | |
| 747 | BinaryStreamReader Reader(FunctionLineTables[SymbolName], |
| 748 | llvm::endianness::little); |
| 749 | |
| 750 | DebugLinesSubsectionRef Lines; |
| 751 | if (Error E = Lines.initialize(Reader)) |
| 752 | return createStringError(EC: errorToErrorCode(Err: std::move(E)), S: getFileName()); |
| 753 | |
| 754 | // Find the associated symbol table information. |
| 755 | LVSymbolTableEntry SymbolTableEntry = getSymbolTableEntry(Name: SymbolName); |
| 756 | LVScope *Function = SymbolTableEntry.Scope; |
| 757 | if (!Function) |
| 758 | continue; |
| 759 | |
| 760 | LVAddress Addendum = SymbolTableEntry.Address; |
| 761 | LVSectionIndex SectionIndex = SymbolTableEntry.SectionIndex; |
| 762 | |
| 763 | // The given scope represents the function that contains the line numbers. |
| 764 | // Collect all generated debug lines associated with the function. |
| 765 | CULines.clear(); |
| 766 | |
| 767 | // For the given scope, collect all scopes ranges. |
| 768 | LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); |
| 769 | ScopesWithRanges->clear(); |
| 770 | Function->getRanges(RangeList&: *ScopesWithRanges); |
| 771 | ScopesWithRanges->sort(); |
| 772 | |
| 773 | uint16_t Segment = Lines.header()->RelocSegment; |
| 774 | uint32_t Begin = Lines.header()->RelocOffset; |
| 775 | uint32_t Size = Lines.header()->CodeSize; |
| 776 | for (const LineColumnEntry &Block : Lines) |
| 777 | if (Error Err = createLines(LineNumbers: Block.LineNumbers, Addendum, Segment, Begin, |
| 778 | Size, NameIndex: Block.NameIndex)) |
| 779 | return Err; |
| 780 | |
| 781 | // Include lines from any inlined functions within the current function. |
| 782 | includeInlineeLines(SectionIndex, Function); |
| 783 | |
| 784 | if (Error Err = createInstructions(Function, SectionIndex)) |
| 785 | return Err; |
| 786 | |
| 787 | processLines(DebugLines: &CULines, SectionIndex, Function); |
| 788 | } |
| 789 | |
| 790 | return Error::success(); |
| 791 | } |
| 792 | |
| 793 | void LVCodeViewReader::sortScopes() { Root->sort(); } |
| 794 | |
| 795 | void LVCodeViewReader::print(raw_ostream &OS) const { |
| 796 | LLVM_DEBUG(dbgs() << "CreateReaders\n" ); |
| 797 | } |
| 798 | |
| 799 | void LVCodeViewReader::mapRangeAddress(const ObjectFile &Obj, |
| 800 | const SectionRef &Section, |
| 801 | bool IsComdat) { |
| 802 | if (!Obj.isCOFF()) |
| 803 | return; |
| 804 | |
| 805 | const COFFObjectFile *Object = cast<COFFObjectFile>(Val: &Obj); |
| 806 | |
| 807 | for (const SymbolRef &Sym : Object->symbols()) { |
| 808 | if (!Section.containsSymbol(S: Sym)) |
| 809 | continue; |
| 810 | |
| 811 | COFFSymbolRef Symbol = Object->getCOFFSymbol(Symbol: Sym); |
| 812 | if (Symbol.getComplexType() != llvm::COFF::IMAGE_SYM_DTYPE_FUNCTION) |
| 813 | continue; |
| 814 | |
| 815 | StringRef SymbolName; |
| 816 | Expected<StringRef> SymNameOrErr = Object->getSymbolName(Symbol); |
| 817 | if (!SymNameOrErr) { |
| 818 | W.startLine() << "Invalid symbol name: " << Symbol.getSectionNumber() |
| 819 | << "\n" ; |
| 820 | consumeError(Err: SymNameOrErr.takeError()); |
| 821 | continue; |
| 822 | } |
| 823 | SymbolName = *SymNameOrErr; |
| 824 | |
| 825 | LLVM_DEBUG({ |
| 826 | Expected<const coff_section *> SectionOrErr = |
| 827 | Object->getSection(Symbol.getSectionNumber()); |
| 828 | if (!SectionOrErr) { |
| 829 | W.startLine() << "Invalid section number: " << Symbol.getSectionNumber() |
| 830 | << "\n" ; |
| 831 | consumeError(SectionOrErr.takeError()); |
| 832 | return; |
| 833 | } |
| 834 | W.printNumber("Section #" , Symbol.getSectionNumber()); |
| 835 | W.printString("Name" , SymbolName); |
| 836 | W.printHex("Value" , Symbol.getValue()); |
| 837 | }); |
| 838 | |
| 839 | // Record the symbol name (linkage) and its loading address. |
| 840 | addToSymbolTable(Name: SymbolName, Address: Symbol.getValue(), SectionIndex: Symbol.getSectionNumber(), |
| 841 | IsComdat); |
| 842 | } |
| 843 | } |
| 844 | |
| 845 | Error LVCodeViewReader::createScopes(COFFObjectFile &Obj) { |
| 846 | if (Error Err = loadTargetInfo(Obj)) |
| 847 | return Err; |
| 848 | |
| 849 | // Initialization required when processing a COFF file: |
| 850 | // Cache the symbols relocations. |
| 851 | // Create a mapping for virtual addresses. |
| 852 | // Get the functions entry points. |
| 853 | cacheRelocations(); |
| 854 | mapVirtualAddress(COFFObj: Obj); |
| 855 | |
| 856 | for (const SectionRef &Section : Obj.sections()) { |
| 857 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
| 858 | if (!SectionNameOrErr) |
| 859 | return SectionNameOrErr.takeError(); |
| 860 | // .debug$T is a standard CodeView type section, while .debug$P is the |
| 861 | // same format but used for MSVC precompiled header object files. |
| 862 | if (*SectionNameOrErr == ".debug$T" || *SectionNameOrErr == ".debug$P" ) |
| 863 | if (Error Err = traverseTypeSection(SectionName: *SectionNameOrErr, Section)) |
| 864 | return Err; |
| 865 | } |
| 866 | |
| 867 | // Process collected namespaces. |
| 868 | LogicalVisitor.processNamespaces(); |
| 869 | |
| 870 | for (const SectionRef &Section : Obj.sections()) { |
| 871 | Expected<StringRef> SectionNameOrErr = Section.getName(); |
| 872 | if (!SectionNameOrErr) |
| 873 | return SectionNameOrErr.takeError(); |
| 874 | if (*SectionNameOrErr == ".debug$S" ) |
| 875 | if (Error Err = traverseSymbolSection(SectionName: *SectionNameOrErr, Section)) |
| 876 | return Err; |
| 877 | } |
| 878 | |
| 879 | // Check if we have to close the Compile Unit scope. |
| 880 | LogicalVisitor.closeScope(); |
| 881 | |
| 882 | // Traverse the strings recorded and transform them into filenames. |
| 883 | LogicalVisitor.processFiles(); |
| 884 | |
| 885 | // Process collected element lines. |
| 886 | LogicalVisitor.processLines(); |
| 887 | |
| 888 | // Translate composite names into a single component. |
| 889 | Root->transformScopedName(); |
| 890 | return Error::success(); |
| 891 | } |
| 892 | |
| 893 | Error LVCodeViewReader::createScopes(PDBFile &Pdb) { |
| 894 | if (Error Err = loadTargetInfo(Pdb)) |
| 895 | return Err; |
| 896 | |
| 897 | if (!Pdb.hasPDBTpiStream() || !Pdb.hasPDBDbiStream()) |
| 898 | return Error::success(); |
| 899 | |
| 900 | // Open the executable associated with the PDB file and get the section |
| 901 | // addresses used to calculate linear addresses for CodeView Symbols. |
| 902 | if (!ExePath.empty()) { |
| 903 | ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = |
| 904 | MemoryBuffer::getFileOrSTDIN(Filename: ExePath); |
| 905 | if (BuffOrErr.getError()) { |
| 906 | return createStringError(EC: errc::bad_file_descriptor, |
| 907 | Fmt: "File '%s' does not exist." , Vals: ExePath.c_str()); |
| 908 | } |
| 909 | BinaryBuffer = std::move(BuffOrErr.get()); |
| 910 | |
| 911 | // Check if the buffer corresponds to a PECOFF executable. |
| 912 | assert(identify_magic(BinaryBuffer->getBuffer()) == |
| 913 | file_magic::pecoff_executable && |
| 914 | "Invalid PECOFF executable file." ); |
| 915 | |
| 916 | Expected<std::unique_ptr<Binary>> BinOrErr = |
| 917 | createBinary(Source: BinaryBuffer->getMemBufferRef()); |
| 918 | if (errorToErrorCode(Err: BinOrErr.takeError())) { |
| 919 | return createStringError(EC: errc::not_supported, |
| 920 | Fmt: "Binary object format in '%s' is not supported." , |
| 921 | Vals: ExePath.c_str()); |
| 922 | } |
| 923 | BinaryExecutable = std::move(*BinOrErr); |
| 924 | if (COFFObjectFile *COFFObject = |
| 925 | dyn_cast<COFFObjectFile>(Val: BinaryExecutable.get())) |
| 926 | mapVirtualAddress(COFFObj: *COFFObject); |
| 927 | } |
| 928 | |
| 929 | // In order to generate a full logical view, we have to traverse both |
| 930 | // streams TPI and IPI if they are present. The following table gives |
| 931 | // the stream where a specified type is located. If the IPI stream is |
| 932 | // not present, all the types are located in the TPI stream. |
| 933 | // |
| 934 | // TPI Stream: |
| 935 | // LF_POINTER LF_MODIFIER LF_PROCEDURE LF_MFUNCTION |
| 936 | // LF_LABEL LF_ARGLIST LF_FIELDLIST LF_ARRAY |
| 937 | // LF_CLASS LF_STRUCTURE LF_INTERFACE LF_UNION |
| 938 | // LF_ENUM LF_TYPESERVER2 LF_VFTABLE LF_VTSHAPE |
| 939 | // LF_BITFIELD LF_METHODLIST LF_PRECOMP LF_ENDPRECOMP |
| 940 | // |
| 941 | // IPI stream: |
| 942 | // LF_FUNC_ID LF_MFUNC_ID LF_BUILDINFO |
| 943 | // LF_SUBSTR_LIST LF_STRING_ID LF_UDT_SRC_LINE |
| 944 | // LF_UDT_MOD_SRC_LINE |
| 945 | |
| 946 | LazyRandomTypeCollection &Types = types(); |
| 947 | LazyRandomTypeCollection &Ids = ids(); |
| 948 | if (Error Err = traverseTypes(Pdb, Types, Ids)) |
| 949 | return Err; |
| 950 | |
| 951 | // Process collected namespaces. |
| 952 | LogicalVisitor.processNamespaces(); |
| 953 | |
| 954 | LLVM_DEBUG({ W.getOStream() << "Traversing inlined lines\n" ; }); |
| 955 | |
| 956 | auto VisitInlineeLines = [&](int32_t Modi, const SymbolGroup &SG, |
| 957 | DebugInlineeLinesSubsectionRef &Lines) -> Error { |
| 958 | return collectInlineeInfo(Lines, SG: &SG); |
| 959 | }; |
| 960 | |
| 961 | FilterOptions Filters = {}; |
| 962 | LinePrinter Printer(/*Indent=*/2, false, nulls(), Filters); |
| 963 | const PrintScope (Printer, /*IndentLevel=*/2); |
| 964 | if (Error Err = iterateModuleSubsections<DebugInlineeLinesSubsectionRef>( |
| 965 | File&: Input, HeaderScope, Callback: VisitInlineeLines)) |
| 966 | return Err; |
| 967 | |
| 968 | // Traverse global symbols. |
| 969 | LLVM_DEBUG({ W.getOStream() << "Traversing global symbols\n" ; }); |
| 970 | if (Pdb.hasPDBGlobalsStream()) { |
| 971 | Expected<GlobalsStream &> GlobalsOrErr = Pdb.getPDBGlobalsStream(); |
| 972 | if (!GlobalsOrErr) |
| 973 | return GlobalsOrErr.takeError(); |
| 974 | GlobalsStream &Globals = *GlobalsOrErr; |
| 975 | const GSIHashTable &Table = Globals.getGlobalsTable(); |
| 976 | Expected<SymbolStream &> ExpectedSyms = Pdb.getPDBSymbolStream(); |
| 977 | if (ExpectedSyms) { |
| 978 | |
| 979 | SymbolVisitorCallbackPipeline Pipeline; |
| 980 | SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); |
| 981 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr, |
| 982 | LogicalVisitor.getShared()); |
| 983 | |
| 984 | // As the global symbols do not have an associated Compile Unit, create |
| 985 | // one, as the container for all global symbols. |
| 986 | RecordPrefix Prefix(SymbolKind::S_COMPILE3); |
| 987 | CVSymbol Symbol(&Prefix, sizeof(Prefix)); |
| 988 | uint32_t Offset = 0; |
| 989 | if (Error Err = Traverser.visitSymbolBegin(Record&: Symbol, Offset)) |
| 990 | consumeError(Err: std::move(Err)); |
| 991 | else { |
| 992 | // The CodeView compile unit containing the global symbols does not |
| 993 | // have a name; generate one using its parent name (object filename) |
| 994 | // follow by the '_global' string. |
| 995 | std::string Name(CompileUnit->getParentScope()->getName()); |
| 996 | CompileUnit->setName(Name.append(s: "_global" )); |
| 997 | |
| 998 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
| 999 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
| 1000 | CVSymbolVisitor Visitor(Pipeline); |
| 1001 | |
| 1002 | BinaryStreamRef SymStream = |
| 1003 | ExpectedSyms->getSymbolArray().getUnderlyingStream(); |
| 1004 | for (uint32_t PubSymOff : Table) { |
| 1005 | Expected<CVSymbol> Sym = readSymbolFromStream(Stream: SymStream, Offset: PubSymOff); |
| 1006 | if (Sym) { |
| 1007 | if (Error Err = Visitor.visitSymbolRecord(Record&: *Sym, Offset: PubSymOff)) |
| 1008 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
| 1009 | S: getFileName()); |
| 1010 | } else { |
| 1011 | consumeError(Err: Sym.takeError()); |
| 1012 | } |
| 1013 | } |
| 1014 | } |
| 1015 | |
| 1016 | LogicalVisitor.closeScope(); |
| 1017 | } else { |
| 1018 | consumeError(Err: ExpectedSyms.takeError()); |
| 1019 | } |
| 1020 | } |
| 1021 | |
| 1022 | // Traverse symbols (DBI). |
| 1023 | LLVM_DEBUG({ W.getOStream() << "Traversing symbol groups\n" ; }); |
| 1024 | |
| 1025 | auto VisitSymbolGroup = [&](uint32_t Modi, const SymbolGroup &SG) -> Error { |
| 1026 | Expected<ModuleDebugStreamRef> ExpectedModS = |
| 1027 | getModuleDebugStream(File&: Pdb, Index: Modi); |
| 1028 | if (ExpectedModS) { |
| 1029 | ModuleDebugStreamRef &ModS = *ExpectedModS; |
| 1030 | |
| 1031 | LLVM_DEBUG({ |
| 1032 | W.getOStream() << formatv("Traversing Group: Mod {0:4}\n" , Modi); |
| 1033 | }); |
| 1034 | |
| 1035 | SymbolVisitorCallbackPipeline Pipeline; |
| 1036 | SymbolDeserializer Deserializer(nullptr, CodeViewContainer::Pdb); |
| 1037 | LVSymbolVisitor Traverser(this, W, &LogicalVisitor, Types, Ids, nullptr, |
| 1038 | LogicalVisitor.getShared()); |
| 1039 | |
| 1040 | Pipeline.addCallbackToPipeline(Callbacks&: Deserializer); |
| 1041 | Pipeline.addCallbackToPipeline(Callbacks&: Traverser); |
| 1042 | CVSymbolVisitor Visitor(Pipeline); |
| 1043 | BinarySubstreamRef SS = ModS.getSymbolsSubstream(); |
| 1044 | if (Error Err = |
| 1045 | Visitor.visitSymbolStream(Symbols: ModS.getSymbolArray(), InitialOffset: SS.Offset)) |
| 1046 | return createStringError(EC: errorToErrorCode(Err: std::move(Err)), |
| 1047 | S: getFileName()); |
| 1048 | } else { |
| 1049 | // If the module stream does not exist, it is not an error condition. |
| 1050 | consumeError(Err: ExpectedModS.takeError()); |
| 1051 | } |
| 1052 | |
| 1053 | return Error::success(); |
| 1054 | }; |
| 1055 | |
| 1056 | if (Error Err = iterateSymbolGroups(Input, HeaderScope, Callback: VisitSymbolGroup)) |
| 1057 | return Err; |
| 1058 | |
| 1059 | // At this stage, the logical view contains all scopes, symbols and types. |
| 1060 | // For PDBs we can use the module id, to access its specific compile unit. |
| 1061 | // The line record addresses has been already resolved, so we can apply the |
| 1062 | // flow as when processing DWARF. |
| 1063 | |
| 1064 | LLVM_DEBUG({ W.getOStream() << "Traversing lines\n" ; }); |
| 1065 | |
| 1066 | // Record all line records for a Compile Unit. |
| 1067 | CULines.clear(); |
| 1068 | |
| 1069 | auto VisitDebugLines = [this](int32_t Modi, const SymbolGroup &SG, |
| 1070 | DebugLinesSubsectionRef &Lines) -> Error { |
| 1071 | if (!options().getPrintLines()) |
| 1072 | return Error::success(); |
| 1073 | |
| 1074 | uint16_t Segment = Lines.header()->RelocSegment; |
| 1075 | uint32_t Begin = Lines.header()->RelocOffset; |
| 1076 | uint32_t Size = Lines.header()->CodeSize; |
| 1077 | |
| 1078 | LLVM_DEBUG({ W.getOStream() << formatv("Modi = {0}\n" , Modi); }); |
| 1079 | |
| 1080 | // We have line information for a new module; finish processing the |
| 1081 | // collected information for the current module. Once it is done, start |
| 1082 | // recording the line information for the new module. |
| 1083 | if (CurrentModule != Modi) { |
| 1084 | if (Error Err = processModule()) |
| 1085 | return Err; |
| 1086 | CULines.clear(); |
| 1087 | CurrentModule = Modi; |
| 1088 | } |
| 1089 | |
| 1090 | for (const LineColumnEntry &Block : Lines) |
| 1091 | if (Error Err = createLines(LineNumbers: Block.LineNumbers, /*Addendum=*/0, Segment, |
| 1092 | Begin, Size, NameIndex: Block.NameIndex, SG: &SG)) |
| 1093 | return Err; |
| 1094 | |
| 1095 | return Error::success(); |
| 1096 | }; |
| 1097 | |
| 1098 | if (Error Err = iterateModuleSubsections<DebugLinesSubsectionRef>( |
| 1099 | File&: Input, HeaderScope, Callback: VisitDebugLines)) |
| 1100 | return Err; |
| 1101 | |
| 1102 | // Check if we have to close the Compile Unit scope. |
| 1103 | LogicalVisitor.closeScope(); |
| 1104 | |
| 1105 | // Process collected element lines. |
| 1106 | LogicalVisitor.processLines(); |
| 1107 | |
| 1108 | // Translate composite names into a single component. |
| 1109 | Root->transformScopedName(); |
| 1110 | return Error::success(); |
| 1111 | } |
| 1112 | |
| 1113 | Error LVCodeViewReader::processModule() { |
| 1114 | if (LVScope *Scope = getScopeForModule(Modi: CurrentModule)) { |
| 1115 | CompileUnit = static_cast<LVScopeCompileUnit *>(Scope); |
| 1116 | |
| 1117 | LLVM_DEBUG({ dbgs() << "Processing Scope: " << Scope->getName() << "\n" ; }); |
| 1118 | |
| 1119 | // For the given compile unit, collect all scopes ranges. |
| 1120 | // For a complete ranges and lines mapping, the logical view support |
| 1121 | // needs for the compile unit to have a low and high pc values. We |
| 1122 | // can traverse the 'Modules' section and get the information for the |
| 1123 | // specific module. Another option, is from all the ranges collected |
| 1124 | // to take the first and last values. |
| 1125 | LVSectionIndex SectionIndex = DotTextSectionIndex; |
| 1126 | LVRange *ScopesWithRanges = getSectionRanges(SectionIndex); |
| 1127 | ScopesWithRanges->clear(); |
| 1128 | CompileUnit->getRanges(RangeList&: *ScopesWithRanges); |
| 1129 | if (!ScopesWithRanges->empty()) |
| 1130 | CompileUnit->addObject(LowerAddress: ScopesWithRanges->getLower(), |
| 1131 | UpperAddress: ScopesWithRanges->getUpper()); |
| 1132 | ScopesWithRanges->sort(); |
| 1133 | |
| 1134 | if (Error Err = createInstructions()) |
| 1135 | return Err; |
| 1136 | |
| 1137 | // Include lines from any inlined functions within the current function. |
| 1138 | includeInlineeLines(SectionIndex, Function: Scope); |
| 1139 | |
| 1140 | processLines(DebugLines: &CULines, SectionIndex, Function: nullptr); |
| 1141 | } |
| 1142 | |
| 1143 | return Error::success(); |
| 1144 | } |
| 1145 | |
| 1146 | // In order to create the scopes, the CodeView Reader will: |
| 1147 | // = Traverse the TPI/IPI stream (Type visitor): |
| 1148 | // Collect forward references, scoped names, type indexes that will represent |
| 1149 | // a logical element, strings, line records, linkage names. |
| 1150 | // = Traverse the symbols section (Symbol visitor): |
| 1151 | // Create the scopes tree and creates the required logical elements, by |
| 1152 | // using the collected indexes from the type visitor. |
| 1153 | Error LVCodeViewReader::createScopes() { |
| 1154 | LLVM_DEBUG({ |
| 1155 | W.startLine() << "\n" ; |
| 1156 | W.printString("File" , getFileName().str()); |
| 1157 | W.printString("Exe" , ExePath); |
| 1158 | W.printString("Format" , FileFormatName); |
| 1159 | }); |
| 1160 | |
| 1161 | if (Error Err = LVReader::createScopes()) |
| 1162 | return Err; |
| 1163 | |
| 1164 | LogicalVisitor.setRoot(Root); |
| 1165 | |
| 1166 | if (isObj()) { |
| 1167 | if (Error Err = createScopes(Obj&: getObj())) |
| 1168 | return Err; |
| 1169 | } else { |
| 1170 | if (Error Err = createScopes(Pdb&: getPdb())) |
| 1171 | return Err; |
| 1172 | } |
| 1173 | |
| 1174 | return Error::success(); |
| 1175 | } |
| 1176 | |
| 1177 | Error LVCodeViewReader::loadTargetInfo(const ObjectFile &Obj) { |
| 1178 | // Detect the architecture from the object file. We usually don't need OS |
| 1179 | // info to lookup a target and create register info. |
| 1180 | Triple TT; |
| 1181 | TT.setArch(Kind: Triple::ArchType(Obj.getArch())); |
| 1182 | TT.setVendor(Triple::UnknownVendor); |
| 1183 | TT.setOS(Triple::UnknownOS); |
| 1184 | |
| 1185 | // Features to be passed to target/subtarget |
| 1186 | Expected<SubtargetFeatures> Features = Obj.getFeatures(); |
| 1187 | SubtargetFeatures FeaturesValue; |
| 1188 | if (!Features) { |
| 1189 | consumeError(Err: Features.takeError()); |
| 1190 | FeaturesValue = SubtargetFeatures(); |
| 1191 | } |
| 1192 | FeaturesValue = *Features; |
| 1193 | return loadGenericTargetInfo(TheTriple: TT.str(), TheFeatures: FeaturesValue.getString()); |
| 1194 | } |
| 1195 | |
| 1196 | Error LVCodeViewReader::loadTargetInfo(const PDBFile &Pdb) { |
| 1197 | Triple TT; |
| 1198 | TT.setArch(Kind: Triple::ArchType::x86_64); |
| 1199 | TT.setVendor(Triple::UnknownVendor); |
| 1200 | TT.setOS(Triple::Win32); |
| 1201 | |
| 1202 | StringRef TheFeature = "" ; |
| 1203 | |
| 1204 | return loadGenericTargetInfo(TheTriple: TT.str(), TheFeatures: TheFeature); |
| 1205 | } |
| 1206 | |
| 1207 | std::string LVCodeViewReader::getRegisterName(LVSmall Opcode, |
| 1208 | ArrayRef<uint64_t> Operands) { |
| 1209 | // Get Compilation Unit CPU Type. |
| 1210 | CPUType CPU = getCompileUnitCPUType(); |
| 1211 | // For CodeView the register always is in Operands[0]; |
| 1212 | RegisterId Register = (RegisterId(Operands[0])); |
| 1213 | return formatRegisterId(Register, CPU); |
| 1214 | } |
| 1215 | |