Пример #1
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);

    if (Decompressor::isCompressed(Section)) {
      Expected<Decompressor> Decompressor =
          Decompressor::create(name, data, IsLittleEndian, AddressSize == 8);
      if (!Decompressor)
        continue;
      SmallString<32> Out;
      if (auto Err = Decompressor->decompress(Out))
        continue;
      UncompressedSections.emplace_back(std::move(Out));
      data = UncompressedSections.back();
    }

    // Compressed sections names in GNU style starts from ".z",
    // at this point section is decompressed and we drop compression prefix.
    name = name.substr(
        name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.

    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)
            .Case("gdb_index", &GdbIndexSection)
            // 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()) {
          Expected<uint64_t> SymAddrOrErr = Sym->getAddress();
          if (!SymAddrOrErr) {
            std::string Buf;
            raw_string_ostream OS(Buf);
            logAllUnhandledErrors(SymAddrOrErr.takeError(), OS, "");
            OS.flush();
            errs() << "error: failed to compute symbol address: "
                   << Buf << '\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)));
      }
    }
  }
}