146b69c69SDimitry Andric //===- MapFile.cpp --------------------------------------------------------===//
246b69c69SDimitry Andric //
346b69c69SDimitry Andric //                             The LLVM Linker
446b69c69SDimitry Andric //
546b69c69SDimitry Andric // This file is distributed under the University of Illinois Open Source
646b69c69SDimitry Andric // License. See LICENSE.TXT for details.
746b69c69SDimitry Andric //
846b69c69SDimitry Andric //===----------------------------------------------------------------------===//
946b69c69SDimitry Andric //
1046b69c69SDimitry Andric // This file implements the -Map option. It shows lists in order and
1146b69c69SDimitry Andric // hierarchically the output sections, input sections, input files and
1246b69c69SDimitry Andric // symbol:
1346b69c69SDimitry Andric //
1446b69c69SDimitry Andric // Address  Size     Align Out     In      File    Symbol
1546b69c69SDimitry Andric // =================================================================
1646b69c69SDimitry Andric // 00201000 00000015     4 .text
1746b69c69SDimitry Andric // 00201000 0000000e     4         .text
1846b69c69SDimitry Andric // 00201000 0000000e     4                 test.o
1946b69c69SDimitry Andric // 0020100e 00000000     0                         local
2046b69c69SDimitry Andric // 00201005 00000000     0                         f(int)
2146b69c69SDimitry Andric //
2246b69c69SDimitry Andric //===----------------------------------------------------------------------===//
2346b69c69SDimitry Andric 
2446b69c69SDimitry Andric #include "MapFile.h"
2546b69c69SDimitry Andric #include "InputFiles.h"
2646b69c69SDimitry Andric #include "Strings.h"
2746b69c69SDimitry Andric 
2846b69c69SDimitry Andric #include "llvm/Support/raw_ostream.h"
2946b69c69SDimitry Andric 
3046b69c69SDimitry Andric using namespace llvm;
3146b69c69SDimitry Andric using namespace llvm::object;
3246b69c69SDimitry Andric 
3346b69c69SDimitry Andric using namespace lld;
3446b69c69SDimitry Andric using namespace lld::elf;
3546b69c69SDimitry Andric 
3646b69c69SDimitry Andric static void writeOutSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
3746b69c69SDimitry Andric                             uint64_t Size, uint64_t Align, StringRef Name) {
3846b69c69SDimitry Andric   OS << format("%0*llx %0*llx %5lld ", Width, Address, Width, Size, Align)
3946b69c69SDimitry Andric      << left_justify(Name, 7);
4046b69c69SDimitry Andric }
4146b69c69SDimitry Andric 
4246b69c69SDimitry Andric static void writeInSecLine(raw_fd_ostream &OS, int Width, uint64_t Address,
4346b69c69SDimitry Andric                            uint64_t Size, uint64_t Align, StringRef Name) {
4446b69c69SDimitry Andric   // Pass an empty name to align the text to the correct column.
4546b69c69SDimitry Andric   writeOutSecLine(OS, Width, Address, Size, Align, "");
4646b69c69SDimitry Andric   OS << ' ' << left_justify(Name, 7);
4746b69c69SDimitry Andric }
4846b69c69SDimitry Andric 
4946b69c69SDimitry Andric static void writeFileLine(raw_fd_ostream &OS, int Width, uint64_t Address,
5046b69c69SDimitry Andric                           uint64_t Size, uint64_t Align, StringRef Name) {
5146b69c69SDimitry Andric   // Pass an empty name to align the text to the correct column.
5246b69c69SDimitry Andric   writeInSecLine(OS, Width, Address, Size, Align, "");
5346b69c69SDimitry Andric   OS << ' ' << left_justify(Name, 7);
5446b69c69SDimitry Andric }
5546b69c69SDimitry Andric 
5646b69c69SDimitry Andric static void writeSymbolLine(raw_fd_ostream &OS, int Width, uint64_t Address,
5746b69c69SDimitry Andric                             uint64_t Size, StringRef Name) {
5846b69c69SDimitry Andric   // Pass an empty name to align the text to the correct column.
5946b69c69SDimitry Andric   writeFileLine(OS, Width, Address, Size, 0, "");
6046b69c69SDimitry Andric   OS << ' ' << left_justify(Name, 7);
6146b69c69SDimitry Andric }
6246b69c69SDimitry Andric 
6346b69c69SDimitry Andric template <class ELFT>
6446b69c69SDimitry Andric static void writeInputSection(raw_fd_ostream &OS, const InputSection *IS,
6546b69c69SDimitry Andric                               StringRef &PrevName) {
6646b69c69SDimitry Andric   int Width = ELFT::Is64Bits ? 16 : 8;
6746b69c69SDimitry Andric   StringRef Name = IS->Name;
6846b69c69SDimitry Andric   if (Name != PrevName) {
6946b69c69SDimitry Andric     writeInSecLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
7046b69c69SDimitry Andric                    IS->Alignment, Name);
7146b69c69SDimitry Andric     OS << '\n';
7246b69c69SDimitry Andric     PrevName = Name;
7346b69c69SDimitry Andric   }
7446b69c69SDimitry Andric 
7546b69c69SDimitry Andric   elf::ObjectFile<ELFT> *File = IS->template getFile<ELFT>();
7646b69c69SDimitry Andric   if (!File)
7746b69c69SDimitry Andric     return;
7846b69c69SDimitry Andric   writeFileLine(OS, Width, IS->OutSec->Addr + IS->OutSecOff, IS->getSize(),
7946b69c69SDimitry Andric                 IS->Alignment, toString(File));
8046b69c69SDimitry Andric   OS << '\n';
8146b69c69SDimitry Andric 
8246b69c69SDimitry Andric   for (SymbolBody *Sym : File->getSymbols()) {
8346b69c69SDimitry Andric     auto *DR = dyn_cast<DefinedRegular>(Sym);
8446b69c69SDimitry Andric     if (!DR)
8546b69c69SDimitry Andric       continue;
8646b69c69SDimitry Andric     if (DR->Section != IS)
8746b69c69SDimitry Andric       continue;
8846b69c69SDimitry Andric     if (DR->isSection())
8946b69c69SDimitry Andric       continue;
9046b69c69SDimitry Andric     writeSymbolLine(OS, Width, Sym->getVA(), Sym->getSize<ELFT>(),
9146b69c69SDimitry Andric                     toString(*Sym));
9246b69c69SDimitry Andric     OS << '\n';
9346b69c69SDimitry Andric   }
9446b69c69SDimitry Andric }
9546b69c69SDimitry Andric 
9646b69c69SDimitry Andric template <class ELFT>
9746b69c69SDimitry Andric static void writeMapFile2(raw_fd_ostream &OS,
9846b69c69SDimitry Andric                           ArrayRef<OutputSection *> OutputSections) {
9946b69c69SDimitry Andric   int Width = ELFT::Is64Bits ? 16 : 8;
10046b69c69SDimitry Andric 
10146b69c69SDimitry Andric   OS << left_justify("Address", Width) << ' ' << left_justify("Size", Width)
10246b69c69SDimitry Andric      << " Align Out     In      File    Symbol\n";
10346b69c69SDimitry Andric 
10446b69c69SDimitry Andric   for (OutputSection *Sec : OutputSections) {
10546b69c69SDimitry Andric     writeOutSecLine(OS, Width, Sec->Addr, Sec->Size, Sec->Alignment, Sec->Name);
10646b69c69SDimitry Andric     OS << '\n';
10746b69c69SDimitry Andric 
10846b69c69SDimitry Andric     StringRef PrevName = "";
10946b69c69SDimitry Andric     for (InputSection *IS : Sec->Sections) {
11046b69c69SDimitry Andric       writeInputSection<ELFT>(OS, IS, PrevName);
11146b69c69SDimitry Andric     }
11246b69c69SDimitry Andric   }
11346b69c69SDimitry Andric }
11446b69c69SDimitry Andric 
11546b69c69SDimitry Andric template <class ELFT>
11646b69c69SDimitry Andric void elf::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
11746b69c69SDimitry Andric   if (Config->MapFile.empty())
11846b69c69SDimitry Andric     return;
11946b69c69SDimitry Andric 
12046b69c69SDimitry Andric   std::error_code EC;
12146b69c69SDimitry Andric   raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
12246b69c69SDimitry Andric   if (EC)
12346b69c69SDimitry Andric     error("cannot open " + Config->MapFile + ": " + EC.message());
12446b69c69SDimitry Andric   else
12546b69c69SDimitry Andric     writeMapFile2<ELFT>(OS, OutputSections);
12646b69c69SDimitry Andric }
12746b69c69SDimitry Andric 
12846b69c69SDimitry Andric template void elf::writeMapFile<ELF32LE>(ArrayRef<OutputSection *>);
12946b69c69SDimitry Andric template void elf::writeMapFile<ELF32BE>(ArrayRef<OutputSection *>);
13046b69c69SDimitry Andric template void elf::writeMapFile<ELF64LE>(ArrayRef<OutputSection *>);
13146b69c69SDimitry Andric template void elf::writeMapFile<ELF64BE>(ArrayRef<OutputSection *>);
132