1//===-- LVReader.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 LVReader class. 10// 11//===----------------------------------------------------------------------===// 12 13#include "llvm/DebugInfo/LogicalView/Core/LVReader.h" 14#include "llvm/DebugInfo/LogicalView/Core/LVLine.h" 15#include "llvm/DebugInfo/LogicalView/Core/LVScope.h" 16#include "llvm/Support/FileSystem.h" 17#include "llvm/Support/FormatAdapters.h" 18#include "llvm/Support/FormatVariadic.h" 19#include <tuple> 20 21using namespace llvm; 22using namespace llvm::logicalview; 23 24#define DEBUG_TYPE "Reader" 25 26// Detect elements that are inserted more than once at different scopes, 27// causing a crash on the reader destruction, as the element is already 28// deleted from other scope. Helper for CodeView reader. 29bool checkIntegrityScopesTree(LVScope *Root) { 30 using LVDuplicateEntry = std::tuple<LVElement *, LVScope *, LVScope *>; 31 using LVDuplicate = std::vector<LVDuplicateEntry>; 32 LVDuplicate Duplicate; 33 34 using LVIntegrity = std::map<LVElement *, LVScope *>; 35 LVIntegrity Integrity; 36 37 // Add the given element to the integrity map. 38 auto AddElement = [&](LVElement *Element, LVScope *Scope) { 39 LVIntegrity::iterator Iter = Integrity.find(Element); 40 if (Iter == Integrity.end()) 41 Integrity.emplace(Element, Scope); 42 else 43 // We found a duplicate. 44 Duplicate.emplace_back(Element, Scope, Iter->second); 45 }; 46 47 // Recursively add all the elements in the scope. 48 std::function<void(LVScope * Parent)> TraverseScope = [&](LVScope *Parent) { 49 auto Traverse = [&](const auto *Set) { 50 if (Set) 51 for (const auto &Entry : *Set) 52 AddElement(Entry, Parent); 53 }; 54 if (const LVScopes *Scopes = Parent->getScopes()) { 55 for (LVScope *Scope : *Scopes) { 56 AddElement(Scope, Parent); 57 TraverseScope(Scope); 58 } 59 } 60 Traverse(Parent->getSymbols()); 61 Traverse(Parent->getTypes()); 62 Traverse(Parent->getLines()); 63 }; 64 65 // Start traversing the scopes root and print any duplicates. 66 TraverseScope(Root); 67 bool PassIntegrity = true; 68 if (Duplicate.size()) { 69 std::stable_sort(begin(Duplicate), end(Duplicate), 70 [](const auto &l, const auto &r) { 71 return std::get<0>(l)->getID() < std::get<0>(r)->getID(); 72 }); 73 74 auto PrintIndex = [](unsigned Index) { 75 if (Index) 76 dbgs() << format("%8d: ", Index); 77 else 78 dbgs() << format("%8c: ", ' '); 79 }; 80 auto PrintElement = [&](LVElement *Element, unsigned Index = 0) { 81 PrintIndex(Index); 82 std::string ElementName(Element->getName()); 83 dbgs() << format("%15s ID=0x%08x '%s'\n", Element->kind(), 84 Element->getID(), ElementName.c_str()); 85 }; 86 87 std::string RootName(Root->getName()); 88 dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); 89 dbgs() << format("Root: '%s'\nDuplicated elements: %d\n", RootName.c_str(), 90 Duplicate.size()); 91 dbgs() << formatv("{0}\n", fmt_repeat('=', 72)); 92 93 unsigned Index = 0; 94 for (const LVDuplicateEntry &Entry : Duplicate) { 95 LVElement *Element; 96 LVScope *First; 97 LVScope *Second; 98 std::tie(Element, First, Second) = Entry; 99 dbgs() << formatv("\n{0}\n", fmt_repeat('-', 72)); 100 PrintElement(Element, ++Index); 101 PrintElement(First); 102 PrintElement(Second); 103 dbgs() << formatv("{0}\n", fmt_repeat('-', 72)); 104 } 105 PassIntegrity = false; 106 } 107 return PassIntegrity; 108} 109 110//===----------------------------------------------------------------------===// 111// Class to represent a split context. 112//===----------------------------------------------------------------------===// 113Error LVSplitContext::createSplitFolder(StringRef Where) { 114 // The 'location' will represent the root directory for the output created 115 // by the context. It will contain the different CUs files, that will be 116 // extracted from a single ELF. 117 Location = std::string(Where); 118 119 // Add a trailing slash, if there is none. 120 size_t Pos = Location.find_last_of('/'); 121 if (Location.length() != Pos + 1) 122 Location.append("/"); 123 124 // Make sure the new directory exists, creating it if necessary. 125 if (std::error_code EC = llvm::sys::fs::create_directories(Location)) 126 return createStringError(EC, "Error: could not create directory %s", 127 Location.c_str()); 128 129 return Error::success(); 130} 131 132std::error_code LVSplitContext::open(std::string ContextName, 133 std::string Extension, raw_ostream &OS) { 134 assert(OutputFile == nullptr && "OutputFile already set."); 135 136 // Transforms '/', '\', '.', ':' into '_'. 137 std::string Name(flattenedFilePath(ContextName)); 138 Name.append(Extension); 139 // Add the split context location folder name. 140 if (!Location.empty()) 141 Name.insert(0, Location); 142 143 std::error_code EC; 144 OutputFile = std::make_unique<ToolOutputFile>(Name, EC, sys::fs::OF_None); 145 if (EC) 146 return EC; 147 148 // Don't remove output file. 149 OutputFile->keep(); 150 return std::error_code(); 151} 152 153LVReader *CurrentReader = nullptr; 154LVReader &LVReader::getInstance() { 155 if (CurrentReader) 156 return *CurrentReader; 157 outs() << "Invalid instance reader.\n"; 158 llvm_unreachable("Invalid instance reader."); 159} 160void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; } 161 162Error LVReader::createSplitFolder() { 163 if (OutputSplit) { 164 // If the '--output=split' was specified, but no '--split-folder' 165 // option, use the input file as base for the split location. 166 if (options().getOutputFolder().empty()) 167 options().setOutputFolder(getFilename().str() + "_cus"); 168 169 SmallString<128> SplitFolder; 170 SplitFolder = options().getOutputFolder(); 171 sys::fs::make_absolute(SplitFolder); 172 173 // Return error if unable to create a split context location. 174 if (Error Err = SplitContext.createSplitFolder(SplitFolder)) 175 return Err; 176 177 OS << "\nSplit View Location: '" << SplitContext.getLocation() << "'\n"; 178 } 179 180 return Error::success(); 181} 182 183// Get the filename for given object. 184StringRef LVReader::getFilename(LVObject *Object, size_t Index) const { 185 // TODO: The current CodeView Reader implementation does not have support 186 // for multiple compile units. Until we have a proper offset calculation, 187 // check only in the current compile unit. 188 if (CompileUnits.size()) { 189 // Get Compile Unit for the given object. 190 LVCompileUnits::const_iterator Iter = 191 std::prev(CompileUnits.lower_bound(Object->getOffset())); 192 if (Iter != CompileUnits.end()) 193 return Iter->second->getFilename(Index); 194 } 195 196 return CompileUnit ? CompileUnit->getFilename(Index) : StringRef(); 197} 198 199// The Reader is the module that creates the logical view using the debug 200// information contained in the binary file specified in the command line. 201// This is the main entry point for the Reader and performs the following 202// steps: 203// - Process any patterns collected from the '--select' options. 204// - For each compile unit in the debug information: 205// * Create the logical elements (scopes, symbols, types, lines). 206// * Collect debug ranges and debug locations. 207// * Move the collected logical lines to their associated scopes. 208// - Once all the compile units have been processed, traverse the scopes 209// tree in order to: 210// * Calculate symbol coverage. 211// * Detect invalid ranges and locations. 212// * "resolve" the logical elements. During this pass, the names and 213// file information are updated, to reflect any dependency with other 214// logical elements. 215Error LVReader::doLoad() { 216 // Set current Reader instance. 217 setInstance(this); 218 219 // Before any scopes creation, process any pattern specified by the 220 // --select and --select-offsets options. 221 patterns().addGenericPatterns(options().Select.Generic); 222 patterns().addOffsetPatterns(options().Select.Offsets); 223 224 // Add any specific element printing requests based on the element kind. 225 patterns().addRequest(options().Select.Elements); 226 patterns().addRequest(options().Select.Lines); 227 patterns().addRequest(options().Select.Scopes); 228 patterns().addRequest(options().Select.Symbols); 229 patterns().addRequest(options().Select.Types); 230 231 // Once we have processed the requests for any particular kind of elements, 232 // we need to update the report options, in order to have a default value. 233 patterns().updateReportOptions(); 234 235 // Delegate the scope tree creation to the specific reader. 236 if (Error Err = createScopes()) 237 return Err; 238 239 if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root)) 240 return llvm::make_error<StringError>("Duplicated elements in Scopes Tree", 241 inconvertibleErrorCode()); 242 243 // Calculate symbol coverage and detect invalid debug locations and ranges. 244 Root->processRangeInformation(); 245 246 // As the elements can depend on elements from a different compile unit, 247 // information such as name and file/line source information needs to be 248 // updated. 249 Root->resolveElements(); 250 251 sortScopes(); 252 return Error::success(); 253} 254 255// Default handler for a generic reader. 256Error LVReader::doPrint() { 257 // Set current Reader instance. 258 setInstance(this); 259 260 // Check for any '--report' request. 261 if (options().getReportExecute()) { 262 // Requested details. 263 if (options().getReportList()) 264 if (Error Err = printMatchedElements(/*UseMatchedElements=*/true)) 265 return Err; 266 // Requested only children. 267 if (options().getReportChildren() && !options().getReportParents()) 268 if (Error Err = printMatchedElements(/*UseMatchedElements=*/false)) 269 return Err; 270 // Requested (parents) or (parents and children). 271 if (options().getReportParents() || options().getReportView()) 272 if (Error Err = printScopes()) 273 return Err; 274 275 return Error::success(); 276 } 277 278 return printScopes(); 279} 280 281Error LVReader::printScopes() { 282 if (bool DoPrint = 283 (options().getPrintExecute() || options().getComparePrint())) { 284 if (Error Err = createSplitFolder()) 285 return Err; 286 287 // Start printing from the root. 288 bool DoMatch = options().getSelectGenericPattern() || 289 options().getSelectGenericKind() || 290 options().getSelectOffsetPattern(); 291 return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS); 292 } 293 294 return Error::success(); 295} 296 297Error LVReader::printMatchedElements(bool UseMatchedElements) { 298 if (Error Err = createSplitFolder()) 299 return Err; 300 301 return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements); 302} 303 304void LVReader::print(raw_ostream &OS) const { 305 OS << "LVReader\n"; 306 LLVM_DEBUG(dbgs() << "PrintReader\n"); 307} 308