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