xref: /aosp_15_r20/external/stg/btf_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 2020-2024 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: Maria Teguiani
19*9e3b08aeSAndroid Build Coastguard Worker // Author: Giuliano Procida
20*9e3b08aeSAndroid Build Coastguard Worker // Author: Ignes Simeonova
21*9e3b08aeSAndroid Build Coastguard Worker // Author: Aleksei Vetrov
22*9e3b08aeSAndroid Build Coastguard Worker 
23*9e3b08aeSAndroid Build Coastguard Worker #include "btf_reader.h"
24*9e3b08aeSAndroid Build Coastguard Worker 
25*9e3b08aeSAndroid Build Coastguard Worker #include <algorithm>
26*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
27*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
28*9e3b08aeSAndroid Build Coastguard Worker #include <cstring>
29*9e3b08aeSAndroid Build Coastguard Worker #include <map>
30*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
31*9e3b08aeSAndroid Build Coastguard Worker #include <sstream>
32*9e3b08aeSAndroid Build Coastguard Worker #include <string>
33*9e3b08aeSAndroid Build Coastguard Worker #include <string_view>
34*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
35*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
36*9e3b08aeSAndroid Build Coastguard Worker 
37*9e3b08aeSAndroid Build Coastguard Worker #include <linux/btf.h>
38*9e3b08aeSAndroid Build Coastguard Worker #include "elf_dwarf_handle.h"
39*9e3b08aeSAndroid Build Coastguard Worker #include "elf_loader.h"
40*9e3b08aeSAndroid Build Coastguard Worker #include "error.h"
41*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
42*9e3b08aeSAndroid Build Coastguard Worker #include "reader_options.h"
43*9e3b08aeSAndroid Build Coastguard Worker 
44*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
45*9e3b08aeSAndroid Build Coastguard Worker 
46*9e3b08aeSAndroid Build Coastguard Worker namespace btf {
47*9e3b08aeSAndroid Build Coastguard Worker 
48*9e3b08aeSAndroid Build Coastguard Worker namespace {
49*9e3b08aeSAndroid Build Coastguard Worker 
50*9e3b08aeSAndroid Build Coastguard Worker // BTF Specification: https://www.kernel.org/doc/html/latest/bpf/btf.html
51*9e3b08aeSAndroid Build Coastguard Worker class Structs {
52*9e3b08aeSAndroid Build Coastguard Worker  public:
53*9e3b08aeSAndroid Build Coastguard Worker   explicit Structs(Graph& graph);
54*9e3b08aeSAndroid Build Coastguard Worker   Id Process(std::string_view data);
55*9e3b08aeSAndroid Build Coastguard Worker 
56*9e3b08aeSAndroid Build Coastguard Worker  private:
57*9e3b08aeSAndroid Build Coastguard Worker   struct MemoryRange {
58*9e3b08aeSAndroid Build Coastguard Worker     const char* start;
59*9e3b08aeSAndroid Build Coastguard Worker     const char* limit;
60*9e3b08aeSAndroid Build Coastguard Worker     bool Empty() const;
61*9e3b08aeSAndroid Build Coastguard Worker     template <typename T> const T* Pull(size_t count = 1);
62*9e3b08aeSAndroid Build Coastguard Worker   };
63*9e3b08aeSAndroid Build Coastguard Worker 
64*9e3b08aeSAndroid Build Coastguard Worker   MemoryRange string_section_;
65*9e3b08aeSAndroid Build Coastguard Worker 
66*9e3b08aeSAndroid Build Coastguard Worker   Maker<uint32_t> maker_;
67*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Id> void_;
68*9e3b08aeSAndroid Build Coastguard Worker   std::optional<Id> variadic_;
69*9e3b08aeSAndroid Build Coastguard Worker   std::map<std::string, Id> btf_symbols_;
70*9e3b08aeSAndroid Build Coastguard Worker 
71*9e3b08aeSAndroid Build Coastguard Worker   Id ProcessAligned(std::string_view data);
72*9e3b08aeSAndroid Build Coastguard Worker 
73*9e3b08aeSAndroid Build Coastguard Worker   Id GetVoid();
74*9e3b08aeSAndroid Build Coastguard Worker   Id GetVariadic();
75*9e3b08aeSAndroid Build Coastguard Worker   Id GetIdRaw(uint32_t btf_index);
76*9e3b08aeSAndroid Build Coastguard Worker   Id GetId(uint32_t btf_index);
77*9e3b08aeSAndroid Build Coastguard Worker   Id GetParameterId(uint32_t btf_index);
78*9e3b08aeSAndroid Build Coastguard Worker   template <typename Node, typename... Args>
79*9e3b08aeSAndroid Build Coastguard Worker   void Set(uint32_t id, Args&&... args);
80*9e3b08aeSAndroid Build Coastguard Worker 
81*9e3b08aeSAndroid Build Coastguard Worker   Id BuildTypes(MemoryRange memory);
82*9e3b08aeSAndroid Build Coastguard Worker   void BuildOneType(const btf_type* t, uint32_t btf_index,
83*9e3b08aeSAndroid Build Coastguard Worker                     MemoryRange& memory);
84*9e3b08aeSAndroid Build Coastguard Worker   Id BuildSymbols();
85*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> BuildMembers(
86*9e3b08aeSAndroid Build Coastguard Worker       bool kflag, const btf_member* members, size_t vlen);
87*9e3b08aeSAndroid Build Coastguard Worker   Enumeration::Enumerators BuildEnums(
88*9e3b08aeSAndroid Build Coastguard Worker       bool is_signed, const struct btf_enum* enums, size_t vlen);
89*9e3b08aeSAndroid Build Coastguard Worker   Enumeration::Enumerators BuildEnums64(
90*9e3b08aeSAndroid Build Coastguard Worker       bool is_signed, const struct btf_enum64* enums, size_t vlen);
91*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> BuildParams(const struct btf_param* params, size_t vlen);
92*9e3b08aeSAndroid Build Coastguard Worker   Id BuildEnumUnderlyingType(size_t size, bool is_signed);
93*9e3b08aeSAndroid Build Coastguard Worker   std::string GetName(uint32_t name_off);
94*9e3b08aeSAndroid Build Coastguard Worker };
95*9e3b08aeSAndroid Build Coastguard Worker 
Empty() const96*9e3b08aeSAndroid Build Coastguard Worker bool Structs::MemoryRange::Empty() const {
97*9e3b08aeSAndroid Build Coastguard Worker   return start == limit;
98*9e3b08aeSAndroid Build Coastguard Worker }
99*9e3b08aeSAndroid Build Coastguard Worker 
100*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
Pull(size_t count)101*9e3b08aeSAndroid Build Coastguard Worker const T* Structs::MemoryRange::Pull(size_t count) {
102*9e3b08aeSAndroid Build Coastguard Worker   const char* saved = start;
103*9e3b08aeSAndroid Build Coastguard Worker   start += sizeof(T) * count;
104*9e3b08aeSAndroid Build Coastguard Worker   Check(start <= limit) << "type data extends past end of type section";
105*9e3b08aeSAndroid Build Coastguard Worker   return reinterpret_cast<const T*>(saved);
106*9e3b08aeSAndroid Build Coastguard Worker }
107*9e3b08aeSAndroid Build Coastguard Worker 
Structs(Graph & graph)108*9e3b08aeSAndroid Build Coastguard Worker Structs::Structs(Graph& graph)
109*9e3b08aeSAndroid Build Coastguard Worker     : maker_(graph) {}
110*9e3b08aeSAndroid Build Coastguard Worker 
111*9e3b08aeSAndroid Build Coastguard Worker // Get the index of the void type, creating one if needed.
GetVoid()112*9e3b08aeSAndroid Build Coastguard Worker Id Structs::GetVoid() {
113*9e3b08aeSAndroid Build Coastguard Worker   if (!void_) {
114*9e3b08aeSAndroid Build Coastguard Worker     void_ = {maker_.Add<Special>(Special::Kind::VOID)};
115*9e3b08aeSAndroid Build Coastguard Worker   }
116*9e3b08aeSAndroid Build Coastguard Worker   return *void_;
117*9e3b08aeSAndroid Build Coastguard Worker }
118*9e3b08aeSAndroid Build Coastguard Worker 
119*9e3b08aeSAndroid Build Coastguard Worker // Get the index of the variadic parameter type, creating one if needed.
GetVariadic()120*9e3b08aeSAndroid Build Coastguard Worker Id Structs::GetVariadic() {
121*9e3b08aeSAndroid Build Coastguard Worker   if (!variadic_) {
122*9e3b08aeSAndroid Build Coastguard Worker     variadic_ = {maker_.Add<Special>(Special::Kind::VARIADIC)};
123*9e3b08aeSAndroid Build Coastguard Worker   }
124*9e3b08aeSAndroid Build Coastguard Worker   return *variadic_;
125*9e3b08aeSAndroid Build Coastguard Worker }
126*9e3b08aeSAndroid Build Coastguard Worker 
127*9e3b08aeSAndroid Build Coastguard Worker // Map BTF type index to node ID.
GetIdRaw(uint32_t btf_index)128*9e3b08aeSAndroid Build Coastguard Worker Id Structs::GetIdRaw(uint32_t btf_index) {
129*9e3b08aeSAndroid Build Coastguard Worker   return maker_.Get(btf_index);
130*9e3b08aeSAndroid Build Coastguard Worker }
131*9e3b08aeSAndroid Build Coastguard Worker 
132*9e3b08aeSAndroid Build Coastguard Worker // Translate BTF type index to node ID, for non-parameters.
GetId(uint32_t btf_index)133*9e3b08aeSAndroid Build Coastguard Worker Id Structs::GetId(uint32_t btf_index) {
134*9e3b08aeSAndroid Build Coastguard Worker   return btf_index ? GetIdRaw(btf_index) : GetVoid();
135*9e3b08aeSAndroid Build Coastguard Worker }
136*9e3b08aeSAndroid Build Coastguard Worker 
137*9e3b08aeSAndroid Build Coastguard Worker // Translate BTF type index to node ID, for parameters.
GetParameterId(uint32_t btf_index)138*9e3b08aeSAndroid Build Coastguard Worker Id Structs::GetParameterId(uint32_t btf_index) {
139*9e3b08aeSAndroid Build Coastguard Worker   return btf_index ? GetIdRaw(btf_index) : GetVariadic();
140*9e3b08aeSAndroid Build Coastguard Worker }
141*9e3b08aeSAndroid Build Coastguard Worker 
142*9e3b08aeSAndroid Build Coastguard Worker // For a BTF type index, populate the node with the corresponding ID.
143*9e3b08aeSAndroid Build Coastguard Worker template <typename Node, typename... Args>
Set(uint32_t id,Args &&...args)144*9e3b08aeSAndroid Build Coastguard Worker void Structs::Set(uint32_t id, Args&&... args) {
145*9e3b08aeSAndroid Build Coastguard Worker   maker_.Set<Node>(id, std::forward<Args>(args)...);
146*9e3b08aeSAndroid Build Coastguard Worker }
147*9e3b08aeSAndroid Build Coastguard Worker 
Process(std::string_view btf_data)148*9e3b08aeSAndroid Build Coastguard Worker Id Structs::Process(std::string_view btf_data) {
149*9e3b08aeSAndroid Build Coastguard Worker   // TODO: Remove this hack once the upstream binaries have proper
150*9e3b08aeSAndroid Build Coastguard Worker   // alignment.
151*9e3b08aeSAndroid Build Coastguard Worker   //
152*9e3b08aeSAndroid Build Coastguard Worker   // Copy the data to aligned heap-allocated memory, if needed.
153*9e3b08aeSAndroid Build Coastguard Worker   return reinterpret_cast<uintptr_t>(btf_data.data()) % alignof(btf_header) > 0
154*9e3b08aeSAndroid Build Coastguard Worker       ? ProcessAligned(std::string(btf_data))
155*9e3b08aeSAndroid Build Coastguard Worker       : ProcessAligned(btf_data);
156*9e3b08aeSAndroid Build Coastguard Worker }
157*9e3b08aeSAndroid Build Coastguard Worker 
ProcessAligned(std::string_view btf_data)158*9e3b08aeSAndroid Build Coastguard Worker Id Structs::ProcessAligned(std::string_view btf_data) {
159*9e3b08aeSAndroid Build Coastguard Worker   Check(sizeof(btf_header) <= btf_data.size())
160*9e3b08aeSAndroid Build Coastguard Worker       << "BTF section too small for header";
161*9e3b08aeSAndroid Build Coastguard Worker   const btf_header* header =
162*9e3b08aeSAndroid Build Coastguard Worker       reinterpret_cast<const btf_header*>(btf_data.data());
163*9e3b08aeSAndroid Build Coastguard Worker   Check(header->magic == 0xEB9F) << "Magic field must be 0xEB9F for BTF";
164*9e3b08aeSAndroid Build Coastguard Worker 
165*9e3b08aeSAndroid Build Coastguard Worker   const char* header_limit = btf_data.begin() + header->hdr_len;
166*9e3b08aeSAndroid Build Coastguard Worker   const char* type_start = header_limit + header->type_off;
167*9e3b08aeSAndroid Build Coastguard Worker   const char* type_limit = type_start + header->type_len;
168*9e3b08aeSAndroid Build Coastguard Worker   const char* string_start = header_limit + header->str_off;
169*9e3b08aeSAndroid Build Coastguard Worker   const char* string_limit = string_start + header->str_len;
170*9e3b08aeSAndroid Build Coastguard Worker 
171*9e3b08aeSAndroid Build Coastguard Worker   Check(btf_data.begin() + sizeof(btf_header) <= header_limit)
172*9e3b08aeSAndroid Build Coastguard Worker       << "header exceeds length";
173*9e3b08aeSAndroid Build Coastguard Worker   Check(header_limit <= type_start) << "type section overlaps header";
174*9e3b08aeSAndroid Build Coastguard Worker   Check(type_start <= type_limit) << "type section ill-formed";
175*9e3b08aeSAndroid Build Coastguard Worker   Check(reinterpret_cast<uintptr_t>(type_start) % alignof(btf_type) == 0)
176*9e3b08aeSAndroid Build Coastguard Worker       << "misaligned type section";
177*9e3b08aeSAndroid Build Coastguard Worker   Check(type_limit <= string_start)
178*9e3b08aeSAndroid Build Coastguard Worker       << "string section does not follow type section";
179*9e3b08aeSAndroid Build Coastguard Worker   Check(string_start <= string_limit) << "string section ill-formed";
180*9e3b08aeSAndroid Build Coastguard Worker   Check(string_limit <= btf_data.end())
181*9e3b08aeSAndroid Build Coastguard Worker       << "string section extends beyond end of BTF data";
182*9e3b08aeSAndroid Build Coastguard Worker 
183*9e3b08aeSAndroid Build Coastguard Worker   const MemoryRange type_section{type_start, type_limit};
184*9e3b08aeSAndroid Build Coastguard Worker   string_section_ = MemoryRange{string_start, string_limit};
185*9e3b08aeSAndroid Build Coastguard Worker   return BuildTypes(type_section);
186*9e3b08aeSAndroid Build Coastguard Worker }
187*9e3b08aeSAndroid Build Coastguard Worker 
188*9e3b08aeSAndroid Build Coastguard Worker // vlen: vector length, the number of struct/union members
BuildMembers(bool kflag,const btf_member * members,size_t vlen)189*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> Structs::BuildMembers(
190*9e3b08aeSAndroid Build Coastguard Worker     bool kflag, const btf_member* members, size_t vlen) {
191*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> result;
192*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < vlen; ++i) {
193*9e3b08aeSAndroid Build Coastguard Worker     const auto& raw_member = members[i];
194*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetName(raw_member.name_off);
195*9e3b08aeSAndroid Build Coastguard Worker     const auto raw_offset = raw_member.offset;
196*9e3b08aeSAndroid Build Coastguard Worker     const auto offset = kflag ? BTF_MEMBER_BIT_OFFSET(raw_offset) : raw_offset;
197*9e3b08aeSAndroid Build Coastguard Worker     const auto bitfield_size = kflag ? BTF_MEMBER_BITFIELD_SIZE(raw_offset) : 0;
198*9e3b08aeSAndroid Build Coastguard Worker     result.push_back(
199*9e3b08aeSAndroid Build Coastguard Worker         maker_.Add<Member>(name, GetId(raw_member.type),
200*9e3b08aeSAndroid Build Coastguard Worker                            static_cast<uint64_t>(offset), bitfield_size));
201*9e3b08aeSAndroid Build Coastguard Worker   }
202*9e3b08aeSAndroid Build Coastguard Worker   return result;
203*9e3b08aeSAndroid Build Coastguard Worker }
204*9e3b08aeSAndroid Build Coastguard Worker 
205*9e3b08aeSAndroid Build Coastguard Worker // vlen: vector length, the number of enum values
BuildEnums(bool is_signed,const struct btf_enum * enums,size_t vlen)206*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::pair<std::string, int64_t>> Structs::BuildEnums(
207*9e3b08aeSAndroid Build Coastguard Worker     bool is_signed, const struct btf_enum* enums, size_t vlen) {
208*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<std::string, int64_t>> result;
209*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < vlen; ++i) {
210*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetName(enums[i].name_off);
211*9e3b08aeSAndroid Build Coastguard Worker     const uint32_t unsigned_value = enums[i].val;
212*9e3b08aeSAndroid Build Coastguard Worker     if (is_signed) {
213*9e3b08aeSAndroid Build Coastguard Worker       const int32_t signed_value = unsigned_value;
214*9e3b08aeSAndroid Build Coastguard Worker       result.emplace_back(name, static_cast<int64_t>(signed_value));
215*9e3b08aeSAndroid Build Coastguard Worker     } else {
216*9e3b08aeSAndroid Build Coastguard Worker       result.emplace_back(name, static_cast<int64_t>(unsigned_value));
217*9e3b08aeSAndroid Build Coastguard Worker     }
218*9e3b08aeSAndroid Build Coastguard Worker   }
219*9e3b08aeSAndroid Build Coastguard Worker   return result;
220*9e3b08aeSAndroid Build Coastguard Worker }
221*9e3b08aeSAndroid Build Coastguard Worker 
BuildEnums64(bool is_signed,const struct btf_enum64 * enums,size_t vlen)222*9e3b08aeSAndroid Build Coastguard Worker std::vector<std::pair<std::string, int64_t>> Structs::BuildEnums64(
223*9e3b08aeSAndroid Build Coastguard Worker     bool is_signed, const struct btf_enum64* enums, size_t vlen) {
224*9e3b08aeSAndroid Build Coastguard Worker   std::vector<std::pair<std::string, int64_t>> result;
225*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < vlen; ++i) {
226*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetName(enums[i].name_off);
227*9e3b08aeSAndroid Build Coastguard Worker     const uint32_t low = enums[i].val_lo32;
228*9e3b08aeSAndroid Build Coastguard Worker     const uint32_t high = enums[i].val_hi32;
229*9e3b08aeSAndroid Build Coastguard Worker     const uint64_t unsigned_value = (static_cast<uint64_t>(high) << 32) | low;
230*9e3b08aeSAndroid Build Coastguard Worker     if (is_signed) {
231*9e3b08aeSAndroid Build Coastguard Worker       const int64_t signed_value = unsigned_value;
232*9e3b08aeSAndroid Build Coastguard Worker       result.emplace_back(name, signed_value);
233*9e3b08aeSAndroid Build Coastguard Worker     } else {
234*9e3b08aeSAndroid Build Coastguard Worker       // TODO: very large unsigned values are stored as negative numbers
235*9e3b08aeSAndroid Build Coastguard Worker       result.emplace_back(name, static_cast<int64_t>(unsigned_value));
236*9e3b08aeSAndroid Build Coastguard Worker     }
237*9e3b08aeSAndroid Build Coastguard Worker   }
238*9e3b08aeSAndroid Build Coastguard Worker   return result;
239*9e3b08aeSAndroid Build Coastguard Worker }
240*9e3b08aeSAndroid Build Coastguard Worker 
241*9e3b08aeSAndroid Build Coastguard Worker // vlen: vector length, the number of parameters
BuildParams(const struct btf_param * params,size_t vlen)242*9e3b08aeSAndroid Build Coastguard Worker std::vector<Id> Structs::BuildParams(const struct btf_param* params,
243*9e3b08aeSAndroid Build Coastguard Worker                                      size_t vlen) {
244*9e3b08aeSAndroid Build Coastguard Worker   std::vector<Id> result;
245*9e3b08aeSAndroid Build Coastguard Worker   result.reserve(vlen);
246*9e3b08aeSAndroid Build Coastguard Worker   for (size_t i = 0; i < vlen; ++i) {
247*9e3b08aeSAndroid Build Coastguard Worker     const auto name = GetName(params[i].name_off);
248*9e3b08aeSAndroid Build Coastguard Worker     const auto type = params[i].type;
249*9e3b08aeSAndroid Build Coastguard Worker     result.push_back(GetParameterId(type));
250*9e3b08aeSAndroid Build Coastguard Worker   }
251*9e3b08aeSAndroid Build Coastguard Worker   return result;
252*9e3b08aeSAndroid Build Coastguard Worker }
253*9e3b08aeSAndroid Build Coastguard Worker 
BuildEnumUnderlyingType(size_t size,bool is_signed)254*9e3b08aeSAndroid Build Coastguard Worker Id Structs::BuildEnumUnderlyingType(size_t size, bool is_signed) {
255*9e3b08aeSAndroid Build Coastguard Worker   std::ostringstream os;
256*9e3b08aeSAndroid Build Coastguard Worker   os << (is_signed ? "enum-underlying-signed-" : "enum-underlying-unsigned-")
257*9e3b08aeSAndroid Build Coastguard Worker      << (8 * size);
258*9e3b08aeSAndroid Build Coastguard Worker   const auto encoding = is_signed ? Primitive::Encoding::SIGNED_INTEGER
259*9e3b08aeSAndroid Build Coastguard Worker                                   : Primitive::Encoding::UNSIGNED_INTEGER;
260*9e3b08aeSAndroid Build Coastguard Worker   return maker_.Add<Primitive>(os.str(), encoding, size);
261*9e3b08aeSAndroid Build Coastguard Worker }
262*9e3b08aeSAndroid Build Coastguard Worker 
BuildTypes(MemoryRange memory)263*9e3b08aeSAndroid Build Coastguard Worker Id Structs::BuildTypes(MemoryRange memory) {
264*9e3b08aeSAndroid Build Coastguard Worker   // Alas, BTF overloads type id 0 to mean both void (for everything but
265*9e3b08aeSAndroid Build Coastguard Worker   // function parameters) and variadic (for function parameters). We determine
266*9e3b08aeSAndroid Build Coastguard Worker   // which is intended and create void and variadic types on demand.
267*9e3b08aeSAndroid Build Coastguard Worker 
268*9e3b08aeSAndroid Build Coastguard Worker   // The type section is parsed sequentially and each type's index is its id.
269*9e3b08aeSAndroid Build Coastguard Worker   uint32_t btf_index = 1;
270*9e3b08aeSAndroid Build Coastguard Worker   while (!memory.Empty()) {
271*9e3b08aeSAndroid Build Coastguard Worker     const auto* t = memory.Pull<struct btf_type>();
272*9e3b08aeSAndroid Build Coastguard Worker     BuildOneType(t, btf_index, memory);
273*9e3b08aeSAndroid Build Coastguard Worker     ++btf_index;
274*9e3b08aeSAndroid Build Coastguard Worker   }
275*9e3b08aeSAndroid Build Coastguard Worker 
276*9e3b08aeSAndroid Build Coastguard Worker   return BuildSymbols();
277*9e3b08aeSAndroid Build Coastguard Worker }
278*9e3b08aeSAndroid Build Coastguard Worker 
BuildOneType(const btf_type * t,uint32_t btf_index,MemoryRange & memory)279*9e3b08aeSAndroid Build Coastguard Worker void Structs::BuildOneType(const btf_type* t, uint32_t btf_index,
280*9e3b08aeSAndroid Build Coastguard Worker                            MemoryRange& memory) {
281*9e3b08aeSAndroid Build Coastguard Worker   const auto kind = BTF_INFO_KIND(t->info);
282*9e3b08aeSAndroid Build Coastguard Worker   const auto vlen = BTF_INFO_VLEN(t->info);
283*9e3b08aeSAndroid Build Coastguard Worker   Check(kind < NR_BTF_KINDS) << "Unknown BTF kind: " << static_cast<int>(kind);
284*9e3b08aeSAndroid Build Coastguard Worker 
285*9e3b08aeSAndroid Build Coastguard Worker   switch (kind) {
286*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_INT: {
287*9e3b08aeSAndroid Build Coastguard Worker       const auto info = *memory.Pull<uint32_t>();
288*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
289*9e3b08aeSAndroid Build Coastguard Worker       const auto raw_encoding = BTF_INT_ENCODING(info);
290*9e3b08aeSAndroid Build Coastguard Worker       const auto offset = BTF_INT_OFFSET(info);
291*9e3b08aeSAndroid Build Coastguard Worker       const auto bits = BTF_INT_BITS(info);
292*9e3b08aeSAndroid Build Coastguard Worker       const auto is_bool = raw_encoding & BTF_INT_BOOL;
293*9e3b08aeSAndroid Build Coastguard Worker       const auto is_signed = raw_encoding & BTF_INT_SIGNED;
294*9e3b08aeSAndroid Build Coastguard Worker       const auto is_char = raw_encoding & BTF_INT_CHAR;
295*9e3b08aeSAndroid Build Coastguard Worker       Primitive::Encoding encoding =
296*9e3b08aeSAndroid Build Coastguard Worker           is_bool ? Primitive::Encoding::BOOLEAN
297*9e3b08aeSAndroid Build Coastguard Worker                 : is_char ? is_signed ? Primitive::Encoding::SIGNED_CHARACTER
298*9e3b08aeSAndroid Build Coastguard Worker                                       : Primitive::Encoding::UNSIGNED_CHARACTER
299*9e3b08aeSAndroid Build Coastguard Worker                           : is_signed ? Primitive::Encoding::SIGNED_INTEGER
300*9e3b08aeSAndroid Build Coastguard Worker                                       : Primitive::Encoding::UNSIGNED_INTEGER;
301*9e3b08aeSAndroid Build Coastguard Worker       if (offset) {
302*9e3b08aeSAndroid Build Coastguard Worker         Die() << "BTF INT non-zero offset " << offset;
303*9e3b08aeSAndroid Build Coastguard Worker       }
304*9e3b08aeSAndroid Build Coastguard Worker       if (bits != 8 * t->size) {
305*9e3b08aeSAndroid Build Coastguard Worker         Die() << "BTF INT bits != 8 * size";
306*9e3b08aeSAndroid Build Coastguard Worker       }
307*9e3b08aeSAndroid Build Coastguard Worker       Set<Primitive>(btf_index, name, encoding, t->size);
308*9e3b08aeSAndroid Build Coastguard Worker       break;
309*9e3b08aeSAndroid Build Coastguard Worker     }
310*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_FLOAT: {
311*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
312*9e3b08aeSAndroid Build Coastguard Worker       const auto encoding = Primitive::Encoding::REAL_NUMBER;
313*9e3b08aeSAndroid Build Coastguard Worker       Set<Primitive>(btf_index, name, encoding, t->size);
314*9e3b08aeSAndroid Build Coastguard Worker       break;
315*9e3b08aeSAndroid Build Coastguard Worker     }
316*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_PTR: {
317*9e3b08aeSAndroid Build Coastguard Worker       Set<PointerReference>(btf_index, PointerReference::Kind::POINTER,
318*9e3b08aeSAndroid Build Coastguard Worker                             GetId(t->type));
319*9e3b08aeSAndroid Build Coastguard Worker       break;
320*9e3b08aeSAndroid Build Coastguard Worker     }
321*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_TYPEDEF: {
322*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
323*9e3b08aeSAndroid Build Coastguard Worker       Set<Typedef>(btf_index, name, GetId(t->type));
324*9e3b08aeSAndroid Build Coastguard Worker       break;
325*9e3b08aeSAndroid Build Coastguard Worker     }
326*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_VOLATILE:
327*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_CONST:
328*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_RESTRICT: {
329*9e3b08aeSAndroid Build Coastguard Worker       const auto qualifier = kind == BTF_KIND_CONST
330*9e3b08aeSAndroid Build Coastguard Worker                              ? Qualifier::CONST
331*9e3b08aeSAndroid Build Coastguard Worker                              : kind == BTF_KIND_VOLATILE
332*9e3b08aeSAndroid Build Coastguard Worker                              ? Qualifier::VOLATILE
333*9e3b08aeSAndroid Build Coastguard Worker                              : Qualifier::RESTRICT;
334*9e3b08aeSAndroid Build Coastguard Worker       Set<Qualified>(btf_index, qualifier, GetId(t->type));
335*9e3b08aeSAndroid Build Coastguard Worker       break;
336*9e3b08aeSAndroid Build Coastguard Worker     }
337*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_ARRAY: {
338*9e3b08aeSAndroid Build Coastguard Worker       const auto* array = memory.Pull<struct btf_array>();
339*9e3b08aeSAndroid Build Coastguard Worker       Set<Array>(btf_index, array->nelems, GetId(array->type));
340*9e3b08aeSAndroid Build Coastguard Worker       break;
341*9e3b08aeSAndroid Build Coastguard Worker     }
342*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_STRUCT:
343*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_UNION: {
344*9e3b08aeSAndroid Build Coastguard Worker       const auto struct_union_kind = kind == BTF_KIND_STRUCT
345*9e3b08aeSAndroid Build Coastguard Worker                                      ? StructUnion::Kind::STRUCT
346*9e3b08aeSAndroid Build Coastguard Worker                                      : StructUnion::Kind::UNION;
347*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
348*9e3b08aeSAndroid Build Coastguard Worker       const bool kflag = BTF_INFO_KFLAG(t->info);
349*9e3b08aeSAndroid Build Coastguard Worker       const auto* btf_members = memory.Pull<struct btf_member>(vlen);
350*9e3b08aeSAndroid Build Coastguard Worker       const auto members = BuildMembers(kflag, btf_members, vlen);
351*9e3b08aeSAndroid Build Coastguard Worker       Set<StructUnion>(btf_index, struct_union_kind, name, t->size,
352*9e3b08aeSAndroid Build Coastguard Worker                        std::vector<Id>(), std::vector<Id>(), members);
353*9e3b08aeSAndroid Build Coastguard Worker       break;
354*9e3b08aeSAndroid Build Coastguard Worker     }
355*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_ENUM: {
356*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
357*9e3b08aeSAndroid Build Coastguard Worker       const bool is_signed = BTF_INFO_KFLAG(t->info);
358*9e3b08aeSAndroid Build Coastguard Worker       const auto* enums = memory.Pull<struct btf_enum>(vlen);
359*9e3b08aeSAndroid Build Coastguard Worker       const auto enumerators = BuildEnums(is_signed, enums, vlen);
360*9e3b08aeSAndroid Build Coastguard Worker       // BTF only considers structs and unions as forward-declared types, and
361*9e3b08aeSAndroid Build Coastguard Worker       // does not include forward-declared enums. They are treated as
362*9e3b08aeSAndroid Build Coastguard Worker       // BTF_KIND_ENUMs with vlen set to zero.
363*9e3b08aeSAndroid Build Coastguard Worker       if (vlen) {
364*9e3b08aeSAndroid Build Coastguard Worker         // create a synthetic underlying type
365*9e3b08aeSAndroid Build Coastguard Worker         const Id underlying = BuildEnumUnderlyingType(t->size, is_signed);
366*9e3b08aeSAndroid Build Coastguard Worker         Set<Enumeration>(btf_index, name, underlying, enumerators);
367*9e3b08aeSAndroid Build Coastguard Worker       } else {
368*9e3b08aeSAndroid Build Coastguard Worker         // BTF actually provides size (4), but it's meaningless.
369*9e3b08aeSAndroid Build Coastguard Worker         Set<Enumeration>(btf_index, name);
370*9e3b08aeSAndroid Build Coastguard Worker       }
371*9e3b08aeSAndroid Build Coastguard Worker       break;
372*9e3b08aeSAndroid Build Coastguard Worker     }
373*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_ENUM64: {
374*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
375*9e3b08aeSAndroid Build Coastguard Worker       const bool is_signed = BTF_INFO_KFLAG(t->info);
376*9e3b08aeSAndroid Build Coastguard Worker       const auto* enums = memory.Pull<struct btf_enum64>(vlen);
377*9e3b08aeSAndroid Build Coastguard Worker       const auto enumerators = BuildEnums64(is_signed, enums, vlen);
378*9e3b08aeSAndroid Build Coastguard Worker       // create a synthetic underlying type
379*9e3b08aeSAndroid Build Coastguard Worker       const Id underlying = BuildEnumUnderlyingType(t->size, is_signed);
380*9e3b08aeSAndroid Build Coastguard Worker       Set<Enumeration>(btf_index, name, underlying, enumerators);
381*9e3b08aeSAndroid Build Coastguard Worker       break;
382*9e3b08aeSAndroid Build Coastguard Worker     }
383*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_FWD: {
384*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
385*9e3b08aeSAndroid Build Coastguard Worker       const auto struct_union_kind = BTF_INFO_KFLAG(t->info)
386*9e3b08aeSAndroid Build Coastguard Worker                                      ? StructUnion::Kind::UNION
387*9e3b08aeSAndroid Build Coastguard Worker                                      : StructUnion::Kind::STRUCT;
388*9e3b08aeSAndroid Build Coastguard Worker       Set<StructUnion>(btf_index, struct_union_kind, name);
389*9e3b08aeSAndroid Build Coastguard Worker       break;
390*9e3b08aeSAndroid Build Coastguard Worker     }
391*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_FUNC: {
392*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
393*9e3b08aeSAndroid Build Coastguard Worker       // TODO: map linkage (vlen) to symbol properties
394*9e3b08aeSAndroid Build Coastguard Worker       Set<ElfSymbol>(btf_index, name, std::nullopt, true,
395*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::SymbolType::FUNCTION,
396*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::Binding::GLOBAL,
397*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::Visibility::DEFAULT,
398*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt,
399*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt,
400*9e3b08aeSAndroid Build Coastguard Worker                      GetId(t->type),
401*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt);
402*9e3b08aeSAndroid Build Coastguard Worker       const bool inserted =
403*9e3b08aeSAndroid Build Coastguard Worker           btf_symbols_.insert({name, GetIdRaw(btf_index)}).second;
404*9e3b08aeSAndroid Build Coastguard Worker       Check(inserted) << "duplicate symbol " << name;
405*9e3b08aeSAndroid Build Coastguard Worker       break;
406*9e3b08aeSAndroid Build Coastguard Worker     }
407*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_FUNC_PROTO: {
408*9e3b08aeSAndroid Build Coastguard Worker       const auto* params = memory.Pull<struct btf_param>(vlen);
409*9e3b08aeSAndroid Build Coastguard Worker       const auto parameters = BuildParams(params, vlen);
410*9e3b08aeSAndroid Build Coastguard Worker       Set<Function>(btf_index, GetId(t->type), parameters);
411*9e3b08aeSAndroid Build Coastguard Worker       break;
412*9e3b08aeSAndroid Build Coastguard Worker     }
413*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_VAR: {
414*9e3b08aeSAndroid Build Coastguard Worker       // NOTE: global variables are not yet emitted by pahole -J
415*9e3b08aeSAndroid Build Coastguard Worker       const auto* variable = memory.Pull<struct btf_var>();
416*9e3b08aeSAndroid Build Coastguard Worker       const auto name = GetName(t->name_off);
417*9e3b08aeSAndroid Build Coastguard Worker       // TODO: map variable->linkage to symbol properties
418*9e3b08aeSAndroid Build Coastguard Worker       (void) variable;
419*9e3b08aeSAndroid Build Coastguard Worker       Set<ElfSymbol>(btf_index, name, std::nullopt, true,
420*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::SymbolType::OBJECT,
421*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::Binding::GLOBAL,
422*9e3b08aeSAndroid Build Coastguard Worker                      ElfSymbol::Visibility::DEFAULT,
423*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt,
424*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt,
425*9e3b08aeSAndroid Build Coastguard Worker                      GetId(t->type),
426*9e3b08aeSAndroid Build Coastguard Worker                      std::nullopt);
427*9e3b08aeSAndroid Build Coastguard Worker       const bool inserted =
428*9e3b08aeSAndroid Build Coastguard Worker           btf_symbols_.insert({name, GetIdRaw(btf_index)}).second;
429*9e3b08aeSAndroid Build Coastguard Worker       Check(inserted) << "duplicate symbol " << name;
430*9e3b08aeSAndroid Build Coastguard Worker       break;
431*9e3b08aeSAndroid Build Coastguard Worker     }
432*9e3b08aeSAndroid Build Coastguard Worker     case BTF_KIND_DATASEC: {
433*9e3b08aeSAndroid Build Coastguard Worker       // Just skip BTF DATASEC entries. They partially duplicate ELF symbol
434*9e3b08aeSAndroid Build Coastguard Worker       // table information, if they exist at all.
435*9e3b08aeSAndroid Build Coastguard Worker       memory.Pull<struct btf_var_secinfo>(vlen);
436*9e3b08aeSAndroid Build Coastguard Worker       break;
437*9e3b08aeSAndroid Build Coastguard Worker     }
438*9e3b08aeSAndroid Build Coastguard Worker     default: {
439*9e3b08aeSAndroid Build Coastguard Worker       Die() << "Unhandled BTF kind: " << static_cast<int>(kind);
440*9e3b08aeSAndroid Build Coastguard Worker       break;
441*9e3b08aeSAndroid Build Coastguard Worker     }
442*9e3b08aeSAndroid Build Coastguard Worker   }
443*9e3b08aeSAndroid Build Coastguard Worker }
444*9e3b08aeSAndroid Build Coastguard Worker 
GetName(uint32_t name_off)445*9e3b08aeSAndroid Build Coastguard Worker std::string Structs::GetName(uint32_t name_off) {
446*9e3b08aeSAndroid Build Coastguard Worker   const char* name_begin = string_section_.start + name_off;
447*9e3b08aeSAndroid Build Coastguard Worker   const char* const limit = string_section_.limit;
448*9e3b08aeSAndroid Build Coastguard Worker   Check(name_begin < limit) << "name offset exceeds string section length";
449*9e3b08aeSAndroid Build Coastguard Worker   const char* name_end = std::find(name_begin, limit, '\0');
450*9e3b08aeSAndroid Build Coastguard Worker   Check(name_end < limit) << "name continues past the string section limit";
451*9e3b08aeSAndroid Build Coastguard Worker   return {name_begin, static_cast<size_t>(name_end - name_begin)};
452*9e3b08aeSAndroid Build Coastguard Worker }
453*9e3b08aeSAndroid Build Coastguard Worker 
BuildSymbols()454*9e3b08aeSAndroid Build Coastguard Worker Id Structs::BuildSymbols() {
455*9e3b08aeSAndroid Build Coastguard Worker   return maker_.Add<Interface>(btf_symbols_);
456*9e3b08aeSAndroid Build Coastguard Worker }
457*9e3b08aeSAndroid Build Coastguard Worker 
458*9e3b08aeSAndroid Build Coastguard Worker }  // namespace
459*9e3b08aeSAndroid Build Coastguard Worker 
ReadSection(Graph & graph,std::string_view data)460*9e3b08aeSAndroid Build Coastguard Worker Id ReadSection(Graph& graph, std::string_view data) {
461*9e3b08aeSAndroid Build Coastguard Worker   return Structs(graph).Process(data);
462*9e3b08aeSAndroid Build Coastguard Worker }
463*9e3b08aeSAndroid Build Coastguard Worker 
ReadFile(Graph & graph,const std::string & path,ReadOptions)464*9e3b08aeSAndroid Build Coastguard Worker Id ReadFile(Graph& graph, const std::string& path, ReadOptions) {
465*9e3b08aeSAndroid Build Coastguard Worker   ElfDwarfHandle handle(path);
466*9e3b08aeSAndroid Build Coastguard Worker   const elf::ElfLoader loader(handle.GetElf());
467*9e3b08aeSAndroid Build Coastguard Worker   return ReadSection(graph, loader.GetSectionRawData(".BTF"));
468*9e3b08aeSAndroid Build Coastguard Worker }
469*9e3b08aeSAndroid Build Coastguard Worker 
470*9e3b08aeSAndroid Build Coastguard Worker }  // namespace btf
471*9e3b08aeSAndroid Build Coastguard Worker 
472*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
473