1e28b9357SCarlos Alberto Enciso //===-- LVReader.cpp ------------------------------------------------------===// 2e28b9357SCarlos Alberto Enciso // 3e28b9357SCarlos Alberto Enciso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e28b9357SCarlos Alberto Enciso // See https://llvm.org/LICENSE.txt for license information. 5e28b9357SCarlos Alberto Enciso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e28b9357SCarlos Alberto Enciso // 7e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===// 8e28b9357SCarlos Alberto Enciso // 9e28b9357SCarlos Alberto Enciso // This implements the LVReader class. 10e28b9357SCarlos Alberto Enciso // 11e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===// 12e28b9357SCarlos Alberto Enciso 13e28b9357SCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVReader.h" 14e28b9357SCarlos Alberto Enciso #include "llvm/DebugInfo/LogicalView/Core/LVScope.h" 15e28b9357SCarlos Alberto Enciso #include "llvm/Support/FileSystem.h" 16e28b9357SCarlos Alberto Enciso #include "llvm/Support/FormatAdapters.h" 17e28b9357SCarlos Alberto Enciso #include "llvm/Support/FormatVariadic.h" 18e28b9357SCarlos Alberto Enciso #include <tuple> 19e28b9357SCarlos Alberto Enciso 20e28b9357SCarlos Alberto Enciso using namespace llvm; 21e28b9357SCarlos Alberto Enciso using namespace llvm::logicalview; 22e28b9357SCarlos Alberto Enciso 23e28b9357SCarlos Alberto Enciso #define DEBUG_TYPE "Reader" 24e28b9357SCarlos Alberto Enciso 252c155d37SCarlos Alberto Enciso // Detect elements that are inserted more than once at different scopes, 262c155d37SCarlos Alberto Enciso // causing a crash on the reader destruction, as the element is already 272c155d37SCarlos Alberto Enciso // deleted from other scope. Helper for CodeView reader. 282c155d37SCarlos Alberto Enciso bool checkIntegrityScopesTree(LVScope *Root) { 292c155d37SCarlos Alberto Enciso using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>; 302c155d37SCarlos Alberto Enciso using LVDuplicate = std::vector<LVDuplicateEntry>; 312c155d37SCarlos Alberto Enciso LVDuplicate Duplicate; 322c155d37SCarlos Alberto Enciso 332c155d37SCarlos Alberto Enciso using LVIntegrity = std::map<LVElement *, LVScope *>; 342c155d37SCarlos Alberto Enciso LVIntegrity Integrity; 352c155d37SCarlos Alberto Enciso 362c155d37SCarlos Alberto Enciso // Add the given element to the integrity map. 372c155d37SCarlos Alberto Enciso auto AddElement = [&](LVElement *Element, LVScope *Scope) { 382c155d37SCarlos Alberto Enciso LVIntegrity::iterator Iter = Integrity.find(Element); 392c155d37SCarlos Alberto Enciso if (Iter == Integrity.end()) 402c155d37SCarlos Alberto Enciso Integrity.emplace(Element, Scope); 412c155d37SCarlos Alberto Enciso else 422c155d37SCarlos Alberto Enciso // We found a duplicate. 432c155d37SCarlos Alberto Enciso Duplicate.emplace_back(Element, Scope, Iter->second); 442c155d37SCarlos Alberto Enciso }; 452c155d37SCarlos Alberto Enciso 462c155d37SCarlos Alberto Enciso // Recursively add all the elements in the scope. 472c155d37SCarlos Alberto Enciso std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) { 482c155d37SCarlos Alberto Enciso auto Traverse = [&](const auto *Set) { 492c155d37SCarlos Alberto Enciso if (Set) 502c155d37SCarlos Alberto Enciso for (const auto &Entry : *Set) 512c155d37SCarlos Alberto Enciso AddElement(Entry, Parent); 522c155d37SCarlos Alberto Enciso }; 532c155d37SCarlos Alberto Enciso if (const LVScopes *Scopes = Parent->getScopes()) { 542c155d37SCarlos Alberto Enciso for (LVScope *Scope : *Scopes) { 552c155d37SCarlos Alberto Enciso AddElement(Scope, Parent); 562c155d37SCarlos Alberto Enciso TraverseScope(Scope); 572c155d37SCarlos Alberto Enciso } 582c155d37SCarlos Alberto Enciso } 592c155d37SCarlos Alberto Enciso Traverse(Parent->getSymbols()); 602c155d37SCarlos Alberto Enciso Traverse(Parent->getTypes()); 612c155d37SCarlos Alberto Enciso Traverse(Parent->getLines()); 622c155d37SCarlos Alberto Enciso }; 632c155d37SCarlos Alberto Enciso 642c155d37SCarlos Alberto Enciso // Start traversing the scopes root and print any duplicates. 652c155d37SCarlos Alberto Enciso TraverseScope(Root); 662c155d37SCarlos Alberto Enciso bool PassIntegrity = true; 672c155d37SCarlos Alberto Enciso if (Duplicate.size()) { 682c155d37SCarlos Alberto Enciso std::stable_sort(begin(Duplicate), end(Duplicate), 692c155d37SCarlos Alberto Enciso [](const auto &l, const auto &r) { 702c155d37SCarlos Alberto Enciso return std::get<0>(l)->getID() < std::get<0>(r)->getID(); 712c155d37SCarlos Alberto Enciso }); 722c155d37SCarlos Alberto Enciso 732c155d37SCarlos Alberto Enciso auto PrintIndex = [](unsigned Index) { 742c155d37SCarlos Alberto Enciso if (Index) 752c155d37SCarlos Alberto Enciso dbgs() << format("%8d: ", Index); 762c155d37SCarlos Alberto Enciso else 772c155d37SCarlos Alberto Enciso dbgs() << format("%8c: ", ' '); 782c155d37SCarlos Alberto Enciso }; 792c155d37SCarlos Alberto Enciso auto PrintElement = [&](LVElement *Element, unsigned Index = 0) { 802c155d37SCarlos Alberto Enciso PrintIndex(Index); 812c155d37SCarlos Alberto Enciso std::string ElementName(Element->getName()); 822c155d37SCarlos Alberto Enciso dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(), 832c155d37SCarlos Alberto Enciso Element->getID(), ElementName.c_str()); 842c155d37SCarlos Alberto Enciso }; 852c155d37SCarlos Alberto Enciso 862c155d37SCarlos Alberto Enciso std::string RootName(Root->getName()); 872c155d37SCarlos Alberto Enciso dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); 882c155d37SCarlos Alberto Enciso dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(), 892c155d37SCarlos Alberto Enciso Duplicate.size()); 902c155d37SCarlos Alberto Enciso dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); 912c155d37SCarlos Alberto Enciso 922c155d37SCarlos Alberto Enciso unsigned Index = 0; 932c155d37SCarlos Alberto Enciso for (const LVDuplicateEntry &Entry : Duplicate) { 942c155d37SCarlos Alberto Enciso LVElement *Element; 952c155d37SCarlos Alberto Enciso LVScope *First; 962c155d37SCarlos Alberto Enciso LVScope *Second; 972c155d37SCarlos Alberto Enciso std::tie(Element, First, Second) = Entry; 982c155d37SCarlos Alberto Enciso dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72)); 992c155d37SCarlos Alberto Enciso PrintElement(Element, ++Index); 1002c155d37SCarlos Alberto Enciso PrintElement(First); 1012c155d37SCarlos Alberto Enciso PrintElement(Second); 1022c155d37SCarlos Alberto Enciso dbgs() << formatv("{0}\n", fmt_repeat('-', 72)); 1032c155d37SCarlos Alberto Enciso } 1042c155d37SCarlos Alberto Enciso PassIntegrity = false; 1052c155d37SCarlos Alberto Enciso } 1062c155d37SCarlos Alberto Enciso return PassIntegrity; 1072c155d37SCarlos Alberto Enciso } 1082c155d37SCarlos Alberto Enciso 109e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===// 110e28b9357SCarlos Alberto Enciso // Class to represent a split context. 111e28b9357SCarlos Alberto Enciso //===----------------------------------------------------------------------===// 112e28b9357SCarlos Alberto Enciso Error LVSplitContext::createSplitFolder(StringRef Where) { 113e28b9357SCarlos Alberto Enciso // The 'location' will represent the root directory for the output created 114e28b9357SCarlos Alberto Enciso // by the context. It will contain the different CUs files, that will be 115e28b9357SCarlos Alberto Enciso // extracted from a single ELF. 116e28b9357SCarlos Alberto Enciso Location = std::string(Where); 117e28b9357SCarlos Alberto Enciso 118e28b9357SCarlos Alberto Enciso // Add a trailing slash, if there is none. 119e28b9357SCarlos Alberto Enciso size_t Pos = Location.find_last_of('/'); 120e28b9357SCarlos Alberto Enciso if (Location.length() != Pos + 1) 121e28b9357SCarlos Alberto Enciso Location.append("/"); 122e28b9357SCarlos Alberto Enciso 123e28b9357SCarlos Alberto Enciso // Make sure the new directory exists, creating it if necessary. 124e28b9357SCarlos Alberto Enciso if (std::error_code EC = llvm::sys::fs::create_directories(Location)) 125e28b9357SCarlos Alberto Enciso return createStringError(EC, "Error: could not create directory %s", 126e28b9357SCarlos Alberto Enciso Location.c_str()); 127e28b9357SCarlos Alberto Enciso 128e28b9357SCarlos Alberto Enciso return Error::success(); 129e28b9357SCarlos Alberto Enciso } 130e28b9357SCarlos Alberto Enciso 131e28b9357SCarlos Alberto Enciso std::error_code LVSplitContext::open(std::string ContextName, 132e28b9357SCarlos Alberto Enciso std::string Extension, raw_ostream &OS) { 133e28b9357SCarlos Alberto Enciso assert(OutputFile == nullptr && "OutputFile already set."); 134e28b9357SCarlos Alberto Enciso 135e28b9357SCarlos Alberto Enciso // Transforms '/', '\', '.', ':' into '_'. 136e28b9357SCarlos Alberto Enciso std::string Name(flattenedFilePath(ContextName)); 137e28b9357SCarlos Alberto Enciso Name.append(Extension); 138e28b9357SCarlos Alberto Enciso // Add the split context location folder name. 139e28b9357SCarlos Alberto Enciso if (!Location.empty()) 140e28b9357SCarlos Alberto Enciso Name.insert(0, Location); 141e28b9357SCarlos Alberto Enciso 142e28b9357SCarlos Alberto Enciso std::error_code EC; 143e28b9357SCarlos Alberto Enciso OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None); 144e28b9357SCarlos Alberto Enciso if (EC) 145e28b9357SCarlos Alberto Enciso return EC; 146e28b9357SCarlos Alberto Enciso 147e28b9357SCarlos Alberto Enciso // Don't remove output file. 148e28b9357SCarlos Alberto Enciso OutputFile->keep(); 149e28b9357SCarlos Alberto Enciso return std::error_code(); 150e28b9357SCarlos Alberto Enciso } 151e28b9357SCarlos Alberto Enciso 152e28b9357SCarlos Alberto Enciso LVReader *CurrentReader = nullptr; 153e28b9357SCarlos Alberto Enciso LVReader &LVReader::getInstance() { 154e28b9357SCarlos Alberto Enciso if (CurrentReader) 155e28b9357SCarlos Alberto Enciso return *CurrentReader; 156e28b9357SCarlos Alberto Enciso outs() << "Invalid instance reader.\n"; 157e28b9357SCarlos Alberto Enciso llvm_unreachable("Invalid instance reader."); 158e28b9357SCarlos Alberto Enciso } 159e28b9357SCarlos Alberto Enciso void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; } 160e28b9357SCarlos Alberto Enciso 161e28b9357SCarlos Alberto Enciso Error LVReader::createSplitFolder() { 162e28b9357SCarlos Alberto Enciso if (OutputSplit) { 163e28b9357SCarlos Alberto Enciso // If the '--output=split' was specified, but no '--split-folder' 164e28b9357SCarlos Alberto Enciso // option, use the input file as base for the split location. 165e28b9357SCarlos Alberto Enciso if (options().getOutputFolder().empty()) 166e28b9357SCarlos Alberto Enciso options().setOutputFolder(getFilename().str() + "_cus"); 167e28b9357SCarlos Alberto Enciso 168e28b9357SCarlos Alberto Enciso SmallString<128> SplitFolder; 169e28b9357SCarlos Alberto Enciso SplitFolder = options().getOutputFolder(); 170e28b9357SCarlos Alberto Enciso sys::fs::make_absolute(SplitFolder); 171e28b9357SCarlos Alberto Enciso 172e28b9357SCarlos Alberto Enciso // Return error if unable to create a split context location. 173e28b9357SCarlos Alberto Enciso if (Error Err = SplitContext.createSplitFolder(SplitFolder)) 174e28b9357SCarlos Alberto Enciso return Err; 175e28b9357SCarlos Alberto Enciso 176e28b9357SCarlos Alberto Enciso OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n"; 177e28b9357SCarlos Alberto Enciso } 178e28b9357SCarlos Alberto Enciso 179e28b9357SCarlos Alberto Enciso return Error::success(); 180e28b9357SCarlos Alberto Enciso } 181e28b9357SCarlos Alberto Enciso 182e28b9357SCarlos Alberto Enciso // Get the filename for given object. 183e28b9357SCarlos Alberto Enciso StringRef LVReader::getFilename(LVObject *Object, size_t Index) const { 184*e7950fceSCarlos Alberto Enciso // TODO: The current CodeView Reader implementation does not have support 185*e7950fceSCarlos Alberto Enciso // for multiple compile units. Until we have a proper offset calculation, 186*e7950fceSCarlos Alberto Enciso // check only in the current compile unit. 187e28b9357SCarlos Alberto Enciso if (CompileUnits.size()) { 188e28b9357SCarlos Alberto Enciso // Get Compile Unit for the given object. 189e28b9357SCarlos Alberto Enciso LVCompileUnits::const_iterator Iter = 190e28b9357SCarlos Alberto Enciso std::prev(CompileUnits.lower_bound(Object->getOffset())); 191e28b9357SCarlos Alberto Enciso if (Iter != CompileUnits.end()) 192e28b9357SCarlos Alberto Enciso return Iter->second->getFilename(Index); 193e28b9357SCarlos Alberto Enciso } 194e28b9357SCarlos Alberto Enciso 195e28b9357SCarlos Alberto Enciso return CompileUnit ? CompileUnit->getFilename(Index) : StringRef(); 196e28b9357SCarlos Alberto Enciso } 197e28b9357SCarlos Alberto Enciso 198e28b9357SCarlos Alberto Enciso // The Reader is the module that creates the logical view using the debug 199e28b9357SCarlos Alberto Enciso // information contained in the binary file specified in the command line. 200e28b9357SCarlos Alberto Enciso // This is the main entry point for the Reader and performs the following 201e28b9357SCarlos Alberto Enciso // steps: 202e28b9357SCarlos Alberto Enciso // - Process any patterns collected from the '--select' options. 203e28b9357SCarlos Alberto Enciso // - For each compile unit in the debug information: 204e28b9357SCarlos Alberto Enciso // * Create the logical elements (scopes, symbols, types, lines). 205e28b9357SCarlos Alberto Enciso // * Collect debug ranges and debug locations. 206e28b9357SCarlos Alberto Enciso // * Move the collected logical lines to their associated scopes. 207e28b9357SCarlos Alberto Enciso // - Once all the compile units have been processed, traverse the scopes 208e28b9357SCarlos Alberto Enciso // tree in order to: 209e28b9357SCarlos Alberto Enciso // * Calculate symbol coverage. 210e28b9357SCarlos Alberto Enciso // * Detect invalid ranges and locations. 211e28b9357SCarlos Alberto Enciso // * "resolve" the logical elements. During this pass, the names and 212e28b9357SCarlos Alberto Enciso // file information are updated, to reflect any dependency with other 213e28b9357SCarlos Alberto Enciso // logical elements. 214e28b9357SCarlos Alberto Enciso Error LVReader::doLoad() { 215e28b9357SCarlos Alberto Enciso // Set current Reader instance. 216e28b9357SCarlos Alberto Enciso setInstance(this); 217e28b9357SCarlos Alberto Enciso 2180332a8e7SCarlos Alberto Enciso // Before any scopes creation, process any pattern specified by the 2190332a8e7SCarlos Alberto Enciso // --select and --select-offsets options. 2200332a8e7SCarlos Alberto Enciso patterns().addGenericPatterns(options().Select.Generic); 2210332a8e7SCarlos Alberto Enciso patterns().addOffsetPatterns(options().Select.Offsets); 2220332a8e7SCarlos Alberto Enciso 2230332a8e7SCarlos Alberto Enciso // Add any specific element printing requests based on the element kind. 2240332a8e7SCarlos Alberto Enciso patterns().addRequest(options().Select.Elements); 2250332a8e7SCarlos Alberto Enciso patterns().addRequest(options().Select.Lines); 2260332a8e7SCarlos Alberto Enciso patterns().addRequest(options().Select.Scopes); 2270332a8e7SCarlos Alberto Enciso patterns().addRequest(options().Select.Symbols); 2280332a8e7SCarlos Alberto Enciso patterns().addRequest(options().Select.Types); 2290332a8e7SCarlos Alberto Enciso 2300332a8e7SCarlos Alberto Enciso // Once we have processed the requests for any particular kind of elements, 2310332a8e7SCarlos Alberto Enciso // we need to update the report options, in order to have a default value. 2320332a8e7SCarlos Alberto Enciso patterns().updateReportOptions(); 2330332a8e7SCarlos Alberto Enciso 234e28b9357SCarlos Alberto Enciso // Delegate the scope tree creation to the specific reader. 235e28b9357SCarlos Alberto Enciso if (Error Err = createScopes()) 236e28b9357SCarlos Alberto Enciso return Err; 237e28b9357SCarlos Alberto Enciso 2382c155d37SCarlos Alberto Enciso if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root)) 2392c155d37SCarlos Alberto Enciso return llvm::make_error<StringError>("Duplicated elements in Scopes Tree", 2402c155d37SCarlos Alberto Enciso inconvertibleErrorCode()); 2412c155d37SCarlos Alberto Enciso 2423c397c90SCarlos Alberto Enciso // Calculate symbol coverage and detect invalid debug locations and ranges. 2433c397c90SCarlos Alberto Enciso Root->processRangeInformation(); 2443c397c90SCarlos Alberto Enciso 245e28b9357SCarlos Alberto Enciso // As the elements can depend on elements from a different compile unit, 246e28b9357SCarlos Alberto Enciso // information such as name and file/line source information needs to be 247e28b9357SCarlos Alberto Enciso // updated. 248e28b9357SCarlos Alberto Enciso Root->resolveElements(); 249e28b9357SCarlos Alberto Enciso 250e28b9357SCarlos Alberto Enciso sortScopes(); 251e28b9357SCarlos Alberto Enciso return Error::success(); 252e28b9357SCarlos Alberto Enciso } 253e28b9357SCarlos Alberto Enciso 254e28b9357SCarlos Alberto Enciso // Default handler for a generic reader. 255e28b9357SCarlos Alberto Enciso Error LVReader::doPrint() { 256e28b9357SCarlos Alberto Enciso // Set current Reader instance. 257e28b9357SCarlos Alberto Enciso setInstance(this); 258e28b9357SCarlos Alberto Enciso 2590332a8e7SCarlos Alberto Enciso // Check for any '--report' request. 2600332a8e7SCarlos Alberto Enciso if (options().getReportExecute()) { 2610332a8e7SCarlos Alberto Enciso // Requested details. 2620332a8e7SCarlos Alberto Enciso if (options().getReportList()) 2630332a8e7SCarlos Alberto Enciso if (Error Err = printMatchedElements(/*UseMatchedElements=*/true)) 2640332a8e7SCarlos Alberto Enciso return Err; 2650332a8e7SCarlos Alberto Enciso // Requested only children. 2660332a8e7SCarlos Alberto Enciso if (options().getReportChildren() && !options().getReportParents()) 2670332a8e7SCarlos Alberto Enciso if (Error Err = printMatchedElements(/*UseMatchedElements=*/false)) 2680332a8e7SCarlos Alberto Enciso return Err; 2690332a8e7SCarlos Alberto Enciso // Requested (parents) or (parents and children). 2700332a8e7SCarlos Alberto Enciso if (options().getReportParents() || options().getReportView()) 2710332a8e7SCarlos Alberto Enciso if (Error Err = printScopes()) 2720332a8e7SCarlos Alberto Enciso return Err; 2730332a8e7SCarlos Alberto Enciso 2740332a8e7SCarlos Alberto Enciso return Error::success(); 2750332a8e7SCarlos Alberto Enciso } 2760332a8e7SCarlos Alberto Enciso 277e28b9357SCarlos Alberto Enciso return printScopes(); 278e28b9357SCarlos Alberto Enciso } 279e28b9357SCarlos Alberto Enciso 280e28b9357SCarlos Alberto Enciso Error LVReader::printScopes() { 281e98a4c5aSCarlos Alberto Enciso if (bool DoPrint = 282e98a4c5aSCarlos Alberto Enciso (options().getPrintExecute() || options().getComparePrint())) { 283e28b9357SCarlos Alberto Enciso if (Error Err = createSplitFolder()) 284e28b9357SCarlos Alberto Enciso return Err; 285e28b9357SCarlos Alberto Enciso 286e28b9357SCarlos Alberto Enciso // Start printing from the root. 2870332a8e7SCarlos Alberto Enciso bool DoMatch = options().getSelectGenericPattern() || 2880332a8e7SCarlos Alberto Enciso options().getSelectGenericKind() || 2890332a8e7SCarlos Alberto Enciso options().getSelectOffsetPattern(); 290e28b9357SCarlos Alberto Enciso return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS); 291e28b9357SCarlos Alberto Enciso } 292e28b9357SCarlos Alberto Enciso 293e28b9357SCarlos Alberto Enciso return Error::success(); 294e28b9357SCarlos Alberto Enciso } 295e28b9357SCarlos Alberto Enciso 296e28b9357SCarlos Alberto Enciso Error LVReader::printMatchedElements(bool UseMatchedElements) { 297e28b9357SCarlos Alberto Enciso if (Error Err = createSplitFolder()) 298e28b9357SCarlos Alberto Enciso return Err; 299e28b9357SCarlos Alberto Enciso 300e28b9357SCarlos Alberto Enciso return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements); 301e28b9357SCarlos Alberto Enciso } 302e28b9357SCarlos Alberto Enciso 303e28b9357SCarlos Alberto Enciso void LVReader::print(raw_ostream &OS) const { 304e28b9357SCarlos Alberto Enciso OS << "LVReader\n"; 305e28b9357SCarlos Alberto Enciso LLVM_DEBUG(dbgs() << "PrintReader\n"); 306e28b9357SCarlos Alberto Enciso } 307