xref: /aosp_15_r20/external/stg/elf_reader.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2022 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License.  You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker //     https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Aleksei Vetrov
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #include "elf_reader.h"
21*9e3b08aeSAndroid Build Coastguard Worker 
22*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
23*9e3b08aeSAndroid Build Coastguard Worker #include <map>
24*9e3b08aeSAndroid Build Coastguard Worker #include <memory>
25*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
26*9e3b08aeSAndroid Build Coastguard Worker #include <string>
27*9e3b08aeSAndroid Build Coastguard Worker #include <string_view>
28*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
29*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
30*9e3b08aeSAndroid Build Coastguard Worker 
31*9e3b08aeSAndroid Build Coastguard Worker #include "dwarf_processor.h"
32*9e3b08aeSAndroid Build Coastguard Worker #include "dwarf_wrappers.h"
33*9e3b08aeSAndroid Build Coastguard Worker #include "elf_dwarf_handle.h"
34*9e3b08aeSAndroid Build Coastguard Worker #include "elf_loader.h"
35*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
36*9e3b08aeSAndroid Build Coastguard Worker #include "filter.h"
37*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
38*9e3b08aeSAndroid Build Coastguard Worker #include "reader_options.h"
39*9e3b08aeSAndroid Build Coastguard Worker #include "runtime.h"
40*9e3b08aeSAndroid Build Coastguard Worker #include "type_normalisation.h"
41*9e3b08aeSAndroid Build Coastguard Worker #include "type_resolution.h"
42*9e3b08aeSAndroid Build Coastguard Worker #include "unification.h"
43*9e3b08aeSAndroid Build Coastguard Worker 
44*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
45*9e3b08aeSAndroid Build Coastguard Worker namespace elf {
46*9e3b08aeSAndroid Build Coastguard Worker namespace internal {
47*9e3b08aeSAndroid Build Coastguard Worker 
48*9e3b08aeSAndroid Build Coastguard Worker namespace {
49*9e3b08aeSAndroid Build Coastguard Worker 
50*9e3b08aeSAndroid Build Coastguard Worker template <typename M, typename K>
MaybeGet(const M & map,const K & key)51*9e3b08aeSAndroid Build Coastguard Worker std::optional<typename M::mapped_type> MaybeGet(const M& map, const K& key) {
52*9e3b08aeSAndroid Build Coastguard Worker   const auto it = map.find(key);
53*9e3b08aeSAndroid Build Coastguard Worker   if (it == map.end()) {
54*9e3b08aeSAndroid Build Coastguard Worker     return {};
55*9e3b08aeSAndroid Build Coastguard Worker   }
56*9e3b08aeSAndroid Build Coastguard Worker   return {it->second};
57*9e3b08aeSAndroid Build Coastguard Worker }
58*9e3b08aeSAndroid Build Coastguard Worker 
59*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
60*9e3b08aeSAndroid Build Coastguard Worker 
ConvertSymbolType(SymbolTableEntry::SymbolType symbol_type)61*9e3b08aeSAndroid Build Coastguard Worker ElfSymbol::SymbolType ConvertSymbolType(
62*9e3b08aeSAndroid Build Coastguard Worker     SymbolTableEntry::SymbolType symbol_type) {
63*9e3b08aeSAndroid Build Coastguard Worker   switch (symbol_type) {
64*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::NOTYPE:
65*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::NOTYPE;
66*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::OBJECT:
67*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::OBJECT;
68*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::FUNCTION:
69*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::FUNCTION;
70*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::COMMON:
71*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::COMMON;
72*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::TLS:
73*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::TLS;
74*9e3b08aeSAndroid Build Coastguard Worker     case SymbolTableEntry::SymbolType::GNU_IFUNC:
75*9e3b08aeSAndroid Build Coastguard Worker       return ElfSymbol::SymbolType::GNU_IFUNC;
76*9e3b08aeSAndroid Build Coastguard Worker     default:
77*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unsupported ELF symbol type: " << symbol_type;
78*9e3b08aeSAndroid Build Coastguard Worker   }
79*9e3b08aeSAndroid Build Coastguard Worker }
80*9e3b08aeSAndroid Build Coastguard Worker 
GetKsymtabSymbols(const SymbolTable & symbols)81*9e3b08aeSAndroid Build Coastguard Worker SymbolNameList GetKsymtabSymbols(const SymbolTable& symbols) {
82*9e3b08aeSAndroid Build Coastguard Worker   constexpr std::string_view kKsymtabPrefix = "__ksymtab_";
83*9e3b08aeSAndroid Build Coastguard Worker   SymbolNameList result;
84*9e3b08aeSAndroid Build Coastguard Worker   result.reserve(symbols.size() / 2);
85*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : symbols) {
86*9e3b08aeSAndroid Build Coastguard Worker     if (symbol.name.substr(0, kKsymtabPrefix.size()) == kKsymtabPrefix) {
87*9e3b08aeSAndroid Build Coastguard Worker       result.emplace(symbol.name.substr(kKsymtabPrefix.size()));
88*9e3b08aeSAndroid Build Coastguard Worker     }
89*9e3b08aeSAndroid Build Coastguard Worker   }
90*9e3b08aeSAndroid Build Coastguard Worker   return result;
91*9e3b08aeSAndroid Build Coastguard Worker }
92*9e3b08aeSAndroid Build Coastguard Worker 
GetCRCValuesMap(const SymbolTable & symbols,const ElfLoader & elf)93*9e3b08aeSAndroid Build Coastguard Worker CRCValuesMap GetCRCValuesMap(const SymbolTable& symbols, const ElfLoader& elf) {
94*9e3b08aeSAndroid Build Coastguard Worker   constexpr std::string_view kCRCPrefix = "__crc_";
95*9e3b08aeSAndroid Build Coastguard Worker 
96*9e3b08aeSAndroid Build Coastguard Worker   CRCValuesMap crc_values;
97*9e3b08aeSAndroid Build Coastguard Worker 
98*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : symbols) {
99*9e3b08aeSAndroid Build Coastguard Worker     const std::string_view name = symbol.name;
100*9e3b08aeSAndroid Build Coastguard Worker     if (name.substr(0, kCRCPrefix.size()) == kCRCPrefix) {
101*9e3b08aeSAndroid Build Coastguard Worker       const std::string_view name_suffix = name.substr(kCRCPrefix.size());
102*9e3b08aeSAndroid Build Coastguard Worker       if (!crc_values.emplace(name_suffix, elf.GetElfSymbolCRC(symbol))
103*9e3b08aeSAndroid Build Coastguard Worker                .second) {
104*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Multiple CRC values for symbol '" << name_suffix << '\'';
105*9e3b08aeSAndroid Build Coastguard Worker       }
106*9e3b08aeSAndroid Build Coastguard Worker     }
107*9e3b08aeSAndroid Build Coastguard Worker   }
108*9e3b08aeSAndroid Build Coastguard Worker 
109*9e3b08aeSAndroid Build Coastguard Worker   return crc_values;
110*9e3b08aeSAndroid Build Coastguard Worker }
111*9e3b08aeSAndroid Build Coastguard Worker 
GetNamespacesMap(const SymbolTable & symbols,const ElfLoader & elf)112*9e3b08aeSAndroid Build Coastguard Worker NamespacesMap GetNamespacesMap(const SymbolTable& symbols,
113*9e3b08aeSAndroid Build Coastguard Worker                                const ElfLoader& elf) {
114*9e3b08aeSAndroid Build Coastguard Worker   constexpr std::string_view kNSPrefix = "__kstrtabns_";
115*9e3b08aeSAndroid Build Coastguard Worker 
116*9e3b08aeSAndroid Build Coastguard Worker   NamespacesMap namespaces;
117*9e3b08aeSAndroid Build Coastguard Worker 
118*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : symbols) {
119*9e3b08aeSAndroid Build Coastguard Worker     const std::string_view name = symbol.name;
120*9e3b08aeSAndroid Build Coastguard Worker     if (name.substr(0, kNSPrefix.size()) == kNSPrefix) {
121*9e3b08aeSAndroid Build Coastguard Worker       const std::string_view name_suffix = name.substr(kNSPrefix.size());
122*9e3b08aeSAndroid Build Coastguard Worker       const std::string_view ns = elf.GetElfSymbolNamespace(symbol);
123*9e3b08aeSAndroid Build Coastguard Worker       if (ns.empty()) {
124*9e3b08aeSAndroid Build Coastguard Worker         // The global namespace is explicitly represented as the empty string,
125*9e3b08aeSAndroid Build Coastguard Worker         // but the common interpretation is that such symbols lack an export
126*9e3b08aeSAndroid Build Coastguard Worker         // namespace.
127*9e3b08aeSAndroid Build Coastguard Worker         continue;
128*9e3b08aeSAndroid Build Coastguard Worker       }
129*9e3b08aeSAndroid Build Coastguard Worker       if (!namespaces.emplace(name_suffix, ns).second) {
130*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Multiple namespaces for symbol '" << name_suffix << '\'';
131*9e3b08aeSAndroid Build Coastguard Worker       }
132*9e3b08aeSAndroid Build Coastguard Worker     }
133*9e3b08aeSAndroid Build Coastguard Worker   }
134*9e3b08aeSAndroid Build Coastguard Worker 
135*9e3b08aeSAndroid Build Coastguard Worker   return namespaces;
136*9e3b08aeSAndroid Build Coastguard Worker }
137*9e3b08aeSAndroid Build Coastguard Worker 
GetCFIAddressMap(const SymbolTable & symbols,const ElfLoader & elf)138*9e3b08aeSAndroid Build Coastguard Worker AddressMap GetCFIAddressMap(const SymbolTable& symbols, const ElfLoader& elf) {
139*9e3b08aeSAndroid Build Coastguard Worker   AddressMap name_to_address;
140*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : symbols) {
141*9e3b08aeSAndroid Build Coastguard Worker     const std::string_view name_prefix = UnwrapCFISymbolName(symbol.name);
142*9e3b08aeSAndroid Build Coastguard Worker     const size_t address = elf.GetAbsoluteAddress(symbol);
143*9e3b08aeSAndroid Build Coastguard Worker     if (!name_to_address.emplace(name_prefix, address).second) {
144*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Multiple CFI symbols referring to symbol '" << name_prefix
145*9e3b08aeSAndroid Build Coastguard Worker             << '\'';
146*9e3b08aeSAndroid Build Coastguard Worker     }
147*9e3b08aeSAndroid Build Coastguard Worker   }
148*9e3b08aeSAndroid Build Coastguard Worker   return name_to_address;
149*9e3b08aeSAndroid Build Coastguard Worker }
150*9e3b08aeSAndroid Build Coastguard Worker 
IsPublicFunctionOrVariable(const SymbolTableEntry & symbol)151*9e3b08aeSAndroid Build Coastguard Worker bool IsPublicFunctionOrVariable(const SymbolTableEntry& symbol) {
152*9e3b08aeSAndroid Build Coastguard Worker   const auto symbol_type = symbol.symbol_type;
153*9e3b08aeSAndroid Build Coastguard Worker   // Reject symbols that are not functions or variables.
154*9e3b08aeSAndroid Build Coastguard Worker   if (symbol_type != SymbolTableEntry::SymbolType::FUNCTION &&
155*9e3b08aeSAndroid Build Coastguard Worker       symbol_type != SymbolTableEntry::SymbolType::OBJECT &&
156*9e3b08aeSAndroid Build Coastguard Worker       symbol_type != SymbolTableEntry::SymbolType::TLS &&
157*9e3b08aeSAndroid Build Coastguard Worker       symbol_type != SymbolTableEntry::SymbolType::GNU_IFUNC) {
158*9e3b08aeSAndroid Build Coastguard Worker     return false;
159*9e3b08aeSAndroid Build Coastguard Worker   }
160*9e3b08aeSAndroid Build Coastguard Worker 
161*9e3b08aeSAndroid Build Coastguard Worker   // Function or variable of ValueType::ABSOLUTE is not expected in any binary,
162*9e3b08aeSAndroid Build Coastguard Worker   // but GNU `ld` adds object of such type for every version name defined in
163*9e3b08aeSAndroid Build Coastguard Worker   // file. Such symbol should be rejected, because in fact it is not variable.
164*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.value_type == SymbolTableEntry::ValueType::ABSOLUTE) {
165*9e3b08aeSAndroid Build Coastguard Worker     Check(symbol_type == SymbolTableEntry::SymbolType::OBJECT)
166*9e3b08aeSAndroid Build Coastguard Worker         << "Unexpected function or variable with ABSOLUTE value type";
167*9e3b08aeSAndroid Build Coastguard Worker     return false;
168*9e3b08aeSAndroid Build Coastguard Worker   }
169*9e3b08aeSAndroid Build Coastguard Worker 
170*9e3b08aeSAndroid Build Coastguard Worker   // Undefined symbol is dependency of the binary but is not part of ABI
171*9e3b08aeSAndroid Build Coastguard Worker   // provided by binary and should be rejected.
172*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.value_type == SymbolTableEntry::ValueType::UNDEFINED) {
173*9e3b08aeSAndroid Build Coastguard Worker     return false;
174*9e3b08aeSAndroid Build Coastguard Worker   }
175*9e3b08aeSAndroid Build Coastguard Worker 
176*9e3b08aeSAndroid Build Coastguard Worker   // Local symbol is not visible outside the binary, so it is not public
177*9e3b08aeSAndroid Build Coastguard Worker   // and should be rejected.
178*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.binding == SymbolTableEntry::Binding::LOCAL) {
179*9e3b08aeSAndroid Build Coastguard Worker     return false;
180*9e3b08aeSAndroid Build Coastguard Worker   }
181*9e3b08aeSAndroid Build Coastguard Worker 
182*9e3b08aeSAndroid Build Coastguard Worker   // "Hidden" and "internal" visibility values mean that symbol is not public
183*9e3b08aeSAndroid Build Coastguard Worker   // and should be rejected.
184*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.visibility == SymbolTableEntry::Visibility::HIDDEN ||
185*9e3b08aeSAndroid Build Coastguard Worker       symbol.visibility == SymbolTableEntry::Visibility::INTERNAL) {
186*9e3b08aeSAndroid Build Coastguard Worker     return false;
187*9e3b08aeSAndroid Build Coastguard Worker   }
188*9e3b08aeSAndroid Build Coastguard Worker 
189*9e3b08aeSAndroid Build Coastguard Worker   return true;
190*9e3b08aeSAndroid Build Coastguard Worker }
191*9e3b08aeSAndroid Build Coastguard Worker 
IsLinuxKernelFunctionOrVariable(const SymbolNameList & ksymtab,const SymbolTableEntry & symbol)192*9e3b08aeSAndroid Build Coastguard Worker bool IsLinuxKernelFunctionOrVariable(const SymbolNameList& ksymtab,
193*9e3b08aeSAndroid Build Coastguard Worker                                      const SymbolTableEntry& symbol) {
194*9e3b08aeSAndroid Build Coastguard Worker   // We use symbol name extracted from __ksymtab_ symbols as a proxy for the
195*9e3b08aeSAndroid Build Coastguard Worker   // real symbol in the ksymtab. Such names can still be duplicated by LOCAL
196*9e3b08aeSAndroid Build Coastguard Worker   // symbols so drop them to avoid false matches.
197*9e3b08aeSAndroid Build Coastguard Worker   if (symbol.binding == SymbolTableEntry::Binding::LOCAL) {
198*9e3b08aeSAndroid Build Coastguard Worker     return false;
199*9e3b08aeSAndroid Build Coastguard Worker   }
200*9e3b08aeSAndroid Build Coastguard Worker   // TODO: handle undefined ksymtab symbols
201*9e3b08aeSAndroid Build Coastguard Worker   return ksymtab.contains(symbol.name);
202*9e3b08aeSAndroid Build Coastguard Worker }
203*9e3b08aeSAndroid Build Coastguard Worker 
204*9e3b08aeSAndroid Build Coastguard Worker namespace {
205*9e3b08aeSAndroid Build Coastguard Worker 
206*9e3b08aeSAndroid Build Coastguard Worker class Reader {
207*9e3b08aeSAndroid Build Coastguard Worker  public:
Reader(Runtime & runtime,Graph & graph,ElfDwarfHandle & elf_dwarf_handle,ReadOptions options,const std::unique_ptr<Filter> & file_filter)208*9e3b08aeSAndroid Build Coastguard Worker   Reader(Runtime& runtime, Graph& graph, ElfDwarfHandle& elf_dwarf_handle,
209*9e3b08aeSAndroid Build Coastguard Worker          ReadOptions options, const std::unique_ptr<Filter>& file_filter)
210*9e3b08aeSAndroid Build Coastguard Worker       : graph_(graph),
211*9e3b08aeSAndroid Build Coastguard Worker         elf_dwarf_handle_(elf_dwarf_handle),
212*9e3b08aeSAndroid Build Coastguard Worker         elf_(elf_dwarf_handle_.GetElf()),
213*9e3b08aeSAndroid Build Coastguard Worker         options_(options),
214*9e3b08aeSAndroid Build Coastguard Worker         file_filter_(file_filter),
215*9e3b08aeSAndroid Build Coastguard Worker         runtime_(runtime) {}
216*9e3b08aeSAndroid Build Coastguard Worker 
217*9e3b08aeSAndroid Build Coastguard Worker   Id Read();
218*9e3b08aeSAndroid Build Coastguard Worker 
219*9e3b08aeSAndroid Build Coastguard Worker  private:
220*9e3b08aeSAndroid Build Coastguard Worker   using SymbolIndex =
221*9e3b08aeSAndroid Build Coastguard Worker       std::map<std::pair<dwarf::Address, std::string>, std::vector<size_t>>;
222*9e3b08aeSAndroid Build Coastguard Worker 
223*9e3b08aeSAndroid Build Coastguard Worker   void GetLinuxKernelSymbols(
224*9e3b08aeSAndroid Build Coastguard Worker       const std::vector<SymbolTableEntry>& all_symbols,
225*9e3b08aeSAndroid Build Coastguard Worker       std::vector<std::pair<ElfSymbol, size_t>>& symbols) const;
226*9e3b08aeSAndroid Build Coastguard Worker   void GetUserspaceSymbols(
227*9e3b08aeSAndroid Build Coastguard Worker       const std::vector<SymbolTableEntry>& all_symbols,
228*9e3b08aeSAndroid Build Coastguard Worker       std::vector<std::pair<ElfSymbol, size_t>>& symbols) const;
229*9e3b08aeSAndroid Build Coastguard Worker 
BuildRoot(const std::vector<std::pair<ElfSymbol,size_t>> & symbols)230*9e3b08aeSAndroid Build Coastguard Worker   Id BuildRoot(const std::vector<std::pair<ElfSymbol, size_t>>& symbols) {
231*9e3b08aeSAndroid Build Coastguard Worker     // On destruction, the unification object will remove or rewrite each graph
232*9e3b08aeSAndroid Build Coastguard Worker     // node for which it has a mapping.
233*9e3b08aeSAndroid Build Coastguard Worker     //
234*9e3b08aeSAndroid Build Coastguard Worker     // Graph rewriting is expensive so an important optimisation is to restrict
235*9e3b08aeSAndroid Build Coastguard Worker     // the nodes in consideration to the ones allocated by the DWARF processor
236*9e3b08aeSAndroid Build Coastguard Worker     // here and any symbol or type roots that follow. This is done by setting
237*9e3b08aeSAndroid Build Coastguard Worker     // the starting node ID to be the current graph limit.
238*9e3b08aeSAndroid Build Coastguard Worker     Unification unification(runtime_, graph_, graph_.Limit());
239*9e3b08aeSAndroid Build Coastguard Worker 
240*9e3b08aeSAndroid Build Coastguard Worker     const dwarf::Types types =
241*9e3b08aeSAndroid Build Coastguard Worker         dwarf::Process(elf_dwarf_handle_.GetDwarf(),
242*9e3b08aeSAndroid Build Coastguard Worker                        elf_.IsLittleEndianBinary(), file_filter_, graph_);
243*9e3b08aeSAndroid Build Coastguard Worker 
244*9e3b08aeSAndroid Build Coastguard Worker     // A less important optimisation is avoiding copying the mapping array as it
245*9e3b08aeSAndroid Build Coastguard Worker     // is populated. This is done by reserving space to the new graph limit.
246*9e3b08aeSAndroid Build Coastguard Worker     unification.Reserve(graph_.Limit());
247*9e3b08aeSAndroid Build Coastguard Worker 
248*9e3b08aeSAndroid Build Coastguard Worker     // fill address to id
249*9e3b08aeSAndroid Build Coastguard Worker     //
250*9e3b08aeSAndroid Build Coastguard Worker     // In general, we want to handle as many of the following cases as possible.
251*9e3b08aeSAndroid Build Coastguard Worker     // In practice, determining the correct ELF-DWARF match may be impossible.
252*9e3b08aeSAndroid Build Coastguard Worker     //
253*9e3b08aeSAndroid Build Coastguard Worker     // * compiler-driven aliasing - multiple symbols with same address
254*9e3b08aeSAndroid Build Coastguard Worker     // * zero-size symbol false aliasing - multiple symbols and types with same
255*9e3b08aeSAndroid Build Coastguard Worker     //   address
256*9e3b08aeSAndroid Build Coastguard Worker     // * weak/strong linkage symbols - multiple symbols and types with same
257*9e3b08aeSAndroid Build Coastguard Worker     //   address
258*9e3b08aeSAndroid Build Coastguard Worker     // * assembly symbols - multiple declarations but no definition and no
259*9e3b08aeSAndroid Build Coastguard Worker     //   address in DWARF.
260*9e3b08aeSAndroid Build Coastguard Worker     SymbolIndex address_name_to_index;
261*9e3b08aeSAndroid Build Coastguard Worker     for (size_t i = 0; i < types.symbols.size(); ++i) {
262*9e3b08aeSAndroid Build Coastguard Worker       const auto& symbol = types.symbols[i];
263*9e3b08aeSAndroid Build Coastguard Worker       address_name_to_index[{symbol.address, symbol.linkage_name}].push_back(i);
264*9e3b08aeSAndroid Build Coastguard Worker     }
265*9e3b08aeSAndroid Build Coastguard Worker 
266*9e3b08aeSAndroid Build Coastguard Worker     std::map<std::string, Id> symbols_map;
267*9e3b08aeSAndroid Build Coastguard Worker     for (auto [symbol, address] : symbols) {
268*9e3b08aeSAndroid Build Coastguard Worker       // TODO: add VersionInfoToString to SymbolKey name
269*9e3b08aeSAndroid Build Coastguard Worker       // TODO: check for uniqueness of SymbolKey in map after
270*9e3b08aeSAndroid Build Coastguard Worker       // support for version info
271*9e3b08aeSAndroid Build Coastguard Worker       MaybeAddTypeInfo(address_name_to_index, types.symbols, address, symbol,
272*9e3b08aeSAndroid Build Coastguard Worker                        unification);
273*9e3b08aeSAndroid Build Coastguard Worker       symbols_map.emplace(VersionedSymbolName(symbol),
274*9e3b08aeSAndroid Build Coastguard Worker                           graph_.Add<ElfSymbol>(symbol));
275*9e3b08aeSAndroid Build Coastguard Worker     }
276*9e3b08aeSAndroid Build Coastguard Worker 
277*9e3b08aeSAndroid Build Coastguard Worker     std::map<std::string, Id> types_map;
278*9e3b08aeSAndroid Build Coastguard Worker     if (options_.Test(ReadOptions::TYPE_ROOTS)) {
279*9e3b08aeSAndroid Build Coastguard Worker       const InterfaceKey get_key(graph_);
280*9e3b08aeSAndroid Build Coastguard Worker       for (const auto id : types.named_type_ids) {
281*9e3b08aeSAndroid Build Coastguard Worker         const auto [it, inserted] = types_map.emplace(get_key(id), id);
282*9e3b08aeSAndroid Build Coastguard Worker         if (!inserted && !unification.Unify(id, it->second)) {
283*9e3b08aeSAndroid Build Coastguard Worker           Die() << "found conflicting interface type: " << it->first;
284*9e3b08aeSAndroid Build Coastguard Worker         }
285*9e3b08aeSAndroid Build Coastguard Worker       }
286*9e3b08aeSAndroid Build Coastguard Worker     }
287*9e3b08aeSAndroid Build Coastguard Worker 
288*9e3b08aeSAndroid Build Coastguard Worker     Id root = graph_.Add<Interface>(
289*9e3b08aeSAndroid Build Coastguard Worker         std::move(symbols_map), std::move(types_map));
290*9e3b08aeSAndroid Build Coastguard Worker 
291*9e3b08aeSAndroid Build Coastguard Worker     // Use all named types and DWARF declarations as roots for type resolution.
292*9e3b08aeSAndroid Build Coastguard Worker     std::vector<Id> roots;
293*9e3b08aeSAndroid Build Coastguard Worker     roots.reserve(types.named_type_ids.size() + types.symbols.size() + 1);
294*9e3b08aeSAndroid Build Coastguard Worker     for (const auto& symbol : types.symbols) {
295*9e3b08aeSAndroid Build Coastguard Worker       roots.push_back(symbol.type_id);
296*9e3b08aeSAndroid Build Coastguard Worker     }
297*9e3b08aeSAndroid Build Coastguard Worker     for (const auto id : types.named_type_ids) {
298*9e3b08aeSAndroid Build Coastguard Worker       roots.push_back(id);
299*9e3b08aeSAndroid Build Coastguard Worker     }
300*9e3b08aeSAndroid Build Coastguard Worker     roots.push_back(root);
301*9e3b08aeSAndroid Build Coastguard Worker 
302*9e3b08aeSAndroid Build Coastguard Worker     stg::ResolveTypes(runtime_, graph_, unification, {roots});
303*9e3b08aeSAndroid Build Coastguard Worker 
304*9e3b08aeSAndroid Build Coastguard Worker     unification.Update(root);
305*9e3b08aeSAndroid Build Coastguard Worker     return root;
306*9e3b08aeSAndroid Build Coastguard Worker   }
307*9e3b08aeSAndroid Build Coastguard Worker 
IsEqual(Unification & unification,const dwarf::Types::Symbol & lhs,const dwarf::Types::Symbol & rhs)308*9e3b08aeSAndroid Build Coastguard Worker   static bool IsEqual(Unification& unification,
309*9e3b08aeSAndroid Build Coastguard Worker                       const dwarf::Types::Symbol& lhs,
310*9e3b08aeSAndroid Build Coastguard Worker                       const dwarf::Types::Symbol& rhs) {
311*9e3b08aeSAndroid Build Coastguard Worker     return lhs.scoped_name == rhs.scoped_name
312*9e3b08aeSAndroid Build Coastguard Worker         && lhs.linkage_name == rhs.linkage_name
313*9e3b08aeSAndroid Build Coastguard Worker         && lhs.address == rhs.address
314*9e3b08aeSAndroid Build Coastguard Worker         && unification.Unify(lhs.type_id, rhs.type_id);
315*9e3b08aeSAndroid Build Coastguard Worker   }
316*9e3b08aeSAndroid Build Coastguard Worker 
SymbolTableEntryToElfSymbol(const CRCValuesMap & crc_values,const NamespacesMap & namespaces,const SymbolTableEntry & symbol)317*9e3b08aeSAndroid Build Coastguard Worker   static ElfSymbol SymbolTableEntryToElfSymbol(
318*9e3b08aeSAndroid Build Coastguard Worker       const CRCValuesMap& crc_values, const NamespacesMap& namespaces,
319*9e3b08aeSAndroid Build Coastguard Worker       const SymbolTableEntry& symbol) {
320*9e3b08aeSAndroid Build Coastguard Worker     return {
321*9e3b08aeSAndroid Build Coastguard Worker         /* symbol_name = */ std::string(symbol.name),
322*9e3b08aeSAndroid Build Coastguard Worker         /* version_info = */ std::nullopt,
323*9e3b08aeSAndroid Build Coastguard Worker         /* is_defined = */
324*9e3b08aeSAndroid Build Coastguard Worker         symbol.value_type != SymbolTableEntry::ValueType::UNDEFINED,
325*9e3b08aeSAndroid Build Coastguard Worker         /* symbol_type = */ ConvertSymbolType(symbol.symbol_type),
326*9e3b08aeSAndroid Build Coastguard Worker         /* binding = */ symbol.binding,
327*9e3b08aeSAndroid Build Coastguard Worker         /* visibility = */ symbol.visibility,
328*9e3b08aeSAndroid Build Coastguard Worker         /* crc = */ MaybeGet(crc_values, std::string(symbol.name)),
329*9e3b08aeSAndroid Build Coastguard Worker         /* ns = */ MaybeGet(namespaces, std::string(symbol.name)),
330*9e3b08aeSAndroid Build Coastguard Worker         /* type_id = */ std::nullopt,
331*9e3b08aeSAndroid Build Coastguard Worker         /* full_name = */ std::nullopt};
332*9e3b08aeSAndroid Build Coastguard Worker   }
333*9e3b08aeSAndroid Build Coastguard Worker 
MaybeAddTypeInfo(const SymbolIndex & address_name_to_index,const std::vector<dwarf::Types::Symbol> & dwarf_symbols,size_t address_value,ElfSymbol & node,Unification & unification)334*9e3b08aeSAndroid Build Coastguard Worker   static void MaybeAddTypeInfo(
335*9e3b08aeSAndroid Build Coastguard Worker       const SymbolIndex& address_name_to_index,
336*9e3b08aeSAndroid Build Coastguard Worker       const std::vector<dwarf::Types::Symbol>& dwarf_symbols,
337*9e3b08aeSAndroid Build Coastguard Worker       size_t address_value, ElfSymbol& node, Unification& unification) {
338*9e3b08aeSAndroid Build Coastguard Worker     // TLS symbols address may be incorrect because of unsupported
339*9e3b08aeSAndroid Build Coastguard Worker     // relocations. Resetting it to zero the same way as it is done in
340*9e3b08aeSAndroid Build Coastguard Worker     // dwarf::Entry::GetAddressFromLocation.
341*9e3b08aeSAndroid Build Coastguard Worker     // TODO: match TLS variables by address
342*9e3b08aeSAndroid Build Coastguard Worker     const dwarf::Address address =
343*9e3b08aeSAndroid Build Coastguard Worker         node.symbol_type == ElfSymbol::SymbolType::TLS
344*9e3b08aeSAndroid Build Coastguard Worker             ? dwarf::Address{dwarf::Address::Kind::TLS, 0}
345*9e3b08aeSAndroid Build Coastguard Worker             : dwarf::Address{dwarf::Address::Kind::ADDRESS, address_value};
346*9e3b08aeSAndroid Build Coastguard Worker     // try to find the first symbol with given address
347*9e3b08aeSAndroid Build Coastguard Worker     const auto start_it = address_name_to_index.lower_bound(
348*9e3b08aeSAndroid Build Coastguard Worker         std::make_pair(address, std::string()));
349*9e3b08aeSAndroid Build Coastguard Worker     auto best_symbols_it = address_name_to_index.end();
350*9e3b08aeSAndroid Build Coastguard Worker     bool matched_by_name = false;
351*9e3b08aeSAndroid Build Coastguard Worker     size_t candidates = 0;
352*9e3b08aeSAndroid Build Coastguard Worker     for (auto it = start_it;
353*9e3b08aeSAndroid Build Coastguard Worker          it != address_name_to_index.end() && it->first.first == address;
354*9e3b08aeSAndroid Build Coastguard Worker          ++it) {
355*9e3b08aeSAndroid Build Coastguard Worker       ++candidates;
356*9e3b08aeSAndroid Build Coastguard Worker       // We have at least matching addresses.
357*9e3b08aeSAndroid Build Coastguard Worker       if (it->first.second == node.symbol_name) {
358*9e3b08aeSAndroid Build Coastguard Worker         // If we have also matching names we can stop looking further.
359*9e3b08aeSAndroid Build Coastguard Worker         matched_by_name = true;
360*9e3b08aeSAndroid Build Coastguard Worker         best_symbols_it = it;
361*9e3b08aeSAndroid Build Coastguard Worker         break;
362*9e3b08aeSAndroid Build Coastguard Worker       }
363*9e3b08aeSAndroid Build Coastguard Worker       if (best_symbols_it == address_name_to_index.end()) {
364*9e3b08aeSAndroid Build Coastguard Worker         // Otherwise keep the first match.
365*9e3b08aeSAndroid Build Coastguard Worker         best_symbols_it = it;
366*9e3b08aeSAndroid Build Coastguard Worker       }
367*9e3b08aeSAndroid Build Coastguard Worker     }
368*9e3b08aeSAndroid Build Coastguard Worker     if (best_symbols_it != address_name_to_index.end()) {
369*9e3b08aeSAndroid Build Coastguard Worker       const auto& best_symbols = best_symbols_it->second;
370*9e3b08aeSAndroid Build Coastguard Worker       Check(!best_symbols.empty()) << "best_symbols.empty()";
371*9e3b08aeSAndroid Build Coastguard Worker       const auto& best_symbol = dwarf_symbols[best_symbols[0]];
372*9e3b08aeSAndroid Build Coastguard Worker       for (size_t i = 1; i < best_symbols.size(); ++i) {
373*9e3b08aeSAndroid Build Coastguard Worker         const auto& other = dwarf_symbols[best_symbols[i]];
374*9e3b08aeSAndroid Build Coastguard Worker         // TODO: allow "compatible" duplicates, for example
375*9e3b08aeSAndroid Build Coastguard Worker         // "void foo(int bar)" vs "void foo(const int bar)"
376*9e3b08aeSAndroid Build Coastguard Worker         if (!IsEqual(unification, best_symbol, other)) {
377*9e3b08aeSAndroid Build Coastguard Worker           Die() << "Duplicate DWARF symbol: address="
378*9e3b08aeSAndroid Build Coastguard Worker                 << best_symbols_it->first.first
379*9e3b08aeSAndroid Build Coastguard Worker                 << ", name=" << best_symbols_it->first.second;
380*9e3b08aeSAndroid Build Coastguard Worker         }
381*9e3b08aeSAndroid Build Coastguard Worker       }
382*9e3b08aeSAndroid Build Coastguard Worker       if (best_symbol.scoped_name.empty()) {
383*9e3b08aeSAndroid Build Coastguard Worker         Die() << "Anonymous DWARF symbol: address="
384*9e3b08aeSAndroid Build Coastguard Worker               << best_symbols_it->first.first
385*9e3b08aeSAndroid Build Coastguard Worker               << ", name=" << best_symbols_it->first.second;
386*9e3b08aeSAndroid Build Coastguard Worker       }
387*9e3b08aeSAndroid Build Coastguard Worker       // There may be multiple DWARF symbols with same address (zero-length
388*9e3b08aeSAndroid Build Coastguard Worker       // arrays), or ELF symbol has different name from DWARF symbol (aliases).
389*9e3b08aeSAndroid Build Coastguard Worker       // But if we have both situations at once, we can't match ELF to DWARF and
390*9e3b08aeSAndroid Build Coastguard Worker       // it should be fixed in analysed binary source code.
391*9e3b08aeSAndroid Build Coastguard Worker       Check(matched_by_name || candidates == 1)
392*9e3b08aeSAndroid Build Coastguard Worker           << "Multiple candidate symbols without matching name: address="
393*9e3b08aeSAndroid Build Coastguard Worker           << best_symbols_it->first.first
394*9e3b08aeSAndroid Build Coastguard Worker           << ", name=" << best_symbols_it->first.second;
395*9e3b08aeSAndroid Build Coastguard Worker       node.type_id = best_symbol.type_id;
396*9e3b08aeSAndroid Build Coastguard Worker       node.full_name = best_symbol.scoped_name;
397*9e3b08aeSAndroid Build Coastguard Worker     }
398*9e3b08aeSAndroid Build Coastguard Worker   }
399*9e3b08aeSAndroid Build Coastguard Worker 
400*9e3b08aeSAndroid Build Coastguard Worker   Graph& graph_;
401*9e3b08aeSAndroid Build Coastguard Worker   ElfDwarfHandle& elf_dwarf_handle_;
402*9e3b08aeSAndroid Build Coastguard Worker   ElfLoader elf_;
403*9e3b08aeSAndroid Build Coastguard Worker   ReadOptions options_;
404*9e3b08aeSAndroid Build Coastguard Worker   const std::unique_ptr<Filter>& file_filter_;
405*9e3b08aeSAndroid Build Coastguard Worker   Runtime& runtime_;
406*9e3b08aeSAndroid Build Coastguard Worker };
407*9e3b08aeSAndroid Build Coastguard Worker 
GetLinuxKernelSymbols(const std::vector<SymbolTableEntry> & all_symbols,std::vector<std::pair<ElfSymbol,size_t>> & symbols) const408*9e3b08aeSAndroid Build Coastguard Worker void Reader::GetLinuxKernelSymbols(
409*9e3b08aeSAndroid Build Coastguard Worker     const std::vector<SymbolTableEntry>& all_symbols,
410*9e3b08aeSAndroid Build Coastguard Worker     std::vector<std::pair<ElfSymbol, size_t>>& symbols) const {
411*9e3b08aeSAndroid Build Coastguard Worker   const auto crcs = GetCRCValuesMap(all_symbols, elf_);
412*9e3b08aeSAndroid Build Coastguard Worker   const auto namespaces = GetNamespacesMap(all_symbols, elf_);
413*9e3b08aeSAndroid Build Coastguard Worker   const auto ksymtab_symbols = GetKsymtabSymbols(all_symbols);
414*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : all_symbols) {
415*9e3b08aeSAndroid Build Coastguard Worker     if (IsLinuxKernelFunctionOrVariable(ksymtab_symbols, symbol)) {
416*9e3b08aeSAndroid Build Coastguard Worker       const size_t address = elf_.GetAbsoluteAddress(symbol);
417*9e3b08aeSAndroid Build Coastguard Worker       symbols.emplace_back(
418*9e3b08aeSAndroid Build Coastguard Worker           SymbolTableEntryToElfSymbol(crcs, namespaces, symbol), address);
419*9e3b08aeSAndroid Build Coastguard Worker     }
420*9e3b08aeSAndroid Build Coastguard Worker   }
421*9e3b08aeSAndroid Build Coastguard Worker }
422*9e3b08aeSAndroid Build Coastguard Worker 
GetUserspaceSymbols(const std::vector<SymbolTableEntry> & all_symbols,std::vector<std::pair<ElfSymbol,size_t>> & symbols) const423*9e3b08aeSAndroid Build Coastguard Worker void Reader::GetUserspaceSymbols(
424*9e3b08aeSAndroid Build Coastguard Worker     const std::vector<SymbolTableEntry>& all_symbols,
425*9e3b08aeSAndroid Build Coastguard Worker     std::vector<std::pair<ElfSymbol, size_t>>& symbols) const {
426*9e3b08aeSAndroid Build Coastguard Worker   const auto cfi_address_map = GetCFIAddressMap(elf_.GetCFISymbols(), elf_);
427*9e3b08aeSAndroid Build Coastguard Worker   for (const auto& symbol : all_symbols) {
428*9e3b08aeSAndroid Build Coastguard Worker     if (IsPublicFunctionOrVariable(symbol)) {
429*9e3b08aeSAndroid Build Coastguard Worker       const auto cfi_it = cfi_address_map.find(std::string(symbol.name));
430*9e3b08aeSAndroid Build Coastguard Worker       const size_t address = cfi_it != cfi_address_map.end()
431*9e3b08aeSAndroid Build Coastguard Worker                                  ? cfi_it->second
432*9e3b08aeSAndroid Build Coastguard Worker                                  : elf_.GetAbsoluteAddress(symbol);
433*9e3b08aeSAndroid Build Coastguard Worker       symbols.emplace_back(
434*9e3b08aeSAndroid Build Coastguard Worker           SymbolTableEntryToElfSymbol({}, {}, symbol), address);
435*9e3b08aeSAndroid Build Coastguard Worker     }
436*9e3b08aeSAndroid Build Coastguard Worker   }
437*9e3b08aeSAndroid Build Coastguard Worker }
438*9e3b08aeSAndroid Build Coastguard Worker 
Read()439*9e3b08aeSAndroid Build Coastguard Worker Id Reader::Read() {
440*9e3b08aeSAndroid Build Coastguard Worker   const auto all_symbols = elf_.GetElfSymbols();
441*9e3b08aeSAndroid Build Coastguard Worker   const auto get_symbols = elf_.IsLinuxKernelBinary()
442*9e3b08aeSAndroid Build Coastguard Worker                            ? &Reader::GetLinuxKernelSymbols
443*9e3b08aeSAndroid Build Coastguard Worker                            : &Reader::GetUserspaceSymbols;
444*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<ElfSymbol, size_t>> symbols;
445*9e3b08aeSAndroid Build Coastguard Worker   symbols.reserve(all_symbols.size());
446*9e3b08aeSAndroid Build Coastguard Worker   (this->*get_symbols)(all_symbols, symbols);
447*9e3b08aeSAndroid Build Coastguard Worker   symbols.shrink_to_fit();
448*9e3b08aeSAndroid Build Coastguard Worker 
449*9e3b08aeSAndroid Build Coastguard Worker   const Id root = BuildRoot(symbols);
450*9e3b08aeSAndroid Build Coastguard Worker 
451*9e3b08aeSAndroid Build Coastguard Worker   // Types produced by ELF/DWARF readers may require removing useless
452*9e3b08aeSAndroid Build Coastguard Worker   // qualifiers.
453*9e3b08aeSAndroid Build Coastguard Worker   return RemoveUselessQualifiers(graph_, root);
454*9e3b08aeSAndroid Build Coastguard Worker }
455*9e3b08aeSAndroid Build Coastguard Worker 
456*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
457*9e3b08aeSAndroid Build Coastguard Worker }  // namespace internal
458*9e3b08aeSAndroid Build Coastguard Worker 
Read(Runtime & runtime,Graph & graph,ElfDwarfHandle & elf_dwarf_handle,ReadOptions options,const std::unique_ptr<Filter> & file_filter)459*9e3b08aeSAndroid Build Coastguard Worker Id Read(Runtime& runtime, Graph& graph, ElfDwarfHandle& elf_dwarf_handle,
460*9e3b08aeSAndroid Build Coastguard Worker         ReadOptions options, const std::unique_ptr<Filter>& file_filter) {
461*9e3b08aeSAndroid Build Coastguard Worker   return internal::Reader(runtime, graph, elf_dwarf_handle, options,
462*9e3b08aeSAndroid Build Coastguard Worker                           file_filter)
463*9e3b08aeSAndroid Build Coastguard Worker       .Read();
464*9e3b08aeSAndroid Build Coastguard Worker }
465*9e3b08aeSAndroid Build Coastguard Worker 
466*9e3b08aeSAndroid Build Coastguard Worker }  // namespace elf
467*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
468