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