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 21 using namespace llvm; 22 using 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. 29 bool 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 //===----------------------------------------------------------------------===// 113 Error 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 132 std::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 153 LVReader *CurrentReader = nullptr; 154 LVReader &LVReader::getInstance() { 155 if (CurrentReader) 156 return *CurrentReader; 157 outs() << "Invalid instance reader.\n"; 158 llvm_unreachable("Invalid instance reader."); 159 } 160 void LVReader::setInstance(LVReader *Reader) { CurrentReader = Reader; } 161 162 Error 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. 184 StringRef LVReader::getFilename(LVObject *Object, size_t Index) const { 185 if (CompileUnits.size()) { 186 // Get Compile Unit for the given object. 187 LVCompileUnits::const_iterator Iter = 188 std::prev(CompileUnits.lower_bound(Object->getOffset())); 189 if (Iter != CompileUnits.end()) 190 return Iter->second->getFilename(Index); 191 } 192 193 return CompileUnit ? CompileUnit->getFilename(Index) : StringRef(); 194 } 195 196 // The Reader is the module that creates the logical view using the debug 197 // information contained in the binary file specified in the command line. 198 // This is the main entry point for the Reader and performs the following 199 // steps: 200 // - Process any patterns collected from the '--select' options. 201 // - For each compile unit in the debug information: 202 // * Create the logical elements (scopes, symbols, types, lines). 203 // * Collect debug ranges and debug locations. 204 // * Move the collected logical lines to their associated scopes. 205 // - Once all the compile units have been processed, traverse the scopes 206 // tree in order to: 207 // * Calculate symbol coverage. 208 // * Detect invalid ranges and locations. 209 // * "resolve" the logical elements. During this pass, the names and 210 // file information are updated, to reflect any dependency with other 211 // logical elements. 212 Error LVReader::doLoad() { 213 // Set current Reader instance. 214 setInstance(this); 215 216 // Before any scopes creation, process any pattern specified by the 217 // --select and --select-offsets options. 218 patterns().addGenericPatterns(options().Select.Generic); 219 patterns().addOffsetPatterns(options().Select.Offsets); 220 221 // Add any specific element printing requests based on the element kind. 222 patterns().addRequest(options().Select.Elements); 223 patterns().addRequest(options().Select.Lines); 224 patterns().addRequest(options().Select.Scopes); 225 patterns().addRequest(options().Select.Symbols); 226 patterns().addRequest(options().Select.Types); 227 228 // Once we have processed the requests for any particular kind of elements, 229 // we need to update the report options, in order to have a default value. 230 patterns().updateReportOptions(); 231 232 // Delegate the scope tree creation to the specific reader. 233 if (Error Err = createScopes()) 234 return Err; 235 236 if (options().getInternalIntegrity() && !checkIntegrityScopesTree(Root)) 237 return llvm::make_error<StringError>("Duplicated elements in Scopes Tree", 238 inconvertibleErrorCode()); 239 240 // Calculate symbol coverage and detect invalid debug locations and ranges. 241 Root->processRangeInformation(); 242 243 // As the elements can depend on elements from a different compile unit, 244 // information such as name and file/line source information needs to be 245 // updated. 246 Root->resolveElements(); 247 248 sortScopes(); 249 return Error::success(); 250 } 251 252 // Default handler for a generic reader. 253 Error LVReader::doPrint() { 254 // Set current Reader instance. 255 setInstance(this); 256 257 // Check for any '--report' request. 258 if (options().getReportExecute()) { 259 // Requested details. 260 if (options().getReportList()) 261 if (Error Err = printMatchedElements(/*UseMatchedElements=*/true)) 262 return Err; 263 // Requested only children. 264 if (options().getReportChildren() && !options().getReportParents()) 265 if (Error Err = printMatchedElements(/*UseMatchedElements=*/false)) 266 return Err; 267 // Requested (parents) or (parents and children). 268 if (options().getReportParents() || options().getReportView()) 269 if (Error Err = printScopes()) 270 return Err; 271 272 return Error::success(); 273 } 274 275 return printScopes(); 276 } 277 278 Error LVReader::printScopes() { 279 if (bool DoPrint = 280 (options().getPrintExecute() || options().getComparePrint())) { 281 if (Error Err = createSplitFolder()) 282 return Err; 283 284 // Start printing from the root. 285 bool DoMatch = options().getSelectGenericPattern() || 286 options().getSelectGenericKind() || 287 options().getSelectOffsetPattern(); 288 return Root->doPrint(OutputSplit, DoMatch, DoPrint, OS); 289 } 290 291 return Error::success(); 292 } 293 294 Error LVReader::printMatchedElements(bool UseMatchedElements) { 295 if (Error Err = createSplitFolder()) 296 return Err; 297 298 return Root->doPrintMatches(OutputSplit, OS, UseMatchedElements); 299 } 300 301 void LVReader::print(raw_ostream &OS) const { 302 OS << "LVReader\n"; 303 LLVM_DEBUG(dbgs() << "PrintReader\n"); 304 } 305