10b57cec5SDimitry Andric //===- SymbolSize.cpp -----------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/Object/SymbolSize.h" 100b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 110b57cec5SDimitry Andric #include "llvm/Object/COFF.h" 120b57cec5SDimitry Andric #include "llvm/Object/ELFObjectFile.h" 130b57cec5SDimitry Andric #include "llvm/Object/MachO.h" 145ffd83dbSDimitry Andric #include "llvm/Object/Wasm.h" 15fe6060f1SDimitry Andric #include "llvm/Object/XCOFFObjectFile.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric using namespace llvm; 180b57cec5SDimitry Andric using namespace object; 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric // Orders increasingly by (SectionID, Address). 210b57cec5SDimitry Andric int llvm::object::compareAddress(const SymEntry *A, const SymEntry *B) { 220b57cec5SDimitry Andric if (A->SectionID != B->SectionID) 230b57cec5SDimitry Andric return A->SectionID < B->SectionID ? -1 : 1; 240b57cec5SDimitry Andric if (A->Address != B->Address) 250b57cec5SDimitry Andric return A->Address < B->Address ? -1 : 1; 260b57cec5SDimitry Andric return 0; 270b57cec5SDimitry Andric } 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric static unsigned getSectionID(const ObjectFile &O, SectionRef Sec) { 300b57cec5SDimitry Andric if (auto *M = dyn_cast<MachOObjectFile>(&O)) 310b57cec5SDimitry Andric return M->getSectionID(Sec); 325ffd83dbSDimitry Andric if (isa<WasmObjectFile>(&O)) 335ffd83dbSDimitry Andric return Sec.getIndex(); 34fe6060f1SDimitry Andric if (isa<XCOFFObjectFile>(&O)) 35fe6060f1SDimitry Andric return Sec.getIndex(); 360b57cec5SDimitry Andric return cast<COFFObjectFile>(O).getSectionID(Sec); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric static unsigned getSymbolSectionID(const ObjectFile &O, SymbolRef Sym) { 400b57cec5SDimitry Andric if (auto *M = dyn_cast<MachOObjectFile>(&O)) 410b57cec5SDimitry Andric return M->getSymbolSectionID(Sym); 425ffd83dbSDimitry Andric if (const auto *M = dyn_cast<WasmObjectFile>(&O)) 435ffd83dbSDimitry Andric return M->getSymbolSectionId(Sym); 44fe6060f1SDimitry Andric if (const auto *M = dyn_cast<XCOFFObjectFile>(&O)) 45fe6060f1SDimitry Andric return M->getSymbolSectionID(Sym); 460b57cec5SDimitry Andric return cast<COFFObjectFile>(O).getSymbolSectionID(Sym); 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric std::vector<std::pair<SymbolRef, uint64_t>> 500b57cec5SDimitry Andric llvm::object::computeSymbolSizes(const ObjectFile &O) { 510b57cec5SDimitry Andric std::vector<std::pair<SymbolRef, uint64_t>> Ret; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric if (const auto *E = dyn_cast<ELFObjectFileBase>(&O)) { 540b57cec5SDimitry Andric auto Syms = E->symbols(); 55e8d8bef9SDimitry Andric if (Syms.empty()) 560b57cec5SDimitry Andric Syms = E->getDynamicSymbolIterators(); 570b57cec5SDimitry Andric for (ELFSymbolRef Sym : Syms) 580b57cec5SDimitry Andric Ret.push_back({Sym, Sym.getSize()}); 590b57cec5SDimitry Andric return Ret; 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 625f757f3fSDimitry Andric if (const auto *E = dyn_cast<XCOFFObjectFile>(&O)) { 635f757f3fSDimitry Andric for (XCOFFSymbolRef Sym : E->symbols()) 645f757f3fSDimitry Andric Ret.push_back({Sym, Sym.getSize()}); 655f757f3fSDimitry Andric return Ret; 665f757f3fSDimitry Andric } 675f757f3fSDimitry Andric 68*0fca6ea1SDimitry Andric if (const auto *E = dyn_cast<WasmObjectFile>(&O)) { 69*0fca6ea1SDimitry Andric for (SymbolRef Sym : E->symbols()) { 70*0fca6ea1SDimitry Andric Ret.push_back({Sym, E->getSymbolSize(Sym)}); 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric return Ret; 73*0fca6ea1SDimitry Andric } 74*0fca6ea1SDimitry Andric 750b57cec5SDimitry Andric // Collect sorted symbol addresses. Include dummy addresses for the end 760b57cec5SDimitry Andric // of each section. 770b57cec5SDimitry Andric std::vector<SymEntry> Addresses; 780b57cec5SDimitry Andric unsigned SymNum = 0; 790b57cec5SDimitry Andric for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) { 800b57cec5SDimitry Andric SymbolRef Sym = *I; 815ffd83dbSDimitry Andric Expected<uint64_t> ValueOrErr = Sym.getValue(); 825ffd83dbSDimitry Andric if (!ValueOrErr) 835ffd83dbSDimitry Andric // TODO: Actually report errors helpfully. 845ffd83dbSDimitry Andric report_fatal_error(ValueOrErr.takeError()); 855ffd83dbSDimitry Andric Addresses.push_back({I, *ValueOrErr, SymNum, getSymbolSectionID(O, Sym)}); 860b57cec5SDimitry Andric ++SymNum; 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric for (SectionRef Sec : O.sections()) { 890b57cec5SDimitry Andric uint64_t Address = Sec.getAddress(); 900b57cec5SDimitry Andric uint64_t Size = Sec.getSize(); 910b57cec5SDimitry Andric Addresses.push_back( 920b57cec5SDimitry Andric {O.symbol_end(), Address + Size, 0, getSectionID(O, Sec)}); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric if (Addresses.empty()) 960b57cec5SDimitry Andric return Ret; 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress); 990b57cec5SDimitry Andric 1008a4dda33SDimitry Andric // Compute the size as the gap to the next symbol. If multiple symbols have 1018a4dda33SDimitry Andric // the same address, give both the same size. Because Addresses is sorted, 1025f757f3fSDimitry Andric // use two pointers to keep track of the current symbol vs. the next symbol 1038a4dda33SDimitry Andric // that doesn't have the same address for size computation. 1048a4dda33SDimitry Andric for (unsigned I = 0, NextI = 0, N = Addresses.size() - 1; I < N; ++I) { 1050b57cec5SDimitry Andric auto &P = Addresses[I]; 1060b57cec5SDimitry Andric if (P.I == O.symbol_end()) 1070b57cec5SDimitry Andric continue; 1080b57cec5SDimitry Andric 1098a4dda33SDimitry Andric // If the next pointer is behind, update it to the next symbol. 1108a4dda33SDimitry Andric if (NextI <= I) { 1118a4dda33SDimitry Andric NextI = I + 1; 1120b57cec5SDimitry Andric while (NextI < N && Addresses[NextI].Address == P.Address) 1130b57cec5SDimitry Andric ++NextI; 1148a4dda33SDimitry Andric } 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric uint64_t Size = Addresses[NextI].Address - P.Address; 1170b57cec5SDimitry Andric P.Address = Size; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric // Assign the sorted symbols in the original order. 1210b57cec5SDimitry Andric Ret.resize(SymNum); 1220b57cec5SDimitry Andric for (SymEntry &P : Addresses) { 1230b57cec5SDimitry Andric if (P.I == O.symbol_end()) 1240b57cec5SDimitry Andric continue; 1250b57cec5SDimitry Andric Ret[P.Number] = {*P.I, P.Address}; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric return Ret; 1280b57cec5SDimitry Andric } 129