1 //===- SymbolSize.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Object/SymbolSize.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "llvm/Object/COFF.h"
12 #include "llvm/Object/ELFObjectFile.h"
13 #include "llvm/Object/MachO.h"
14 #include "llvm/Object/Wasm.h"
15 #include "llvm/Object/XCOFFObjectFile.h"
18 using namespace object
;
20 // Orders increasingly by (SectionID, Address).
21 int llvm::object::compareAddress(const SymEntry
*A
, const SymEntry
*B
) {
22 if (A
->SectionID
!= B
->SectionID
)
23 return A
->SectionID
< B
->SectionID
? -1 : 1;
24 if (A
->Address
!= B
->Address
)
25 return A
->Address
< B
->Address
? -1 : 1;
29 static unsigned getSectionID(const ObjectFile
&O
, SectionRef Sec
) {
30 if (auto *M
= dyn_cast
<MachOObjectFile
>(&O
))
31 return M
->getSectionID(Sec
);
32 if (isa
<WasmObjectFile
>(&O
))
33 return Sec
.getIndex();
34 if (isa
<XCOFFObjectFile
>(&O
))
35 return Sec
.getIndex();
36 return cast
<COFFObjectFile
>(O
).getSectionID(Sec
);
39 static unsigned getSymbolSectionID(const ObjectFile
&O
, SymbolRef Sym
) {
40 if (auto *M
= dyn_cast
<MachOObjectFile
>(&O
))
41 return M
->getSymbolSectionID(Sym
);
42 if (const auto *M
= dyn_cast
<WasmObjectFile
>(&O
))
43 return M
->getSymbolSectionId(Sym
);
44 if (const auto *M
= dyn_cast
<XCOFFObjectFile
>(&O
))
45 return M
->getSymbolSectionID(Sym
);
46 return cast
<COFFObjectFile
>(O
).getSymbolSectionID(Sym
);
49 std::vector
<std::pair
<SymbolRef
, uint64_t>>
50 llvm::object::computeSymbolSizes(const ObjectFile
&O
) {
51 std::vector
<std::pair
<SymbolRef
, uint64_t>> Ret
;
53 if (const auto *E
= dyn_cast
<ELFObjectFileBase
>(&O
)) {
54 auto Syms
= E
->symbols();
56 Syms
= E
->getDynamicSymbolIterators();
57 for (ELFSymbolRef Sym
: Syms
)
58 Ret
.push_back({Sym
, Sym
.getSize()});
62 if (const auto *E
= dyn_cast
<XCOFFObjectFile
>(&O
)) {
63 for (XCOFFSymbolRef Sym
: E
->symbols())
64 Ret
.push_back({Sym
, Sym
.getSize()});
68 if (const auto *E
= dyn_cast
<WasmObjectFile
>(&O
)) {
69 for (SymbolRef Sym
: E
->symbols()) {
70 Ret
.push_back({Sym
, E
->getSymbolSize(Sym
)});
75 // Collect sorted symbol addresses. Include dummy addresses for the end
77 std::vector
<SymEntry
> Addresses
;
79 for (symbol_iterator I
= O
.symbol_begin(), E
= O
.symbol_end(); I
!= E
; ++I
) {
81 Expected
<uint64_t> ValueOrErr
= Sym
.getValue();
83 // TODO: Actually report errors helpfully.
84 report_fatal_error(ValueOrErr
.takeError());
85 Addresses
.push_back({I
, *ValueOrErr
, SymNum
, getSymbolSectionID(O
, Sym
)});
88 for (SectionRef Sec
: O
.sections()) {
89 uint64_t Address
= Sec
.getAddress();
90 uint64_t Size
= Sec
.getSize();
92 {O
.symbol_end(), Address
+ Size
, 0, getSectionID(O
, Sec
)});
95 if (Addresses
.empty())
98 array_pod_sort(Addresses
.begin(), Addresses
.end(), compareAddress
);
100 // Compute the size as the gap to the next symbol. If multiple symbols have
101 // the same address, give both the same size. Because Addresses is sorted,
102 // use two pointers to keep track of the current symbol vs. the next symbol
103 // that doesn't have the same address for size computation.
104 for (unsigned I
= 0, NextI
= 0, N
= Addresses
.size() - 1; I
< N
; ++I
) {
105 auto &P
= Addresses
[I
];
106 if (P
.I
== O
.symbol_end())
109 // If the next pointer is behind, update it to the next symbol.
112 while (NextI
< N
&& Addresses
[NextI
].Address
== P
.Address
)
116 uint64_t Size
= Addresses
[NextI
].Address
- P
.Address
;
120 // Assign the sorted symbols in the original order.
122 for (SymEntry
&P
: Addresses
) {
123 if (P
.I
== O
.symbol_end())
125 Ret
[P
.Number
] = {*P
.I
, P
.Address
};