1 /*
2  * Copyright (C) 2015 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 #include "record.h"
18 
19 #include <inttypes.h>
20 #include <algorithm>
21 #include <unordered_map>
22 
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 
26 #include "dso.h"
27 #include "perf_regs.h"
28 #include "tracing.h"
29 #include "utils.h"
30 
RecordTypeToString(int record_type)31 static std::string RecordTypeToString(int record_type) {
32   static std::unordered_map<int, std::string> record_type_names = {
33       {PERF_RECORD_MMAP, "mmap"},
34       {PERF_RECORD_LOST, "lost"},
35       {PERF_RECORD_COMM, "comm"},
36       {PERF_RECORD_EXIT, "exit"},
37       {PERF_RECORD_THROTTLE, "throttle"},
38       {PERF_RECORD_UNTHROTTLE, "unthrottle"},
39       {PERF_RECORD_FORK, "fork"},
40       {PERF_RECORD_READ, "read"},
41       {PERF_RECORD_SAMPLE, "sample"},
42       {PERF_RECORD_BUILD_ID, "build_id"},
43       {PERF_RECORD_MMAP2, "mmap2"},
44       {PERF_RECORD_TRACING_DATA, "tracing_data"},
45       {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"},
46       {SIMPLE_PERF_RECORD_DSO, "dso"},
47       {SIMPLE_PERF_RECORD_SYMBOL, "symbol"},
48       {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
49   };
50 
51   auto it = record_type_names.find(record_type);
52   if (it != record_type_names.end()) {
53     return it->second;
54   }
55   return android::base::StringPrintf("unknown(%d)", record_type);
56 }
57 
58 template <>
MoveToBinaryFormat(const RecordHeader & data,char * & p)59 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
60   data.MoveToBinaryFormat(p);
61 }
62 
SampleId()63 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); }
64 
65 // Return sample_id size in binary format.
CreateContent(const perf_event_attr & attr,uint64_t event_id)66 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
67   sample_id_all = attr.sample_id_all;
68   sample_type = attr.sample_type;
69   id_data.id = event_id;
70   // Other data are not necessary. TODO: Set missing SampleId data.
71   return Size();
72 }
73 
ReadFromBinaryFormat(const perf_event_attr & attr,const char * p,const char * end)74 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p,
75                                     const char* end) {
76   sample_id_all = attr.sample_id_all;
77   sample_type = attr.sample_type;
78   if (sample_id_all) {
79     if (sample_type & PERF_SAMPLE_TID) {
80       MoveFromBinaryFormat(tid_data, p);
81     }
82     if (sample_type & PERF_SAMPLE_TIME) {
83       MoveFromBinaryFormat(time_data, p);
84     }
85     if (sample_type & PERF_SAMPLE_ID) {
86       MoveFromBinaryFormat(id_data, p);
87     }
88     if (sample_type & PERF_SAMPLE_STREAM_ID) {
89       MoveFromBinaryFormat(stream_id_data, p);
90     }
91     if (sample_type & PERF_SAMPLE_CPU) {
92       MoveFromBinaryFormat(cpu_data, p);
93     }
94     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
95       MoveFromBinaryFormat(id_data, p);
96     }
97   }
98   CHECK_LE(p, end);
99   if (p < end) {
100     LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
101   }
102 }
103 
WriteToBinaryFormat(char * & p) const104 void SampleId::WriteToBinaryFormat(char*& p) const {
105   if (sample_id_all) {
106     if (sample_type & PERF_SAMPLE_TID) {
107       MoveToBinaryFormat(tid_data, p);
108     }
109     if (sample_type & PERF_SAMPLE_TIME) {
110       MoveToBinaryFormat(time_data, p);
111     }
112     if (sample_type & PERF_SAMPLE_ID) {
113       MoveToBinaryFormat(id_data, p);
114     }
115     if (sample_type & PERF_SAMPLE_STREAM_ID) {
116       MoveToBinaryFormat(stream_id_data, p);
117     }
118     if (sample_type & PERF_SAMPLE_CPU) {
119       MoveToBinaryFormat(cpu_data, p);
120     }
121   }
122 }
123 
Dump(size_t indent) const124 void SampleId::Dump(size_t indent) const {
125   if (sample_id_all) {
126     if (sample_type & PERF_SAMPLE_TID) {
127       PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid,
128                     tid_data.tid);
129     }
130     if (sample_type & PERF_SAMPLE_TIME) {
131       PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
132     }
133     if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
134       PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
135     }
136     if (sample_type & PERF_SAMPLE_STREAM_ID) {
137       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n",
138                     stream_id_data.stream_id);
139     }
140     if (sample_type & PERF_SAMPLE_CPU) {
141       PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu,
142                     cpu_data.res);
143     }
144   }
145 }
146 
Size() const147 size_t SampleId::Size() const {
148   size_t size = 0;
149   if (sample_id_all) {
150     if (sample_type & PERF_SAMPLE_TID) {
151       size += sizeof(PerfSampleTidType);
152     }
153     if (sample_type & PERF_SAMPLE_TIME) {
154       size += sizeof(PerfSampleTimeType);
155     }
156     if (sample_type & PERF_SAMPLE_ID) {
157       size += sizeof(PerfSampleIdType);
158     }
159     if (sample_type & PERF_SAMPLE_STREAM_ID) {
160       size += sizeof(PerfSampleStreamIdType);
161     }
162     if (sample_type & PERF_SAMPLE_CPU) {
163       size += sizeof(PerfSampleCpuType);
164     }
165     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
166       size += sizeof(PerfSampleIdType);
167     }
168   }
169   return size;
170 }
171 
Record(Record && other)172 Record::Record(Record&& other) {
173   header = other.header;
174   sample_id = other.sample_id;
175   binary_ = other.binary_;
176   own_binary_ = other.own_binary_;
177   other.binary_ = nullptr;
178   other.own_binary_ = false;
179 }
180 
Dump(size_t indent) const181 void Record::Dump(size_t indent) const {
182   PrintIndented(indent, "record %s: type %u, misc %u, size %u\n",
183                 RecordTypeToString(type()).c_str(), type(), misc(), size());
184   DumpData(indent + 1);
185   sample_id.Dump(indent + 1);
186 }
187 
Timestamp() const188 uint64_t Record::Timestamp() const { return sample_id.time_data.time; }
Cpu() const189 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; }
Id() const190 uint64_t Record::Id() const { return sample_id.id_data.id; }
191 
UpdateBinary(const char * new_binary)192 void Record::UpdateBinary(const char* new_binary) {
193   if (own_binary_) {
194     delete[] binary_;
195   }
196   own_binary_ = true;
197   binary_ = new_binary;
198 }
199 
MmapRecord(const perf_event_attr & attr,const char * p)200 MmapRecord::MmapRecord(const perf_event_attr& attr, const char* p) : Record(p) {
201   const char* end = p + size();
202   p += header_size();
203   data = reinterpret_cast<const MmapRecordDataType*>(p);
204   p += sizeof(*data);
205   filename = p;
206   p += Align(strlen(filename) + 1, 8);
207   CHECK_LE(p, end);
208   sample_id.ReadFromBinaryFormat(attr, p, end);
209 }
210 
MmapRecord(const perf_event_attr & attr,bool in_kernel,uint32_t pid,uint32_t tid,uint64_t addr,uint64_t len,uint64_t pgoff,const std::string & filename,uint64_t event_id,uint64_t time)211 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel,
212                        uint32_t pid, uint32_t tid, uint64_t addr, uint64_t len,
213                        uint64_t pgoff, const std::string& filename,
214                        uint64_t event_id, uint64_t time) {
215   SetTypeAndMisc(PERF_RECORD_MMAP,
216                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
217   sample_id.CreateContent(attr, event_id);
218   sample_id.time_data.time = time;
219   MmapRecordDataType data;
220   data.pid = pid;
221   data.tid = tid;
222   data.addr = addr;
223   data.len = len;
224   data.pgoff = pgoff;
225   SetDataAndFilename(data, filename);
226 }
227 
SetDataAndFilename(const MmapRecordDataType & data,const std::string & filename)228 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data,
229                                     const std::string& filename) {
230   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
231           sample_id.Size());
232   char* new_binary = new char[size()];
233   char* p = new_binary;
234   MoveToBinaryFormat(header, p);
235   this->data = reinterpret_cast<MmapRecordDataType*>(p);
236   MoveToBinaryFormat(data, p);
237   this->filename = p;
238   strcpy(p, filename.c_str());
239   p += Align(filename.size() + 1, 8);
240   sample_id.WriteToBinaryFormat(p);
241   UpdateBinary(new_binary);
242 }
243 
DumpData(size_t indent) const244 void MmapRecord::DumpData(size_t indent) const {
245   PrintIndented(indent,
246                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
247                 data->pid, data->tid, data->addr, data->len);
248   PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff,
249                 filename);
250 }
251 
Mmap2Record(const perf_event_attr & attr,const char * p)252 Mmap2Record::Mmap2Record(const perf_event_attr& attr, const char* p)
253     : Record(p) {
254   const char* end = p + size();
255   p += header_size();
256   data = reinterpret_cast<const Mmap2RecordDataType*>(p);
257   p += sizeof(*data);
258   filename = p;
259   p += Align(strlen(filename) + 1, 8);
260   CHECK_LE(p, end);
261   sample_id.ReadFromBinaryFormat(attr, p, end);
262 }
263 
SetDataAndFilename(const Mmap2RecordDataType & data,const std::string & filename)264 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data,
265                                      const std::string& filename) {
266   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
267           sample_id.Size());
268   char* new_binary = new char[size()];
269   char* p = new_binary;
270   MoveToBinaryFormat(header, p);
271   this->data = reinterpret_cast<Mmap2RecordDataType*>(p);
272   MoveToBinaryFormat(data, p);
273   this->filename = p;
274   strcpy(p, filename.c_str());
275   p += Align(filename.size() + 1, 8);
276   sample_id.WriteToBinaryFormat(p);
277   UpdateBinary(new_binary);
278 }
279 
DumpData(size_t indent) const280 void Mmap2Record::DumpData(size_t indent) const {
281   PrintIndented(indent,
282                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
283                 data->pid, data->tid, data->addr, data->len);
284   PrintIndented(indent, "pgoff 0x" PRIx64 ", maj %u, min %u, ino %" PRId64
285                         ", ino_generation %" PRIu64 "\n",
286                 data->pgoff, data->maj, data->min, data->ino,
287                 data->ino_generation);
288   PrintIndented(indent, "prot %u, flags %u, filenames %s\n", data->prot,
289                 data->flags, filename);
290 }
291 
CommRecord(const perf_event_attr & attr,const char * p)292 CommRecord::CommRecord(const perf_event_attr& attr, const char* p) : Record(p) {
293   const char* end = p + size();
294   p += header_size();
295   data = reinterpret_cast<const CommRecordDataType*>(p);
296   p += sizeof(*data);
297   comm = p;
298   p += Align(strlen(p) + 1, 8);
299   CHECK_LE(p, end);
300   sample_id.ReadFromBinaryFormat(attr, p, end);
301 }
302 
CommRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,const std::string & comm,uint64_t event_id,uint64_t time)303 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
304                        const std::string& comm, uint64_t event_id, uint64_t time) {
305   SetTypeAndMisc(PERF_RECORD_COMM, 0);
306   CommRecordDataType data;
307   data.pid = pid;
308   data.tid = tid;
309   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
310   sample_id.time_data.time = time;
311   SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) +
312           sample_id_size);
313   char* new_binary = new char[size()];
314   char* p = new_binary;
315   MoveToBinaryFormat(header, p);
316   this->data = reinterpret_cast<CommRecordDataType*>(p);
317   MoveToBinaryFormat(data, p);
318   this->comm = p;
319   strcpy(p, comm.c_str());
320   p += Align(comm.size() + 1, 8);
321   sample_id.WriteToBinaryFormat(p);
322   UpdateBinary(new_binary);
323 }
324 
DumpData(size_t indent) const325 void CommRecord::DumpData(size_t indent) const {
326   PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid,
327                 comm);
328 }
329 
ExitOrForkRecord(const perf_event_attr & attr,const char * p)330 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, const char* p)
331     : Record(p) {
332   const char* end = p + size();
333   p += header_size();
334   data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
335   p += sizeof(*data);
336   CHECK_LE(p, end);
337   sample_id.ReadFromBinaryFormat(attr, p, end);
338 }
339 
DumpData(size_t indent) const340 void ExitOrForkRecord::DumpData(size_t indent) const {
341   PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid,
342                 data->ppid, data->tid, data->ptid);
343 }
344 
ForkRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,uint32_t ppid,uint32_t ptid,uint64_t event_id)345 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
346                        uint32_t ppid, uint32_t ptid, uint64_t event_id) {
347   SetTypeAndMisc(PERF_RECORD_FORK, 0);
348   ExitOrForkRecordDataType data;
349   data.pid = pid;
350   data.ppid = ppid;
351   data.tid = tid;
352   data.ptid = ptid;
353   data.time = 0;
354   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
355   SetSize(header_size() + sizeof(data) + sample_id_size);
356   char* new_binary = new char[size()];
357   char* p = new_binary;
358   MoveToBinaryFormat(header, p);
359   this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p);
360   MoveToBinaryFormat(data, p);
361   sample_id.WriteToBinaryFormat(p);
362   UpdateBinary(new_binary);
363 }
364 
LostRecord(const perf_event_attr & attr,const char * p)365 LostRecord::LostRecord(const perf_event_attr& attr, const char* p) : Record(p) {
366   const char* end = p + size();
367   p += header_size();
368   MoveFromBinaryFormat(id, p);
369   MoveFromBinaryFormat(lost, p);
370   CHECK_LE(p, end);
371   sample_id.ReadFromBinaryFormat(attr, p, end);
372 }
373 
DumpData(size_t indent) const374 void LostRecord::DumpData(size_t indent) const {
375   PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
376 }
377 
SampleRecord(const perf_event_attr & attr,const char * p)378 SampleRecord::SampleRecord(const perf_event_attr& attr, const char* p)
379     : Record(p) {
380   const char* end = p + size();
381   p += header_size();
382   sample_type = attr.sample_type;
383 
384   // Set a default id value to report correctly even if ID is not recorded.
385   id_data.id = 0;
386   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
387     MoveFromBinaryFormat(id_data, p);
388   }
389   if (sample_type & PERF_SAMPLE_IP) {
390     MoveFromBinaryFormat(ip_data, p);
391   }
392   if (sample_type & PERF_SAMPLE_TID) {
393     MoveFromBinaryFormat(tid_data, p);
394   }
395   if (sample_type & PERF_SAMPLE_TIME) {
396     MoveFromBinaryFormat(time_data, p);
397   }
398   if (sample_type & PERF_SAMPLE_ADDR) {
399     MoveFromBinaryFormat(addr_data, p);
400   }
401   if (sample_type & PERF_SAMPLE_ID) {
402     MoveFromBinaryFormat(id_data, p);
403   }
404   if (sample_type & PERF_SAMPLE_STREAM_ID) {
405     MoveFromBinaryFormat(stream_id_data, p);
406   }
407   if (sample_type & PERF_SAMPLE_CPU) {
408     MoveFromBinaryFormat(cpu_data, p);
409   }
410   if (sample_type & PERF_SAMPLE_PERIOD) {
411     MoveFromBinaryFormat(period_data, p);
412   }
413   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
414     MoveFromBinaryFormat(callchain_data.ip_nr, p);
415     callchain_data.ips = reinterpret_cast<const uint64_t*>(p);
416     p += callchain_data.ip_nr * sizeof(uint64_t);
417   }
418   if (sample_type & PERF_SAMPLE_RAW) {
419     MoveFromBinaryFormat(raw_data.size, p);
420     raw_data.data = p;
421     p += raw_data.size;
422   }
423   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
424     MoveFromBinaryFormat(branch_stack_data.stack_nr, p);
425     branch_stack_data.stack = reinterpret_cast<const BranchStackItemType*>(p);
426     p += branch_stack_data.stack_nr * sizeof(BranchStackItemType);
427   }
428   if (sample_type & PERF_SAMPLE_REGS_USER) {
429     MoveFromBinaryFormat(regs_user_data.abi, p);
430     if (regs_user_data.abi == 0) {
431       regs_user_data.reg_mask = 0;
432     } else {
433       regs_user_data.reg_mask = attr.sample_regs_user;
434       size_t bit_nr = 0;
435       for (size_t i = 0; i < 64; ++i) {
436         if ((regs_user_data.reg_mask >> i) & 1) {
437           bit_nr++;
438         }
439       }
440       regs_user_data.reg_nr = bit_nr;
441       regs_user_data.regs = reinterpret_cast<const uint64_t*>(p);
442       p += bit_nr * sizeof(uint64_t);
443     }
444   }
445   if (sample_type & PERF_SAMPLE_STACK_USER) {
446     MoveFromBinaryFormat(stack_user_data.size, p);
447     if (stack_user_data.size == 0) {
448       stack_user_data.dyn_size = 0;
449     } else {
450       stack_user_data.data = p;
451       p += stack_user_data.size;
452       MoveFromBinaryFormat(stack_user_data.dyn_size, p);
453     }
454   }
455   // TODO: Add parsing of other PERF_SAMPLE_*.
456   CHECK_LE(p, end);
457   if (p < end) {
458     LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
459   }
460 }
461 
SampleRecord(const perf_event_attr & attr,uint64_t id,uint64_t ip,uint32_t pid,uint32_t tid,uint64_t time,uint32_t cpu,uint64_t period,const std::vector<uint64_t> & ips)462 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id,
463                            uint64_t ip, uint32_t pid, uint32_t tid,
464                            uint64_t time, uint32_t cpu, uint64_t period,
465                            const std::vector<uint64_t>& ips) {
466   SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER);
467   sample_type = attr.sample_type;
468   CHECK_EQ(0u, sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID
469       | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_CPU
470       | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER
471       | PERF_SAMPLE_STACK_USER));
472   ip_data.ip = ip;
473   tid_data.pid = pid;
474   tid_data.tid = tid;
475   time_data.time = time;
476   id_data.id = id;
477   cpu_data.cpu = cpu;
478   cpu_data.res = 0;
479   period_data.period = period;
480   callchain_data.ip_nr = ips.size();
481   raw_data.size = 0;
482   branch_stack_data.stack_nr = 0;
483   regs_user_data.abi = 0;
484   regs_user_data.reg_mask = 0;
485   stack_user_data.size = 0;
486 
487   uint32_t size = header_size();
488   if (sample_type & PERF_SAMPLE_IP) {
489     size += sizeof(ip_data);
490   }
491   if (sample_type & PERF_SAMPLE_TID) {
492     size += sizeof(tid_data);
493   }
494   if (sample_type & PERF_SAMPLE_TIME) {
495     size += sizeof(time_data);
496   }
497   if (sample_type & PERF_SAMPLE_ID) {
498     size += sizeof(id_data);
499   }
500   if (sample_type & PERF_SAMPLE_CPU) {
501     size += sizeof(cpu_data);
502   }
503   if (sample_type & PERF_SAMPLE_PERIOD) {
504     size += sizeof(period_data);
505   }
506   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
507     size += sizeof(uint64_t) * (ips.size() + 1);
508   }
509   if (sample_type & PERF_SAMPLE_REGS_USER) {
510     size += sizeof(uint64_t);
511   }
512   if (sample_type & PERF_SAMPLE_STACK_USER) {
513     size += sizeof(uint64_t);
514   }
515 
516   SetSize(size);
517   char* new_binary = new char[size];
518   char* p = new_binary;
519   MoveToBinaryFormat(header, p);
520   if (sample_type & PERF_SAMPLE_IP) {
521     MoveToBinaryFormat(ip_data, p);
522   }
523   if (sample_type & PERF_SAMPLE_TID) {
524     MoveToBinaryFormat(tid_data, p);
525   }
526   if (sample_type & PERF_SAMPLE_TIME) {
527     MoveToBinaryFormat(time_data, p);
528   }
529   if (sample_type & PERF_SAMPLE_ID) {
530     MoveToBinaryFormat(id_data, p);
531   }
532   if (sample_type & PERF_SAMPLE_CPU) {
533     MoveToBinaryFormat(cpu_data, p);
534   }
535   if (sample_type & PERF_SAMPLE_PERIOD) {
536     MoveToBinaryFormat(period_data, p);
537   }
538   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
539     MoveToBinaryFormat(callchain_data.ip_nr, p);
540     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
541     MoveToBinaryFormat(ips.data(), ips.size(), p);
542   }
543   if (sample_type & PERF_SAMPLE_REGS_USER) {
544     MoveToBinaryFormat(regs_user_data.abi, p);
545   }
546   if (sample_type & PERF_SAMPLE_STACK_USER) {
547     MoveToBinaryFormat(stack_user_data.size, p);
548   }
549   CHECK_EQ(p, new_binary + size);
550   UpdateBinary(new_binary);
551 }
552 
ReplaceRegAndStackWithCallChain(const std::vector<uint64_t> & ips)553 void SampleRecord::ReplaceRegAndStackWithCallChain(
554     const std::vector<uint64_t>& ips) {
555   uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1);
556   uint32_t size_reduced_in_reg_stack =
557       regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size +
558       sizeof(uint64_t);
559   CHECK_LE(size_added_in_callchain, size_reduced_in_reg_stack);
560   uint32_t size_reduced = size_reduced_in_reg_stack - size_added_in_callchain;
561   SetSize(size() - size_reduced);
562   char* p = const_cast<char*>(binary_);
563   MoveToBinaryFormat(header, p);
564   p = const_cast<char*>(stack_user_data.data + stack_user_data.size +
565                         sizeof(uint64_t)) -
566       (size_reduced_in_reg_stack - size_added_in_callchain);
567   stack_user_data.size = 0;
568   regs_user_data.abi = 0;
569   p -= sizeof(uint64_t);
570   *reinterpret_cast<uint64_t*>(p) = stack_user_data.size;
571   p -= sizeof(uint64_t);
572   *reinterpret_cast<uint64_t*>(p) = regs_user_data.abi;
573   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
574     p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType);
575     memmove(p, branch_stack_data.stack,
576             branch_stack_data.stack_nr * sizeof(BranchStackItemType));
577     p -= sizeof(uint64_t);
578     *reinterpret_cast<uint64_t*>(p) = branch_stack_data.stack_nr;
579   }
580   if (sample_type & PERF_SAMPLE_RAW) {
581     p -= raw_data.size;
582     memmove(p, raw_data.data, raw_data.size);
583     p -= sizeof(uint32_t);
584     *reinterpret_cast<uint32_t*>(p) = raw_data.size;
585   }
586   p -= ips.size() * sizeof(uint64_t);
587   memcpy(p, ips.data(), ips.size() * sizeof(uint64_t));
588   p -= sizeof(uint64_t);
589   *reinterpret_cast<uint64_t*>(p) = PERF_CONTEXT_USER;
590   p -= sizeof(uint64_t) * (callchain_data.ip_nr);
591   callchain_data.ips = reinterpret_cast<uint64_t*>(p);
592   callchain_data.ip_nr += ips.size() + 1;
593   p -= sizeof(uint64_t);
594   *reinterpret_cast<uint64_t*>(p) = callchain_data.ip_nr;
595 }
596 
DumpData(size_t indent) const597 void SampleRecord::DumpData(size_t indent) const {
598   PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
599   if (sample_type & PERF_SAMPLE_IP) {
600     PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
601   }
602   if (sample_type & PERF_SAMPLE_TID) {
603     PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
604   }
605   if (sample_type & PERF_SAMPLE_TIME) {
606     PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
607   }
608   if (sample_type & PERF_SAMPLE_ADDR) {
609     PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
610   }
611   if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
612     PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
613   }
614   if (sample_type & PERF_SAMPLE_STREAM_ID) {
615     PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
616   }
617   if (sample_type & PERF_SAMPLE_CPU) {
618     PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
619   }
620   if (sample_type & PERF_SAMPLE_PERIOD) {
621     PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
622   }
623   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
624     PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr);
625     for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
626       PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]);
627     }
628   }
629   if (sample_type & PERF_SAMPLE_RAW) {
630     PrintIndented(indent, "raw size=%zu\n", raw_data.size);
631     const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data);
632     size_t size = raw_data.size / sizeof(uint32_t);
633     for (size_t i = 0; i < size; ++i) {
634       PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
635     }
636   }
637   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
638     PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n",
639                   branch_stack_data.stack_nr);
640     for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) {
641       auto& item = branch_stack_data.stack[i];
642       PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64
643                                 ", flags 0x%" PRIx64 "\n",
644                     item.from, item.to, item.flags);
645     }
646   }
647   if (sample_type & PERF_SAMPLE_REGS_USER) {
648     PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
649     for (size_t i = 0, pos = 0; i < 64; ++i) {
650       if ((regs_user_data.reg_mask >> i) & 1) {
651         PrintIndented(
652             indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
653             GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
654             regs_user_data.regs[pos++]);
655       }
656     }
657   }
658   if (sample_type & PERF_SAMPLE_STACK_USER) {
659     PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n",
660                   stack_user_data.size, stack_user_data.dyn_size);
661     const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
662     const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
663     while (p < end) {
664       PrintIndented(indent + 1, "");
665       for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
666         printf(" %016" PRIx64, *p);
667       }
668       printf("\n");
669     }
670     printf("\n");
671   }
672 }
673 
Timestamp() const674 uint64_t SampleRecord::Timestamp() const { return time_data.time; }
Cpu() const675 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; }
Id() const676 uint64_t SampleRecord::Id() const { return id_data.id; }
677 
BuildIdRecord(const char * p)678 BuildIdRecord::BuildIdRecord(const char* p) : Record(p) {
679   const char* end = p + size();
680   p += header_size();
681   MoveFromBinaryFormat(pid, p);
682   build_id = BuildId(p, BUILD_ID_SIZE);
683   p += Align(build_id.Size(), 8);
684   filename = p;
685   p += Align(strlen(filename) + 1, 64);
686   CHECK_EQ(p, end);
687 }
688 
DumpData(size_t indent) const689 void BuildIdRecord::DumpData(size_t indent) const {
690   PrintIndented(indent, "pid %u\n", pid);
691   PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
692   PrintIndented(indent, "filename %s\n", filename);
693 }
694 
BuildIdRecord(bool in_kernel,pid_t pid,const BuildId & build_id,const std::string & filename)695 BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
696                              const std::string& filename) {
697   SetTypeAndMisc(PERF_RECORD_BUILD_ID,
698                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
699   this->pid = pid;
700   this->build_id = build_id;
701   SetSize(header_size() + sizeof(pid) + Align(build_id.Size(), 8) +
702           Align(filename.size() + 1, 64));
703   char* new_binary = new char[size()];
704   char* p = new_binary;
705   MoveToBinaryFormat(header, p);
706   MoveToBinaryFormat(pid, p);
707   memcpy(p, build_id.Data(), build_id.Size());
708   p += Align(build_id.Size(), 8);
709   this->filename = p;
710   strcpy(p, filename.c_str());
711   UpdateBinary(new_binary);
712 }
713 
KernelSymbolRecord(const char * p)714 KernelSymbolRecord::KernelSymbolRecord(const char* p) : Record(p) {
715   const char* end = p + size();
716   p += header_size();
717   MoveFromBinaryFormat(kallsyms_size, p);
718   kallsyms = p;
719   p += Align(kallsyms_size, 8);
720   CHECK_EQ(p, end);
721 }
722 
DumpData(size_t indent) const723 void KernelSymbolRecord::DumpData(size_t indent) const {
724   PrintIndented(indent, "kallsyms: %s\n",
725                 std::string(kallsyms, kallsyms + kallsyms_size).c_str());
726 }
727 
KernelSymbolRecord(const std::string & kallsyms)728 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) {
729   SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0);
730   kallsyms_size = kallsyms.size();
731   SetSize(header_size() + 4 + Align(kallsyms.size(), 8));
732   char* new_binary = new char[size()];
733   char* p = new_binary;
734   MoveToBinaryFormat(header, p);
735   MoveToBinaryFormat(kallsyms_size, p);
736   this->kallsyms = p;
737   memcpy(p, kallsyms.data(), kallsyms_size);
738   UpdateBinary(new_binary);
739 }
740 
DsoRecord(const char * p)741 DsoRecord::DsoRecord(const char* p) : Record(p) {
742   const char* end = p + size();
743   p += header_size();
744   MoveFromBinaryFormat(dso_type, p);
745   MoveFromBinaryFormat(dso_id, p);
746   MoveFromBinaryFormat(min_vaddr, p);
747   dso_name = p;
748   p += Align(strlen(dso_name) + 1, 8);
749   CHECK_EQ(p, end);
750 }
751 
DsoRecord(uint64_t dso_type,uint64_t dso_id,const std::string & dso_name,uint64_t min_vaddr)752 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id,
753                      const std::string& dso_name, uint64_t min_vaddr) {
754   SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0);
755   this->dso_type = dso_type;
756   this->dso_id = dso_id;
757   this->min_vaddr = min_vaddr;
758   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8));
759   char* new_binary = new char[size()];
760   char* p = new_binary;
761   MoveToBinaryFormat(header, p);
762   MoveToBinaryFormat(dso_type, p);
763   MoveToBinaryFormat(dso_id, p);
764   MoveToBinaryFormat(min_vaddr, p);
765   this->dso_name = p;
766   strcpy(p, dso_name.c_str());
767   UpdateBinary(new_binary);
768 }
769 
DumpData(size_t indent) const770 void DsoRecord::DumpData(size_t indent) const {
771   PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n",
772                 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type);
773   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
774   PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr);
775   PrintIndented(indent, "dso_name: %s\n", dso_name);
776 }
777 
SymbolRecord(const char * p)778 SymbolRecord::SymbolRecord(const char* p) : Record(p) {
779   const char* end = p + size();
780   p += header_size();
781   MoveFromBinaryFormat(addr, p);
782   MoveFromBinaryFormat(len, p);
783   MoveFromBinaryFormat(dso_id, p);
784   name = p;
785   p += Align(strlen(name) + 1, 8);
786   CHECK_EQ(p, end);
787 }
788 
SymbolRecord(uint64_t addr,uint64_t len,const std::string & name,uint64_t dso_id)789 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
790                            uint64_t dso_id) {
791   SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
792   this->addr = addr;
793   this->len = len;
794   this->dso_id = dso_id;
795   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8));
796   char* new_binary = new char[size()];
797   char* p = new_binary;
798   MoveToBinaryFormat(header, p);
799   MoveToBinaryFormat(addr, p);
800   MoveToBinaryFormat(len, p);
801   MoveToBinaryFormat(dso_id, p);
802   this->name = p;
803   strcpy(p, name.c_str());
804   UpdateBinary(new_binary);
805 }
806 
DumpData(size_t indent) const807 void SymbolRecord::DumpData(size_t indent) const {
808   PrintIndented(indent, "name: %s\n", name);
809   PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr);
810   PrintIndented(indent, "len: 0x%" PRIx64 "\n", len);
811   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
812 }
813 
TracingDataRecord(const char * p)814 TracingDataRecord::TracingDataRecord(const char* p) : Record(p) {
815   const char* end = p + size();
816   p += header_size();
817   MoveFromBinaryFormat(data_size, p);
818   data = p;
819   p += Align(data_size, 64);
820   CHECK_EQ(p, end);
821 }
822 
TracingDataRecord(const std::vector<char> & tracing_data)823 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
824   SetTypeAndMisc(PERF_RECORD_TRACING_DATA, 0);
825   data_size = tracing_data.size();
826   SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
827   char* new_binary = new char[size()];
828   char* p = new_binary;
829   MoveToBinaryFormat(header, p);
830   MoveToBinaryFormat(data_size, p);
831   data = p;
832   memcpy(p, tracing_data.data(), data_size);
833   UpdateBinary(new_binary);
834 }
835 
DumpData(size_t indent) const836 void TracingDataRecord::DumpData(size_t indent) const {
837   Tracing tracing(std::vector<char>(data, data + data_size));
838   tracing.Dump(indent);
839 }
840 
EventIdRecord(const char * p)841 EventIdRecord::EventIdRecord(const char* p) : Record(p) {
842   const char* end = p + size();
843   p += header_size();
844   MoveFromBinaryFormat(count, p);
845   data = reinterpret_cast<const EventIdData*>(p);
846   p += sizeof(data[0]) * count;
847   CHECK_EQ(p, end);
848 }
849 
EventIdRecord(const std::vector<uint64_t> & data)850 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) {
851   SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0);
852   SetSize(header_size() + sizeof(uint64_t) * (1 + data.size()));
853   char* new_binary = new char[size()];
854   char* p = new_binary;
855   MoveToBinaryFormat(header, p);
856   count = data.size() / 2;
857   MoveToBinaryFormat(count, p);
858   this->data = reinterpret_cast<EventIdData*>(p);
859   memcpy(p, data.data(), sizeof(uint64_t) * data.size());
860   UpdateBinary(new_binary);
861 }
862 
DumpData(size_t indent) const863 void EventIdRecord::DumpData(size_t indent) const {
864   PrintIndented(indent, "count: %" PRIu64 "\n", count);
865   for (size_t i = 0; i < count; ++i) {
866     PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i,
867                   data[i].attr_id);
868     PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i,
869                   data[i].event_id);
870   }
871 }
872 
UnknownRecord(const char * p)873 UnknownRecord::UnknownRecord(const char* p) : Record(p) {
874   p += header_size();
875   data = p;
876 }
877 
DumpData(size_t) const878 void UnknownRecord::DumpData(size_t) const {}
879 
ReadRecordFromBuffer(const perf_event_attr & attr,uint32_t type,const char * p)880 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
881                                              uint32_t type, const char* p) {
882   switch (type) {
883     case PERF_RECORD_MMAP:
884       return std::unique_ptr<Record>(new MmapRecord(attr, p));
885     case PERF_RECORD_MMAP2:
886       return std::unique_ptr<Record>(new Mmap2Record(attr, p));
887     case PERF_RECORD_COMM:
888       return std::unique_ptr<Record>(new CommRecord(attr, p));
889     case PERF_RECORD_EXIT:
890       return std::unique_ptr<Record>(new ExitRecord(attr, p));
891     case PERF_RECORD_FORK:
892       return std::unique_ptr<Record>(new ForkRecord(attr, p));
893     case PERF_RECORD_LOST:
894       return std::unique_ptr<Record>(new LostRecord(attr, p));
895     case PERF_RECORD_SAMPLE:
896       return std::unique_ptr<Record>(new SampleRecord(attr, p));
897     case PERF_RECORD_TRACING_DATA:
898       return std::unique_ptr<Record>(new TracingDataRecord(p));
899     case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
900       return std::unique_ptr<Record>(new KernelSymbolRecord(p));
901     case SIMPLE_PERF_RECORD_DSO:
902       return std::unique_ptr<Record>(new DsoRecord(p));
903     case SIMPLE_PERF_RECORD_SYMBOL:
904       return std::unique_ptr<Record>(new SymbolRecord(p));
905     case SIMPLE_PERF_RECORD_EVENT_ID:
906       return std::unique_ptr<Record>(new EventIdRecord(p));
907     default:
908       return std::unique_ptr<Record>(new UnknownRecord(p));
909   }
910 }
911 
ReadRecordFromOwnedBuffer(const perf_event_attr & attr,uint32_t type,const char * p)912 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
913                                                   uint32_t type,
914                                                   const char* p) {
915   std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p);
916   if (record != nullptr) {
917     record->OwnBinary();
918   } else {
919     delete[] p;
920   }
921   return record;
922 }
923 
ReadRecordsFromBuffer(const perf_event_attr & attr,const char * buf,size_t buf_size)924 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(
925     const perf_event_attr& attr, const char* buf, size_t buf_size) {
926   std::vector<std::unique_ptr<Record>> result;
927   const char* p = buf;
928   const char* end = buf + buf_size;
929   while (p < end) {
930     RecordHeader header(p);
931     CHECK_LE(p + header.size, end);
932     CHECK_NE(0u, header.size);
933     result.push_back(ReadRecordFromBuffer(attr, header.type, p));
934     p += header.size;
935   }
936   return result;
937 }
938 
ReadRecordFromBuffer(const perf_event_attr & attr,const char * p)939 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
940                                              const char* p) {
941   auto header = reinterpret_cast<const perf_event_header*>(p);
942   return ReadRecordFromBuffer(attr, header->type, p);
943 }
944 
IsHappensBefore(const RecordWithSeq & other) const945 bool RecordCache::RecordWithSeq::IsHappensBefore(
946     const RecordWithSeq& other) const {
947   bool is_sample = (record->type() == PERF_RECORD_SAMPLE);
948   bool is_other_sample = (other.record->type() == PERF_RECORD_SAMPLE);
949   uint64_t time = record->Timestamp();
950   uint64_t other_time = other.record->Timestamp();
951   // The record with smaller time happens first.
952   if (time != other_time) {
953     return time < other_time;
954   }
955   // If happening at the same time, make non-sample records before sample
956   // records, because non-sample records may contain useful information to
957   // parse sample records.
958   if (is_sample != is_other_sample) {
959     return is_sample ? false : true;
960   }
961   // Otherwise, use the same order as they enter the cache.
962   return seq < other.seq;
963 }
964 
operator ()(const RecordWithSeq & r1,const RecordWithSeq & r2)965 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
966                                                const RecordWithSeq& r2) {
967   return r2.IsHappensBefore(r1);
968 }
969 
RecordCache(bool has_timestamp,size_t min_cache_size,uint64_t min_time_diff_in_ns)970 RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size,
971                          uint64_t min_time_diff_in_ns)
972     : has_timestamp_(has_timestamp),
973       min_cache_size_(min_cache_size),
974       min_time_diff_in_ns_(min_time_diff_in_ns),
975       last_time_(0),
976       cur_seq_(0),
977       queue_(RecordComparator()) {}
978 
~RecordCache()979 RecordCache::~RecordCache() { PopAll(); }
980 
Push(std::unique_ptr<Record> record)981 void RecordCache::Push(std::unique_ptr<Record> record) {
982   if (has_timestamp_) {
983     last_time_ = std::max(last_time_, record->Timestamp());
984   }
985   queue_.push(RecordWithSeq(cur_seq_++, record.release()));
986 }
987 
Push(std::vector<std::unique_ptr<Record>> records)988 void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
989   for (auto& r : records) {
990     Push(std::move(r));
991   }
992 }
993 
Pop()994 std::unique_ptr<Record> RecordCache::Pop() {
995   if (queue_.size() < min_cache_size_) {
996     return nullptr;
997   }
998   Record* r = queue_.top().record;
999   if (has_timestamp_) {
1000     if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
1001       return nullptr;
1002     }
1003   }
1004   queue_.pop();
1005   return std::unique_ptr<Record>(r);
1006 }
1007 
PopAll()1008 std::vector<std::unique_ptr<Record>> RecordCache::PopAll() {
1009   std::vector<std::unique_ptr<Record>> result;
1010   while (!queue_.empty()) {
1011     result.emplace_back(queue_.top().record);
1012     queue_.pop();
1013   }
1014   return result;
1015 }
1016 
ForcedPop()1017 std::unique_ptr<Record> RecordCache::ForcedPop() {
1018   if (queue_.empty()) {
1019     return nullptr;
1020   }
1021   Record* r = queue_.top().record;
1022   queue_.pop();
1023   return std::unique_ptr<Record>(r);
1024 }
1025