std::string get_line_from_offset(StringRef buffer, std::size_t offset) { assert(buffer.size() > offset); auto line_start = buffer.find_last_of("\r\n", offset) + 1; auto line_end = buffer.find_first_of("\r\n", offset); return std::string(buffer.begin() + line_start, buffer.begin() + line_end); }
DeclNameViewer::DeclNameViewer(StringRef Text): IsValid(true), HasParen(false) { auto ArgStart = Text.find_first_of('('); if (ArgStart == StringRef::npos) { BaseName = Text; return; } HasParen = true; BaseName = Text.substr(0, ArgStart); auto ArgEnd = Text.find_last_of(')'); if (ArgEnd == StringRef::npos) { IsValid = false; return; } StringRef AllArgs = Text.substr(ArgStart + 1, ArgEnd - ArgStart - 1); AllArgs.split(Labels, ":"); if (Labels.empty()) return; if ((IsValid = Labels.back().empty())) { Labels.pop_back(); std::transform(Labels.begin(), Labels.end(), Labels.begin(), [](StringRef Label) { return Label == "_" ? StringRef() : Label; }); } }
/// \brief Parse \p Input as line sample. /// /// \param Input input line. /// \param IsCallsite true if the line represents an inlined callsite. /// \param Depth the depth of the inline stack. /// \param NumSamples total samples of the line/inlined callsite. /// \param LineOffset line offset to the start of the function. /// \param Discriminator discriminator of the line. /// \param TargetCountMap map from indirect call target to count. /// /// returns true if parsing is successful. static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth, unsigned &NumSamples, unsigned &LineOffset, unsigned &Discriminator, StringRef &CalleeName, DenseMap<StringRef, unsigned> &TargetCountMap) { for (Depth = 0; Input[Depth] == ' '; Depth++) ; if (Depth == 0) return false; size_t n1 = Input.find(':'); StringRef Loc = Input.substr(Depth, n1 - Depth); size_t n2 = Loc.find('.'); if (n2 == StringRef::npos) { if (Loc.getAsInteger(10, LineOffset)) return false; Discriminator = 0; } else { if (Loc.substr(0, n2).getAsInteger(10, LineOffset)) return false; if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator)) return false; } StringRef Rest = Input.substr(n1 + 2); if (Rest[0] >= '0' && Rest[0] <= '9') { IsCallsite = false; size_t n3 = Rest.find(' '); if (n3 == StringRef::npos) { if (Rest.getAsInteger(10, NumSamples)) return false; } else { if (Rest.substr(0, n3).getAsInteger(10, NumSamples)) return false; } while (n3 != StringRef::npos) { n3 += Rest.substr(n3).find_first_not_of(' '); Rest = Rest.substr(n3); n3 = Rest.find(' '); StringRef pair = Rest; if (n3 != StringRef::npos) { pair = Rest.substr(0, n3); } int n4 = pair.find(':'); unsigned count; if (pair.substr(n4 + 1).getAsInteger(10, count)) return false; TargetCountMap[pair.substr(0, n4)] = count; } } else { IsCallsite = true; int n3 = Rest.find_last_of(':'); CalleeName = Rest.substr(0, n3); if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples)) return false; } return true; }
std::string ModuleFile::Dependency::getPrettyPrintedPath() const { StringRef pathWithoutScope = RawPath; if (isScoped()) { size_t splitPoint = pathWithoutScope.find_last_of('\0'); pathWithoutScope = pathWithoutScope.slice(0, splitPoint); } std::string output = pathWithoutScope.str(); std::replace(output.begin(), output.end(), '\0', '.'); return output; }
StringRef extension(StringRef path, Style style) { StringRef fname = filename(path, style); size_t pos = fname.find_last_of('.'); if (pos == StringRef::npos) return StringRef(); else if ((fname.size() == 1 && fname == ".") || (fname.size() == 2 && fname == "..")) return StringRef(); else return fname.substr(pos); }
static unsigned getColumnNumber(StringRef buffer, llvm::SMLoc loc) { assert(loc.getPointer() >= buffer.data()); assert((size_t)(loc.getPointer() - buffer.data()) <= buffer.size()); StringRef UpToLoc = buffer.slice(0, loc.getPointer() - buffer.data()); size_t ColumnNo = UpToLoc.size(); size_t NewlinePos = UpToLoc.find_last_of("\r\n"); if (NewlinePos != StringRef::npos) ColumnNo -= NewlinePos; return static_cast<unsigned>(ColumnNo); }
bool Punycode::decodePunycode(StringRef InputPunycode, std::vector<uint32_t> &OutCodePoints) { OutCodePoints.clear(); OutCodePoints.reserve(InputPunycode.size()); // -- Build the decoded string as UTF32 first because we need random access. uint32_t n = initial_n; int i = 0; int bias = initial_bias; /// let output = an empty string indexed from 0 // consume all code points before the last delimiter (if there is one) // and copy them to output, size_t lastDelimiter = InputPunycode.find_last_of(delimiter); if (lastDelimiter != StringRef::npos) { for (char c : InputPunycode.slice(0, lastDelimiter)) { // fail on any non-basic code point if (static_cast<unsigned char>(c) > 0x7f) return true; OutCodePoints.push_back(c); } // if more than zero code points were consumed then consume one more // (which will be the last delimiter) InputPunycode = InputPunycode.slice(lastDelimiter + 1, InputPunycode.size()); } while (!InputPunycode.empty()) { int oldi = i; int w = 1; for (int k = base; ; k += base) { // consume a code point, or fail if there was none to consume if (InputPunycode.empty()) return true; char codePoint = InputPunycode.front(); InputPunycode = InputPunycode.slice(1, InputPunycode.size()); // let digit = the code point's digit-value, fail if it has none int digit = digit_index(codePoint); if (digit < 0) return true; i = i + digit * w; int t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias; if (digit < t) break; w = w * (base - t); } bias = adapt(i - oldi, OutCodePoints.size() + 1, oldi == 0); n = n + i / (OutCodePoints.size() + 1); i = i % (OutCodePoints.size() + 1); // if n is a basic code point then fail if (n < 0x80) return true; // insert n into output at position i OutCodePoints.insert(OutCodePoints.begin() + i, n); i++; } return true; }
Status ModuleFile::associateWithFileContext(FileUnit *file, SourceLoc diagLoc) { PrettyModuleFileDeserialization stackEntry(*this); assert(getStatus() == Status::Valid && "invalid module file"); assert(!FileContext && "already associated with an AST module"); FileContext = file; if (file->getParentModule()->getName().str() != Name) return error(Status::NameMismatch); ASTContext &ctx = getContext(); llvm::Triple moduleTarget(llvm::Triple::normalize(TargetTriple)); if (!areCompatibleArchitectures(moduleTarget, ctx.LangOpts.Target) || !areCompatibleOSs(moduleTarget, ctx.LangOpts.Target)) { return error(Status::TargetIncompatible); } if (ctx.LangOpts.EnableTargetOSChecking && isTargetTooNew(moduleTarget, ctx.LangOpts.Target)) { return error(Status::TargetTooNew); } for (const auto &searchPathPair : SearchPaths) ctx.addSearchPath(searchPathPair.first, searchPathPair.second); auto clangImporter = static_cast<ClangImporter *>(ctx.getClangModuleLoader()); bool missingDependency = false; for (auto &dependency : Dependencies) { assert(!dependency.isLoaded() && "already loaded?"); if (dependency.isHeader()) { // The path may be empty if the file being loaded is a partial AST, // and the current compiler invocation is a merge-modules step. if (!dependency.RawPath.empty()) { bool hadError = clangImporter->importHeader(dependency.RawPath, file->getParentModule(), importedHeaderInfo.fileSize, importedHeaderInfo.fileModTime, importedHeaderInfo.contents, diagLoc); if (hadError) return error(Status::FailedToLoadBridgingHeader); } Module *importedHeaderModule = clangImporter->getImportedHeaderModule(); dependency.Import = { {}, importedHeaderModule }; continue; } StringRef modulePathStr = dependency.RawPath; StringRef scopePath; if (dependency.isScoped()) { auto splitPoint = modulePathStr.find_last_of('\0'); assert(splitPoint != StringRef::npos); scopePath = modulePathStr.substr(splitPoint+1); modulePathStr = modulePathStr.slice(0, splitPoint); } SmallVector<Identifier, 4> modulePath; while (!modulePathStr.empty()) { StringRef nextComponent; std::tie(nextComponent, modulePathStr) = modulePathStr.split('\0'); modulePath.push_back(ctx.getIdentifier(nextComponent)); assert(!modulePath.back().empty() && "invalid module name (submodules not yet supported)"); } auto module = getModule(modulePath); if (!module) { // If we're missing the module we're shadowing, treat that specially. if (modulePath.size() == 1 && modulePath.front() == file->getParentModule()->getName()) { return error(Status::MissingShadowedModule); } // Otherwise, continue trying to load dependencies, so that we can list // everything that's missing. missingDependency = true; continue; } // This is for backwards-compatibility with modules that still rely on the // "HasUnderlyingModule" flag. if (Bits.HasUnderlyingModule && module == ShadowedModule) dependency.forceExported(); if (scopePath.empty()) { dependency.Import = { {}, module }; } else { auto scopeID = ctx.getIdentifier(scopePath); assert(!scopeID.empty() && "invalid decl name (non-top-level decls not supported)"); auto path = Module::AccessPathTy({scopeID, SourceLoc()}); dependency.Import = { ctx.AllocateCopy(path), module }; } } if (missingDependency) { return error(Status::MissingDependency); } if (Bits.HasEntryPoint) { FileContext->getParentModule()->registerEntryPointFile(FileContext, SourceLoc(), None); } return getStatus(); }
// Returns the last element of a path, which is supposed to be a filename. static StringRef getBasename(StringRef Path) { size_t Pos = Path.find_last_of("\\/"); if (Pos == StringRef::npos) return Path; return Path.substr(Pos + 1); }
void MCObjectDisassembler::buildCFG(MCModule *Module) { typedef std::map<uint64_t, BBInfo> BBInfoByAddrTy; BBInfoByAddrTy BBInfos; AddressSetTy Splits; AddressSetTy Calls; error_code ec; for (symbol_iterator SI = Obj.begin_symbols(), SE = Obj.end_symbols(); SI != SE; SI.increment(ec)) { if (ec) break; SymbolRef::Type SymType; SI->getType(SymType); if (SymType == SymbolRef::ST_Function) { uint64_t SymAddr; SI->getAddress(SymAddr); SymAddr = getEffectiveLoadAddr(SymAddr); Calls.push_back(SymAddr); Splits.push_back(SymAddr); } } assert(Module->func_begin() == Module->func_end() && "Module already has a CFG!"); // First, determine the basic block boundaries and call targets. for (MCModule::atom_iterator AI = Module->atom_begin(), AE = Module->atom_end(); AI != AE; ++AI) { MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI); if (!TA) continue; Calls.push_back(TA->getBeginAddr()); BBInfos[TA->getBeginAddr()].Atom = TA; for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end(); II != IE; ++II) { if (MIA.isTerminator(II->Inst)) Splits.push_back(II->Address + II->Size); uint64_t Target; if (MIA.evaluateBranch(II->Inst, II->Address, II->Size, Target)) { if (MIA.isCall(II->Inst)) Calls.push_back(Target); Splits.push_back(Target); } } } RemoveDupsFromAddressVector(Splits); RemoveDupsFromAddressVector(Calls); // Split text atoms into basic block atoms. for (AddressSetTy::const_iterator SI = Splits.begin(), SE = Splits.end(); SI != SE; ++SI) { MCAtom *A = Module->findAtomContaining(*SI); if (!A) continue; MCTextAtom *TA = cast<MCTextAtom>(A); if (TA->getBeginAddr() == *SI) continue; MCTextAtom *NewAtom = TA->split(*SI); BBInfos[NewAtom->getBeginAddr()].Atom = NewAtom; StringRef BBName = TA->getName(); BBName = BBName.substr(0, BBName.find_last_of(':')); NewAtom->setName((BBName + ":" + utohexstr(*SI)).str()); } // Compute succs/preds. for (MCModule::atom_iterator AI = Module->atom_begin(), AE = Module->atom_end(); AI != AE; ++AI) { MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI); if (!TA) continue; BBInfo &CurBB = BBInfos[TA->getBeginAddr()]; const MCDecodedInst &LI = TA->back(); if (MIA.isBranch(LI.Inst)) { uint64_t Target; if (MIA.evaluateBranch(LI.Inst, LI.Address, LI.Size, Target)) CurBB.addSucc(BBInfos[Target]); if (MIA.isConditionalBranch(LI.Inst)) CurBB.addSucc(BBInfos[LI.Address + LI.Size]); } else if (!MIA.isTerminator(LI.Inst)) CurBB.addSucc(BBInfos[LI.Address + LI.Size]); } // Create functions and basic blocks. for (AddressSetTy::const_iterator CI = Calls.begin(), CE = Calls.end(); CI != CE; ++CI) { BBInfo &BBI = BBInfos[*CI]; if (!BBI.Atom) continue; MCFunction &MCFN = *Module->createFunction(BBI.Atom->getName()); // Create MCBBs. SmallSetVector<BBInfo*, 16> Worklist; Worklist.insert(&BBI); for (size_t wi = 0; wi < Worklist.size(); ++wi) { BBInfo *BBI = Worklist[wi]; if (!BBI->Atom) continue; BBI->BB = &MCFN.createBlock(*BBI->Atom); // Add all predecessors and successors to the worklist. for (BBInfoSetTy::iterator SI = BBI->Succs.begin(), SE = BBI->Succs.end(); SI != SE; ++SI) Worklist.insert(*SI); for (BBInfoSetTy::iterator PI = BBI->Preds.begin(), PE = BBI->Preds.end(); PI != PE; ++PI) Worklist.insert(*PI); } // Set preds/succs. for (size_t wi = 0; wi < Worklist.size(); ++wi) { BBInfo *BBI = Worklist[wi]; MCBasicBlock *MCBB = BBI->BB; if (!MCBB) continue; for (BBInfoSetTy::iterator SI = BBI->Succs.begin(), SE = BBI->Succs.end(); SI != SE; ++SI) if ((*SI)->BB) MCBB->addSuccessor((*SI)->BB); for (BBInfoSetTy::iterator PI = BBI->Preds.begin(), PE = BBI->Preds.end(); PI != PE; ++PI) if ((*PI)->BB) MCBB->addPredecessor((*PI)->BB); } } }
// Drop directory components and replace extension with ".exe". static std::string getOutputPath(StringRef Path) { auto P = Path.find_last_of("\\/"); StringRef S = (P == StringRef::npos) ? Path : Path.substr(P + 1); return (S.substr(0, S.rfind('.')) + ".exe").str(); }
/// Parse \p Input as line sample. /// /// \param Input input line. /// \param IsCallsite true if the line represents an inlined callsite. /// \param Depth the depth of the inline stack. /// \param NumSamples total samples of the line/inlined callsite. /// \param LineOffset line offset to the start of the function. /// \param Discriminator discriminator of the line. /// \param TargetCountMap map from indirect call target to count. /// /// returns true if parsing is successful. static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth, uint64_t &NumSamples, uint32_t &LineOffset, uint32_t &Discriminator, StringRef &CalleeName, DenseMap<StringRef, uint64_t> &TargetCountMap) { for (Depth = 0; Input[Depth] == ' '; Depth++) ; if (Depth == 0) return false; size_t n1 = Input.find(':'); StringRef Loc = Input.substr(Depth, n1 - Depth); size_t n2 = Loc.find('.'); if (n2 == StringRef::npos) { if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset)) return false; Discriminator = 0; } else { if (Loc.substr(0, n2).getAsInteger(10, LineOffset)) return false; if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator)) return false; } StringRef Rest = Input.substr(n1 + 2); if (Rest[0] >= '0' && Rest[0] <= '9') { IsCallsite = false; size_t n3 = Rest.find(' '); if (n3 == StringRef::npos) { if (Rest.getAsInteger(10, NumSamples)) return false; } else { if (Rest.substr(0, n3).getAsInteger(10, NumSamples)) return false; } // Find call targets and their sample counts. // Note: In some cases, there are symbols in the profile which are not // mangled. To accommodate such cases, use colon + integer pairs as the // anchor points. // An example: // _M_construct<char *>:1000 string_view<std::allocator<char> >:437 // ":1000" and ":437" are used as anchor points so the string above will // be interpreted as // target: _M_construct<char *> // count: 1000 // target: string_view<std::allocator<char> > // count: 437 while (n3 != StringRef::npos) { n3 += Rest.substr(n3).find_first_not_of(' '); Rest = Rest.substr(n3); n3 = Rest.find_first_of(':'); if (n3 == StringRef::npos || n3 == 0) return false; StringRef Target; uint64_t count, n4; while (true) { // Get the segment after the current colon. StringRef AfterColon = Rest.substr(n3 + 1); // Get the target symbol before the current colon. Target = Rest.substr(0, n3); // Check if the word after the current colon is an integer. n4 = AfterColon.find_first_of(' '); n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size(); StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1); if (!WordAfterColon.getAsInteger(10, count)) break; // Try to find the next colon. uint64_t n5 = AfterColon.find_first_of(':'); if (n5 == StringRef::npos) return false; n3 += n5 + 1; } // An anchor point is found. Save the {target, count} pair TargetCountMap[Target] = count; if (n4 == Rest.size()) break; // Change n3 to the next blank space after colon + integer pair. n3 = n4; } } else { IsCallsite = true; size_t n3 = Rest.find_last_of(':'); CalleeName = Rest.substr(0, n3); if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples)) return false; } return true; }