1 //===-- LVReaderHandler.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 class implements the Reader Handler. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/DebugInfo/LogicalView/LVReaderHandler.h" 14 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" 15 #include "llvm/DebugInfo/LogicalView/Core/LVCompare.h" 16 #include "llvm/DebugInfo/LogicalView/Readers/LVCodeViewReader.h" 17 #include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h" 18 #include "llvm/DebugInfo/PDB/Native/NativeSession.h" 19 #include "llvm/DebugInfo/PDB/PDB.h" 20 #include "llvm/Object/COFF.h" 21 22 using namespace llvm; 23 using namespace llvm::object; 24 using namespace llvm::pdb; 25 using namespace llvm::logicalview; 26 27 #define DEBUG_TYPE "ReaderHandler" 28 29 Error LVReaderHandler::process() { 30 if (Error Err = createReaders()) 31 return Err; 32 if (Error Err = printReaders()) 33 return Err; 34 if (Error Err = compareReaders()) 35 return Err; 36 37 return Error::success(); 38 } 39 40 Error LVReaderHandler::createReader(StringRef Filename, LVReaders &Readers, 41 PdbOrObj &Input, StringRef FileFormatName, 42 StringRef ExePath) { 43 auto CreateOneReader = [&]() -> std::unique_ptr<LVReader> { 44 if (isa<ObjectFile *>(Input)) { 45 ObjectFile &Obj = *cast<ObjectFile *>(Input); 46 if (Obj.isCOFF()) { 47 COFFObjectFile *COFF = cast<COFFObjectFile>(&Obj); 48 return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, 49 *COFF, W, ExePath); 50 } 51 if (Obj.isELF() || Obj.isMachO() || Obj.isWasm()) 52 return std::make_unique<LVDWARFReader>(Filename, FileFormatName, Obj, 53 W); 54 } 55 if (isa<PDBFile *>(Input)) { 56 PDBFile &Pdb = *cast<PDBFile *>(Input); 57 return std::make_unique<LVCodeViewReader>(Filename, FileFormatName, Pdb, 58 W, ExePath); 59 } 60 return nullptr; 61 }; 62 63 std::unique_ptr<LVReader> ReaderObj = CreateOneReader(); 64 if (!ReaderObj) 65 return createStringError(errc::invalid_argument, 66 "unable to create reader for: '%s'", 67 Filename.str().c_str()); 68 69 LVReader *Reader = ReaderObj.get(); 70 Readers.emplace_back(std::move(ReaderObj)); 71 return Reader->doLoad(); 72 } 73 74 Error LVReaderHandler::handleArchive(LVReaders &Readers, StringRef Filename, 75 Archive &Arch) { 76 Error Err = Error::success(); 77 for (const Archive::Child &Child : Arch.children(Err)) { 78 Expected<MemoryBufferRef> BuffOrErr = Child.getMemoryBufferRef(); 79 if (Error Err = BuffOrErr.takeError()) 80 return createStringError(errorToErrorCode(std::move(Err)), "%s", 81 Filename.str().c_str()); 82 Expected<StringRef> NameOrErr = Child.getName(); 83 if (Error Err = NameOrErr.takeError()) 84 return createStringError(errorToErrorCode(std::move(Err)), "%s", 85 Filename.str().c_str()); 86 std::string Name = (Filename + "(" + NameOrErr.get() + ")").str(); 87 if (Error Err = handleBuffer(Readers, Name, BuffOrErr.get())) 88 return createStringError(errorToErrorCode(std::move(Err)), "%s", 89 Filename.str().c_str()); 90 } 91 92 return Error::success(); 93 } 94 95 // Search for a matching executable image for the given PDB path. 96 static std::string searchForExe(const StringRef Path, 97 const StringRef Extension) { 98 SmallString<128> ExePath(Path); 99 llvm::sys::path::replace_extension(ExePath, Extension); 100 101 std::unique_ptr<IPDBSession> Session; 102 if (Error Err = loadDataForEXE(PDB_ReaderType::Native, ExePath, Session)) { 103 consumeError(std::move(Err)); 104 return {}; 105 } 106 // We have a candidate for the executable image. 107 Expected<std::string> PdbPathOrErr = NativeSession::searchForPdb({ExePath}); 108 if (!PdbPathOrErr) { 109 consumeError(PdbPathOrErr.takeError()); 110 return {}; 111 } 112 // Convert any Windows backslashes into forward slashes to get the path. 113 std::string ConvertedPath = sys::path::convert_to_slash( 114 PdbPathOrErr.get(), sys::path::Style::windows); 115 if (ConvertedPath == Path) 116 return std::string(ExePath); 117 118 return {}; 119 } 120 121 // Search for a matching object image for the given PDB path. 122 static std::string searchForObj(const StringRef Path, 123 const StringRef Extension) { 124 SmallString<128> ObjPath(Path); 125 llvm::sys::path::replace_extension(ObjPath, Extension); 126 if (llvm::sys::fs::exists(ObjPath)) { 127 ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = 128 MemoryBuffer::getFileOrSTDIN(ObjPath); 129 if (!BuffOrErr) 130 return {}; 131 return std::string(ObjPath); 132 } 133 134 return {}; 135 } 136 137 Error LVReaderHandler::handleBuffer(LVReaders &Readers, StringRef Filename, 138 MemoryBufferRef Buffer, StringRef ExePath) { 139 // As PDB does not support the Binary interface, at this point we can check 140 // if the buffer corresponds to a PDB or PE file. 141 file_magic FileMagic = identify_magic(Buffer.getBuffer()); 142 if (FileMagic == file_magic::pdb) { 143 if (!ExePath.empty()) 144 return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath); 145 146 // Search in the directory derived from the given 'Filename' for a 147 // matching object file (.o, .obj, .lib) or a matching executable file 148 // (.exe/.dll) and try to create the reader based on the matched file. 149 // If no matching file is found then we load the original PDB file. 150 std::vector<StringRef> ExecutableExtensions = {"exe", "dll"}; 151 for (StringRef Extension : ExecutableExtensions) { 152 std::string ExecutableImage = searchForExe(Filename, Extension); 153 if (ExecutableImage.empty()) 154 continue; 155 if (Error Err = handleObject(Readers, Filename, Buffer.getBuffer(), 156 ExecutableImage)) { 157 consumeError(std::move(Err)); 158 continue; 159 } 160 return Error::success(); 161 } 162 163 std::vector<StringRef> ObjectExtensions = {"o", "obj", "lib"}; 164 for (StringRef Extension : ObjectExtensions) { 165 std::string ObjectImage = searchForObj(Filename, Extension); 166 if (ObjectImage.empty()) 167 continue; 168 if (Error Err = handleFile(Readers, ObjectImage)) { 169 consumeError(std::move(Err)); 170 continue; 171 } 172 return Error::success(); 173 } 174 175 // No matching executable/object image was found. Load the given PDB. 176 return handleObject(Readers, Filename, Buffer.getBuffer(), ExePath); 177 } 178 if (FileMagic == file_magic::pecoff_executable) { 179 // If we have a valid executable, try to find a matching PDB file. 180 Expected<std::string> PdbPath = NativeSession::searchForPdb({Filename}); 181 if (errorToErrorCode(PdbPath.takeError())) { 182 return createStringError( 183 errc::not_supported, 184 "Binary object format in '%s' does not have debug info.", 185 Filename.str().c_str()); 186 } 187 // Process the matching PDB file and pass the executable filename. 188 return handleFile(Readers, PdbPath.get(), Filename); 189 } 190 191 Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buffer); 192 if (errorToErrorCode(BinOrErr.takeError())) { 193 return createStringError(errc::not_supported, 194 "Binary object format in '%s' is not supported.", 195 Filename.str().c_str()); 196 } 197 return handleObject(Readers, Filename, *BinOrErr.get()); 198 } 199 200 Error LVReaderHandler::handleFile(LVReaders &Readers, StringRef Filename, 201 StringRef ExePath) { 202 // Convert any Windows backslashes into forward slashes to get the path. 203 std::string ConvertedPath = 204 sys::path::convert_to_slash(Filename, sys::path::Style::windows); 205 ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = 206 MemoryBuffer::getFileOrSTDIN(ConvertedPath); 207 if (BuffOrErr.getError()) { 208 return createStringError(errc::bad_file_descriptor, 209 "File '%s' does not exist.", 210 ConvertedPath.c_str()); 211 } 212 std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get()); 213 return handleBuffer(Readers, ConvertedPath, *Buffer, ExePath); 214 } 215 216 Error LVReaderHandler::handleMach(LVReaders &Readers, StringRef Filename, 217 MachOUniversalBinary &Mach) { 218 for (const MachOUniversalBinary::ObjectForArch &ObjForArch : Mach.objects()) { 219 std::string ObjName = (Twine(Filename) + Twine("(") + 220 Twine(ObjForArch.getArchFlagName()) + Twine(")")) 221 .str(); 222 if (Expected<std::unique_ptr<MachOObjectFile>> MachOOrErr = 223 ObjForArch.getAsObjectFile()) { 224 MachOObjectFile &Obj = **MachOOrErr; 225 PdbOrObj Input = &Obj; 226 if (Error Err = 227 createReader(Filename, Readers, Input, Obj.getFileFormatName())) 228 return Err; 229 continue; 230 } else 231 consumeError(MachOOrErr.takeError()); 232 if (Expected<std::unique_ptr<Archive>> ArchiveOrErr = 233 ObjForArch.getAsArchive()) { 234 if (Error Err = handleArchive(Readers, ObjName, *ArchiveOrErr.get())) 235 return Err; 236 continue; 237 } else 238 consumeError(ArchiveOrErr.takeError()); 239 } 240 return Error::success(); 241 } 242 243 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename, 244 Binary &Binary) { 245 if (PdbOrObj Input = dyn_cast<ObjectFile>(&Binary)) 246 return createReader(Filename, Readers, Input, 247 cast<ObjectFile *>(Input)->getFileFormatName()); 248 249 if (MachOUniversalBinary *Fat = dyn_cast<MachOUniversalBinary>(&Binary)) 250 return handleMach(Readers, Filename, *Fat); 251 252 if (Archive *Arch = dyn_cast<Archive>(&Binary)) 253 return handleArchive(Readers, Filename, *Arch); 254 255 return createStringError(errc::not_supported, 256 "Binary object format in '%s' is not supported.", 257 Filename.str().c_str()); 258 } 259 260 Error LVReaderHandler::handleObject(LVReaders &Readers, StringRef Filename, 261 StringRef Buffer, StringRef ExePath) { 262 std::unique_ptr<IPDBSession> Session; 263 if (Error Err = loadDataForPDB(PDB_ReaderType::Native, Filename, Session)) 264 return createStringError(errorToErrorCode(std::move(Err)), "%s", 265 Filename.str().c_str()); 266 267 std::unique_ptr<NativeSession> PdbSession; 268 PdbSession.reset(static_cast<NativeSession *>(Session.release())); 269 PdbOrObj Input = &PdbSession->getPDBFile(); 270 StringRef FileFormatName; 271 size_t Pos = Buffer.find_first_of("\r\n"); 272 if (Pos) 273 FileFormatName = Buffer.substr(0, Pos - 1); 274 return createReader(Filename, Readers, Input, FileFormatName, ExePath); 275 } 276 277 Error LVReaderHandler::createReaders() { 278 LLVM_DEBUG(dbgs() << "createReaders\n"); 279 for (std::string &Object : Objects) { 280 LVReaders Readers; 281 if (Error Err = createReader(Object, Readers)) 282 return Err; 283 TheReaders.insert(TheReaders.end(), 284 std::make_move_iterator(Readers.begin()), 285 std::make_move_iterator(Readers.end())); 286 } 287 288 return Error::success(); 289 } 290 291 Error LVReaderHandler::printReaders() { 292 LLVM_DEBUG(dbgs() << "printReaders\n"); 293 if (options().getPrintExecute()) 294 for (const std::unique_ptr<LVReader> &Reader : TheReaders) 295 if (Error Err = Reader->doPrint()) 296 return Err; 297 298 return Error::success(); 299 } 300 301 Error LVReaderHandler::compareReaders() { 302 LLVM_DEBUG(dbgs() << "compareReaders\n"); 303 size_t ReadersCount = TheReaders.size(); 304 if (options().getCompareExecute() && ReadersCount >= 2) { 305 // If we have more than 2 readers, compare them by pairs. 306 size_t ViewPairs = ReadersCount / 2; 307 LVCompare Compare(OS); 308 for (size_t Pair = 0, Index = 0; Pair < ViewPairs; ++Pair) { 309 if (Error Err = Compare.execute(TheReaders[Index].get(), 310 TheReaders[Index + 1].get())) 311 return Err; 312 Index += 2; 313 } 314 } 315 316 return Error::success(); 317 } 318 319 void LVReaderHandler::print(raw_ostream &OS) const { OS << "ReaderHandler\n"; } 320