static bool getGNUDebuglinkContents(const Binary *Bin, std::string &DebugName, uint32_t &CRCHash) { const ObjectFile *Obj = dyn_cast<ObjectFile>(Bin); if (!Obj) return false; for (const SectionRef &Section : Obj->sections()) { StringRef Name; Section.getName(Name); Name = Name.substr(Name.find_first_not_of("._")); if (Name == "gnu_debuglink") { StringRef Data; Section.getContents(Data); DataExtractor DE(Data, Obj->isLittleEndian(), 0); uint32_t Offset = 0; if (const char *DebugNameStr = DE.getCStr(&Offset)) { // 4-byte align the offset. Offset = (Offset + 3) & ~0x3; if (DE.isValidOffsetForDataOfSize(Offset, 4)) { DebugName = DebugNameStr; CRCHash = DE.getU32(&Offset); return true; } } break; } } return false; }
// Split S into linker script tokens. std::vector<StringRef> ScriptParserBase::tokenize(StringRef S) { std::vector<StringRef> Ret; for (;;) { S = skipSpace(S); if (S.empty()) return Ret; // Quoted token if (S.startswith("\"")) { size_t E = S.find("\"", 1); if (E == StringRef::npos) { error("unclosed quote"); return {}; } Ret.push_back(S.substr(1, E - 1)); S = S.substr(E + 1); continue; } // Unquoted token size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789_.$/\\~=+[]*?-:!<>"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. if (Pos == 0) Pos = 1; Ret.push_back(S.substr(0, Pos)); S = S.substr(Pos); } }
BreakableToken::Split getCommentSplit(StringRef Text, unsigned ContentStartColumn, unsigned ColumnLimit) { if (ColumnLimit <= ContentStartColumn + 1) return BreakableToken::Split(StringRef::npos, 0); unsigned MaxSplit = ColumnLimit - ContentStartColumn + 1; StringRef::size_type SpaceOffset = Text.rfind(' ', MaxSplit); if (SpaceOffset == StringRef::npos || // Don't break at leading whitespace. Text.find_last_not_of(' ', SpaceOffset) == StringRef::npos) { // Make sure that we don't break at leading whitespace that // reaches past MaxSplit. StringRef::size_type FirstNonWhitespace = Text.find_first_not_of(" "); if (FirstNonWhitespace == StringRef::npos) // If the comment is only whitespace, we cannot split. return BreakableToken::Split(StringRef::npos, 0); SpaceOffset = Text.find(' ', std::max<unsigned>(MaxSplit, FirstNonWhitespace)); } if (SpaceOffset != StringRef::npos && SpaceOffset != 0) { StringRef BeforeCut = Text.substr(0, SpaceOffset).rtrim(); StringRef AfterCut = Text.substr(SpaceOffset).ltrim(); return BreakableToken::Split(BeforeCut.size(), AfterCut.begin() - BeforeCut.end()); } return BreakableToken::Split(StringRef::npos, 0); }
/// \brief Attempt to read the lock file with the given name, if it exists. /// /// \param LockFileName The name of the lock file to read. /// /// \returns The process ID of the process that owns this lock file Optional<std::pair<std::string, int> > LockFileManager::readLockFile(StringRef LockFileName) { // Check whether the lock file exists. If not, clearly there's nothing // to read, so we just return. if (!sys::fs::exists(LockFileName)) return None; // Read the owning host and PID out of the lock file. If it appears that the // owning process is dead, the lock file is invalid. OwningPtr<MemoryBuffer> MB; if (MemoryBuffer::getFile(LockFileName, MB)) return None; StringRef Hostname; StringRef PIDStr; std::tie(Hostname, PIDStr) = getToken(MB->getBuffer(), " "); PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" ")); int PID; if (!PIDStr.getAsInteger(10, PID)) return std::make_pair(std::string(Hostname), PID); // Delete the lock file. It's invalid anyway. sys::fs::remove(LockFileName); return None; }
void Output::scalarString(StringRef &S) { const char ScalarSafeChars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/^., \t"; this->newLineCheck(); if (S.empty()) { // Print '' for the empty string because leaving the field empty is not // allowed. this->outputUpToEndOfLine("''"); return; } if (S.find_first_not_of(ScalarSafeChars) == StringRef::npos && !isspace(S.front()) && !isspace(S.back())) { // If the string consists only of safe characters, print it out without // quotes. this->outputUpToEndOfLine(S); return; } unsigned i = 0; unsigned j = 0; unsigned End = S.size(); output("'"); // Starting single quote. const char *Base = S.data(); while (j < End) { // Escape a single quote by doubling it. if (S[j] == '\'') { output(StringRef(&Base[i], j - i + 1)); output("'"); i = j + 1; } ++j; } output(StringRef(&Base[i], j - i)); this->outputUpToEndOfLine("'"); // Ending single quote. }
// Find decorated symbol, namely /sym@[0-9]+/ or /\?sym@@.+/. bool findDecoratedSymbol(PECOFFLinkingContext *ctx, ResolvableSymbols *syms, std::string sym, std::string &res) { const std::set<std::string> &defined = syms->defined(); // Search for /sym@[0-9]+/ { std::string s = sym + '@'; auto it = defined.lower_bound(s); for (auto e = defined.end(); it != e; ++it) { if (!StringRef(*it).startswith(s)) break; if (it->size() == s.size()) continue; StringRef suffix = StringRef(*it).substr(s.size()); if (suffix.find_first_not_of("0123456789") != StringRef::npos) continue; res = *it; return true; } } // Search for /\?sym@@.+/ { std::string s = "?" + ctx->undecorateSymbol(sym).str() + "@@"; auto it = defined.lower_bound(s); if (it != defined.end() && StringRef(*it).startswith(s)) { res = *it; return true; } } return false; }
/// \brief Attempt to read the lock file with the given name, if it exists. /// /// \param LockFileName The name of the lock file to read. /// /// \returns The process ID of the process that owns this lock file Optional<std::pair<std::string, int> > LockFileManager::readLockFile(StringRef LockFileName) { // Read the owning host and PID out of the lock file. If it appears that the // owning process is dead, the lock file is invalid. std::unique_ptr<MemoryBuffer> MB; if (MemoryBuffer::getFile(LockFileName, MB)) { sys::fs::remove(LockFileName); return None; } StringRef Hostname; StringRef PIDStr; std::tie(Hostname, PIDStr) = getToken(MB->getBuffer(), " "); PIDStr = PIDStr.substr(PIDStr.find_first_not_of(" ")); int PID; if (!PIDStr.getAsInteger(10, PID)) { auto Owner = std::make_pair(std::string(Hostname), PID); if (processStillExecuting(Owner.first, Owner.second)) return Owner; } // Delete the lock file. It's invalid anyway. sys::fs::remove(LockFileName); return None; }
static void DumpInput(const StringRef &Filename) { OwningPtr<MemoryBuffer> Buff; if (error_code ec = MemoryBuffer::getFileOrSTDIN(Filename, Buff)) { errs() << Filename << ": " << ec.message() << "\n"; return; } OwningPtr<ObjectFile> Obj(ObjectFile::createObjectFile(Buff.take())); StringRef DebugInfoSection; StringRef DebugAbbrevSection; StringRef DebugLineSection; StringRef DebugArangesSection; StringRef DebugStringSection; error_code ec; for (ObjectFile::section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); i != e; i.increment(ec)) { StringRef name; i->getName(name); StringRef data; i->getContents(data); if (name.startswith("__DWARF,")) name = name.substr(8); // Skip "__DWARF," prefix. name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. if (name == "debug_info") DebugInfoSection = data; else if (name == "debug_abbrev") DebugAbbrevSection = data; else if (name == "debug_line") DebugLineSection = data; else if (name == "debug_aranges") DebugArangesSection = data; else if (name == "debug_str") DebugStringSection = data; } OwningPtr<DIContext> dictx(DIContext::getDWARFContext(/*FIXME*/true, DebugInfoSection, DebugAbbrevSection, DebugArangesSection, DebugLineSection, DebugStringSection)); if (Address == -1ULL) { outs() << Filename << ":\tfile format " << Obj->getFileFormatName() << "\n\n"; // Dump the complete DWARF structure. dictx->dump(outs()); } else { // Print line info for the specified address. DILineInfo dli = dictx->getLineInfoForAddress(Address); outs() << (dli.getFileName() ? dli.getFileName() : "<unknown>") << ':' << dli.getLine() << ':' << dli.getColumn() << '\n'; } }
size_t swift::ide::getOffsetOfTrimmedLine(unsigned LineIndex, StringRef Text) { size_t LineOffset = swift::ide::getOffsetOfLine(LineIndex, Text); // Skip leading whitespace. size_t FirstNonWSOnLine = Text.find_first_not_of(" \t\v\f", LineOffset); if (FirstNonWSOnLine != std::string::npos) LineOffset = FirstNonWSOnLine; return LineOffset; }
/// getToken - This function extracts one token from source, ignoring any /// leading characters that appear in the Delimiters string, and ending the /// token at any of the characters that appear in the Delimiters string. If /// there are no tokens in the source string, an empty string is returned. /// The function returns a pair containing the extracted token and the /// remaining tail string. std::pair<StringRef, StringRef> llvm::getToken(StringRef Source, StringRef Delimiters) { // Figure out where the token starts. StringRef::size_type Start = Source.find_first_not_of(Delimiters); // Find the next occurrence of the delimiter. StringRef::size_type End = Source.find_first_of(Delimiters, Start); return std::make_pair(Source.slice(Start, End), Source.substr(End)); }
void ELFLinkingContext::notifyInputSectionName(StringRef name) { // Save sections names which can be represented as a C identifier. if (name.find_first_not_of("0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "_") == StringRef::npos) { std::lock_guard<std::mutex> lock(_cidentMutex); _cidentSections.insert(name); } }
/// Retrieve the section named \a SecName in \a Obj. /// /// To accommodate for platform discrepancies, the name passed should be /// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'. /// This function will strip the initial platform-specific characters. static Optional<object::SectionRef> getSectionByName(const object::ObjectFile &Obj, StringRef SecName) { for (const object::SectionRef &Section : Obj.sections()) { StringRef SectionName; Section.getName(SectionName); SectionName = SectionName.substr(SectionName.find_first_not_of("._")); if (SectionName != SecName) continue; return Section; } return None; }
static unsigned measureASCIIArt(StringRef S, unsigned NumLeadingSpaces) { StringRef Spaces = S.substr(0, NumLeadingSpaces); if (Spaces.size() != NumLeadingSpaces) return 0; if (Spaces.find_first_not_of(' ') != StringRef::npos) return 0; S = S.drop_front(NumLeadingSpaces); if (S.startswith(" * ")) return NumLeadingSpaces + 3; if (S.startswith(" *\n") || S.startswith(" *\n\r")) return NumLeadingSpaces + 2; return 0; }
size_t swift::ide::getExpandedIndentForLine(unsigned LineIndex, CodeFormatOptions Options, StringRef Text) { size_t LineOffset = getOffsetOfLine(LineIndex, Text); // Tab-expand all leading whitespace size_t FirstNonWSOnLine = Text.find_first_not_of(" \t\v\f", LineOffset); size_t Indent = 0; while (LineOffset < Text.size() && LineOffset < FirstNonWSOnLine) { if (Text[LineOffset++] == '\t') Indent += Options.TabWidth; else Indent += 1; } return Indent; }
static void PrintCheckFailed(const SourceMgr &SM, const CheckString &CheckStr, StringRef Buffer, StringMap<StringRef> &VariableTable) { // Otherwise, we have an error, emit an error message. SM.PrintMessage(CheckStr.Loc, SourceMgr::DK_Error, "expected string not found in input"); // Print the "scanning from here" line. If the current position is at the // end of a line, advance to the start of the next line. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t\n\r")); SM.PrintMessage(SMLoc::getFromPointer(Buffer.data()), SourceMgr::DK_Note, "scanning from here"); // Allow the pattern to print additional information if desired. CheckStr.Pat.PrintFailureInfo(SM, Buffer, VariableTable); }
static bool ByteArrayFromString(ByteArrayTy &ByteArray, StringRef &Str, SourceMgr &SM) { while (!Str.empty()) { // Strip horizontal whitespace. if (size_t Pos = Str.find_first_not_of(" \t\r")) { Str = Str.substr(Pos); continue; } // If this is the end of a line or start of a comment, remove the rest of // the line. if (Str[0] == '\n' || Str[0] == '#') { // Strip to the end of line if we already processed any bytes on this // line. This strips the comment and/or the \n. if (Str[0] == '\n') { Str = Str.substr(1); } else { Str = Str.substr(Str.find_first_of('\n')); if (!Str.empty()) Str = Str.substr(1); } continue; } // Get the current token. size_t Next = Str.find_first_of(" \t\n\r#"); StringRef Value = Str.substr(0, Next); // Convert to a byte and add to the byte vector. unsigned ByteVal; if (Value.getAsInteger(0, ByteVal) || ByteVal > 255) { // If we have an error, print it and skip to the end of line. SM.PrintMessage(SMLoc::getFromPointer(Value.data()), SourceMgr::DK_Error, "invalid input token"); Str = Str.substr(Str.find('\n')); ByteArray.clear(); continue; } ByteArray.push_back(std::make_pair((unsigned char)ByteVal, Value.data())); Str = Str.substr(Next); } return false; }
// Split S into linker script tokens. void ScriptParserBase::tokenize(MemoryBufferRef MB) { std::vector<StringRef> Vec; MBs.push_back(MB); StringRef S = MB.getBuffer(); StringRef Begin = S; for (;;) { S = skipSpace(S); if (S.empty()) break; // Quoted token. Note that double-quote characters are parts of a token // because, in a glob match context, only unquoted tokens are interpreted // as glob patterns. Double-quoted tokens are literal patterns in that // context. if (S.startswith("\"")) { size_t E = S.find("\"", 1); if (E == StringRef::npos) { StringRef Filename = MB.getBufferIdentifier(); size_t Lineno = Begin.substr(0, S.data() - Begin.data()).count('\n'); error(Filename + ":" + Twine(Lineno + 1) + ": unclosed quote"); return; } Vec.push_back(S.take_front(E + 1)); S = S.substr(E + 1); continue; } // Unquoted token. This is more relaxed than tokens in C-like language, // so that you can write "file-name.cpp" as one bare token, for example. size_t Pos = S.find_first_not_of( "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789_.$/\\~=+[]*?-:!<>^"); // A character that cannot start a word (which is usually a // punctuation) forms a single character token. if (Pos == 0) Pos = 1; Vec.push_back(S.substr(0, Pos)); S = S.substr(Pos); } Tokens.insert(Tokens.begin() + Pos, Vec.begin(), Vec.end()); }
static bool SkipToToken(StringRef &Str) { for (;;) { if (Str.empty()) return false; // Strip horizontal whitespace and commas. if (size_t Pos = Str.find_first_not_of(" \t\r\n,")) { Str = Str.substr(Pos); continue; } // If this is the start of a comment, remove the rest of the line. if (Str[0] == '#') { Str = Str.substr(Str.find_first_of('\n')); continue; } return true; } }
static void printName(raw_ostream &OS, StringRef Name) { if (Name.find_first_not_of("0123456789_." "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == Name.npos) { OS << Name; return; } OS << '"'; for (const char *B = Name.begin(), *E = Name.end(); B < E; ++B) { if (*B == '"') // Unquoted " OS << "\\\""; else if (*B != '\\') // Neither " or backslash OS << *B; else if (B + 1 == E) // Trailing backslash OS << "\\\\"; else { OS << B[0] << B[1]; // Quoted character ++B; } } OS << '"'; }
void swift::trimLeadingWhitespaceFromLines(StringRef RawText, unsigned WhitespaceToTrim, SmallVectorImpl<StringRef> &OutLines) { SmallVector<StringRef, 8> Lines; bool IsFirstLine = true; while (!RawText.empty()) { size_t Pos = RawText.find_first_of("\n\r"); if (Pos == StringRef::npos) Pos = RawText.size(); StringRef Line = RawText.substr(0, Pos); Lines.push_back(Line); if (!IsFirstLine) { size_t NonWhitespacePos = RawText.find_first_not_of(' '); if (NonWhitespacePos != StringRef::npos) WhitespaceToTrim = std::min(WhitespaceToTrim, static_cast<unsigned>(NonWhitespacePos)); } IsFirstLine = false; RawText = RawText.drop_front(Pos); unsigned NewlineBytes = measureNewline(RawText); RawText = RawText.drop_front(NewlineBytes); } IsFirstLine = true; for (auto &Line : Lines) { if (!IsFirstLine) { Line = Line.drop_front(WhitespaceToTrim); } IsFirstLine = false; } OutLines.append(Lines.begin(), Lines.end()); }
const RetainSummary * RetainSummaryManager::generateSummary(const FunctionDecl *FD, bool &AllowAnnotations) { // We generate "stop" summaries for implicitly defined functions. if (FD->isImplicit()) return getPersistentStopSummary(); const IdentifierInfo *II = FD->getIdentifier(); StringRef FName = II ? II->getName() : ""; // Strip away preceding '_'. Doing this here will effect all the checks // down below. FName = FName.substr(FName.find_first_not_of('_')); // Inspect the result type. Strip away any typedefs. const auto *FT = FD->getType()->getAs<FunctionType>(); QualType RetTy = FT->getReturnType(); if (TrackOSObjects) if (const RetainSummary *S = getSummaryForOSObject(FD, FName, RetTy)) return S; if (const auto *MD = dyn_cast<CXXMethodDecl>(FD)) if (!isOSObjectRelated(MD)) return getPersistentSummary(RetEffect::MakeNoRet(), ArgEffects(AF.getEmptyMap()), ArgEffect(DoNothing), ArgEffect(StopTracking), ArgEffect(DoNothing)); if (TrackObjCAndCFObjects) if (const RetainSummary *S = getSummaryForObjCOrCFObject(FD, FName, RetTy, FT, AllowAnnotations)) return S; return getDefaultSummary(); }
std::string Regex::sub(StringRef Repl, StringRef String, std::string *Error) { SmallVector<StringRef, 8> Matches; // Reset error, if given. if (Error && !Error->empty()) *Error = ""; // Return the input if there was no match. if (!match(String, &Matches)) return String; // Otherwise splice in the replacement string, starting with the prefix before // the match. std::string Res(String.begin(), Matches[0].begin()); // Then the replacement string, honoring possible substitutions. while (!Repl.empty()) { // Skip to the next escape. std::pair<StringRef, StringRef> Split = Repl.split('\\'); // Add the skipped substring. Res += Split.first; // Check for terminimation and trailing backslash. if (Split.second.empty()) { if (Repl.size() != Split.first.size() && Error && Error->empty()) *Error = "replacement string contained trailing backslash"; break; } // Otherwise update the replacement string and interpret escapes. Repl = Split.second; // FIXME: We should have a StringExtras function for mapping C99 escapes. switch (Repl[0]) { // Treat all unrecognized characters as self-quoting. default: Res += Repl[0]; Repl = Repl.substr(1); break; // Single character escapes. case 't': Res += '\t'; Repl = Repl.substr(1); break; case 'n': Res += '\n'; Repl = Repl.substr(1); break; // Decimal escapes are backreferences. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { // Extract the backreference number. StringRef Ref = Repl.slice(0, Repl.find_first_not_of("0123456789")); Repl = Repl.substr(Ref.size()); unsigned RefValue; if (!Ref.getAsInteger(10, RefValue) && RefValue < Matches.size()) Res += Matches[RefValue]; else if (Error && Error->empty()) *Error = "invalid backreference string '" + Ref.str() + "'"; break; } } } // And finally the suffix. Res += StringRef(Matches[0].end(), String.end() - Matches[0].end()); return Res; }
DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : IsLittleEndian(Obj->isLittleEndian()), AddressSize(Obj->getBytesInAddress()) { for (const SectionRef &Section : Obj->sections()) { StringRef name; Section.getName(name); StringRef data; Section.getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. // Check if debug info section is compressed with zlib. if (name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(data, OriginalSize)) continue; UncompressedSections.resize(UncompressedSections.size() + 1); if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) != zlib::StatusOK) { UncompressedSections.pop_back(); continue; } // Make data point to uncompressed section contents and save its contents. name = name.substr(1); data = UncompressedSections.back(); } StringRef *SectionData = StringSwitch<StringRef *>(name) .Case("debug_info", &InfoSection.Data) .Case("debug_abbrev", &AbbrevSection) .Case("debug_loc", &LocSection.Data) .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_pubtypes", &PubTypesSection) .Case("debug_gnu_pubnames", &GnuPubNamesSection) .Case("debug_gnu_pubtypes", &GnuPubTypesSection) .Case("debug_info.dwo", &InfoDWOSection.Data) .Case("debug_abbrev.dwo", &AbbrevDWOSection) .Case("debug_loc.dwo", &LocDWOSection.Data) .Case("debug_line.dwo", &LineDWOSection.Data) .Case("debug_str.dwo", &StringDWOSection) .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) .Case("debug_addr", &AddrSection) // Any more debug info sections go here. .Default(nullptr); if (SectionData) { *SectionData = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; } } else if (name == "debug_types") { // Find debug_types data by section rather than name as there are // multiple, comdat grouped, debug_types sections. TypesSections[Section].Data = data; } else if (name == "debug_types.dwo") { TypesDWOSections[Section].Data = data; } section_iterator RelocatedSection = Section.getRelocatedSection(); if (RelocatedSection == Obj->section_end()) continue; StringRef RelSecName; RelocatedSection->getName(RelSecName); RelSecName = RelSecName.substr( RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName) .Case("debug_info", &InfoSection.Relocs) .Case("debug_loc", &LocSection.Relocs) .Case("debug_info.dwo", &InfoDWOSection.Relocs) .Case("debug_line", &LineSection.Relocs) .Default(nullptr); if (!Map) { // Find debug_types relocs by section rather than name as there are // multiple, comdat grouped, debug_types sections. if (RelSecName == "debug_types") Map = &TypesSections[*RelocatedSection].Relocs; else if (RelSecName == "debug_types.dwo") Map = &TypesDWOSections[*RelocatedSection].Relocs; else continue; } if (Section.relocation_begin() != Section.relocation_end()) { uint64_t SectionSize; RelocatedSection->getSize(SectionSize); for (const RelocationRef &Reloc : Section.relocations()) { uint64_t Address; Reloc.getOffset(Address); uint64_t Type; Reloc.getType(Type); uint64_t SymAddr = 0; // ELF relocations may need the symbol address if (Obj->isELF()) { object::symbol_iterator Sym = Reloc.getSymbol(); Sym->getAddress(SymAddr); } object::RelocVisitor V(Obj->getFileFormatName()); // The section address is always 0 for debug sections. object::RelocToApply R(V.visit(Type, Reloc, 0, SymAddr)); if (V.error()) { SmallString<32> Name; error_code ec(Reloc.getTypeName(Name)); if (ec) { errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n"; } errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }
DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : IsLittleEndian(Obj->isLittleEndian()), AddressSize(Obj->getBytesInAddress()) { error_code ec; for (object::section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); i != e; i.increment(ec)) { StringRef name; i->getName(name); StringRef data; i->getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. // Check if debug info section is compressed with zlib. if (name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(data, OriginalSize)) continue; OwningPtr<MemoryBuffer> UncompressedSection; if (zlib::uncompress(data, UncompressedSection, OriginalSize) != zlib::StatusOK) continue; // Make data point to uncompressed section contents and save its contents. name = name.substr(1); data = UncompressedSection->getBuffer(); UncompressedSections.push_back(UncompressedSection.take()); } StringRef *Section = StringSwitch<StringRef*>(name) .Case("debug_info", &InfoSection) .Case("debug_abbrev", &AbbrevSection) .Case("debug_line", &LineSection) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_info.dwo", &InfoDWOSection) .Case("debug_abbrev.dwo", &AbbrevDWOSection) .Case("debug_str.dwo", &StringDWOSection) .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) .Case("debug_addr", &AddrSection) // Any more debug info sections go here. .Default(0); if (!Section) continue; *Section = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; } // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(name) .Case("debug_info", &InfoRelocMap) .Case("debug_info.dwo", &InfoDWORelocMap) .Case("debug_line", &LineRelocMap) .Default(0); if (!Map) continue; if (i->begin_relocations() != i->end_relocations()) { uint64_t SectionSize; i->getSize(SectionSize); for (object::relocation_iterator reloc_i = i->begin_relocations(), reloc_e = i->end_relocations(); reloc_i != reloc_e; reloc_i.increment(ec)) { uint64_t Address; reloc_i->getOffset(Address); uint64_t Type; reloc_i->getType(Type); uint64_t SymAddr = 0; // ELF relocations may need the symbol address if (Obj->isELF()) { object::SymbolRef Sym; reloc_i->getSymbol(Sym); Sym.getAddress(SymAddr); } object::RelocVisitor V(Obj->getFileFormatName()); // The section address is always 0 for debug sections. object::RelocToApply R(V.visit(Type, *reloc_i, 0, SymAddr)); if (V.error()) { SmallString<32> Name; error_code ec(reloc_i->getTypeName(Name)); if (ec) { errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n"; } errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }
/// \brief After the file has been processed, check to see if we got all of /// the expected diagnostics and check to see if there were any unexpected /// ones. bool DiagnosticVerifier::verifyFile(unsigned BufferID, bool shouldAutoApplyFixes) { using llvm::SMLoc; const SourceLoc BufferStartLoc = SM.getLocForBufferStart(BufferID); CharSourceRange EntireRange = SM.getRangeForBuffer(BufferID); StringRef InputFile = SM.extractText(EntireRange); StringRef BufferName = SM.getIdentifierForBuffer(BufferID); // Queue up all of the diagnostics, allowing us to sort them and emit them in // file order. std::vector<llvm::SMDiagnostic> Errors; unsigned PrevExpectedContinuationLine = 0; std::vector<ExpectedDiagnosticInfo> ExpectedDiagnostics; auto addError = [&](const char *Loc, std::string message, ArrayRef<llvm::SMFixIt> FixIts = {}) { auto loc = SourceLoc(SMLoc::getFromPointer(Loc)); auto diag = SM.GetMessage(loc, llvm::SourceMgr::DK_Error, message, {}, FixIts); Errors.push_back(diag); }; // Scan the memory buffer looking for expected-note/warning/error. for (size_t Match = InputFile.find("expected-"); Match != StringRef::npos; Match = InputFile.find("expected-", Match+1)) { // Process this potential match. If we fail to process it, just move on to // the next match. StringRef MatchStart = InputFile.substr(Match); const char *DiagnosticLoc = MatchStart.data(); llvm::SourceMgr::DiagKind ExpectedClassification; if (MatchStart.startswith("expected-note")) { ExpectedClassification = llvm::SourceMgr::DK_Note; MatchStart = MatchStart.substr(strlen("expected-note")); } else if (MatchStart.startswith("expected-warning")) { ExpectedClassification = llvm::SourceMgr::DK_Warning; MatchStart = MatchStart.substr(strlen("expected-warning")); } else if (MatchStart.startswith("expected-error")) { ExpectedClassification = llvm::SourceMgr::DK_Error; MatchStart = MatchStart.substr(strlen("expected-error")); } else continue; // Skip any whitespace before the {{. MatchStart = MatchStart.substr(MatchStart.find_first_not_of(" \t")); size_t TextStartIdx = MatchStart.find("{{"); if (TextStartIdx == StringRef::npos) { addError(MatchStart.data(), "expected {{ in expected-warning/note/error line"); continue; } int LineOffset = 0; if (TextStartIdx > 0 && MatchStart[0] == '@') { if (MatchStart[1] != '+' && MatchStart[1] != '-') { addError(MatchStart.data(), "expected '+'/'-' for line offset"); continue; } StringRef Offs; if (MatchStart[1] == '+') Offs = MatchStart.slice(2, TextStartIdx).rtrim(); else Offs = MatchStart.slice(1, TextStartIdx).rtrim(); size_t SpaceIndex = Offs.find(' '); if (SpaceIndex != StringRef::npos && SpaceIndex < TextStartIdx) { size_t Delta = Offs.size() - SpaceIndex; MatchStart = MatchStart.substr(TextStartIdx - Delta); TextStartIdx = Delta; Offs = Offs.slice(0, SpaceIndex); } else { MatchStart = MatchStart.substr(TextStartIdx); TextStartIdx = 0; } if (Offs.getAsInteger(10, LineOffset)) { addError(MatchStart.data(), "expected line offset before '{{'"); continue; } } ExpectedDiagnosticInfo Expected(DiagnosticLoc, ExpectedClassification); unsigned Count = 1; if (TextStartIdx > 0) { StringRef CountStr = MatchStart.substr(0, TextStartIdx).trim(); if (CountStr == "*") { Expected.mayAppear = true; } else { if (CountStr.getAsInteger(10, Count)) { addError(MatchStart.data(), "expected match count before '{{'"); continue; } if (Count == 0) { addError(MatchStart.data(), "expected positive match count before '{{'"); continue; } } // Resync up to the '{{'. MatchStart = MatchStart.substr(TextStartIdx); } size_t End = MatchStart.find("}}"); if (End == StringRef::npos) { addError(MatchStart.data(), "didn't find '}}' to match '{{' in expected-warning/note/error line"); continue; } llvm::SmallString<256> Buf; Expected.MessageRange = MatchStart.slice(2, End); Expected.MessageStr = Lexer::getEncodedStringSegment(Expected.MessageRange, Buf); if (PrevExpectedContinuationLine) Expected.LineNo = PrevExpectedContinuationLine; else Expected.LineNo = SM.getLineAndColumn( BufferStartLoc.getAdvancedLoc(MatchStart.data() - InputFile.data()), BufferID).first; Expected.LineNo += LineOffset; // Check if the next expected diagnostic should be in the same line. StringRef AfterEnd = MatchStart.substr(End + strlen("}}")); AfterEnd = AfterEnd.substr(AfterEnd.find_first_not_of(" \t")); if (AfterEnd.startswith("\\")) PrevExpectedContinuationLine = Expected.LineNo; else PrevExpectedContinuationLine = 0; // Scan for fix-its: {{10-14=replacement text}} StringRef ExtraChecks = MatchStart.substr(End+2).ltrim(" \t"); while (ExtraChecks.startswith("{{")) { // First make sure we have a closing "}}". size_t EndLoc = ExtraChecks.find("}}"); if (EndLoc == StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in fix-it verification"); break; } // Allow for close braces to appear in the replacement text. while (EndLoc+2 < ExtraChecks.size() && ExtraChecks[EndLoc+2] == '}') ++EndLoc; StringRef FixItStr = ExtraChecks.slice(2, EndLoc); // Check for matching a later "}}" on a different line. if (FixItStr.find_first_of("\r\n") != StringRef::npos) { addError(ExtraChecks.data(), "didn't find '}}' to match '{{' in " "fix-it verification"); break; } // Prepare for the next round of checks. ExtraChecks = ExtraChecks.substr(EndLoc+2).ltrim(); // Special case for specifying no fixits should appear. if (FixItStr == "none") { Expected.noFixitsMayAppear = true; continue; } // Parse the pieces of the fix-it. size_t MinusLoc = FixItStr.find('-'); if (MinusLoc == StringRef::npos) { addError(FixItStr.data(), "expected '-' in fix-it verification"); continue; } StringRef StartColStr = FixItStr.slice(0, MinusLoc); StringRef AfterMinus = FixItStr.substr(MinusLoc+1); size_t EqualLoc = AfterMinus.find('='); if (EqualLoc == StringRef::npos) { addError(AfterMinus.data(), "expected '=' after '-' in fix-it verification"); continue; } StringRef EndColStr = AfterMinus.slice(0, EqualLoc); StringRef AfterEqual = AfterMinus.substr(EqualLoc+1); ExpectedFixIt FixIt; FixIt.StartLoc = StartColStr.data()-2; FixIt.EndLoc = FixItStr.data()+EndLoc; if (StartColStr.getAsInteger(10, FixIt.StartCol)) { addError(StartColStr.data(), "invalid column number in fix-it verification"); continue; } if (EndColStr.getAsInteger(10, FixIt.EndCol)) { addError(EndColStr.data(), "invalid column number in fix-it verification"); continue; } // Translate literal "\\n" into '\n', inefficiently. StringRef fixItText = AfterEqual.slice(0, EndLoc); for (const char *current = fixItText.begin(), *end = fixItText.end(); current != end; /* in loop */) { if (*current == '\\' && current + 1 < end) { if (current[1] == 'n') { FixIt.Text += '\n'; current += 2; } else { // Handle \}, \\, etc. FixIt.Text += current[1]; current += 2; } } else { FixIt.Text += *current++; } } Expected.Fixits.push_back(FixIt); } Expected.ExpectedEnd = ExtraChecks.data(); // Don't include trailing whitespace in the expected-foo{{}} range. while (isspace(Expected.ExpectedEnd[-1])) --Expected.ExpectedEnd; // Add the diagnostic the expected number of times. for (; Count; --Count) ExpectedDiagnostics.push_back(Expected); } // Make sure all the expected diagnostics appeared. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if we had this expected diagnostic. auto FoundDiagnosticIter = findDiagnostic(expected, BufferName); if (FoundDiagnosticIter == CapturedDiagnostics.end()) { // Diagnostic didn't exist. If this is a 'mayAppear' diagnostic, then // we're ok. Otherwise, leave it in the list. if (expected.mayAppear) ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); continue; } auto &FoundDiagnostic = *FoundDiagnosticIter; const char *IncorrectFixit = nullptr; // Verify that any expected fix-its are present in the diagnostic. for (auto fixit : expected.Fixits) { // If we found it, we're ok. if (!checkForFixIt(fixit, FoundDiagnostic, InputFile)) IncorrectFixit = fixit.StartLoc; } // If we have any expected fixits that didn't get matched, then they are // wrong. Replace the failed fixit with what actually happened. if (IncorrectFixit) { if (FoundDiagnostic.getFixIts().empty()) { addError(IncorrectFixit, "expected fix-it not seen"); continue; } // If we had an incorrect expected fixit, render it and produce a fixit // of our own. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.Fixits[0].StartLoc); auto replEndLoc = SMLoc::getFromPointer(expected.Fixits.back().EndLoc); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(IncorrectFixit, "expected fix-it not seen; actual fix-its: " + actual, fix); } else if (expected.noFixitsMayAppear && !FoundDiagnostic.getFixIts().empty() && !expected.mayAppear) { // If there was no fixit specification, but some were produced, add a // fixit to add them in. auto actual = renderFixits(FoundDiagnostic.getFixIts(), InputFile); auto replStartLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 8); // {{none}} length auto replEndLoc = SMLoc::getFromPointer(expected.ExpectedEnd - 1); llvm::SMFixIt fix(llvm::SMRange(replStartLoc, replEndLoc), actual); addError(replStartLoc.getPointer(), "expected no fix-its; actual fix-it seen: " + actual, fix); } // Actually remove the diagnostic from the list, so we don't match it // again. We do have to do this after checking fix-its, though, because // the diagnostic owns its fix-its. CapturedDiagnostics.erase(FoundDiagnosticIter); // We found the diagnostic, so remove it... unless we allow an arbitrary // number of diagnostics, in which case we want to reprocess this. if (expected.mayAppear) ++i; else ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Check to see if we have any incorrect diagnostics. If so, diagnose them as // such. for (unsigned i = ExpectedDiagnostics.size(); i != 0; ) { --i; auto &expected = ExpectedDiagnostics[i]; // Check to see if any found diagnostics have the right line and // classification, but the wrong text. auto I = CapturedDiagnostics.begin(); for (auto E = CapturedDiagnostics.end(); I != E; ++I) { // Verify the file and line of the diagnostic. if (I->getLineNo() != (int)expected.LineNo || I->getFilename() != BufferName || I->getKind() != expected.Classification) continue; // Otherwise, we found it, break out. break; } if (I == CapturedDiagnostics.end()) continue; auto StartLoc = SMLoc::getFromPointer(expected.MessageRange.begin()); auto EndLoc = SMLoc::getFromPointer(expected.MessageRange.end()); llvm::SMFixIt fixIt(llvm::SMRange{ StartLoc, EndLoc }, I->getMessage()); addError(expected.MessageRange.begin(), "incorrect message found", fixIt); CapturedDiagnostics.erase(I); ExpectedDiagnostics.erase(ExpectedDiagnostics.begin()+i); } // Diagnose expected diagnostics that didn't appear. std::reverse(ExpectedDiagnostics.begin(), ExpectedDiagnostics.end()); for (auto const &expected : ExpectedDiagnostics) { std::string message = "expected "+getDiagKindString(expected.Classification) + " not produced"; // Get the range of the expected-foo{{}} diagnostic specifier. auto StartLoc = expected.ExpectedStart; auto EndLoc = expected.ExpectedEnd; // A very common case if for the specifier to be the last thing on the line. // In this case, eat any trailing whitespace. while (isspace(*EndLoc) && *EndLoc != '\n' && *EndLoc != '\r') ++EndLoc; // If we found the end of the line, we can do great things. Otherwise, // avoid nuking whitespace that might be zapped through other means. if (*EndLoc != '\n' && *EndLoc != '\r') { EndLoc = expected.ExpectedEnd; } else { // If we hit the end of line, then zap whitespace leading up to it. auto FileStart = InputFile.data(); while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we got to the end of the line, and the thing before this diagnostic // is a "//" then we can remove it too. if (StartLoc-2 >= FileStart && StartLoc[-1] == '/' && StartLoc[-2] == '/') StartLoc -= 2; // Perform another round of general whitespace nuking to cleanup // whitespace before the //. while (StartLoc-1 != FileStart && isspace(StartLoc[-1]) && StartLoc[-1] != '\n' && StartLoc[-1] != '\r') --StartLoc; // If we found a \n, then we can nuke the entire line. if (StartLoc-1 != FileStart && (StartLoc[-1] == '\n' || StartLoc[-1] == '\r')) --StartLoc; } // Remove the expected-foo{{}} as a fixit. llvm::SMFixIt fixIt(llvm::SMRange{ SMLoc::getFromPointer(StartLoc), SMLoc::getFromPointer(EndLoc) }, ""); addError(expected.ExpectedStart, message, fixIt); } // Verify that there are no diagnostics (in MemoryBuffer) left in the list. for (unsigned i = 0, e = CapturedDiagnostics.size(); i != e; ++i) { if (CapturedDiagnostics[i].getFilename() != BufferName) continue; std::string Message = "unexpected "+getDiagKindString(CapturedDiagnostics[i].getKind())+ " produced: "+CapturedDiagnostics[i].getMessage().str(); addError(CapturedDiagnostics[i].getLoc().getPointer(), Message); } // Sort the diagnostics by their address in the memory buffer as the primary // key. This ensures that an "unexpected diagnostic" and // "expected diagnostic" in the same place are emitted next to each other. std::sort(Errors.begin(), Errors.end(), [&](const llvm::SMDiagnostic &lhs, const llvm::SMDiagnostic &rhs) -> bool { return lhs.getLoc().getPointer() < rhs.getLoc().getPointer(); }); // Emit all of the queue'd up errors. for (auto Err : Errors) SM.getLLVMSourceMgr().PrintMessage(llvm::errs(), Err); // If auto-apply fixits is on, rewrite the original source file. if (shouldAutoApplyFixes) autoApplyFixes(BufferID, Errors); return !Errors.empty(); }
DWARFContextInMemory::DWARFContextInMemory(object::ObjectFile *Obj) : IsLittleEndian(Obj->isLittleEndian()) { error_code ec; for (object::section_iterator i = Obj->begin_sections(), e = Obj->end_sections(); i != e; i.increment(ec)) { StringRef name; i->getName(name); StringRef data; i->getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. if (name == "debug_info") InfoSection = data; else if (name == "debug_abbrev") AbbrevSection = data; else if (name == "debug_line") LineSection = data; else if (name == "debug_aranges") ARangeSection = data; else if (name == "debug_str") StringSection = data; else if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; RangeSection = data; } else if (name == "debug_info.dwo") InfoDWOSection = data; else if (name == "debug_abbrev.dwo") AbbrevDWOSection = data; else if (name == "debug_str.dwo") StringDWOSection = data; else if (name == "debug_str_offsets.dwo") StringOffsetDWOSection = data; // Any more debug info sections go here. else continue; // TODO: For now only handle relocations for the debug_info section. RelocAddrMap *Map; if (name == "debug_info") Map = &InfoRelocMap; else if (name == "debug_info.dwo") Map = &InfoDWORelocMap; else continue; if (i->begin_relocations() != i->end_relocations()) { uint64_t SectionSize; i->getSize(SectionSize); for (object::relocation_iterator reloc_i = i->begin_relocations(), reloc_e = i->end_relocations(); reloc_i != reloc_e; reloc_i.increment(ec)) { uint64_t Address; reloc_i->getAddress(Address); uint64_t Type; reloc_i->getType(Type); object::RelocVisitor V(Obj->getFileFormatName()); // The section address is always 0 for debug sections. object::RelocToApply R(V.visit(Type, *reloc_i)); if (V.error()) { SmallString<32> Name; error_code ec(reloc_i->getTypeName(Name)); if (ec) { errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n"; } errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }
DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), AddressSize(Obj.getBytesInAddress()) { for (const SectionRef &Section : Obj.sections()) { StringRef name; Section.getName(name); // Skip BSS and Virtual sections, they aren't interesting. bool IsBSS = Section.isBSS(); if (IsBSS) continue; bool IsVirtual = Section.isVirtual(); if (IsVirtual) continue; StringRef data; // Try to obtain an already relocated version of this section. // Else use the unrelocated section from the object file. We'll have to // apply relocations ourselves later. if (!L || !L->getLoadedSectionContents(name,data)) Section.getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. // Check if debug info section is compressed with zlib. if (name.startswith("zdebug_")) { uint64_t OriginalSize; if (!zlib::isAvailable() || !consumeCompressedDebugSectionHeader(data, OriginalSize)) continue; UncompressedSections.resize(UncompressedSections.size() + 1); if (zlib::uncompress(data, UncompressedSections.back(), OriginalSize) != zlib::StatusOK) { UncompressedSections.pop_back(); continue; } // Make data point to uncompressed section contents and save its contents. name = name.substr(1); data = UncompressedSections.back(); } StringRef *SectionData = StringSwitch<StringRef *>(name) .Case("debug_info", &InfoSection.Data) .Case("debug_abbrev", &AbbrevSection) .Case("debug_loc", &LocSection.Data) .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_pubtypes", &PubTypesSection) .Case("debug_gnu_pubnames", &GnuPubNamesSection) .Case("debug_gnu_pubtypes", &GnuPubTypesSection) .Case("debug_info.dwo", &InfoDWOSection.Data) .Case("debug_abbrev.dwo", &AbbrevDWOSection) .Case("debug_loc.dwo", &LocDWOSection.Data) .Case("debug_line.dwo", &LineDWOSection.Data) .Case("debug_str.dwo", &StringDWOSection) .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) .Case("debug_addr", &AddrSection) .Case("apple_names", &AppleNamesSection.Data) .Case("apple_types", &AppleTypesSection.Data) .Case("apple_namespaces", &AppleNamespacesSection.Data) .Case("apple_namespac", &AppleNamespacesSection.Data) .Case("apple_objc", &AppleObjCSection.Data) // Any more debug info sections go here. .Default(nullptr); if (SectionData) { *SectionData = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; } } else if (name == "debug_types") { // Find debug_types data by section rather than name as there are // multiple, comdat grouped, debug_types sections. TypesSections[Section].Data = data; } else if (name == "debug_types.dwo") { TypesDWOSections[Section].Data = data; } section_iterator RelocatedSection = Section.getRelocatedSection(); if (RelocatedSection == Obj.section_end()) continue; StringRef RelSecName; StringRef RelSecData; RelocatedSection->getName(RelSecName); // If the section we're relocating was relocated already by the JIT, // then we used the relocated version above, so we do not need to process // relocations for it now. if (L && L->getLoadedSectionContents(RelSecName,RelSecData)) continue; RelSecName = RelSecName.substr( RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName) .Case("debug_info", &InfoSection.Relocs) .Case("debug_loc", &LocSection.Relocs) .Case("debug_info.dwo", &InfoDWOSection.Relocs) .Case("debug_line", &LineSection.Relocs) .Case("apple_names", &AppleNamesSection.Relocs) .Case("apple_types", &AppleTypesSection.Relocs) .Case("apple_namespaces", &AppleNamespacesSection.Relocs) .Case("apple_namespac", &AppleNamespacesSection.Relocs) .Case("apple_objc", &AppleObjCSection.Relocs) .Default(nullptr); if (!Map) { // Find debug_types relocs by section rather than name as there are // multiple, comdat grouped, debug_types sections. if (RelSecName == "debug_types") Map = &TypesSections[*RelocatedSection].Relocs; else if (RelSecName == "debug_types.dwo") Map = &TypesDWOSections[*RelocatedSection].Relocs; else continue; } if (Section.relocation_begin() != Section.relocation_end()) { uint64_t SectionSize = RelocatedSection->getSize(); for (const RelocationRef &Reloc : Section.relocations()) { uint64_t Address; Reloc.getOffset(Address); uint64_t Type; Reloc.getType(Type); uint64_t SymAddr = 0; uint64_t SectionLoadAddress = 0; object::symbol_iterator Sym = Reloc.getSymbol(); object::section_iterator RSec = Obj.section_end(); // First calculate the address of the symbol or section as it appears // in the objct file if (Sym != Obj.symbol_end()) { Sym->getAddress(SymAddr); // Also remember what section this symbol is in for later Sym->getSection(RSec); } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { // MachO also has relocations that point to sections and // scattered relocations. // FIXME: We are not handling scattered relocations, do we have to? RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); SymAddr = RSec->getAddress(); } // If we are given load addresses for the sections, we need to adjust: // SymAddr = (Address of Symbol Or Section in File) - // (Address of Section in File) + // (Load Address of Section) if (L != nullptr && RSec != Obj.section_end()) { // RSec is now either the section being targetted or the section // containing the symbol being targetted. In either case, // we need to perform the same computation. StringRef SecName; RSec->getName(SecName); SectionLoadAddress = L->getSectionLoadAddress(SecName); if (SectionLoadAddress != 0) SymAddr += SectionLoadAddress - RSec->getAddress(); } object::RelocVisitor V(Obj); object::RelocToApply R(V.visit(Type, Reloc, SymAddr)); if (V.error()) { SmallString<32> Name; std::error_code ec(Reloc.getTypeName(Name)); if (ec) { errs() << "Aaaaaa! Nameless relocation! Aaaaaa!\n"; } errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. /// Returns true in case of an error, false otherwise. static bool ReadCheckFile(SourceMgr &SM, std::vector<CheckString> &CheckStrings) { OwningPtr<MemoryBuffer> File; if (error_code ec = MemoryBuffer::getFileOrSTDIN(CheckFilename.c_str(), File)) { errs() << "Could not open check file '" << CheckFilename << "': " << ec.message() << '\n'; return true; } // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. Remove DOS style line endings. MemoryBuffer *F = CanonicalizeInputFile(File.take(), NoCanonicalizeWhiteSpace); SM.AddNewSourceBuffer(F, SMLoc()); // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); std::vector<std::pair<SMLoc, Pattern> > NotMatches; // LineNumber keeps track of the line on which CheckPrefix instances are // found. unsigned LineNumber = 1; while (1) { // See if Prefix occurs in the memory buffer. size_t PrefixLoc = Buffer.find(CheckPrefix); // If we didn't find a match, we're done. if (PrefixLoc == StringRef::npos) break; LineNumber += Buffer.substr(0, PrefixLoc).count('\n'); Buffer = Buffer.substr(PrefixLoc); const char *CheckPrefixStart = Buffer.data(); // When we find a check prefix, keep track of whether we find CHECK: or // CHECK-NEXT: bool IsCheckNext = false, IsCheckNot = false; // Verify that the : is present after the prefix. if (Buffer[CheckPrefix.size()] == ':') { Buffer = Buffer.substr(CheckPrefix.size()+1); } else if (Buffer.size() > CheckPrefix.size()+6 && memcmp(Buffer.data()+CheckPrefix.size(), "-NEXT:", 6) == 0) { Buffer = Buffer.substr(CheckPrefix.size()+6); IsCheckNext = true; } else if (Buffer.size() > CheckPrefix.size()+5 && memcmp(Buffer.data()+CheckPrefix.size(), "-NOT:", 5) == 0) { Buffer = Buffer.substr(CheckPrefix.size()+5); IsCheckNot = true; } else { Buffer = Buffer.substr(1); continue; } // Okay, we found the prefix, yay. Remember the rest of the line, but // ignore leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. Pattern P; if (P.ParsePattern(Buffer.substr(0, EOL), SM, LineNumber)) return true; Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. if (IsCheckNext && CheckStrings.empty()) { SM.PrintMessage(SMLoc::getFromPointer(CheckPrefixStart), SourceMgr::DK_Error, "found '"+CheckPrefix+"-NEXT:' without previous '"+ CheckPrefix+ ": line"); return true; } // Handle CHECK-NOT. if (IsCheckNot) { NotMatches.push_back(std::make_pair(SMLoc::getFromPointer(Buffer.data()), P)); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.push_back(CheckString(P, PatternLoc, IsCheckNext)); std::swap(NotMatches, CheckStrings.back().NotStrings); } // Add an EOF pattern for any trailing CHECK-NOTs. if (!NotMatches.empty()) { CheckStrings.push_back(CheckString(Pattern(true), SMLoc::getFromPointer(Buffer.data()), false)); std::swap(NotMatches, CheckStrings.back().NotStrings); } if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix '" << CheckPrefix << ":'\n"; return true; } return false; }
/// ReadCheckFile - Read the check file, which specifies the sequence of /// expected strings. The strings are added to the CheckStrings vector. /// Returns true in case of an error, false otherwise. static bool ReadCheckFile(SourceMgr &SM, std::vector<CheckString> &CheckStrings) { ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr = MemoryBuffer::getFileOrSTDIN(CheckFilename); if (std::error_code EC = FileOrErr.getError()) { errs() << "Could not open check file '" << CheckFilename << "': " << EC.message() << '\n'; return true; } // If we want to canonicalize whitespace, strip excess whitespace from the // buffer containing the CHECK lines. Remove DOS style line endings. std::unique_ptr<MemoryBuffer> F = CanonicalizeInputFile( std::move(FileOrErr.get()), NoCanonicalizeWhiteSpace); // Find all instances of CheckPrefix followed by : in the file. StringRef Buffer = F->getBuffer(); SM.AddNewSourceBuffer(std::move(F), SMLoc()); std::vector<Pattern> ImplicitNegativeChecks; for (const auto &PatternString : ImplicitCheckNot) { // Create a buffer with fake command line content in order to display the // command line option responsible for the specific implicit CHECK-NOT. std::string Prefix = std::string("-") + ImplicitCheckNot.ArgStr + "='"; std::string Suffix = "'"; std::unique_ptr<MemoryBuffer> CmdLine = MemoryBuffer::getMemBufferCopy( Prefix + PatternString + Suffix, "command line"); StringRef PatternInBuffer = CmdLine->getBuffer().substr(Prefix.size(), PatternString.size()); SM.AddNewSourceBuffer(std::move(CmdLine), SMLoc()); ImplicitNegativeChecks.push_back(Pattern(Check::CheckNot)); ImplicitNegativeChecks.back().ParsePattern(PatternInBuffer, "IMPLICIT-CHECK", SM, 0); } std::vector<Pattern> DagNotMatches = ImplicitNegativeChecks; // LineNumber keeps track of the line on which CheckPrefix instances are // found. unsigned LineNumber = 1; while (1) { Check::CheckType CheckTy; size_t PrefixLoc; // See if a prefix occurs in the memory buffer. StringRef UsedPrefix = FindFirstMatchingPrefix(Buffer, LineNumber, CheckTy, PrefixLoc); if (UsedPrefix.empty()) break; Buffer = Buffer.drop_front(PrefixLoc); // Location to use for error messages. const char *UsedPrefixStart = Buffer.data() + (PrefixLoc == 0 ? 0 : 1); // PrefixLoc is to the start of the prefix. Skip to the end. Buffer = Buffer.drop_front(UsedPrefix.size() + CheckTypeSize(CheckTy)); // Okay, we found the prefix, yay. Remember the rest of the line, but ignore // leading and trailing whitespace. Buffer = Buffer.substr(Buffer.find_first_not_of(" \t")); // Scan ahead to the end of line. size_t EOL = Buffer.find_first_of("\n\r"); // Remember the location of the start of the pattern, for diagnostics. SMLoc PatternLoc = SMLoc::getFromPointer(Buffer.data()); // Parse the pattern. Pattern P(CheckTy); if (P.ParsePattern(Buffer.substr(0, EOL), UsedPrefix, SM, LineNumber)) return true; // Verify that CHECK-LABEL lines do not define or use variables if ((CheckTy == Check::CheckLabel) && P.hasVariable()) { SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-LABEL:'" " with variable definition or use"); return true; } Buffer = Buffer.substr(EOL); // Verify that CHECK-NEXT lines have at least one CHECK line before them. if ((CheckTy == Check::CheckNext || CheckTy == Check::CheckSame) && CheckStrings.empty()) { StringRef Type = CheckTy == Check::CheckNext ? "NEXT" : "SAME"; SM.PrintMessage(SMLoc::getFromPointer(UsedPrefixStart), SourceMgr::DK_Error, "found '" + UsedPrefix + "-" + Type + "' without previous '" + UsedPrefix + ": line"); return true; } // Handle CHECK-DAG/-NOT. if (CheckTy == Check::CheckDAG || CheckTy == Check::CheckNot) { DagNotMatches.push_back(P); continue; } // Okay, add the string we captured to the output vector and move on. CheckStrings.emplace_back(P, UsedPrefix, PatternLoc, CheckTy); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); DagNotMatches = ImplicitNegativeChecks; } // Add an EOF pattern for any trailing CHECK-DAG/-NOTs, and use the first // prefix as a filler for the error message. if (!DagNotMatches.empty()) { CheckStrings.emplace_back(Pattern(Check::CheckEOF), *CheckPrefixes.begin(), SMLoc::getFromPointer(Buffer.data()), Check::CheckEOF); std::swap(DagNotMatches, CheckStrings.back().DagNotStrings); } if (CheckStrings.empty()) { errs() << "error: no check strings found with prefix" << (CheckPrefixes.size() > 1 ? "es " : " "); prefix_iterator I = CheckPrefixes.begin(); prefix_iterator E = CheckPrefixes.end(); if (I != E) { errs() << "\'" << *I << ":'"; ++I; } for (; I != E; ++I) errs() << ", \'" << *I << ":'"; errs() << '\n'; return true; } return false; }
DWARFContextInMemory::DWARFContextInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L) : IsLittleEndian(Obj.isLittleEndian()), AddressSize(Obj.getBytesInAddress()) { for (const SectionRef &Section : Obj.sections()) { StringRef name; Section.getName(name); // Skip BSS and Virtual sections, they aren't interesting. bool IsBSS = Section.isBSS(); if (IsBSS) continue; bool IsVirtual = Section.isVirtual(); if (IsVirtual) continue; StringRef data; section_iterator RelocatedSection = Section.getRelocatedSection(); // Try to obtain an already relocated version of this section. // Else use the unrelocated section from the object file. We'll have to // apply relocations ourselves later. if (!L || !L->getLoadedSectionContents(*RelocatedSection,data)) Section.getContents(data); name = name.substr(name.find_first_not_of("._")); // Skip . and _ prefixes. bool ZLibStyleCompressed = Section.isCompressed(); if (ZLibStyleCompressed || name.startswith("zdebug_")) { SmallString<32> Out; if (!tryDecompress(name, data, Out, ZLibStyleCompressed, IsLittleEndian, AddressSize == 8)) continue; UncompressedSections.emplace_back(std::move(Out)); data = UncompressedSections.back(); } StringRef *SectionData = StringSwitch<StringRef *>(name) .Case("debug_info", &InfoSection.Data) .Case("debug_abbrev", &AbbrevSection) .Case("debug_loc", &LocSection.Data) .Case("debug_line", &LineSection.Data) .Case("debug_aranges", &ARangeSection) .Case("debug_frame", &DebugFrameSection) .Case("eh_frame", &EHFrameSection) .Case("debug_str", &StringSection) .Case("debug_ranges", &RangeSection) .Case("debug_macinfo", &MacinfoSection) .Case("debug_pubnames", &PubNamesSection) .Case("debug_pubtypes", &PubTypesSection) .Case("debug_gnu_pubnames", &GnuPubNamesSection) .Case("debug_gnu_pubtypes", &GnuPubTypesSection) .Case("debug_info.dwo", &InfoDWOSection.Data) .Case("debug_abbrev.dwo", &AbbrevDWOSection) .Case("debug_loc.dwo", &LocDWOSection.Data) .Case("debug_line.dwo", &LineDWOSection.Data) .Case("debug_str.dwo", &StringDWOSection) .Case("debug_str_offsets.dwo", &StringOffsetDWOSection) .Case("debug_addr", &AddrSection) .Case("apple_names", &AppleNamesSection.Data) .Case("apple_types", &AppleTypesSection.Data) .Case("apple_namespaces", &AppleNamespacesSection.Data) .Case("apple_namespac", &AppleNamespacesSection.Data) .Case("apple_objc", &AppleObjCSection.Data) .Case("debug_cu_index", &CUIndexSection) .Case("debug_tu_index", &TUIndexSection) // Any more debug info sections go here. .Default(nullptr); if (SectionData) { *SectionData = data; if (name == "debug_ranges") { // FIXME: Use the other dwo range section when we emit it. RangeDWOSection = data; } } else if (name == "debug_types") { // Find debug_types data by section rather than name as there are // multiple, comdat grouped, debug_types sections. TypesSections[Section].Data = data; } else if (name == "debug_types.dwo") { TypesDWOSections[Section].Data = data; } if (RelocatedSection == Obj.section_end()) continue; StringRef RelSecName; StringRef RelSecData; RelocatedSection->getName(RelSecName); // If the section we're relocating was relocated already by the JIT, // then we used the relocated version above, so we do not need to process // relocations for it now. if (L && L->getLoadedSectionContents(*RelocatedSection,RelSecData)) continue; // In Mach-o files, the relocations do not need to be applied if // there is no load offset to apply. The value read at the // relocation point already factors in the section address // (actually applying the relocations will produce wrong results // as the section address will be added twice). if (!L && isa<MachOObjectFile>(&Obj)) continue; RelSecName = RelSecName.substr( RelSecName.find_first_not_of("._")); // Skip . and _ prefixes. // TODO: Add support for relocations in other sections as needed. // Record relocations for the debug_info and debug_line sections. RelocAddrMap *Map = StringSwitch<RelocAddrMap*>(RelSecName) .Case("debug_info", &InfoSection.Relocs) .Case("debug_loc", &LocSection.Relocs) .Case("debug_info.dwo", &InfoDWOSection.Relocs) .Case("debug_line", &LineSection.Relocs) .Case("apple_names", &AppleNamesSection.Relocs) .Case("apple_types", &AppleTypesSection.Relocs) .Case("apple_namespaces", &AppleNamespacesSection.Relocs) .Case("apple_namespac", &AppleNamespacesSection.Relocs) .Case("apple_objc", &AppleObjCSection.Relocs) .Default(nullptr); if (!Map) { // Find debug_types relocs by section rather than name as there are // multiple, comdat grouped, debug_types sections. if (RelSecName == "debug_types") Map = &TypesSections[*RelocatedSection].Relocs; else if (RelSecName == "debug_types.dwo") Map = &TypesDWOSections[*RelocatedSection].Relocs; else continue; } if (Section.relocation_begin() != Section.relocation_end()) { uint64_t SectionSize = RelocatedSection->getSize(); for (const RelocationRef &Reloc : Section.relocations()) { uint64_t Address = Reloc.getOffset(); uint64_t Type = Reloc.getType(); uint64_t SymAddr = 0; uint64_t SectionLoadAddress = 0; object::symbol_iterator Sym = Reloc.getSymbol(); object::section_iterator RSec = Obj.section_end(); // First calculate the address of the symbol or section as it appears // in the objct file if (Sym != Obj.symbol_end()) { ErrorOr<uint64_t> SymAddrOrErr = Sym->getAddress(); if (std::error_code EC = SymAddrOrErr.getError()) { errs() << "error: failed to compute symbol address: " << EC.message() << '\n'; continue; } SymAddr = *SymAddrOrErr; // Also remember what section this symbol is in for later auto SectOrErr = Sym->getSection(); if (!SectOrErr) { std::string Buf; raw_string_ostream OS(Buf); logAllUnhandledErrors(SectOrErr.takeError(), OS, ""); OS.flush(); errs() << "error: failed to get symbol section: " << Buf << '\n'; continue; } RSec = *SectOrErr; } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) { // MachO also has relocations that point to sections and // scattered relocations. auto RelocInfo = MObj->getRelocation(Reloc.getRawDataRefImpl()); if (MObj->isRelocationScattered(RelocInfo)) { // FIXME: it's not clear how to correctly handle scattered // relocations. continue; } else { RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl()); SymAddr = RSec->getAddress(); } } // If we are given load addresses for the sections, we need to adjust: // SymAddr = (Address of Symbol Or Section in File) - // (Address of Section in File) + // (Load Address of Section) if (L != nullptr && RSec != Obj.section_end()) { // RSec is now either the section being targeted or the section // containing the symbol being targeted. In either case, // we need to perform the same computation. StringRef SecName; RSec->getName(SecName); // llvm::dbgs() << "Name: '" << SecName // << "', RSec: " << RSec->getRawDataRefImpl() // << ", Section: " << Section.getRawDataRefImpl() << "\n"; SectionLoadAddress = L->getSectionLoadAddress(*RSec); if (SectionLoadAddress != 0) SymAddr += SectionLoadAddress - RSec->getAddress(); } object::RelocVisitor V(Obj); object::RelocToApply R(V.visit(Type, Reloc, SymAddr)); if (V.error()) { SmallString<32> Name; Reloc.getTypeName(Name); errs() << "error: failed to compute relocation: " << Name << "\n"; continue; } if (Address + R.Width > SectionSize) { errs() << "error: " << R.Width << "-byte relocation starting " << Address << " bytes into section " << name << " which is " << SectionSize << " bytes long.\n"; continue; } if (R.Width > 8) { errs() << "error: can't handle a relocation of more than 8 bytes at " "a time.\n"; continue; } DEBUG(dbgs() << "Writing " << format("%p", R.Value) << " at " << format("%p", Address) << " with width " << format("%d", R.Width) << "\n"); Map->insert(std::make_pair(Address, std::make_pair(R.Width, R.Value))); } } } }