Extract an utility for computing symbol sizes on MachO and COFF.
[oota-llvm.git] / lib / Object / SymbolSize.cpp
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/ELFObjectFile.h"
13
14 using namespace llvm;
15 using namespace object;
16
17 namespace {
18 struct SymEntry {
19   symbol_iterator I;
20   uint64_t Address;
21   unsigned Number;
22   SectionRef Section;
23 };
24 }
25
26 static int compareAddress(const SymEntry *A, const SymEntry *B) {
27   if (A->Section == B->Section)
28     return A->Address - B->Address;
29   if (A->Section < B->Section)
30     return -1;
31   return 1;
32 }
33
34 static int compareNumber(const SymEntry *A, const SymEntry *B) {
35   return A->Number - B->Number;
36 }
37
38 ErrorOr<std::vector<std::pair<SymbolRef, uint64_t>>>
39 llvm::object::computeSymbolSizes(const ObjectFile &O) {
40   std::vector<std::pair<SymbolRef, uint64_t>> Ret;
41
42   if (isa<ELFObjectFileBase>(&O)) {
43     for (SymbolRef Sym : O.symbols()) {
44       Ret.push_back({Sym, Sym.getSize()});
45     }
46     return Ret;
47   }
48
49   // Collect sorted symbol addresses. Include dummy addresses for the end
50   // of each section.
51   std::vector<SymEntry> Addresses;
52   unsigned SymNum = 0;
53   for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) {
54     SymbolRef Sym = *I;
55     uint64_t Address;
56     if (std::error_code EC = Sym.getAddress(Address))
57       return EC;
58     section_iterator SecI = O.section_end();
59     if (std::error_code EC = Sym.getSection(SecI))
60       return EC;
61     Addresses.push_back({I, Address, SymNum, *SecI});
62     ++SymNum;
63   }
64   for (const SectionRef Sec : O.sections()) {
65     uint64_t Address = Sec.getAddress();
66     uint64_t Size = Sec.getSize();
67     Addresses.push_back({O.symbol_end(), Address + Size, 0, Sec});
68   }
69   array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress);
70
71   // Compute the size as the gap to the next symbol
72   for (unsigned I = 0, N = Addresses.size() - 1; I < N; ++I) {
73     auto &P = Addresses[I];
74     if (P.I == O.symbol_end())
75       continue;
76     uint64_t Size = Addresses[I + 1].Address - P.Address;
77     P.Address = Size;
78   }
79
80   // Put back in the original order and copy the result
81   array_pod_sort(Addresses.begin(), Addresses.end(), compareNumber);
82   for (SymEntry &P : Addresses) {
83     if (P.I == O.symbol_end())
84       continue;
85     Ret.push_back({*P.I, P.Address});
86   }
87   return Ret;
88 }