1b109c032SRafael Espindola //===- SymbolSize.cpp -----------------------------------------------------===//
2b109c032SRafael Espindola //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b109c032SRafael Espindola //
7b109c032SRafael Espindola //===----------------------------------------------------------------------===//
8b109c032SRafael Espindola 
9b109c032SRafael Espindola #include "llvm/Object/SymbolSize.h"
10b109c032SRafael Espindola #include "llvm/ADT/STLExtras.h"
116bf32210SRafael Espindola #include "llvm/Object/COFF.h"
12b109c032SRafael Espindola #include "llvm/Object/ELFObjectFile.h"
136bf32210SRafael Espindola #include "llvm/Object/MachO.h"
14da6a896eSDerek Schuff #include "llvm/Object/Wasm.h"
15*8a23f74eSEsme-Yi #include "llvm/Object/XCOFFObjectFile.h"
16b109c032SRafael Espindola 
17b109c032SRafael Espindola using namespace llvm;
18b109c032SRafael Espindola using namespace object;
19b109c032SRafael Espindola 
20a3ccf3ddSKuba Brecka // Orders increasingly by (SectionID, Address).
compareAddress(const SymEntry * A,const SymEntry * B)21a3ccf3ddSKuba Brecka int llvm::object::compareAddress(const SymEntry *A, const SymEntry *B) {
226bf32210SRafael Espindola   if (A->SectionID != B->SectionID)
23a3ccf3ddSKuba Brecka     return A->SectionID < B->SectionID ? -1 : 1;
24a3ccf3ddSKuba Brecka   if (A->Address != B->Address)
25a3ccf3ddSKuba Brecka     return A->Address < B->Address ? -1 : 1;
26a3ccf3ddSKuba Brecka   return 0;
27b109c032SRafael Espindola }
28b109c032SRafael Espindola 
getSectionID(const ObjectFile & O,SectionRef Sec)296bf32210SRafael Espindola static unsigned getSectionID(const ObjectFile &O, SectionRef Sec) {
306bf32210SRafael Espindola   if (auto *M = dyn_cast<MachOObjectFile>(&O))
316bf32210SRafael Espindola     return M->getSectionID(Sec);
32a40b3e3bSNate Voorhies   if (isa<WasmObjectFile>(&O))
33da6a896eSDerek Schuff     return Sec.getIndex();
34*8a23f74eSEsme-Yi   if (isa<XCOFFObjectFile>(&O))
35*8a23f74eSEsme-Yi     return Sec.getIndex();
366bf32210SRafael Espindola   return cast<COFFObjectFile>(O).getSectionID(Sec);
376bf32210SRafael Espindola }
386bf32210SRafael Espindola 
getSymbolSectionID(const ObjectFile & O,SymbolRef Sym)396bf32210SRafael Espindola static unsigned getSymbolSectionID(const ObjectFile &O, SymbolRef Sym) {
406bf32210SRafael Espindola   if (auto *M = dyn_cast<MachOObjectFile>(&O))
416bf32210SRafael Espindola     return M->getSymbolSectionID(Sym);
42da6a896eSDerek Schuff   if (const auto *M = dyn_cast<WasmObjectFile>(&O))
43da6a896eSDerek Schuff     return M->getSymbolSectionId(Sym);
44*8a23f74eSEsme-Yi   if (const auto *M = dyn_cast<XCOFFObjectFile>(&O))
45*8a23f74eSEsme-Yi     return M->getSymbolSectionID(Sym);
466bf32210SRafael Espindola   return cast<COFFObjectFile>(O).getSymbolSectionID(Sym);
476bf32210SRafael Espindola }
486bf32210SRafael Espindola 
496bf32210SRafael Espindola std::vector<std::pair<SymbolRef, uint64_t>>
computeSymbolSizes(const ObjectFile & O)50b109c032SRafael Espindola llvm::object::computeSymbolSizes(const ObjectFile &O) {
51b109c032SRafael Espindola   std::vector<std::pair<SymbolRef, uint64_t>> Ret;
52b109c032SRafael Espindola 
53d7a32ea4SRafael Espindola   if (const auto *E = dyn_cast<ELFObjectFileBase>(&O)) {
54d8e96ec7SRafael Espindola     auto Syms = E->symbols();
552082b10dSKazu Hirata     if (Syms.empty())
56d8e96ec7SRafael Espindola       Syms = E->getDynamicSymbolIterators();
57dbb6bd33SRafael Espindola     for (ELFSymbolRef Sym : Syms)
58dbb6bd33SRafael Espindola       Ret.push_back({Sym, Sym.getSize()});
59b109c032SRafael Espindola     return Ret;
60b109c032SRafael Espindola   }
61b109c032SRafael Espindola 
62b109c032SRafael Espindola   // Collect sorted symbol addresses. Include dummy addresses for the end
63b109c032SRafael Espindola   // of each section.
64b109c032SRafael Espindola   std::vector<SymEntry> Addresses;
65b109c032SRafael Espindola   unsigned SymNum = 0;
66b109c032SRafael Espindola   for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) {
67b109c032SRafael Espindola     SymbolRef Sym = *I;
68ff6a0b6aSXing GUO     Expected<uint64_t> ValueOrErr = Sym.getValue();
69ff6a0b6aSXing GUO     if (!ValueOrErr)
70ff6a0b6aSXing GUO       // TODO: Actually report errors helpfully.
71ff6a0b6aSXing GUO       report_fatal_error(ValueOrErr.takeError());
72ff6a0b6aSXing GUO     Addresses.push_back({I, *ValueOrErr, SymNum, getSymbolSectionID(O, Sym)});
73b109c032SRafael Espindola     ++SymNum;
74b109c032SRafael Espindola   }
756bf32210SRafael Espindola   for (SectionRef Sec : O.sections()) {
76b109c032SRafael Espindola     uint64_t Address = Sec.getAddress();
77b109c032SRafael Espindola     uint64_t Size = Sec.getSize();
786bf32210SRafael Espindola     Addresses.push_back(
796bf32210SRafael Espindola         {O.symbol_end(), Address + Size, 0, getSectionID(O, Sec)});
80b109c032SRafael Espindola   }
81bbe980dfSAdrian Prantl 
82bbe980dfSAdrian Prantl   if (Addresses.empty())
83bbe980dfSAdrian Prantl     return Ret;
84bbe980dfSAdrian Prantl 
85b109c032SRafael Espindola   array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress);
86b109c032SRafael Espindola 
87b109c032SRafael Espindola   // Compute the size as the gap to the next symbol
88b109c032SRafael Espindola   for (unsigned I = 0, N = Addresses.size() - 1; I < N; ++I) {
89b109c032SRafael Espindola     auto &P = Addresses[I];
90b109c032SRafael Espindola     if (P.I == O.symbol_end())
91b109c032SRafael Espindola       continue;
9249943652SRafael Espindola 
9349943652SRafael Espindola     // If multiple symbol have the same address, give both the same size.
9449943652SRafael Espindola     unsigned NextI = I + 1;
9549943652SRafael Espindola     while (NextI < N && Addresses[NextI].Address == P.Address)
9649943652SRafael Espindola       ++NextI;
9749943652SRafael Espindola 
9849943652SRafael Espindola     uint64_t Size = Addresses[NextI].Address - P.Address;
99b109c032SRafael Espindola     P.Address = Size;
100b109c032SRafael Espindola   }
101b109c032SRafael Espindola 
102025f46f3SBenjamin Kramer   // Assign the sorted symbols in the original order.
103025f46f3SBenjamin Kramer   Ret.resize(SymNum);
104b109c032SRafael Espindola   for (SymEntry &P : Addresses) {
105b109c032SRafael Espindola     if (P.I == O.symbol_end())
106b109c032SRafael Espindola       continue;
107025f46f3SBenjamin Kramer     Ret[P.Number] = {*P.I, P.Address};
108b109c032SRafael Espindola   }
109b109c032SRafael Espindola   return Ret;
110b109c032SRafael Espindola }
111