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