xref: /aosp_15_r20/external/perfetto/src/traced/probes/ftrace/proto_translation_table.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SRC_TRACED_PROBES_FTRACE_PROTO_TRANSLATION_TABLE_H_
18 #define SRC_TRACED_PROBES_FTRACE_PROTO_TRANSLATION_TABLE_H_
19 
20 #include <stdint.h>
21 
22 #include <deque>
23 #include <iostream>
24 #include <map>
25 #include <memory>
26 #include <optional>
27 #include <set>
28 #include <string>
29 #include <vector>
30 
31 #include "perfetto/ext/base/scoped_file.h"
32 #include "src/traced/probes/ftrace/compact_sched.h"
33 #include "src/traced/probes/ftrace/event_info.h"
34 #include "src/traced/probes/ftrace/format_parser/format_parser.h"
35 #include "src/traced/probes/ftrace/printk_formats_parser.h"
36 
37 namespace perfetto {
38 
39 class FtraceProcfs;
40 
41 namespace protos {
42 namespace pbzero {
43 class FtraceEventBundle;
44 }  // namespace pbzero
45 }  // namespace protos
46 
47 // Used when reading the config to store the group and name info for the
48 // ftrace event.
49 class GroupAndName {
50  public:
GroupAndName(std::string_view group,std::string_view name)51   GroupAndName(std::string_view group, std::string_view name)
52       : group_(group), name_(name) {}
53 
54   bool operator==(const GroupAndName& other) const {
55     return std::tie(group_, name_) == std::tie(other.group(), other.name());
56   }
57 
58   bool operator<(const GroupAndName& other) const {
59     return std::tie(group_, name_) < std::tie(other.group(), other.name());
60   }
61 
name()62   const std::string& name() const { return name_; }
group()63   const std::string& group() const { return group_; }
64 
ToString()65   std::string ToString() const { return group_ + "/" + name_; }
66 
67  private:
68   std::string group_;
69   std::string name_;
70 };
71 
PrintTo(const GroupAndName & event,::std::ostream * os)72 inline void PrintTo(const GroupAndName& event, ::std::ostream* os) {
73   *os << "GroupAndName(" << event.group() << ", " << event.name() << ")";
74 }
75 
76 bool InferFtraceType(const std::string& type_and_name,
77                      size_t size,
78                      bool is_signed,
79                      FtraceFieldType* out);
80 
81 class ProtoTranslationTable {
82  public:
83   struct FtracePageHeaderSpec {
84     FtraceEvent::Field timestamp{};
85     FtraceEvent::Field overwrite{};
86     FtraceEvent::Field size{};
87   };
88 
89   static FtracePageHeaderSpec DefaultPageHeaderSpecForTesting();
90 
91   // This method mutates the |events| and |common_fields| vectors to
92   // fill some of the fields and to delete unused events/fields
93   // before std:move'ing them into the ProtoTranslationTable.
94   static std::unique_ptr<ProtoTranslationTable> Create(
95       const FtraceProcfs* ftrace_procfs,
96       std::vector<Event> events,
97       std::vector<Field> common_fields);
98   virtual ~ProtoTranslationTable();
99 
100   ProtoTranslationTable(const FtraceProcfs* ftrace_procfs,
101                         const std::vector<Event>& events,
102                         std::vector<Field> common_fields,
103                         FtracePageHeaderSpec ftrace_page_header_spec,
104                         CompactSchedEventFormat compact_sched_format,
105                         PrintkMap printk_formats);
106 
largest_id()107   size_t largest_id() const { return largest_id_; }
108 
common_fields()109   const std::vector<Field>& common_fields() const { return common_fields_; }
110 
common_pid()111   const Field* common_pid() const {
112     // corner case: pKVM hypervisor pseudo-tracefs lacks common_pid
113     if (!common_pid_.has_value())
114       return nullptr;
115     return &common_pid_.value();
116   }
117 
118   // Virtual for testing.
GetEvent(const GroupAndName & group_and_name)119   virtual const Event* GetEvent(const GroupAndName& group_and_name) const {
120     if (!group_and_name_to_event_.count(group_and_name))
121       return nullptr;
122     return group_and_name_to_event_.at(group_and_name);
123   }
124 
GetEventsByGroup(const std::string & group)125   const std::vector<const Event*>* GetEventsByGroup(
126       const std::string& group) const {
127     if (!group_to_events_.count(group))
128       return nullptr;
129     return &group_to_events_.at(group);
130   }
131 
GetEventById(size_t id)132   const Event* GetEventById(size_t id) const {
133     if (id == 0 || id > largest_id_)
134       return nullptr;
135     const Event* evt = &events_[id];
136     if (!evt->ftrace_event_id)
137       return nullptr;
138     return evt;
139   }
140 
EventToFtraceId(const GroupAndName & group_and_name)141   size_t EventToFtraceId(const GroupAndName& group_and_name) const {
142     if (!group_and_name_to_event_.count(group_and_name))
143       return 0;
144     return group_and_name_to_event_.at(group_and_name)->ftrace_event_id;
145   }
146 
events()147   const std::deque<Event>& events() { return events_; }
ftrace_page_header_spec()148   const FtracePageHeaderSpec& ftrace_page_header_spec() const {
149     return ftrace_page_header_spec_;
150   }
151 
152   // Returns the size in bytes of the "size" field in the ftrace header. This
153   // usually matches sizeof(void*) in the kernel (which can be != sizeof(void*)
154   // of user space on 32bit-user + 64-bit-kernel configurations).
page_header_size_len()155   inline uint16_t page_header_size_len() const {
156     // TODO(fmayer): Do kernel deepdive to double check this.
157     return ftrace_page_header_spec_.size.size;
158   }
159 
160   // Retrieves the ftrace event from the proto translation
161   // table. If it does not exist, reads the format file and creates a
162   // new event with the proto id set to generic. Virtual for testing.
163   virtual const Event* GetOrCreateEvent(const GroupAndName&);
164 
165   // Retrieves the ftrace event, that's going to be translated to a kprobe, from
166   // the proto translation table. If the event is already known and used for
167   // something other than a kprobe, returns nullptr.
168   virtual const Event* GetOrCreateKprobeEvent(const GroupAndName&);
169 
170   // Removes the ftrace event from the proto translation table.
171   virtual void RemoveEvent(const GroupAndName&);
172 
173   // This is for backwards compatibility. If a group is not specified in the
174   // config then the first event with that name will be returned.
GetEventByName(const std::string & name)175   const Event* GetEventByName(const std::string& name) const {
176     if (!name_to_events_.count(name))
177       return nullptr;
178     return name_to_events_.at(name)[0];
179   }
180 
compact_sched_format()181   const CompactSchedEventFormat& compact_sched_format() const {
182     return compact_sched_format_;
183   }
184 
LookupTraceString(uint64_t address)185   base::StringView LookupTraceString(uint64_t address) const {
186     return printk_formats_.at(address);
187   }
188 
189  private:
190   ProtoTranslationTable(const ProtoTranslationTable&) = delete;
191   ProtoTranslationTable& operator=(const ProtoTranslationTable&) = delete;
192 
193   // Store strings so they can be read when writing the trace output.
194   const char* InternString(const std::string& str);
195 
196   // The event must not already exist.
197   const Event* CreateEventWithProtoId(const GroupAndName& group_and_name,
198                                       uint32_t proto_field_id);
199 
200   uint16_t CreateGenericEventField(const FtraceEvent::Field& ftrace_field,
201                                    Event& event);
202 
203   const FtraceProcfs* ftrace_procfs_;
204   std::deque<Event> events_;
205   size_t largest_id_;
206   std::map<GroupAndName, const Event*> group_and_name_to_event_;
207   std::map<std::string, std::vector<const Event*>> name_to_events_;
208   std::map<std::string, std::vector<const Event*>> group_to_events_;
209   std::vector<Field> common_fields_;
210   std::optional<Field> common_pid_;  // copy of entry in common_fields_
211   FtracePageHeaderSpec ftrace_page_header_spec_{};
212   std::set<std::string> interned_strings_;
213   CompactSchedEventFormat compact_sched_format_;
214   PrintkMap printk_formats_;
215 };
216 
217 // Class for efficient 'is event with id x enabled?' checks.
218 // Mirrors the data in a FtraceConfig but in a format better suited
219 // to be consumed by CpuReader.
220 class EventFilter {
221  public:
222   EventFilter();
223   ~EventFilter();
224   EventFilter(EventFilter&&) = default;
225   EventFilter& operator=(EventFilter&&) = default;
226 
227   void AddEnabledEvent(size_t ftrace_event_id);
228   void DisableEvent(size_t ftrace_event_id);
229   bool IsEventEnabled(size_t ftrace_event_id) const;
230   std::set<size_t> GetEnabledEvents() const;
231   void EnableEventsFrom(const EventFilter&);
232 
233  private:
234   EventFilter(const EventFilter&) = delete;
235   EventFilter& operator=(const EventFilter&) = delete;
236 
237   std::vector<bool> enabled_ids_;
238 };
239 
240 }  // namespace perfetto
241 
242 #endif  // SRC_TRACED_PROBES_FTRACE_PROTO_TRANSLATION_TABLE_H_
243