Example #1
0
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;
}
Example #2
0
// 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);
  }
}
Example #3
0
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);
}
Example #4
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;
}
Example #5
0
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.
}
Example #6
0
// 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;
}
Example #7
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) {
  // 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;
}
Example #8
0
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';
  }
}
Example #9
0
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;
}
Example #10
0
/// 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));
}
Example #11
0
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);
    }
}
Example #12
0
/// 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;
}
Example #13
0
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;
}
Example #14
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;
}
Example #15
0
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);
}
Example #16
0
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;
}
Example #17
0
// 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());
}
Example #18
0
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;
  }
}
Example #19
0
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 << '"';
}
Example #20
0
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());
}
Example #21
0
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)));
      }
    }
  }
}
Example #24
0
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)));
      }
    }
  }
}
Example #25
0
/// \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();
}
Example #26
0
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)));
      }
    }
  }
}
Example #27
0
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)));
      }
    }
  }
}
Example #28
0
/// 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;
}
Example #29
0
/// 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;
}
Example #30
0
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)));
            }
        }
    }
}