Coverage Report

Created: 2018-01-17 17:22

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/wasm/InputFiles.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- InputFiles.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
#include "InputFiles.h"
11
12
#include "Config.h"
13
#include "InputChunks.h"
14
#include "SymbolTable.h"
15
#include "lld/Common/ErrorHandler.h"
16
#include "lld/Common/Memory.h"
17
#include "llvm/Object/Binary.h"
18
#include "llvm/Object/Wasm.h"
19
#include "llvm/Support/raw_ostream.h"
20
21
#define DEBUG_TYPE "lld"
22
23
using namespace lld;
24
using namespace lld::wasm;
25
26
using namespace llvm;
27
using namespace llvm::object;
28
using namespace llvm::wasm;
29
30
0
Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
31
0
  log("Loading: " + Path);
32
0
33
0
  auto MBOrErr = MemoryBuffer::getFile(Path);
34
0
  if (auto EC = MBOrErr.getError()) {
35
0
    error("cannot open " + Path + ": " + EC.message());
36
0
    return None;
37
0
  }
38
0
  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
39
0
  MemoryBufferRef MBRef = MB->getMemBufferRef();
40
0
  make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
41
0
42
0
  return MBRef;
43
0
}
44
45
0
void ObjFile::dumpInfo() const {
46
0
  log("info for: " + getName() + "\n" +
47
0
      "      Total Functions : " + Twine(FunctionSymbols.size()) + "\n" +
48
0
      "        Total Globals : " + Twine(GlobalSymbols.size()) + "\n" +
49
0
      "     Function Imports : " + Twine(NumFunctionImports) + "\n" +
50
0
      "       Global Imports : " + Twine(NumGlobalImports) + "\n" +
51
0
      "        Table Entries : " + Twine(TableSymbols.size()) + "\n");
52
0
}
53
54
0
uint32_t ObjFile::getRelocatedAddress(uint32_t GlobalIndex) const {
55
0
  return GlobalSymbols[GlobalIndex]->getVirtualAddress();
56
0
}
57
58
0
uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
59
0
  Symbol *Sym = FunctionSymbols[Original];
60
0
  uint32_t Index = Sym->getOutputIndex();
61
0
  DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": "
62
0
               << Original << " -> " << Index << "\n");
63
0
  return Index;
64
0
}
65
66
0
uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
67
0
  return TypeMap[Original];
68
0
}
69
70
0
uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
71
0
  Symbol *Sym = TableSymbols[Original];
72
0
  uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;
73
0
  DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
74
0
               << " -> " << Index << "\n");
75
0
  return Index;
76
0
}
77
78
0
uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const {
79
0
  Symbol *Sym = GlobalSymbols[Original];
80
0
  uint32_t Index = Sym->hasOutputIndex() ? Sym->getOutputIndex() : 0;
81
0
  DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original
82
0
               << " -> " << Index << "\n");
83
0
  return Index;
84
0
}
85
86
// Relocations contain an index into the function, global or table index
87
// space of the input file.  This function takes a relocation and returns the
88
// relocated index (i.e. translates from the input index space to the output
89
// index space).
90
0
uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const {
91
0
  switch (Reloc.Type) {
92
0
  case R_WEBASSEMBLY_TYPE_INDEX_LEB:
93
0
    return relocateTypeIndex(Reloc.Index);
94
0
  case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
95
0
    return relocateFunctionIndex(Reloc.Index);
96
0
  case R_WEBASSEMBLY_TABLE_INDEX_I32:
97
0
  case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
98
0
    return relocateTableIndex(Reloc.Index);
99
0
  case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
100
0
  case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
101
0
  case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
102
0
  case R_WEBASSEMBLY_MEMORY_ADDR_I32:
103
0
    return relocateGlobalIndex(Reloc.Index);
104
0
  default:
105
0
    llvm_unreachable("unknown relocation type");
106
0
  }
107
0
}
108
109
0
void ObjFile::parse() {
110
0
  // Parse a memory buffer as a wasm file.
111
0
  DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
112
0
  std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this));
113
0
114
0
  auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
115
0
  if (!Obj)
116
0
    fatal(toString(this) + ": not a wasm file");
117
0
  if (!Obj->isRelocatableObject())
118
0
    fatal(toString(this) + ": not a relocatable wasm file");
119
0
120
0
  Bin.release();
121
0
  WasmObj.reset(Obj);
122
0
123
0
  // Find the code and data sections.  Wasm objects can have at most one code
124
0
  // and one data section.
125
0
  for (const SectionRef &Sec : WasmObj->sections()) {
126
0
    const WasmSection &Section = WasmObj->getWasmSection(Sec);
127
0
    if (Section.Type == WASM_SEC_CODE)
128
0
      CodeSection = &Section;
129
0
    else if (Section.Type == WASM_SEC_DATA)
130
0
      DataSection = &Section;
131
0
  }
132
0
133
0
  initializeSymbols();
134
0
}
135
136
// Return the InputSegment in which a given symbol is defined.
137
0
InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) const {
138
0
  uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym);
139
0
  for (InputSegment *Segment : Segments) {
140
0
    if (Address >= Segment->startVA() && Address < Segment->endVA()) {
141
0
      DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> "
142
0
                   << Segment->getName() << "\n");
143
0
144
0
      return Segment;
145
0
    }
146
0
  }
147
0
  error("symbol not found in any segment: " + WasmSym.Name);
148
0
  return nullptr;
149
0
}
150
151
// Get the value stored in the wasm global represented by this symbol.
152
// This represents the virtual address of the symbol in the input file.
153
0
uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const {
154
0
  const WasmGlobal &Global =
155
0
      getWasmObj()->globals()[Sym.ElementIndex - NumGlobalImports];
156
0
  assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
157
0
  return Global.InitExpr.Value.Int32;
158
0
}
159
160
// Get the signature for a given function symbol, either by looking
161
// it up in function sections (for defined functions), of the imports section
162
// (for imported functions).
163
0
const WasmSignature *ObjFile::getFunctionSig(const WasmSymbol &Sym) const {
164
0
  DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n");
165
0
  return &WasmObj->types()[Sym.FunctionType];
166
0
}
167
168
0
InputFunction *ObjFile::getFunction(const WasmSymbol &Sym) const {
169
0
  uint32_t FunctionIndex = Sym.ElementIndex - NumFunctionImports;
170
0
  return Functions[FunctionIndex];
171
0
}
172
173
0
bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const {
174
0
  StringRef Comdat = Chunk->getComdat();
175
0
  return !Comdat.empty() && Symtab->findComdat(Comdat) != this;
176
0
}
177
178
0
void ObjFile::initializeSymbols() {
179
0
  Symbols.reserve(WasmObj->getNumberOfSymbols());
180
0
181
0
  for (const WasmImport &Import : WasmObj->imports()) {
182
0
    switch (Import.Kind) {
183
0
    case WASM_EXTERNAL_FUNCTION:
184
0
      ++NumFunctionImports;
185
0
      break;
186
0
    case WASM_EXTERNAL_GLOBAL:
187
0
      ++NumGlobalImports;
188
0
      break;
189
0
    }
190
0
  }
191
0
192
0
  FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size());
193
0
  GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size());
194
0
195
0
  ArrayRef<WasmFunction> Funcs = WasmObj->functions();
196
0
  ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
197
0
  ArrayRef<WasmSignature> Types = WasmObj->types();
198
0
  ArrayRef<WasmGlobal> Globals = WasmObj->globals();
199
0
200
0
  for (const auto &C : WasmObj->comdats())
201
0
    Symtab->addComdat(C, this);
202
0
203
0
  FunctionSymbols.resize(NumFunctionImports + Funcs.size());
204
0
  GlobalSymbols.resize(NumGlobalImports + Globals.size());
205
0
206
0
  for (const WasmSegment &S : WasmObj->dataSegments()) {
207
0
    InputSegment *Seg = make<InputSegment>(S, this);
208
0
    Seg->copyRelocations(*DataSection);
209
0
    Segments.emplace_back(Seg);
210
0
  }
211
0
212
0
  for (size_t I = 0; I < Funcs.size(); ++I) {
213
0
    const WasmFunction &Func = Funcs[I];
214
0
    const WasmSignature &Sig = Types[FuncTypes[I]];
215
0
    InputFunction *F = make<InputFunction>(Sig, &Func, this);
216
0
    F->copyRelocations(*CodeSection);
217
0
    Functions.emplace_back(F);
218
0
  }
219
0
220
0
  // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols
221
0
  // in the object
222
0
  for (const SymbolRef &Sym : WasmObj->symbols()) {
223
0
    const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
224
0
    Symbol *S;
225
0
    switch (WasmSym.Type) {
226
0
    case WasmSymbol::SymbolType::FUNCTION_EXPORT: {
227
0
      InputFunction *Function = getFunction(WasmSym);
228
0
      if (!isExcludedByComdat(Function)) {
229
0
        S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
230
0
                          Function);
231
0
        break;
232
0
      } else {
233
0
        Function->Discarded = true;
234
0
        LLVM_FALLTHROUGH; // Exclude function, and add the symbol as undefined
235
0
      }
236
0
    }
237
0
    case WasmSymbol::SymbolType::FUNCTION_IMPORT:
238
0
      S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
239
0
                          getFunctionSig(WasmSym));
240
0
      break;
241
0
    case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
242
0
      InputSegment *Segment = getSegment(WasmSym);
243
0
      if (!isExcludedByComdat(Segment)) {
244
0
        S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
245
0
                          Segment, nullptr, getGlobalValue(WasmSym));
246
0
        break;
247
0
      } else {
248
0
        Segment->Discarded = true;
249
0
        LLVM_FALLTHROUGH; // Exclude global, and add the symbol as undefined
250
0
      }
251
0
    }
252
0
    case WasmSymbol::SymbolType::GLOBAL_IMPORT:
253
0
      S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind);
254
0
      break;
255
0
    }
256
0
257
0
    Symbols.push_back(S);
258
0
    if (WasmSym.isFunction()) {
259
0
      FunctionSymbols[WasmSym.ElementIndex] = S;
260
0
      if (WasmSym.HasAltIndex)
261
0
        FunctionSymbols[WasmSym.AltIndex] = S;
262
0
    } else {
263
0
      GlobalSymbols[WasmSym.ElementIndex] = S;
264
0
      if (WasmSym.HasAltIndex)
265
0
        GlobalSymbols[WasmSym.AltIndex] = S;
266
0
    }
267
0
  }
268
0
269
0
  DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I)
270
0
            assert(FunctionSymbols[I] != nullptr);
271
0
        for (size_t I = 0; I < GlobalSymbols.size(); ++I)
272
0
            assert(GlobalSymbols[I] != nullptr););
273
0
274
0
  // Populate `TableSymbols` with all symbols that are called indirectly
275
0
  uint32_t SegmentCount = WasmObj->elements().size();
276
0
  if (SegmentCount) {
277
0
    if (SegmentCount > 1)
278
0
      fatal(getName() + ": contains more than one element segment");
279
0
    const WasmElemSegment &Segment = WasmObj->elements()[0];
280
0
    if (Segment.Offset.Opcode != WASM_OPCODE_I32_CONST)
281
0
      fatal(getName() + ": unsupported element segment");
282
0
    if (Segment.TableIndex != 0)
283
0
      fatal(getName() + ": unsupported table index in elem segment");
284
0
    if (Segment.Offset.Value.Int32 != 0)
285
0
      fatal(getName() + ": unsupported element segment offset");
286
0
    TableSymbols.reserve(Segment.Functions.size());
287
0
    for (uint64_t FunctionIndex : Segment.Functions)
288
0
      TableSymbols.push_back(FunctionSymbols[FunctionIndex]);
289
0
  }
290
0
291
0
  DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n");
292
0
  DEBUG(dbgs() << "Functions   : " << FunctionSymbols.size() << "\n");
293
0
  DEBUG(dbgs() << "Globals     : " << GlobalSymbols.size() << "\n");
294
0
}
295
296
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
297
0
                                 const WasmSignature *Signature) {
298
0
  return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);
299
0
}
300
301
Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
302
                               const InputSegment *Segment,
303
0
                               InputFunction *Function, uint32_t Address) {
304
0
  Symbol *S;
305
0
  if (Sym.isLocal()) {
306
0
    S = make<Symbol>(Sym.Name, true);
307
0
    S->update(Kind, this, Sym.Flags, Segment, Function, Address);
308
0
    return S;
309
0
  }
310
0
  return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Segment, Function,
311
0
                            Address);
312
0
}
313
314
0
void ArchiveFile::parse() {
315
0
  // Parse a MemoryBufferRef as an archive file.
316
0
  DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
317
0
  File = CHECK(Archive::create(MB), toString(this));
318
0
319
0
  // Read the symbol table to construct Lazy symbols.
320
0
  int Count = 0;
321
0
  for (const Archive::Symbol &Sym : File->symbols()) {
322
0
    Symtab->addLazy(this, &Sym);
323
0
    ++Count;
324
0
  }
325
0
  DEBUG(dbgs() << "Read " << Count << " symbols\n");
326
0
}
327
328
0
void ArchiveFile::addMember(const Archive::Symbol *Sym) {
329
0
  const Archive::Child &C =
330
0
      CHECK(Sym->getMember(),
331
0
            "could not get the member for symbol " + Sym->getName());
332
0
333
0
  // Don't try to load the same member twice (this can happen when members
334
0
  // mutually reference each other).
335
0
  if (!Seen.insert(C.getChildOffset()).second)
336
0
    return;
337
0
338
0
  DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n");
339
0
  DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
340
0
341
0
  MemoryBufferRef MB =
342
0
      CHECK(C.getMemoryBufferRef(),
343
0
            "could not get the buffer for the member defining symbol " +
344
0
                Sym->getName());
345
0
346
0
  if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) {
347
0
    error("unknown file type: " + MB.getBufferIdentifier());
348
0
    return;
349
0
  }
350
0
351
0
  InputFile *Obj = make<ObjFile>(MB);
352
0
  Obj->ParentName = ParentName;
353
0
  Symtab->addFile(Obj);
354
0
}
355
356
// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
357
0
std::string lld::toString(const wasm::InputFile *File) {
358
0
  if (!File)
359
0
    return "<internal>";
360
0
361
0
  if (File->ParentName.empty())
362
0
    return File->getName();
363
0
364
0
  return (File->ParentName + "(" + File->getName() + ")").str();
365
0
}