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 "OfflineUnwinder.h"
28 #include "perf_regs.h"
29 #include "tracing.h"
30 #include "utils.h"
31 
32 using namespace simpleperf;
33 
RecordTypeToString(int record_type)34 static std::string RecordTypeToString(int record_type) {
35   static std::unordered_map<int, std::string> record_type_names = {
36       {PERF_RECORD_MMAP, "mmap"},
37       {PERF_RECORD_LOST, "lost"},
38       {PERF_RECORD_COMM, "comm"},
39       {PERF_RECORD_EXIT, "exit"},
40       {PERF_RECORD_THROTTLE, "throttle"},
41       {PERF_RECORD_UNTHROTTLE, "unthrottle"},
42       {PERF_RECORD_FORK, "fork"},
43       {PERF_RECORD_READ, "read"},
44       {PERF_RECORD_SAMPLE, "sample"},
45       {PERF_RECORD_BUILD_ID, "build_id"},
46       {PERF_RECORD_MMAP2, "mmap2"},
47       {PERF_RECORD_AUX, "aux"},
48       {PERF_RECORD_TRACING_DATA, "tracing_data"},
49       {PERF_RECORD_AUXTRACE_INFO, "auxtrace_info"},
50       {PERF_RECORD_AUXTRACE, "auxtrace"},
51       {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"},
52       {SIMPLE_PERF_RECORD_DSO, "dso"},
53       {SIMPLE_PERF_RECORD_SYMBOL, "symbol"},
54       {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
55       {SIMPLE_PERF_RECORD_CALLCHAIN, "callchain"},
56       {SIMPLE_PERF_RECORD_UNWINDING_RESULT, "unwinding_result"},
57       {SIMPLE_PERF_RECORD_TRACING_DATA, "tracing_data"},
58   };
59 
60   auto it = record_type_names.find(record_type);
61   if (it != record_type_names.end()) {
62     return it->second;
63   }
64   return android::base::StringPrintf("unknown(%d)", record_type);
65 }
66 
67 template <>
MoveToBinaryFormat(const RecordHeader & data,char * & p)68 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
69   data.MoveToBinaryFormat(p);
70 }
71 
SampleId()72 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); }
73 
74 // Return sample_id size in binary format.
CreateContent(const perf_event_attr & attr,uint64_t event_id)75 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
76   sample_id_all = attr.sample_id_all;
77   sample_type = attr.sample_type;
78   id_data.id = event_id;
79   // Other data are not necessary. TODO: Set missing SampleId data.
80   return Size();
81 }
82 
ReadFromBinaryFormat(const perf_event_attr & attr,const char * p,const char * end)83 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p,
84                                     const char* end) {
85   sample_id_all = attr.sample_id_all;
86   sample_type = attr.sample_type;
87   if (sample_id_all) {
88     if (sample_type & PERF_SAMPLE_TID) {
89       MoveFromBinaryFormat(tid_data, p);
90     }
91     if (sample_type & PERF_SAMPLE_TIME) {
92       MoveFromBinaryFormat(time_data, p);
93     }
94     if (sample_type & PERF_SAMPLE_ID) {
95       MoveFromBinaryFormat(id_data, p);
96     }
97     if (sample_type & PERF_SAMPLE_STREAM_ID) {
98       MoveFromBinaryFormat(stream_id_data, p);
99     }
100     if (sample_type & PERF_SAMPLE_CPU) {
101       MoveFromBinaryFormat(cpu_data, p);
102     }
103     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
104       MoveFromBinaryFormat(id_data, p);
105     }
106   }
107   CHECK_LE(p, end);
108   if (p < end) {
109     LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
110   }
111 }
112 
WriteToBinaryFormat(char * & p) const113 void SampleId::WriteToBinaryFormat(char*& p) const {
114   if (sample_id_all) {
115     if (sample_type & PERF_SAMPLE_TID) {
116       MoveToBinaryFormat(tid_data, p);
117     }
118     if (sample_type & PERF_SAMPLE_TIME) {
119       MoveToBinaryFormat(time_data, p);
120     }
121     if (sample_type & PERF_SAMPLE_ID) {
122       MoveToBinaryFormat(id_data, p);
123     }
124     if (sample_type & PERF_SAMPLE_STREAM_ID) {
125       MoveToBinaryFormat(stream_id_data, p);
126     }
127     if (sample_type & PERF_SAMPLE_CPU) {
128       MoveToBinaryFormat(cpu_data, p);
129     }
130   }
131 }
132 
Dump(size_t indent) const133 void SampleId::Dump(size_t indent) const {
134   if (sample_id_all) {
135     if (sample_type & PERF_SAMPLE_TID) {
136       PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid,
137                     tid_data.tid);
138     }
139     if (sample_type & PERF_SAMPLE_TIME) {
140       PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
141     }
142     if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
143       PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
144     }
145     if (sample_type & PERF_SAMPLE_STREAM_ID) {
146       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n",
147                     stream_id_data.stream_id);
148     }
149     if (sample_type & PERF_SAMPLE_CPU) {
150       PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu,
151                     cpu_data.res);
152     }
153   }
154 }
155 
Size() const156 size_t SampleId::Size() const {
157   size_t size = 0;
158   if (sample_id_all) {
159     if (sample_type & PERF_SAMPLE_TID) {
160       size += sizeof(PerfSampleTidType);
161     }
162     if (sample_type & PERF_SAMPLE_TIME) {
163       size += sizeof(PerfSampleTimeType);
164     }
165     if (sample_type & PERF_SAMPLE_ID) {
166       size += sizeof(PerfSampleIdType);
167     }
168     if (sample_type & PERF_SAMPLE_STREAM_ID) {
169       size += sizeof(PerfSampleStreamIdType);
170     }
171     if (sample_type & PERF_SAMPLE_CPU) {
172       size += sizeof(PerfSampleCpuType);
173     }
174     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
175       size += sizeof(PerfSampleIdType);
176     }
177   }
178   return size;
179 }
180 
Record(Record && other)181 Record::Record(Record&& other) noexcept {
182   header = other.header;
183   sample_id = other.sample_id;
184   binary_ = other.binary_;
185   own_binary_ = other.own_binary_;
186   other.binary_ = nullptr;
187   other.own_binary_ = false;
188 }
189 
Dump(size_t indent) const190 void Record::Dump(size_t indent) const {
191   PrintIndented(indent, "record %s: type %u, misc %u, size %u\n",
192                 RecordTypeToString(type()).c_str(), type(), misc(), size());
193   DumpData(indent + 1);
194   sample_id.Dump(indent + 1);
195 }
196 
Timestamp() const197 uint64_t Record::Timestamp() const { return sample_id.time_data.time; }
Cpu() const198 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; }
Id() const199 uint64_t Record::Id() const { return sample_id.id_data.id; }
200 
UpdateBinary(char * new_binary)201 void Record::UpdateBinary(char* new_binary) {
202   if (own_binary_) {
203     delete[] binary_;
204   }
205   own_binary_ = true;
206   binary_ = new_binary;
207 }
208 
MmapRecord(const perf_event_attr & attr,char * p)209 MmapRecord::MmapRecord(const perf_event_attr& attr, char* p) : Record(p) {
210   const char* end = p + size();
211   p += header_size();
212   data = reinterpret_cast<const MmapRecordDataType*>(p);
213   p += sizeof(*data);
214   filename = p;
215   p += Align(strlen(filename) + 1, 8);
216   CHECK_LE(p, end);
217   sample_id.ReadFromBinaryFormat(attr, p, end);
218 }
219 
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)220 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel,
221                        uint32_t pid, uint32_t tid, uint64_t addr, uint64_t len,
222                        uint64_t pgoff, const std::string& filename,
223                        uint64_t event_id, uint64_t time) {
224   SetTypeAndMisc(PERF_RECORD_MMAP,
225                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
226   sample_id.CreateContent(attr, event_id);
227   sample_id.time_data.time = time;
228   MmapRecordDataType data;
229   data.pid = pid;
230   data.tid = tid;
231   data.addr = addr;
232   data.len = len;
233   data.pgoff = pgoff;
234   SetDataAndFilename(data, filename);
235 }
236 
SetDataAndFilename(const MmapRecordDataType & data,const std::string & filename)237 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data,
238                                     const std::string& filename) {
239   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
240           sample_id.Size());
241   char* new_binary = new char[size()];
242   char* p = new_binary;
243   MoveToBinaryFormat(header, p);
244   this->data = reinterpret_cast<MmapRecordDataType*>(p);
245   MoveToBinaryFormat(data, p);
246   this->filename = p;
247   strcpy(p, filename.c_str());
248   p += Align(filename.size() + 1, 8);
249   sample_id.WriteToBinaryFormat(p);
250   UpdateBinary(new_binary);
251 }
252 
DumpData(size_t indent) const253 void MmapRecord::DumpData(size_t indent) const {
254   PrintIndented(indent,
255                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
256                 data->pid, data->tid, data->addr, data->len);
257   PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff,
258                 filename);
259 }
260 
Mmap2Record(const perf_event_attr & attr,char * p)261 Mmap2Record::Mmap2Record(const perf_event_attr& attr, char* p) : Record(p) {
262   const char* end = p + size();
263   p += header_size();
264   data = reinterpret_cast<const Mmap2RecordDataType*>(p);
265   p += sizeof(*data);
266   filename = p;
267   p += Align(strlen(filename) + 1, 8);
268   CHECK_LE(p, end);
269   sample_id.ReadFromBinaryFormat(attr, p, end);
270 }
271 
Mmap2Record(const perf_event_attr & attr,bool in_kernel,uint32_t pid,uint32_t tid,uint64_t addr,uint64_t len,uint64_t pgoff,uint32_t prot,const std::string & filename,uint64_t event_id,uint64_t time)272 Mmap2Record::Mmap2Record(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
273                          uint64_t addr, uint64_t len, uint64_t pgoff, uint32_t prot,
274                          const std::string& filename, uint64_t event_id, uint64_t time) {
275   SetTypeAndMisc(PERF_RECORD_MMAP2, in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
276   sample_id.CreateContent(attr, event_id);
277   sample_id.time_data.time = time;
278   Mmap2RecordDataType data;
279   data.pid = pid;
280   data.tid = tid;
281   data.addr = addr;
282   data.len = len;
283   data.pgoff = pgoff;
284   data.prot = prot;
285   SetDataAndFilename(data, filename);
286 }
287 
SetDataAndFilename(const Mmap2RecordDataType & data,const std::string & filename)288 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data,
289                                      const std::string& filename) {
290   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
291           sample_id.Size());
292   char* new_binary = new char[size()];
293   char* p = new_binary;
294   MoveToBinaryFormat(header, p);
295   this->data = reinterpret_cast<Mmap2RecordDataType*>(p);
296   MoveToBinaryFormat(data, p);
297   this->filename = p;
298   strcpy(p, filename.c_str());
299   p += Align(filename.size() + 1, 8);
300   sample_id.WriteToBinaryFormat(p);
301   UpdateBinary(new_binary);
302 }
303 
DumpData(size_t indent) const304 void Mmap2Record::DumpData(size_t indent) const {
305   PrintIndented(indent,
306                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
307                 data->pid, data->tid, data->addr, data->len);
308   PrintIndented(indent, "pgoff 0x%" PRIx64 ", maj %u, min %u, ino %" PRId64
309                         ", ino_generation %" PRIu64 "\n",
310                 data->pgoff, data->maj, data->min, data->ino,
311                 data->ino_generation);
312   PrintIndented(indent, "prot %u, flags %u, filename %s\n", data->prot,
313                 data->flags, filename);
314 }
315 
CommRecord(const perf_event_attr & attr,char * p)316 CommRecord::CommRecord(const perf_event_attr& attr, char* p) : Record(p) {
317   const char* end = p + size();
318   p += header_size();
319   data = reinterpret_cast<const CommRecordDataType*>(p);
320   p += sizeof(*data);
321   comm = p;
322   p += Align(strlen(p) + 1, 8);
323   CHECK_LE(p, end);
324   sample_id.ReadFromBinaryFormat(attr, p, end);
325 }
326 
CommRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,const std::string & comm,uint64_t event_id,uint64_t time)327 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
328                        const std::string& comm, uint64_t event_id, uint64_t time) {
329   SetTypeAndMisc(PERF_RECORD_COMM, 0);
330   CommRecordDataType data;
331   data.pid = pid;
332   data.tid = tid;
333   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
334   sample_id.time_data.time = time;
335   SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) +
336           sample_id_size);
337   char* new_binary = new char[size()];
338   char* p = new_binary;
339   MoveToBinaryFormat(header, p);
340   this->data = reinterpret_cast<CommRecordDataType*>(p);
341   MoveToBinaryFormat(data, p);
342   this->comm = p;
343   strcpy(p, comm.c_str());
344   p += Align(comm.size() + 1, 8);
345   sample_id.WriteToBinaryFormat(p);
346   UpdateBinary(new_binary);
347 }
348 
SetCommandName(const std::string & name)349 void CommRecord::SetCommandName(const std::string& name) {
350   if (name.compare(comm) == 0) {
351     return;
352   }
353   // The kernel uses a 8-byte aligned space to store command name. Follow it here to allow the same
354   // reading code.
355   size_t old_name_len = Align(strlen(comm) + 1, 8);
356   size_t new_name_len = Align(name.size() + 1, 8);
357   size_t new_size = size() - old_name_len + new_name_len;
358   char* new_binary = new char[new_size];
359   char* p = new_binary;
360   header.size = new_size;
361   MoveToBinaryFormat(header, p);
362   MoveToBinaryFormat(*data, p);
363   data = reinterpret_cast<CommRecordDataType*>(p - sizeof(CommRecordDataType));
364   comm = p;
365   strcpy(p, name.c_str());
366   p += new_name_len;
367   sample_id.WriteToBinaryFormat(p);
368   CHECK_EQ(p, new_binary + new_size);
369   UpdateBinary(new_binary);
370 }
371 
DumpData(size_t indent) const372 void CommRecord::DumpData(size_t indent) const {
373   PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid,
374                 comm);
375 }
376 
ExitOrForkRecord(const perf_event_attr & attr,char * p)377 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, char* p)
378     : Record(p) {
379   const char* end = p + size();
380   p += header_size();
381   data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
382   p += sizeof(*data);
383   CHECK_LE(p, end);
384   sample_id.ReadFromBinaryFormat(attr, p, end);
385 }
386 
DumpData(size_t indent) const387 void ExitOrForkRecord::DumpData(size_t indent) const {
388   PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid,
389                 data->ppid, data->tid, data->ptid);
390 }
391 
ForkRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,uint32_t ppid,uint32_t ptid,uint64_t event_id)392 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
393                        uint32_t ppid, uint32_t ptid, uint64_t event_id) {
394   SetTypeAndMisc(PERF_RECORD_FORK, 0);
395   ExitOrForkRecordDataType data;
396   data.pid = pid;
397   data.ppid = ppid;
398   data.tid = tid;
399   data.ptid = ptid;
400   data.time = 0;
401   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
402   SetSize(header_size() + sizeof(data) + sample_id_size);
403   char* new_binary = new char[size()];
404   char* p = new_binary;
405   MoveToBinaryFormat(header, p);
406   this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p);
407   MoveToBinaryFormat(data, p);
408   sample_id.WriteToBinaryFormat(p);
409   UpdateBinary(new_binary);
410 }
411 
LostRecord(const perf_event_attr & attr,char * p)412 LostRecord::LostRecord(const perf_event_attr& attr, char* p) : Record(p) {
413   const char* end = p + size();
414   p += header_size();
415   MoveFromBinaryFormat(id, p);
416   MoveFromBinaryFormat(lost, p);
417   CHECK_LE(p, end);
418   sample_id.ReadFromBinaryFormat(attr, p, end);
419 }
420 
DumpData(size_t indent) const421 void LostRecord::DumpData(size_t indent) const {
422   PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
423 }
424 
SampleRecord(const perf_event_attr & attr,char * p)425 SampleRecord::SampleRecord(const perf_event_attr& attr, char* p) : Record(p) {
426   const char* end = p + size();
427   p += header_size();
428   sample_type = attr.sample_type;
429 
430   // Set a default id value to report correctly even if ID is not recorded.
431   id_data.id = 0;
432   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
433     MoveFromBinaryFormat(id_data, p);
434   }
435   if (sample_type & PERF_SAMPLE_IP) {
436     MoveFromBinaryFormat(ip_data, p);
437   }
438   if (sample_type & PERF_SAMPLE_TID) {
439     MoveFromBinaryFormat(tid_data, p);
440   }
441   if (sample_type & PERF_SAMPLE_TIME) {
442     MoveFromBinaryFormat(time_data, p);
443   }
444   if (sample_type & PERF_SAMPLE_ADDR) {
445     MoveFromBinaryFormat(addr_data, p);
446   }
447   if (sample_type & PERF_SAMPLE_ID) {
448     MoveFromBinaryFormat(id_data, p);
449   }
450   if (sample_type & PERF_SAMPLE_STREAM_ID) {
451     MoveFromBinaryFormat(stream_id_data, p);
452   }
453   if (sample_type & PERF_SAMPLE_CPU) {
454     MoveFromBinaryFormat(cpu_data, p);
455   }
456   if (sample_type & PERF_SAMPLE_PERIOD) {
457     MoveFromBinaryFormat(period_data, p);
458   }
459   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
460     MoveFromBinaryFormat(callchain_data.ip_nr, p);
461     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
462     p += callchain_data.ip_nr * sizeof(uint64_t);
463   }
464   if (sample_type & PERF_SAMPLE_RAW) {
465     MoveFromBinaryFormat(raw_data.size, p);
466     raw_data.data = p;
467     p += raw_data.size;
468   }
469   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
470     MoveFromBinaryFormat(branch_stack_data.stack_nr, p);
471     branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(p);
472     p += branch_stack_data.stack_nr * sizeof(BranchStackItemType);
473   }
474   if (sample_type & PERF_SAMPLE_REGS_USER) {
475     MoveFromBinaryFormat(regs_user_data.abi, p);
476     if (regs_user_data.abi == 0) {
477       regs_user_data.reg_mask = 0;
478     } else {
479       regs_user_data.reg_mask = attr.sample_regs_user;
480       size_t bit_nr = __builtin_popcountll(regs_user_data.reg_mask);
481       regs_user_data.reg_nr = bit_nr;
482       regs_user_data.regs = reinterpret_cast<uint64_t*>(p);
483       p += bit_nr * sizeof(uint64_t);
484     }
485   }
486   if (sample_type & PERF_SAMPLE_STACK_USER) {
487     MoveFromBinaryFormat(stack_user_data.size, p);
488     if (stack_user_data.size == 0) {
489       stack_user_data.dyn_size = 0;
490     } else {
491       stack_user_data.data = p;
492       p += stack_user_data.size;
493       MoveFromBinaryFormat(stack_user_data.dyn_size, p);
494     }
495   }
496   // TODO: Add parsing of other PERF_SAMPLE_*.
497   CHECK_LE(p, end);
498   if (p < end) {
499     LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
500   }
501 }
502 
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,const std::vector<char> & stack,uint64_t dyn_stack_size)503 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id,
504                            uint64_t ip, uint32_t pid, uint32_t tid,
505                            uint64_t time, uint32_t cpu, uint64_t period,
506                            const std::vector<uint64_t>& ips, const std::vector<char>& stack,
507                            uint64_t dyn_stack_size) {
508   SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER);
509   sample_type = attr.sample_type;
510   CHECK_EQ(0u, sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID
511       | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_CPU
512       | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER
513       | PERF_SAMPLE_STACK_USER));
514   ip_data.ip = ip;
515   tid_data.pid = pid;
516   tid_data.tid = tid;
517   time_data.time = time;
518   id_data.id = id;
519   cpu_data.cpu = cpu;
520   cpu_data.res = 0;
521   period_data.period = period;
522   callchain_data.ip_nr = ips.size();
523   raw_data.size = 0;
524   branch_stack_data.stack_nr = 0;
525   regs_user_data.abi = 0;
526   regs_user_data.reg_mask = 0;
527   regs_user_data.reg_nr = 0;
528   stack_user_data.size = stack.size();
529   stack_user_data.dyn_size = dyn_stack_size;
530 
531   uint32_t size = header_size();
532   if (sample_type & PERF_SAMPLE_IP) {
533     size += sizeof(ip_data);
534   }
535   if (sample_type & PERF_SAMPLE_TID) {
536     size += sizeof(tid_data);
537   }
538   if (sample_type & PERF_SAMPLE_TIME) {
539     size += sizeof(time_data);
540   }
541   if (sample_type & PERF_SAMPLE_ID) {
542     size += sizeof(id_data);
543   }
544   if (sample_type & PERF_SAMPLE_CPU) {
545     size += sizeof(cpu_data);
546   }
547   if (sample_type & PERF_SAMPLE_PERIOD) {
548     size += sizeof(period_data);
549   }
550   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
551     size += sizeof(uint64_t) * (ips.size() + 1);
552   }
553   if (sample_type & PERF_SAMPLE_REGS_USER) {
554     size += sizeof(uint64_t);
555   }
556   if (sample_type & PERF_SAMPLE_STACK_USER) {
557     size += sizeof(uint64_t) + (stack.empty() ? 0 : stack.size() + sizeof(uint64_t));
558   }
559 
560   SetSize(size);
561   char* new_binary = new char[size];
562   char* p = new_binary;
563   MoveToBinaryFormat(header, p);
564   if (sample_type & PERF_SAMPLE_IP) {
565     MoveToBinaryFormat(ip_data, p);
566   }
567   if (sample_type & PERF_SAMPLE_TID) {
568     MoveToBinaryFormat(tid_data, p);
569   }
570   if (sample_type & PERF_SAMPLE_TIME) {
571     MoveToBinaryFormat(time_data, p);
572   }
573   if (sample_type & PERF_SAMPLE_ID) {
574     MoveToBinaryFormat(id_data, p);
575   }
576   if (sample_type & PERF_SAMPLE_CPU) {
577     MoveToBinaryFormat(cpu_data, p);
578   }
579   if (sample_type & PERF_SAMPLE_PERIOD) {
580     MoveToBinaryFormat(period_data, p);
581   }
582   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
583     MoveToBinaryFormat(callchain_data.ip_nr, p);
584     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
585     MoveToBinaryFormat(ips.data(), ips.size(), p);
586   }
587   if (sample_type & PERF_SAMPLE_REGS_USER) {
588     MoveToBinaryFormat(regs_user_data.abi, p);
589   }
590   if (sample_type & PERF_SAMPLE_STACK_USER) {
591     MoveToBinaryFormat(stack_user_data.size, p);
592     if (stack_user_data.size > 0) {
593       stack_user_data.data = p;
594       MoveToBinaryFormat(stack.data(), stack_user_data.size, p);
595       MoveToBinaryFormat(stack_user_data.dyn_size, p);
596     }
597   }
598   CHECK_EQ(p, new_binary + size);
599   UpdateBinary(new_binary);
600 }
601 
ReplaceRegAndStackWithCallChain(const std::vector<uint64_t> & ips)602 void SampleRecord::ReplaceRegAndStackWithCallChain(const std::vector<uint64_t>& ips) {
603   uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1);
604   uint32_t size_reduced_in_reg_stack = regs_user_data.reg_nr * sizeof(uint64_t) +
605       stack_user_data.size + sizeof(uint64_t);
606   uint32_t new_size = size() + size_added_in_callchain - size_reduced_in_reg_stack;
607   BuildBinaryWithNewCallChain(new_size, ips);
608 }
609 
ExcludeKernelCallChain()610 bool SampleRecord::ExcludeKernelCallChain() {
611   if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
612     return true;
613   }
614   size_t i;
615   for (i = 0; i < callchain_data.ip_nr; ++i) {
616     if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
617       break;
618     }
619     // Erase kernel callchain.
620     callchain_data.ips[i] = PERF_CONTEXT_USER;
621   }
622   while (++i < callchain_data.ip_nr) {
623     if (callchain_data.ips[i] < PERF_CONTEXT_MAX) {
624       // Change the sample to make it hit the user space ip address.
625       ip_data.ip = callchain_data.ips[i];
626       if (sample_type & PERF_SAMPLE_IP) {
627         *reinterpret_cast<uint64_t*>(binary_ + header_size()) = ip_data.ip;
628       }
629       header.misc = (header.misc & ~PERF_RECORD_MISC_CPUMODE_MASK) | PERF_RECORD_MISC_USER;
630       reinterpret_cast<perf_event_header*>(binary_)->misc = header.misc;
631       return true;
632     }
633   }
634   return false;
635 }
636 
HasUserCallChain() const637 bool SampleRecord::HasUserCallChain() const {
638   if ((sample_type & PERF_SAMPLE_CALLCHAIN) == 0) {
639     return false;
640   }
641   bool in_user_context = !InKernel();
642   for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
643     if (in_user_context && callchain_data.ips[i] < PERF_CONTEXT_MAX) {
644       return true;
645     }
646     if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
647       in_user_context = true;
648     }
649   }
650   return false;
651 }
652 
UpdateUserCallChain(const std::vector<uint64_t> & user_ips)653 void SampleRecord::UpdateUserCallChain(const std::vector<uint64_t>& user_ips) {
654   size_t kernel_ip_count = 0;
655   for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
656     if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
657       break;
658     }
659     kernel_ip_count++;
660   }
661   if (kernel_ip_count + 1 + user_ips.size() <= callchain_data.ip_nr) {
662     // Callchain isn't changed.
663     return;
664   }
665   size_t new_size = size() + (kernel_ip_count + 1 + user_ips.size() - callchain_data.ip_nr) *
666       sizeof(uint64_t);
667   callchain_data.ip_nr = kernel_ip_count;
668   BuildBinaryWithNewCallChain(new_size, user_ips);
669 }
670 
BuildBinaryWithNewCallChain(uint32_t new_size,const std::vector<uint64_t> & ips)671 void SampleRecord::BuildBinaryWithNewCallChain(uint32_t new_size,
672                                                const std::vector<uint64_t>& ips) {
673   size_t callchain_pos = reinterpret_cast<char*>(callchain_data.ips) - binary_ - sizeof(uint64_t);
674   char* new_binary = binary_;
675   if (new_size > size()) {
676     new_binary = new char[new_size];
677     memcpy(new_binary, binary_, callchain_pos);
678   }
679   char* p = new_binary;
680   SetSize(new_size);
681   MoveToBinaryFormat(header, p);
682   p = new_binary + new_size;
683   if (sample_type & PERF_SAMPLE_STACK_USER) {
684     stack_user_data.size = 0;
685     p -= sizeof(uint64_t);
686     memcpy(p, &stack_user_data.size, sizeof(uint64_t));
687   }
688   if (sample_type & PERF_SAMPLE_REGS_USER) {
689     regs_user_data.abi = 0;
690     p -= sizeof(uint64_t);
691     memcpy(p, &regs_user_data.abi, sizeof(uint64_t));
692   }
693   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
694     p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType);
695     memcpy(p, branch_stack_data.stack, branch_stack_data.stack_nr * sizeof(BranchStackItemType));
696     branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(p);
697     p -= sizeof(uint64_t);
698     memcpy(p, &branch_stack_data.stack_nr, sizeof(uint64_t));
699   }
700   if (sample_type & PERF_SAMPLE_RAW) {
701     p -= raw_data.size;
702     memcpy(p, raw_data.data, raw_data.size);
703     raw_data.data = p;
704     p -= sizeof(uint32_t);
705     memcpy(p, &raw_data.size, sizeof(uint32_t));
706   }
707   uint64_t* p64 = reinterpret_cast<uint64_t*>(p);
708   p64 -= ips.size();
709   memcpy(p64, ips.data(), ips.size() * sizeof(uint64_t));
710   *--p64 = PERF_CONTEXT_USER;
711   if (callchain_data.ip_nr > 0) {
712     p64 -= callchain_data.ip_nr;
713     memcpy(p64, callchain_data.ips, callchain_data.ip_nr * sizeof(uint64_t));
714   }
715   callchain_data.ips = p64;
716   callchain_data.ip_nr += 1 + ips.size();
717   *--p64 = callchain_data.ip_nr;
718   CHECK_EQ(callchain_pos, static_cast<size_t>(reinterpret_cast<char*>(p64) - new_binary))
719     << "record time " << time_data.time;
720   if (new_binary != binary_) {
721     UpdateBinary(new_binary);
722   }
723 }
724 
DumpData(size_t indent) const725 void SampleRecord::DumpData(size_t indent) const {
726   PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
727   if (sample_type & PERF_SAMPLE_IP) {
728     PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
729   }
730   if (sample_type & PERF_SAMPLE_TID) {
731     PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
732   }
733   if (sample_type & PERF_SAMPLE_TIME) {
734     PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
735   }
736   if (sample_type & PERF_SAMPLE_ADDR) {
737     PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
738   }
739   if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
740     PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
741   }
742   if (sample_type & PERF_SAMPLE_STREAM_ID) {
743     PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
744   }
745   if (sample_type & PERF_SAMPLE_CPU) {
746     PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
747   }
748   if (sample_type & PERF_SAMPLE_PERIOD) {
749     PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
750   }
751   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
752     PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr);
753     for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
754       PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]);
755     }
756   }
757   if (sample_type & PERF_SAMPLE_RAW) {
758     PrintIndented(indent, "raw size=%zu\n", raw_data.size);
759     const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data);
760     size_t size = raw_data.size / sizeof(uint32_t);
761     for (size_t i = 0; i < size; ++i) {
762       PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
763     }
764   }
765   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
766     PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n",
767                   branch_stack_data.stack_nr);
768     for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) {
769       auto& item = branch_stack_data.stack[i];
770       PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64
771                                 ", flags 0x%" PRIx64 "\n",
772                     item.from, item.to, item.flags);
773     }
774   }
775   if (sample_type & PERF_SAMPLE_REGS_USER) {
776     PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
777     for (size_t i = 0, pos = 0; i < 64; ++i) {
778       if ((regs_user_data.reg_mask >> i) & 1) {
779         PrintIndented(
780             indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
781             GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
782             regs_user_data.regs[pos++]);
783       }
784     }
785   }
786   if (sample_type & PERF_SAMPLE_STACK_USER) {
787     PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n",
788                   stack_user_data.size, stack_user_data.dyn_size);
789     const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
790     const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
791     while (p < end) {
792       PrintIndented(indent + 1, "");
793       for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
794         printf(" %016" PRIx64, *p);
795       }
796       printf("\n");
797     }
798     printf("\n");
799   }
800 }
801 
Timestamp() const802 uint64_t SampleRecord::Timestamp() const { return time_data.time; }
Cpu() const803 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; }
Id() const804 uint64_t SampleRecord::Id() const { return id_data.id; }
805 
AdjustCallChainGeneratedByKernel()806 void SampleRecord::AdjustCallChainGeneratedByKernel() {
807   // The kernel stores return addrs in the callchain, but we want the addrs of call instructions
808   // along the callchain.
809   uint64_t* ips = callchain_data.ips;
810   uint64_t context = header.misc == PERF_RECORD_MISC_KERNEL ? PERF_CONTEXT_KERNEL
811                                                             : PERF_CONTEXT_USER;
812   bool first_frame = true;
813   for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
814     if (ips[i] < PERF_CONTEXT_MAX) {
815       if (first_frame) {
816         first_frame = false;
817       } else {
818         if (ips[i] < 2) {
819           // A wrong ip address, erase it.
820           ips[i] = context;
821         } else {
822           // Here we want to change the return addr to the addr of the previous instruction. We
823           // don't need to find the exact start addr of the previous instruction. A location in
824         // [start_addr_of_call_inst, start_addr_of_next_inst) is enough.
825 #if defined(__arm__) || defined(__aarch64__)
826           // If we are built for arm/aarch64, this may be a callchain of thumb code. For thumb code,
827           // the real instruction addr is (ip & ~1), and ip - 2 can used to hit the address range
828           // of the previous instruction. For non thumb code, any addr in [ip - 4, ip - 1] is fine.
829           ips[i] -= 2;
830 #else
831           ips[i]--;
832 #endif
833         }
834       }
835     } else {
836       context = ips[i];
837     }
838   }
839 }
840 
GetCallChain(size_t * kernel_ip_count) const841 std::vector<uint64_t> SampleRecord::GetCallChain(size_t* kernel_ip_count) const {
842   std::vector<uint64_t> ips;
843   bool in_kernel = InKernel();
844   ips.push_back(ip_data.ip);
845   *kernel_ip_count = in_kernel ? 1 : 0;
846   if ((sample_type & PERF_SAMPLE_CALLCHAIN) == 0) {
847     return ips;
848   }
849   bool first_ip = true;
850   for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
851     uint64_t ip = callchain_data.ips[i];
852     if (ip >= PERF_CONTEXT_MAX) {
853       switch (ip) {
854         case PERF_CONTEXT_KERNEL:
855           CHECK(in_kernel) << "User space callchain followed by kernel callchain.";
856           break;
857         case PERF_CONTEXT_USER:
858           in_kernel = false;
859           break;
860         default:
861           LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex << ip << std::dec;
862       }
863     } else {
864       if (first_ip) {
865         first_ip = false;
866         // Remove duplication with sample ip.
867         if (ip == ip_data.ip) {
868           continue;
869         }
870       }
871       ips.push_back(ip);
872       if (in_kernel) {
873         ++*kernel_ip_count;
874       }
875     }
876   }
877   return ips;
878 }
879 
AuxRecord(const perf_event_attr & attr,char * p)880 AuxRecord::AuxRecord(const perf_event_attr& attr, char* p) : Record(p) {
881   const char* end = p + size();
882   p += header_size();
883   data = reinterpret_cast<DataType*>(p);
884   p += sizeof(DataType);
885   sample_id.ReadFromBinaryFormat(attr, p, end);
886 }
887 
DumpData(size_t indent) const888 void AuxRecord::DumpData(size_t indent) const {
889   PrintIndented(indent, "aux_offset %" PRIu64 "\n", data->aux_offset);
890   PrintIndented(indent, "aux_size %" PRIu64 "\n", data->aux_size);
891   PrintIndented(indent, "flags 0x%" PRIx64 "\n", data->flags);
892 }
893 
BuildIdRecord(char * p)894 BuildIdRecord::BuildIdRecord(char* p) : Record(p) {
895   const char* end = p + size();
896   p += header_size();
897   MoveFromBinaryFormat(pid, p);
898   build_id = BuildId(p, BUILD_ID_SIZE);
899   p += Align(build_id.Size(), 8);
900   filename = p;
901   p += Align(strlen(filename) + 1, 64);
902   CHECK_EQ(p, end);
903 }
904 
DumpData(size_t indent) const905 void BuildIdRecord::DumpData(size_t indent) const {
906   PrintIndented(indent, "pid %u\n", pid);
907   PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
908   PrintIndented(indent, "filename %s\n", filename);
909 }
910 
BuildIdRecord(bool in_kernel,pid_t pid,const BuildId & build_id,const std::string & filename)911 BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
912                              const std::string& filename) {
913   SetTypeAndMisc(PERF_RECORD_BUILD_ID,
914                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
915   this->pid = pid;
916   this->build_id = build_id;
917   SetSize(header_size() + sizeof(pid) + Align(build_id.Size(), 8) +
918           Align(filename.size() + 1, 64));
919   char* new_binary = new char[size()];
920   char* p = new_binary;
921   MoveToBinaryFormat(header, p);
922   MoveToBinaryFormat(pid, p);
923   memcpy(p, build_id.Data(), build_id.Size());
924   p += Align(build_id.Size(), 8);
925   this->filename = p;
926   strcpy(p, filename.c_str());
927   UpdateBinary(new_binary);
928 }
929 
AuxTraceInfoRecord(char * p)930 AuxTraceInfoRecord::AuxTraceInfoRecord(char* p) : Record(p) {
931   const char* end = p + size();
932   p += header_size();
933   data = reinterpret_cast<DataType*>(p);
934   CHECK_EQ(data->aux_type, AUX_TYPE_ETM);
935   CHECK_EQ(data->version, 0);
936   for (uint32_t i = 0; i < data->nr_cpu; ++i) {
937     CHECK_EQ(data->etm4_info[i].magic, MAGIC_ETM4);
938   }
939   p += sizeof(DataType) + data->nr_cpu * sizeof(ETM4Info);
940   CHECK_EQ(p, end);
941 }
942 
AuxTraceInfoRecord(const DataType & data,const std::vector<ETM4Info> & etm4_info)943 AuxTraceInfoRecord::AuxTraceInfoRecord(const DataType& data,
944                                        const std::vector<ETM4Info>& etm4_info) {
945   SetTypeAndMisc(PERF_RECORD_AUXTRACE_INFO, 0);
946   SetSize(header_size() + sizeof(DataType) + sizeof(ETM4Info) * etm4_info.size());
947   char* new_binary = new char[size()];
948   char* p = new_binary;
949   MoveToBinaryFormat(header, p);
950   this->data = reinterpret_cast<DataType*>(p);
951   MoveToBinaryFormat(data, p);
952   for (auto& etm4 : etm4_info) {
953     MoveToBinaryFormat(etm4, p);
954   }
955   UpdateBinary(new_binary);
956 }
957 
DumpData(size_t indent) const958 void AuxTraceInfoRecord::DumpData(size_t indent) const {
959   PrintIndented(indent, "aux_type %u\n", data->aux_type);
960   PrintIndented(indent, "version %" PRIu64 "\n", data->version);
961   PrintIndented(indent, "nr_cpu %u\n", data->nr_cpu);
962   PrintIndented(indent, "pmu_type %u\n", data->pmu_type);
963   PrintIndented(indent, "snapshot %" PRIu64 "\n", data->snapshot);
964   indent++;
965   for (int i = 0; i < data->nr_cpu; i++) {
966     const ETM4Info& e = data->etm4_info[i];
967     PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
968     PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
969     PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
970     PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
971     PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
972     PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
973     PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
974     PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
975     PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
976   }
977 }
978 
AuxTraceRecord(char * p)979 AuxTraceRecord::AuxTraceRecord(char* p) : Record(p) {
980   const char* end = p + header.size;
981   p += header_size();
982   data = reinterpret_cast<DataType*>(p);
983   p += sizeof(DataType);
984   CHECK_EQ(p, end);
985 }
986 
AuxTraceRecord(uint64_t aux_size,uint64_t offset,uint32_t idx,uint32_t tid,uint32_t cpu)987 AuxTraceRecord::AuxTraceRecord(uint64_t aux_size, uint64_t offset, uint32_t idx, uint32_t tid,
988                                uint32_t cpu) {
989   SetTypeAndMisc(PERF_RECORD_AUXTRACE, 0);
990   SetSize(header_size() + sizeof(DataType));
991   char* new_binary = new char[size()];
992   char* p = new_binary;
993   MoveToBinaryFormat(header, p);
994   data = reinterpret_cast<DataType*>(p);
995   data->aux_size = aux_size;
996   data->offset = offset;
997   data->reserved0 = 0;
998   data->idx = idx;
999   data->tid = tid;
1000   data->cpu = cpu;
1001   data->reserved1 = 0;
1002   UpdateBinary(new_binary);
1003 }
1004 
DumpData(size_t indent) const1005 void AuxTraceRecord::DumpData(size_t indent) const {
1006   PrintIndented(indent, "aux_size %" PRIu64 "\n", data->aux_size);
1007   PrintIndented(indent, "offset %" PRIu64 "\n", data->offset);
1008   PrintIndented(indent, "idx %u\n", data->idx);
1009   PrintIndented(indent, "tid %u\n", data->tid);
1010   PrintIndented(indent, "cpu %u\n", data->cpu);
1011   PrintIndented(indent, "location.file_offset %" PRIu64 "\n", location.file_offset);
1012 }
1013 
KernelSymbolRecord(char * p)1014 KernelSymbolRecord::KernelSymbolRecord(char* p) : Record(p) {
1015   const char* end = p + size();
1016   p += header_size();
1017   MoveFromBinaryFormat(kallsyms_size, p);
1018   kallsyms = p;
1019   p += Align(kallsyms_size, 8);
1020   CHECK_EQ(p, end);
1021 }
1022 
DumpData(size_t indent) const1023 void KernelSymbolRecord::DumpData(size_t indent) const {
1024   PrintIndented(indent, "kallsyms: %s\n",
1025                 std::string(kallsyms, kallsyms + kallsyms_size).c_str());
1026 }
1027 
KernelSymbolRecord(const std::string & kallsyms)1028 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) {
1029   SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0);
1030   kallsyms_size = kallsyms.size();
1031   SetSize(header_size() + 4 + Align(kallsyms.size(), 8));
1032   char* new_binary = new char[size()];
1033   char* p = new_binary;
1034   MoveToBinaryFormat(header, p);
1035   MoveToBinaryFormat(kallsyms_size, p);
1036   this->kallsyms = p;
1037   memcpy(p, kallsyms.data(), kallsyms_size);
1038   UpdateBinary(new_binary);
1039 }
1040 
DsoRecord(char * p)1041 DsoRecord::DsoRecord(char* p) : Record(p) {
1042   const char* end = p + size();
1043   p += header_size();
1044   MoveFromBinaryFormat(dso_type, p);
1045   MoveFromBinaryFormat(dso_id, p);
1046   MoveFromBinaryFormat(min_vaddr, p);
1047   dso_name = p;
1048   p += Align(strlen(dso_name) + 1, 8);
1049   CHECK_EQ(p, end);
1050 }
1051 
DsoRecord(uint64_t dso_type,uint64_t dso_id,const std::string & dso_name,uint64_t min_vaddr)1052 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id,
1053                      const std::string& dso_name, uint64_t min_vaddr) {
1054   SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0);
1055   this->dso_type = dso_type;
1056   this->dso_id = dso_id;
1057   this->min_vaddr = min_vaddr;
1058   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8));
1059   char* new_binary = new char[size()];
1060   char* p = new_binary;
1061   MoveToBinaryFormat(header, p);
1062   MoveToBinaryFormat(dso_type, p);
1063   MoveToBinaryFormat(dso_id, p);
1064   MoveToBinaryFormat(min_vaddr, p);
1065   this->dso_name = p;
1066   strcpy(p, dso_name.c_str());
1067   UpdateBinary(new_binary);
1068 }
1069 
DumpData(size_t indent) const1070 void DsoRecord::DumpData(size_t indent) const {
1071   PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n",
1072                 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type);
1073   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
1074   PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr);
1075   PrintIndented(indent, "dso_name: %s\n", dso_name);
1076 }
1077 
SymbolRecord(char * p)1078 SymbolRecord::SymbolRecord(char* p) : Record(p) {
1079   const char* end = p + size();
1080   p += header_size();
1081   MoveFromBinaryFormat(addr, p);
1082   MoveFromBinaryFormat(len, p);
1083   MoveFromBinaryFormat(dso_id, p);
1084   name = p;
1085   p += Align(strlen(name) + 1, 8);
1086   CHECK_EQ(p, end);
1087 }
1088 
SymbolRecord(uint64_t addr,uint64_t len,const std::string & name,uint64_t dso_id)1089 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
1090                            uint64_t dso_id) {
1091   SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
1092   this->addr = addr;
1093   this->len = len;
1094   this->dso_id = dso_id;
1095   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8));
1096   char* new_binary = new char[size()];
1097   char* p = new_binary;
1098   MoveToBinaryFormat(header, p);
1099   MoveToBinaryFormat(addr, p);
1100   MoveToBinaryFormat(len, p);
1101   MoveToBinaryFormat(dso_id, p);
1102   this->name = p;
1103   strcpy(p, name.c_str());
1104   UpdateBinary(new_binary);
1105 }
1106 
DumpData(size_t indent) const1107 void SymbolRecord::DumpData(size_t indent) const {
1108   PrintIndented(indent, "name: %s\n", name);
1109   PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr);
1110   PrintIndented(indent, "len: 0x%" PRIx64 "\n", len);
1111   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
1112 }
1113 
TracingDataRecord(char * p)1114 TracingDataRecord::TracingDataRecord(char* p) : Record(p) {
1115   const char* end = p + size();
1116   p += header_size();
1117   MoveFromBinaryFormat(data_size, p);
1118   data = p;
1119   p += Align(data_size, 64);
1120   CHECK_EQ(p, end);
1121 }
1122 
TracingDataRecord(const std::vector<char> & tracing_data)1123 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
1124   SetTypeAndMisc(SIMPLE_PERF_RECORD_TRACING_DATA, 0);
1125   data_size = tracing_data.size();
1126   SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
1127   char* new_binary = new char[size()];
1128   char* p = new_binary;
1129   MoveToBinaryFormat(header, p);
1130   MoveToBinaryFormat(data_size, p);
1131   data = p;
1132   memcpy(p, tracing_data.data(), data_size);
1133   UpdateBinary(new_binary);
1134 }
1135 
DumpData(size_t indent) const1136 void TracingDataRecord::DumpData(size_t indent) const {
1137   Tracing tracing(std::vector<char>(data, data + data_size));
1138   tracing.Dump(indent);
1139 }
1140 
EventIdRecord(char * p)1141 EventIdRecord::EventIdRecord(char* p) : Record(p) {
1142   const char* end = p + size();
1143   p += header_size();
1144   MoveFromBinaryFormat(count, p);
1145   data = reinterpret_cast<const EventIdData*>(p);
1146   p += sizeof(data[0]) * count;
1147   CHECK_EQ(p, end);
1148 }
1149 
EventIdRecord(const std::vector<uint64_t> & data)1150 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) {
1151   SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0);
1152   SetSize(header_size() + sizeof(uint64_t) * (1 + data.size()));
1153   char* new_binary = new char[size()];
1154   char* p = new_binary;
1155   MoveToBinaryFormat(header, p);
1156   count = data.size() / 2;
1157   MoveToBinaryFormat(count, p);
1158   this->data = reinterpret_cast<EventIdData*>(p);
1159   memcpy(p, data.data(), sizeof(uint64_t) * data.size());
1160   UpdateBinary(new_binary);
1161 }
1162 
DumpData(size_t indent) const1163 void EventIdRecord::DumpData(size_t indent) const {
1164   PrintIndented(indent, "count: %" PRIu64 "\n", count);
1165   for (size_t i = 0; i < count; ++i) {
1166     PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i,
1167                   data[i].attr_id);
1168     PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i,
1169                   data[i].event_id);
1170   }
1171 }
1172 
CallChainRecord(char * p)1173 CallChainRecord::CallChainRecord(char* p) : Record(p) {
1174   const char* end = p + size();
1175   p += header_size();
1176   MoveFromBinaryFormat(pid, p);
1177   MoveFromBinaryFormat(tid, p);
1178   MoveFromBinaryFormat(chain_type, p);
1179   MoveFromBinaryFormat(time, p);
1180   MoveFromBinaryFormat(ip_nr, p);
1181   ips = reinterpret_cast<uint64_t*>(p);
1182   p += ip_nr * sizeof(uint64_t);
1183   sps = reinterpret_cast<uint64_t*>(p);
1184   p += ip_nr * sizeof(uint64_t);
1185   CHECK_EQ(p, end);
1186 }
1187 
CallChainRecord(pid_t pid,pid_t tid,CallChainJoiner::ChainType type,uint64_t time,const std::vector<uint64_t> & ips,const std::vector<uint64_t> & sps)1188 CallChainRecord::CallChainRecord(pid_t pid, pid_t tid, CallChainJoiner::ChainType type,
1189                                  uint64_t time, const std::vector<uint64_t>& ips,
1190                                  const std::vector<uint64_t>& sps) {
1191   CHECK_EQ(ips.size(), sps.size());
1192   SetTypeAndMisc(SIMPLE_PERF_RECORD_CALLCHAIN, 0);
1193   this->pid = pid;
1194   this->tid = tid;
1195   this->chain_type = static_cast<int>(type);
1196   this->time = time;
1197   this->ip_nr = ips.size();
1198   SetSize(header_size() + (4 + ips.size() * 2) * sizeof(uint64_t));
1199   char* new_binary = new char[size()];
1200   char* p = new_binary;
1201   MoveToBinaryFormat(header, p);
1202   MoveToBinaryFormat(this->pid, p);
1203   MoveToBinaryFormat(this->tid, p);
1204   MoveToBinaryFormat(this->chain_type, p);
1205   MoveToBinaryFormat(this->time, p);
1206   MoveToBinaryFormat(this->ip_nr, p);
1207   this->ips = reinterpret_cast<uint64_t*>(p);
1208   MoveToBinaryFormat(ips.data(), ips.size(), p);
1209   this->sps = reinterpret_cast<uint64_t*>(p);
1210   MoveToBinaryFormat(sps.data(), sps.size(), p);
1211   UpdateBinary(new_binary);
1212 }
1213 
DumpData(size_t indent) const1214 void CallChainRecord::DumpData(size_t indent) const {
1215   const char* type_name = "";
1216   switch (chain_type) {
1217     case CallChainJoiner::ORIGINAL_OFFLINE: type_name = "ORIGINAL_OFFLINE"; break;
1218     case CallChainJoiner::ORIGINAL_REMOTE: type_name = "ORIGINAL_REMOTE"; break;
1219     case CallChainJoiner::JOINED_OFFLINE: type_name = "JOINED_OFFLINE"; break;
1220     case CallChainJoiner::JOINED_REMOTE: type_name = "JOINED_REMOTE"; break;
1221   }
1222   PrintIndented(indent, "pid %u\n", pid);
1223   PrintIndented(indent, "tid %u\n", tid);
1224   PrintIndented(indent, "chain_type %s\n", type_name);
1225   PrintIndented(indent, "time %" PRIu64 "\n", time);
1226   PrintIndented(indent, "ip_nr %" PRIu64 "\n", ip_nr);
1227   for (size_t i = 0; i < ip_nr; ++i) {
1228     PrintIndented(indent + 1, "ip 0x%" PRIx64 ", sp 0x%" PRIx64 "\n", ips[i], sps[i]);
1229   }
1230 }
1231 
UnwindingResultRecord(char * p)1232 UnwindingResultRecord::UnwindingResultRecord(char* p) : Record(p) {
1233   const char* end = p + size();
1234   p += header_size();
1235   MoveFromBinaryFormat(time, p);
1236   MoveFromBinaryFormat(unwinding_result.used_time, p);
1237   uint64_t stop_reason;
1238   MoveFromBinaryFormat(stop_reason, p);
1239   unwinding_result.stop_reason = static_cast<decltype(unwinding_result.stop_reason)>(stop_reason);
1240   MoveFromBinaryFormat(unwinding_result.stop_info, p);
1241   MoveFromBinaryFormat(unwinding_result.stack_start, p);
1242   MoveFromBinaryFormat(unwinding_result.stack_end, p);
1243   CHECK_EQ(p, end);
1244 }
1245 
UnwindingResultRecord(uint64_t time,const UnwindingResult & unwinding_result)1246 UnwindingResultRecord::UnwindingResultRecord(uint64_t time,
1247                                              const UnwindingResult& unwinding_result) {
1248   SetTypeAndMisc(SIMPLE_PERF_RECORD_UNWINDING_RESULT, 0);
1249   SetSize(header_size() + 6 * sizeof(uint64_t));
1250   this->time = time;
1251   this->unwinding_result = unwinding_result;
1252   char* new_binary = new char[size()];
1253   char* p = new_binary;
1254   MoveToBinaryFormat(header, p);
1255   MoveToBinaryFormat(this->time, p);
1256   MoveToBinaryFormat(unwinding_result.used_time, p);
1257   uint64_t stop_reason = unwinding_result.stop_reason;
1258   MoveToBinaryFormat(stop_reason, p);
1259   MoveToBinaryFormat(unwinding_result.stop_info, p);
1260   MoveToBinaryFormat(unwinding_result.stack_start, p);
1261   MoveToBinaryFormat(unwinding_result.stack_end, p);
1262   UpdateBinary(new_binary);
1263 }
1264 
DumpData(size_t indent) const1265 void UnwindingResultRecord::DumpData(size_t indent) const {
1266   PrintIndented(indent, "time %" PRIu64 "\n", time);
1267   PrintIndented(indent, "used_time %" PRIu64 "\n", unwinding_result.used_time);
1268   static std::unordered_map<int, std::string> map = {
1269       {UnwindingResult::UNKNOWN_REASON, "UNKNOWN_REASON"},
1270       {UnwindingResult::EXCEED_MAX_FRAMES_LIMIT, "EXCEED_MAX_FRAME_LIMIT"},
1271       {UnwindingResult::ACCESS_REG_FAILED, "ACCESS_REG_FAILED"},
1272       {UnwindingResult::ACCESS_STACK_FAILED, "ACCESS_STACK_FAILED"},
1273       {UnwindingResult::ACCESS_MEM_FAILED, "ACCESS_MEM_FAILED"},
1274       {UnwindingResult::FIND_PROC_INFO_FAILED, "FIND_PROC_INFO_FAILED"},
1275       {UnwindingResult::EXECUTE_DWARF_INSTRUCTION_FAILED, "EXECUTE_DWARF_INSTRUCTION_FAILED"},
1276       {UnwindingResult::DIFFERENT_ARCH, "DIFFERENT_ARCH"},
1277       {UnwindingResult::MAP_MISSING, "MAP_MISSING"},
1278   };
1279   PrintIndented(indent, "stop_reason %s\n", map[unwinding_result.stop_reason].c_str());
1280   if (unwinding_result.stop_reason == UnwindingResult::ACCESS_REG_FAILED) {
1281     PrintIndented(indent, "regno %" PRIu64 "\n", unwinding_result.stop_info);
1282   } else if (unwinding_result.stop_reason == UnwindingResult::ACCESS_STACK_FAILED ||
1283              unwinding_result.stop_reason == UnwindingResult::ACCESS_MEM_FAILED) {
1284     PrintIndented(indent, "addr 0x%" PRIx64 "\n", unwinding_result.stop_info);
1285   }
1286   PrintIndented(indent, "stack_start 0x%" PRIx64 "\n", unwinding_result.stack_start);
1287   PrintIndented(indent, "stack_end 0x%" PRIx64 "\n", unwinding_result.stack_end);
1288 }
1289 
UnknownRecord(char * p)1290 UnknownRecord::UnknownRecord(char* p) : Record(p) {
1291   p += header_size();
1292   data = p;
1293 }
1294 
DumpData(size_t) const1295 void UnknownRecord::DumpData(size_t) const {}
1296 
ReadRecordFromBuffer(const perf_event_attr & attr,uint32_t type,char * p)1297 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32_t type, char* p) {
1298   switch (type) {
1299     case PERF_RECORD_MMAP:
1300       return std::unique_ptr<Record>(new MmapRecord(attr, p));
1301     case PERF_RECORD_MMAP2:
1302       return std::unique_ptr<Record>(new Mmap2Record(attr, p));
1303     case PERF_RECORD_COMM:
1304       return std::unique_ptr<Record>(new CommRecord(attr, p));
1305     case PERF_RECORD_EXIT:
1306       return std::unique_ptr<Record>(new ExitRecord(attr, p));
1307     case PERF_RECORD_FORK:
1308       return std::unique_ptr<Record>(new ForkRecord(attr, p));
1309     case PERF_RECORD_LOST:
1310       return std::unique_ptr<Record>(new LostRecord(attr, p));
1311     case PERF_RECORD_SAMPLE:
1312       return std::unique_ptr<Record>(new SampleRecord(attr, p));
1313     case PERF_RECORD_AUX:
1314       return std::unique_ptr<Record>(new AuxRecord(attr, p));
1315     case PERF_RECORD_TRACING_DATA:
1316       return std::unique_ptr<Record>(new TracingDataRecord(p));
1317     case PERF_RECORD_AUXTRACE_INFO:
1318       return std::unique_ptr<Record>(new AuxTraceInfoRecord(p));
1319     case PERF_RECORD_AUXTRACE:
1320       return std::unique_ptr<Record>(new AuxTraceRecord(p));
1321     case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
1322       return std::unique_ptr<Record>(new KernelSymbolRecord(p));
1323     case SIMPLE_PERF_RECORD_DSO:
1324       return std::unique_ptr<Record>(new DsoRecord(p));
1325     case SIMPLE_PERF_RECORD_SYMBOL:
1326       return std::unique_ptr<Record>(new SymbolRecord(p));
1327     case SIMPLE_PERF_RECORD_EVENT_ID:
1328       return std::unique_ptr<Record>(new EventIdRecord(p));
1329     case SIMPLE_PERF_RECORD_CALLCHAIN:
1330       return std::unique_ptr<Record>(new CallChainRecord(p));
1331     case SIMPLE_PERF_RECORD_UNWINDING_RESULT:
1332       return std::unique_ptr<Record>(new UnwindingResultRecord(p));
1333     case SIMPLE_PERF_RECORD_TRACING_DATA:
1334       return std::unique_ptr<Record>(new TracingDataRecord(p));
1335     default:
1336       return std::unique_ptr<Record>(new UnknownRecord(p));
1337   }
1338 }
1339 
ReadRecordFromOwnedBuffer(const perf_event_attr & attr,uint32_t type,char * p)1340 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
1341                                                   uint32_t type, char* p) {
1342   std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p);
1343   if (record != nullptr) {
1344     record->OwnBinary();
1345   } else {
1346     delete[] p;
1347   }
1348   return record;
1349 }
1350 
ReadRecordsFromBuffer(const perf_event_attr & attr,char * buf,size_t buf_size)1351 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(
1352     const perf_event_attr& attr, char* buf, size_t buf_size) {
1353   std::vector<std::unique_ptr<Record>> result;
1354   char* p = buf;
1355   char* end = buf + buf_size;
1356   while (p < end) {
1357     RecordHeader header(p);
1358     CHECK_LE(p + header.size, end);
1359     CHECK_NE(0u, header.size);
1360     result.push_back(ReadRecordFromBuffer(attr, header.type, p));
1361     p += header.size;
1362   }
1363   return result;
1364 }
1365 
ReadRecordFromBuffer(const perf_event_attr & attr,char * p)1366 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, char* p) {
1367   auto header = reinterpret_cast<const perf_event_header*>(p);
1368   return ReadRecordFromBuffer(attr, header->type, p);
1369 }
1370