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