xref: /llvm-project-15.0.7/lld/COFF/MapFile.cpp (revision 4f73dbf4)
1 //===- MapFile.cpp --------------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the /lldmap option. It shows lists in order and
11 // hierarchically the output sections, input sections, input files and
12 // symbol:
13 //
14 // Address  Size     Align Out     In      File    Symbol
15 // =================================================================
16 // 00201000 00000015     4 .text
17 // 00201000 0000000e     4         .text
18 // 00201000 0000000e     4                 test.o
19 // 0020100e 00000000     0                         local
20 // 00201005 00000000     0                         f(int)
21 //
22 //===----------------------------------------------------------------------===//
23 
24 #include "MapFile.h"
25 #include "Error.h"
26 #include "Symbols.h"
27 #include "Writer.h"
28 
29 #include "llvm/Support/raw_ostream.h"
30 
31 using namespace llvm;
32 using namespace llvm::object;
33 
34 using namespace lld;
35 using namespace lld::coff;
36 
37 static void writeOutSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
38                             uint64_t Align, StringRef Name) {
39   OS << format("%08llx %08llx %5lld ", Address, Size, Align)
40      << left_justify(Name, 7);
41 }
42 
43 static void writeInSecLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
44                            uint64_t Align, StringRef Name) {
45   // Pass an empty name to align the text to the correct column.
46   writeOutSecLine(OS, Address, Size, Align, "");
47   OS << ' ' << left_justify(Name, 7);
48 }
49 
50 static void writeFileLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
51                           uint64_t Align, StringRef Name) {
52   // Pass an empty name to align the text to the correct column.
53   writeInSecLine(OS, Address, Size, Align, "");
54   OS << ' ' << left_justify(Name, 7);
55 }
56 
57 static void writeSymbolLine(raw_fd_ostream &OS, uint64_t Address, uint64_t Size,
58                             StringRef Name) {
59   // Pass an empty name to align the text to the correct column.
60   writeFileLine(OS, Address, Size, 0, "");
61   OS << ' ' << left_justify(Name, 7);
62 }
63 
64 static void writeSectionChunk(raw_fd_ostream &OS, const SectionChunk *SC,
65                               StringRef &PrevName) {
66   StringRef Name = SC->getSectionName();
67   if (Name != PrevName) {
68     writeInSecLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(), Name);
69     OS << '\n';
70     PrevName = Name;
71   }
72   coff::ObjectFile *File = SC->File;
73   if (!File)
74     return;
75   writeFileLine(OS, SC->getRVA(), SC->getSize(), SC->getAlign(),
76                 toString(File));
77   OS << '\n';
78   ArrayRef<SymbolBody *> Syms = File->getSymbols();
79   for (SymbolBody *Sym : Syms) {
80     auto *DR = dyn_cast<DefinedRegular>(Sym);
81     if (!DR || DR->getChunk() != SC ||
82         DR->getCOFFSymbol().isSectionDefinition())
83       continue;
84     writeSymbolLine(OS, DR->getRVA(), SC->getSize(), toString(*Sym));
85     OS << '\n';
86   }
87 }
88 
89 static void writeMapFile2(raw_fd_ostream &OS,
90                           ArrayRef<OutputSection *> OutputSections) {
91   OS << "Address  Size     Align Out     In      File    Symbol\n";
92 
93   for (OutputSection *Sec : OutputSections) {
94     uint32_t VA = Sec->getRVA();
95     writeOutSecLine(OS, VA, Sec->getVirtualSize(), /*Align=*/PageSize,
96                     Sec->getName());
97     OS << '\n';
98     StringRef PrevName = "";
99     for (Chunk *C : Sec->getChunks())
100       if (const auto *SC = dyn_cast<SectionChunk>(C))
101         writeSectionChunk(OS, SC, PrevName);
102   }
103 }
104 
105 void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) {
106   if (Config->MapFile.empty())
107     return;
108 
109   std::error_code EC;
110   raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
111   if (EC)
112     fatal("cannot open " + Config->MapFile + ": " + EC.message());
113   writeMapFile2(OS, OutputSections);
114 }
115