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 // Collect sorted symbol addresses. Include dummy addresses for the end
70 std::vector
<SymEntry
> Addresses
;
72 for (symbol_iterator I
= O
.symbol_begin(), E
= O
.symbol_end(); I
!= E
; ++I
) {
74 Expected
<uint64_t> ValueOrErr
= Sym
.getValue();
76 // TODO: Actually report errors helpfully.
77 report_fatal_error(ValueOrErr
.takeError());
78 Addresses
.push_back({I
, *ValueOrErr
, SymNum
, getSymbolSectionID(O
, Sym
)});
81 for (SectionRef Sec
: O
.sections()) {
82 uint64_t Address
= Sec
.getAddress();
83 uint64_t Size
= Sec
.getSize();
85 {O
.symbol_end(), Address
+ Size
, 0, getSectionID(O
, Sec
)});
88 if (Addresses
.empty())
91 array_pod_sort(Addresses
.begin(), Addresses
.end(), compareAddress
);
93 // Compute the size as the gap to the next symbol. If multiple symbols have
94 // the same address, give both the same size. Because Addresses is sorted,
95 // use two pointers to keep track of the current symbol vs. the next symbol
96 // that doesn't have the same address for size computation.
97 for (unsigned I
= 0, NextI
= 0, N
= Addresses
.size() - 1; I
< N
; ++I
) {
98 auto &P
= Addresses
[I
];
99 if (P
.I
== O
.symbol_end())
102 // If the next pointer is behind, update it to the next symbol.
105 while (NextI
< N
&& Addresses
[NextI
].Address
== P
.Address
)
109 uint64_t Size
= Addresses
[NextI
].Address
- P
.Address
;
113 // Assign the sorted symbols in the original order.
115 for (SymEntry
&P
: Addresses
) {
116 if (P
.I
== O
.symbol_end())
118 Ret
[P
.Number
] = {*P
.I
, P
.Address
};