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