Coverage Report

Created: 2019-05-19 14:56

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/ELF/MapFile.cpp
Line
Count
Source (jump to first uncovered line)
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements the -Map option. It shows lists in order and
10
// hierarchically the output sections, input sections, input files and
11
// symbol:
12
//
13
//   Address  Size     Align Out     In      Symbol
14
//   00201000 00000015     4 .text
15
//   00201000 0000000e     4         test.o:(.text)
16
//   0020100e 00000000     0                 local
17
//   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 "SymbolTable.h"
26
#include "Symbols.h"
27
#include "SyntheticSections.h"
28
#include "lld/Common/Strings.h"
29
#include "lld/Common/Threads.h"
30
#include "llvm/ADT/MapVector.h"
31
#include "llvm/ADT/SetVector.h"
32
#include "llvm/Support/raw_ostream.h"
33
34
using namespace llvm;
35
using namespace llvm::object;
36
37
using namespace lld;
38
using namespace lld::elf;
39
40
using SymbolMapTy = DenseMap<const SectionBase *, SmallVector<Defined *, 4>>;
41
42
static const std::string Indent8 = "        ";          // 8 spaces
43
static const std::string Indent16 = "                "; // 16 spaces
44
45
// Print out the first three columns of a line.
46
static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA,
47
502
                        uint64_t Size, uint64_t Align) {
48
502
  if (Config->Is64)
49
491
    OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align);
50
11
  else
51
11
    OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align);
52
502
}
53
54
// Returns a list of all symbols that we want to print out.
55
static std::vector<Defined *> getSymbols() {
56
  std::vector<Defined *> V;
57
  for (InputFile *File : ObjectFiles)
58
    for (Symbol *B : File->getSymbols())
59
      if (auto *DR = dyn_cast<Defined>(B))
60
        if (!DR->isSection() && DR->Section && DR->Section->Live &&
61
            (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss))
62
          V.push_back(DR);
63
  return V;
64
}
65
66
// Returns a map from sections to their symbols.
67
18
static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) {
68
18
  SymbolMapTy Ret;
69
18
  for (Defined *DR : Syms)
70
95
    Ret[DR->Section].push_back(DR);
71
18
72
18
  // Sort symbols by address. We want to print out symbols in the
73
18
  // order in the output file rather than the order they appeared
74
18
  // in the input files.
75
18
  for (auto &It : Ret)
76
67
    llvm::stable_sort(It.second, [](Defined *A, Defined *B) {
77
31
      return A->getVA() < B->getVA();
78
31
    });
79
18
  return Ret;
80
18
}
81
82
// Construct a map from symbols to their stringified representations.
83
// Demangling symbols (which is what toString() does) is slow, so
84
// we do that in batch using parallel-for.
85
static DenseMap<Symbol *, std::string>
86
18
getSymbolStrings(ArrayRef<Defined *> Syms) {
87
18
  std::vector<std::string> Str(Syms.size());
88
95
  parallelForEachN(0, Syms.size(), [&](size_t I) {
89
95
    raw_string_ostream OS(Str[I]);
90
95
    OutputSection *OSec = Syms[I]->getOutputSection();
91
95
    uint64_t VMA = Syms[I]->getVA();
92
95
    uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 
00
;
93
95
    writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1);
94
95
    OS << Indent16 << toString(*Syms[I]);
95
95
  });
96
18
97
18
  DenseMap<Symbol *, std::string> Ret;
98
113
  for (size_t I = 0, E = Syms.size(); I < E; 
++I95
)
99
95
    Ret[Syms[I]] = std::move(Str[I]);
100
18
  return Ret;
101
18
}
102
103
// Print .eh_frame contents. Since the section consists of EhSectionPieces,
104
// we need a specialized printer for that section.
105
//
106
// .eh_frame tend to contain a lot of section pieces that are contiguous
107
// both in input file and output file. Such pieces are squashed before
108
// being displayed to make output compact.
109
4
static void printEhFrame(raw_ostream &OS, OutputSection *OSec) {
110
4
  std::vector<EhSectionPiece> Pieces;
111
4
112
14
  auto Add = [&](const EhSectionPiece &P) {
113
14
    // If P is adjacent to Last, squash the two.
114
14
    if (!Pieces.empty()) {
115
10
      EhSectionPiece &Last = Pieces.back();
116
10
      if (Last.Sec == P.Sec && 
Last.InputOff + Last.Size == P.InputOff7
&&
117
10
          
Last.OutputOff + Last.Size == P.OutputOff7
) {
118
4
        Last.Size += P.Size;
119
4
        return;
120
4
      }
121
10
    }
122
10
    Pieces.push_back(P);
123
10
  };
124
4
125
4
  // Gather section pieces.
126
4
  for (const CieRecord *Rec : In.EhFrame->getCieRecords()) {
127
4
    Add(*Rec->Cie);
128
4
    for (const EhSectionPiece *Fde : Rec->Fdes)
129
10
      Add(*Fde);
130
4
  }
131
4
132
4
  // Print out section pieces.
133
10
  for (EhSectionPiece &P : Pieces) {
134
10
    writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff,
135
10
                P.Size, 1);
136
10
    OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x"
137
10
       << Twine::utohexstr(P.InputOff) + ")\n";
138
10
  }
139
4
}
140
141
2.32k
void elf::writeMapFile() {
142
2.32k
  if (Config->MapFile.empty())
143
2.30k
    return;
144
18
145
18
  // Open a map file for writing.
146
18
  std::error_code EC;
147
18
  raw_fd_ostream OS(Config->MapFile, EC, sys::fs::F_None);
148
18
  if (EC) {
149
0
    error("cannot open " + Config->MapFile + ": " + EC.message());
150
0
    return;
151
0
  }
152
18
153
18
  // Collect symbol info that we want to print out.
154
18
  std::vector<Defined *> Syms = getSymbols();
155
18
  SymbolMapTy SectionSyms = getSectionSyms(Syms);
156
18
  DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms);
157
18
158
18
  // Print out the header line.
159
18
  int W = Config->Is64 ? 
1617
:
81
;
160
18
  OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W)
161
18
     << "     Size Align Out     In      Symbol\n";
162
18
163
18
  OutputSection* OSec = nullptr;
164
172
  for (BaseCommand *Base : Script->SectionCommands) {
165
172
    if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
166
8
      if (Cmd->Provide && 
!Cmd->Sym1
)
167
1
        continue;
168
7
      uint64_t LMA = OSec ? 
OSec->getLMA() + Cmd->Addr - OSec->getVA(0)5
:
02
;
169
7
      writeHeader(OS, Cmd->Addr, LMA, Cmd->Size, 1);
170
7
      OS << Cmd->CommandString << '\n';
171
7
      continue;
172
7
    }
173
164
174
164
    OSec = cast<OutputSection>(Base);
175
164
    writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment);
176
164
    OS << OSec->Name << '\n';
177
164
178
164
    // Dump symbols for each input section.
179
179
    for (BaseCommand *Base : OSec->SectionCommands) {
180
179
      if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) {
181
218
        for (InputSection *IS : ISD->Sections) {
182
218
          if (IS == In.EhFrame) {
183
4
            printEhFrame(OS, OSec);
184
4
            continue;
185
4
          }
186
214
187
214
          writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0),
188
214
                      IS->getSize(), IS->Alignment);
189
214
          OS << Indent8 << toString(IS) << '\n';
190
214
          for (Symbol *Sym : SectionSyms[IS])
191
95
            OS << SymStr[Sym] << '\n';
192
214
        }
193
166
        continue;
194
166
      }
195
13
196
13
      if (auto *Cmd = dyn_cast<ByteCommand>(Base)) {
197
5
        writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset,
198
5
                    Cmd->Size, 1);
199
5
        OS << Indent8 << Cmd->CommandString << '\n';
200
5
        continue;
201
5
      }
202
8
203
8
      if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) {
204
8
        if (Cmd->Provide && 
!Cmd->Sym1
)
205
1
          continue;
206
7
        writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0),
207
7
                    Cmd->Size, 1);
208
7
        OS << Indent8 << Cmd->CommandString << '\n';
209
7
        continue;
210
7
      }
211
8
    }
212
164
  }
213
18
}
214
215
13
static void print(StringRef A, StringRef B) {
216
13
  outs() << left_justify(A, 49) << " " << B << "\n";
217
13
}
218
219
// Output a cross reference table to stdout. This is for --cref.
220
//
221
// For each global symbol, we print out a file that defines the symbol
222
// followed by files that uses that symbol. Here is an example.
223
//
224
//     strlen     /lib/x86_64-linux-gnu/libc.so.6
225
//                tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o
226
//                lib/libLLVMSupport.a(PrettyStackTrace.cpp.o)
227
//
228
// In this case, strlen is defined by libc.so.6 and used by other two
229
// files.
230
2.32k
void elf::writeCrossReferenceTable() {
231
2.32k
  if (!Config->Cref)
232
2.32k
    return;
233
2
234
2
  // Collect symbols and files.
235
2
  MapVector<Symbol *, SetVector<InputFile *>> Map;
236
4
  for (InputFile *File : ObjectFiles) {
237
16
    for (Symbol *Sym : File->getSymbols()) {
238
16
      if (isa<SharedSymbol>(Sym))
239
2
        Map[Sym].insert(File);
240
16
      if (auto *D = dyn_cast<Defined>(Sym))
241
10
        if (!D->isLocal() && 
(9
!D->Section9
||
D->Section->Live7
))
242
8
          Map[D].insert(File);
243
16
    }
244
4
  }
245
2
246
2
  // Print out a header.
247
2
  outs() << "Cross Reference Table\n\n";
248
2
  print("Symbol", "File");
249
2
250
2
  // Print out a table.
251
7
  for (auto KV : Map) {
252
7
    Symbol *Sym = KV.first;
253
7
    SetVector<InputFile *> &Files = KV.second;
254
7
255
7
    print(toString(*Sym), toString(Sym->File));
256
7
    for (InputFile *File : Files)
257
10
      if (File != Sym->File)
258
4
        print("", toString(File));
259
7
  }
260
2
}