1//===- SymbolSize.cpp -----------------------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
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 "llvm/Object/SymbolSize.h"
11#include "llvm/ADT/STLExtras.h"
12#include "llvm/Object/COFF.h"
13#include "llvm/Object/ELFObjectFile.h"
14#include "llvm/Object/MachO.h"
15
16using namespace llvm;
17using namespace object;
18
19namespace {
20struct SymEntry {
21  symbol_iterator I;
22  uint64_t Address;
23  unsigned Number;
24  unsigned SectionID;
25};
26}
27
28static int compareAddress(const SymEntry *A, const SymEntry *B) {
29  if (A->SectionID != B->SectionID)
30    return A->SectionID - B->SectionID;
31  return A->Address - B->Address;
32}
33
34static unsigned getSectionID(const ObjectFile &O, SectionRef Sec) {
35  if (auto *M = dyn_cast<MachOObjectFile>(&O))
36    return M->getSectionID(Sec);
37  return cast<COFFObjectFile>(O).getSectionID(Sec);
38}
39
40static unsigned getSymbolSectionID(const ObjectFile &O, SymbolRef Sym) {
41  if (auto *M = dyn_cast<MachOObjectFile>(&O))
42    return M->getSymbolSectionID(Sym);
43  return cast<COFFObjectFile>(O).getSymbolSectionID(Sym);
44}
45
46std::vector<std::pair<SymbolRef, uint64_t>>
47llvm::object::computeSymbolSizes(const ObjectFile &O) {
48  std::vector<std::pair<SymbolRef, uint64_t>> Ret;
49
50  if (const auto *E = dyn_cast<ELFObjectFileBase>(&O)) {
51    auto Syms = E->symbols();
52    if (Syms.begin() == Syms.end())
53      Syms = E->getDynamicSymbolIterators();
54    for (ELFSymbolRef Sym : Syms)
55      Ret.push_back({Sym, Sym.getSize()});
56    return Ret;
57  }
58
59  // Collect sorted symbol addresses. Include dummy addresses for the end
60  // of each section.
61  std::vector<SymEntry> Addresses;
62  unsigned SymNum = 0;
63  for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) {
64    SymbolRef Sym = *I;
65    uint64_t Value = Sym.getValue();
66    Addresses.push_back({I, Value, SymNum, getSymbolSectionID(O, Sym)});
67    ++SymNum;
68  }
69  for (SectionRef Sec : O.sections()) {
70    uint64_t Address = Sec.getAddress();
71    uint64_t Size = Sec.getSize();
72    Addresses.push_back(
73        {O.symbol_end(), Address + Size, 0, getSectionID(O, Sec)});
74  }
75  array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress);
76
77  // Compute the size as the gap to the next symbol
78  for (unsigned I = 0, N = Addresses.size() - 1; I < N; ++I) {
79    auto &P = Addresses[I];
80    if (P.I == O.symbol_end())
81      continue;
82
83    // If multiple symbol have the same address, give both the same size.
84    unsigned NextI = I + 1;
85    while (NextI < N && Addresses[NextI].Address == P.Address)
86      ++NextI;
87
88    uint64_t Size = Addresses[NextI].Address - P.Address;
89    P.Address = Size;
90  }
91
92  // Assign the sorted symbols in the original order.
93  Ret.resize(SymNum);
94  for (SymEntry &P : Addresses) {
95    if (P.I == O.symbol_end())
96      continue;
97    Ret[P.Number] = {*P.I, P.Address};
98  }
99  return Ret;
100}
101