brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.6 KiB · 05ae25f Raw
281 lines · cpp
1//===- MapFile.cpp --------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the -Map option. It shows lists in order and10// hierarchically the output sections, input sections, input files and11// symbol:12//13//   Address  Size     Align Out     In      Symbol14//   00201000 00000015     4 .text15//   00201000 0000000e     4         test.o:(.text)16//   0020100e 00000000     0                 local17//   00201005 00000000     0                 f(int)18//19//===----------------------------------------------------------------------===//20 21#include "MapFile.h"22#include "InputFiles.h"23#include "LinkerScript.h"24#include "OutputSections.h"25#include "Symbols.h"26#include "SyntheticSections.h"27#include "llvm/ADT/MapVector.h"28#include "llvm/ADT/SetVector.h"29#include "llvm/ADT/SmallPtrSet.h"30#include "llvm/Support/Parallel.h"31#include "llvm/Support/TimeProfiler.h"32#include "llvm/Support/raw_ostream.h"33 34using namespace llvm;35using namespace llvm::object;36using namespace lld;37using namespace lld::elf;38 39using SymbolMapTy = DenseMap<const SectionBase *,40                             SmallVector<std::pair<Defined *, uint64_t>, 0>>;41 42static constexpr char indent8[] = "        ";          // 8 spaces43static constexpr char indent16[] = "                "; // 16 spaces44 45// Print out the first three columns of a line.46static void writeHeader(Ctx &ctx, raw_ostream &os, uint64_t vma, uint64_t lma,47                        uint64_t size, uint64_t align) {48  if (ctx.arg.is64)49    os << format("%16llx %16llx %8llx %5lld ", vma, lma, size, align);50  else51    os << format("%8llx %8llx %8llx %5lld ", vma, lma, size, align);52}53 54// Returns a list of all symbols that we want to print out.55static std::vector<Defined *> getSymbols(Ctx &ctx) {56  std::vector<Defined *> v;57  for (ELFFileBase *file : ctx.objectFiles)58    for (Symbol *b : file->getSymbols())59      if (auto *dr = dyn_cast<Defined>(b))60        if (!dr->isSection() && dr->section && dr->section->isLive() &&61            (dr->file == file || dr->hasFlag(NEEDS_COPY) ||62             (isa<SyntheticSection>(dr->section) &&63              cast<SyntheticSection>(dr->section)->bss)))64          v.push_back(dr);65  return v;66}67 68// Returns a map from sections to their symbols.69static SymbolMapTy getSectionSyms(Ctx &ctx, ArrayRef<Defined *> syms) {70  SymbolMapTy ret;71  for (Defined *dr : syms)72    ret[dr->section].emplace_back(dr, dr->getVA(ctx));73 74  // Sort symbols by address. We want to print out symbols in the75  // order in the output file rather than the order they appeared76  // in the input files.77  SmallPtrSet<Defined *, 4> set;78  for (auto &it : ret) {79    // Deduplicate symbols which need a canonical PLT entry/copy relocation.80    set.clear();81    llvm::erase_if(it.second, [&](std::pair<Defined *, uint64_t> a) {82      return !set.insert(a.first).second;83    });84 85    llvm::stable_sort(it.second, llvm::less_second());86  }87  return ret;88}89 90// Construct a map from symbols to their stringified representations.91// Demangling symbols (which is what toStr(ctx, ) does) is slow, so92// we do that in batch using parallel-for.93static DenseMap<Symbol *, std::string>94getSymbolStrings(Ctx &ctx, ArrayRef<Defined *> syms) {95  auto strs = std::make_unique<std::string[]>(syms.size());96  parallelFor(0, syms.size(), [&](size_t i) {97    raw_string_ostream os(strs[i]);98    OutputSection *osec = syms[i]->getOutputSection();99    uint64_t vma = syms[i]->getVA(ctx);100    uint64_t lma = osec ? osec->getLMA() + vma - osec->getVA(0) : 0;101    writeHeader(ctx, os, vma, lma, syms[i]->getSize(), 1);102    os << indent16 << toStr(ctx, *syms[i]);103  });104 105  DenseMap<Symbol *, std::string> ret;106  for (size_t i = 0, e = syms.size(); i < e; ++i)107    ret[syms[i]] = std::move(strs[i]);108  return ret;109}110 111// Print .eh_frame contents. Since the section consists of EhSectionPieces,112// we need a specialized printer for that section.113//114// .eh_frame tend to contain a lot of section pieces that are contiguous115// both in input file and output file. Such pieces are squashed before116// being displayed to make output compact.117static void printEhFrame(Ctx &ctx, raw_ostream &os, const EhFrameSection *sec) {118  std::vector<EhSectionPiece> pieces;119 120  auto add = [&](const EhSectionPiece &p) {121    // If P is adjacent to Last, squash the two.122    if (!pieces.empty()) {123      EhSectionPiece &last = pieces.back();124      if (last.sec == p.sec && last.inputOff + last.size == p.inputOff &&125          last.outputOff + last.size == (unsigned)p.outputOff) {126        last.size += p.size;127        return;128      }129    }130    pieces.push_back(p);131  };132 133  // Gather section pieces.134  for (const CieRecord *rec : sec->getCieRecords()) {135    add(*rec->cie);136    for (const EhSectionPiece *fde : rec->fdes)137      add(*fde);138  }139 140  // Print out section pieces.141  const OutputSection *osec = sec->getOutputSection();142  for (EhSectionPiece &p : pieces) {143    writeHeader(ctx, os, osec->addr + p.outputOff, osec->getLMA() + p.outputOff,144                p.size, 1);145    os << indent8 << toStr(ctx, p.sec->file) << ":(" << p.sec->name << "+0x"146       << Twine::utohexstr(p.inputOff) + ")\n";147  }148}149 150static void writeMapFile(Ctx &ctx, raw_fd_ostream &os) {151  // Collect symbol info that we want to print out.152  std::vector<Defined *> syms = getSymbols(ctx);153  SymbolMapTy sectionSyms = getSectionSyms(ctx, syms);154  DenseMap<Symbol *, std::string> symStr = getSymbolStrings(ctx, syms);155 156  // Print out the header line.157  int w = ctx.arg.is64 ? 16 : 8;158  os << right_justify("VMA", w) << ' ' << right_justify("LMA", w)159     << "     Size Align Out     In      Symbol\n";160 161  OutputSection *osec = nullptr;162  for (SectionCommand *cmd : ctx.script->sectionCommands) {163    if (auto *assign = dyn_cast<SymbolAssignment>(cmd)) {164      if (assign->provide && !assign->sym)165        continue;166      uint64_t lma = osec ? osec->getLMA() + assign->addr - osec->getVA(0) : 0;167      writeHeader(ctx, os, assign->addr, lma, assign->size, 1);168      os << assign->commandString << '\n';169      continue;170    }171    if (isa<SectionClassDesc>(cmd))172      continue;173 174    osec = &cast<OutputDesc>(cmd)->osec;175    writeHeader(ctx, os, osec->addr, osec->getLMA(), osec->size,176                osec->addralign);177    os << osec->name << '\n';178 179    // Dump symbols for each input section.180    for (SectionCommand *subCmd : osec->commands) {181      if (auto *isd = dyn_cast<InputSectionDescription>(subCmd)) {182        for (InputSection *isec : isd->sections) {183          if (auto *ehSec = dyn_cast<EhFrameSection>(isec)) {184            printEhFrame(ctx, os, ehSec);185            continue;186          }187 188          writeHeader(ctx, os, isec->getVA(), osec->getLMA() + isec->outSecOff,189                      isec->getSize(), isec->addralign);190          os << indent8 << toStr(ctx, isec) << '\n';191          for (Symbol *sym : llvm::make_first_range(sectionSyms[isec]))192            os << symStr[sym] << '\n';193        }194        continue;195      }196 197      if (auto *data = dyn_cast<ByteCommand>(subCmd)) {198        writeHeader(ctx, os, osec->addr + data->offset,199                    osec->getLMA() + data->offset, data->size, 1);200        os << indent8 << data->commandString << '\n';201        continue;202      }203 204      if (auto *assign = dyn_cast<SymbolAssignment>(subCmd)) {205        if (assign->provide && !assign->sym)206          continue;207        writeHeader(ctx, os, assign->addr,208                    osec->getLMA() + assign->addr - osec->getVA(0),209                    assign->size, 1);210        os << indent8 << assign->commandString << '\n';211        continue;212      }213    }214  }215}216 217// Output a cross reference table to stdout. This is for --cref.218//219// For each global symbol, we print out a file that defines the symbol220// followed by files that uses that symbol. Here is an example.221//222//     strlen     /lib/x86_64-linux-gnu/libc.so.6223//                tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o224//                lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)225//226// In this case, strlen is defined by libc.so.6 and used by other two227// files.228static void writeCref(Ctx &ctx, raw_fd_ostream &os) {229  // Collect symbols and files.230  MapVector<Symbol *, SetVector<InputFile *>> map;231  for (ELFFileBase *file : ctx.objectFiles) {232    for (Symbol *sym : file->getSymbols()) {233      if (isa<SharedSymbol>(sym))234        map[sym].insert(file);235      if (auto *d = dyn_cast<Defined>(sym))236        if (!d->isLocal())237          map[d].insert(file);238    }239  }240 241  auto print = [&](StringRef a, StringRef b) {242    os << left_justify(a, 49) << ' ' << b << '\n';243  };244 245  // Print a blank line and a header. The format matches GNU ld.246  os << "\nCross Reference Table\n\n";247  print("Symbol", "File");248 249  // Print out a table.250  for (auto kv : map) {251    Symbol *sym = kv.first;252    SetVector<InputFile *> &files = kv.second;253 254    print(toStr(ctx, *sym), toStr(ctx, sym->file));255    for (InputFile *file : files)256      if (file != sym->file)257        print("", toStr(ctx, file));258  }259}260 261void elf::writeMapAndCref(Ctx &ctx) {262  if (ctx.arg.mapFile.empty() && !ctx.arg.cref)263    return;264 265  llvm::TimeTraceScope timeScope("Write map file");266 267  // Open a map file for writing.268  std::error_code ec;269  StringRef mapFile = ctx.arg.mapFile.empty() ? "-" : ctx.arg.mapFile;270  raw_fd_ostream os = ctx.openAuxiliaryFile(mapFile, ec);271  if (ec) {272    ErrAlways(ctx) << "cannot open " << mapFile << ": " << ec.message();273    return;274  }275 276  if (!ctx.arg.mapFile.empty())277    writeMapFile(ctx, os);278  if (ctx.arg.cref)279    writeCref(ctx, os);280}281