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/macros.h>
25 #include <android-base/stringprintf.h>
26
27 #include "OfflineUnwinder.h"
28 #include "dso.h"
29 #include "perf_regs.h"
30 #include "tracing.h"
31 #include "utils.h"
32
33 namespace simpleperf {
34
35 #define CHECK_SIZE(p, end, size) \
36 do { \
37 if (UNLIKELY((end) - (p) < (size))) { \
38 return false; \
39 } \
40 } while (0)
41
42 #define CHECK_SIZE_U64(p, end, u64_count) CHECK_SIZE(p, end, (u64_count) * sizeof(uint64_t))
43
RecordTypeToString(int record_type)44 static std::string RecordTypeToString(int record_type) {
45 static std::unordered_map<int, std::string> record_type_names = {
46 {PERF_RECORD_MMAP, "mmap"},
47 {PERF_RECORD_LOST, "lost"},
48 {PERF_RECORD_COMM, "comm"},
49 {PERF_RECORD_EXIT, "exit"},
50 {PERF_RECORD_THROTTLE, "throttle"},
51 {PERF_RECORD_UNTHROTTLE, "unthrottle"},
52 {PERF_RECORD_FORK, "fork"},
53 {PERF_RECORD_READ, "read"},
54 {PERF_RECORD_SAMPLE, "sample"},
55 {PERF_RECORD_BUILD_ID, "build_id"},
56 {PERF_RECORD_MMAP2, "mmap2"},
57 {PERF_RECORD_AUX, "aux"},
58 {PERF_RECORD_SWITCH, "switch"},
59 {PERF_RECORD_SWITCH_CPU_WIDE, "switch_cpu_wide"},
60 {PERF_RECORD_TRACING_DATA, "tracing_data"},
61 {PERF_RECORD_AUXTRACE_INFO, "auxtrace_info"},
62 {PERF_RECORD_AUXTRACE, "auxtrace"},
63 {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"},
64 {SIMPLE_PERF_RECORD_DSO, "dso"},
65 {SIMPLE_PERF_RECORD_SYMBOL, "symbol"},
66 {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
67 {SIMPLE_PERF_RECORD_CALLCHAIN, "callchain"},
68 {SIMPLE_PERF_RECORD_UNWINDING_RESULT, "unwinding_result"},
69 {SIMPLE_PERF_RECORD_TRACING_DATA, "tracing_data"},
70 };
71
72 auto it = record_type_names.find(record_type);
73 if (it != record_type_names.end()) {
74 return it->second;
75 }
76 return android::base::StringPrintf("unknown(%d)", record_type);
77 }
78
79 template <>
MoveToBinaryFormat(const RecordHeader & data,char * & p)80 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
81 data.MoveToBinaryFormat(p);
82 }
83
SampleId()84 SampleId::SampleId() {
85 memset(this, 0, sizeof(SampleId));
86 }
87
88 // Return sample_id size in binary format.
CreateContent(const perf_event_attr & attr,uint64_t event_id)89 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
90 sample_id_all = attr.sample_id_all;
91 sample_type = attr.sample_type;
92 id_data.id = event_id;
93 // Other data are not necessary. TODO: Set missing SampleId data.
94 return Size();
95 }
96
ReadFromBinaryFormat(const perf_event_attr & attr,const char * p,const char * end)97 bool SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p, const char* end) {
98 sample_id_all = attr.sample_id_all;
99 sample_type = attr.sample_type;
100 if (sample_id_all) {
101 const uint64_t sample_id_mask = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
102 PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU |
103 PERF_SAMPLE_IDENTIFIER;
104 CHECK_SIZE_U64(p, end, __builtin_popcountll(sample_type & sample_id_mask));
105 if (sample_type & PERF_SAMPLE_TID) {
106 MoveFromBinaryFormat(tid_data, p);
107 }
108 if (sample_type & PERF_SAMPLE_TIME) {
109 MoveFromBinaryFormat(time_data, p);
110 }
111 if (sample_type & PERF_SAMPLE_ID) {
112 MoveFromBinaryFormat(id_data, p);
113 }
114 if (sample_type & PERF_SAMPLE_STREAM_ID) {
115 MoveFromBinaryFormat(stream_id_data, p);
116 }
117 if (sample_type & PERF_SAMPLE_CPU) {
118 MoveFromBinaryFormat(cpu_data, p);
119 }
120 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
121 MoveFromBinaryFormat(id_data, p);
122 }
123 }
124 if (UNLIKELY(p < end)) {
125 LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
126 }
127 return true;
128 }
129
WriteToBinaryFormat(char * & p) const130 void SampleId::WriteToBinaryFormat(char*& p) const {
131 if (sample_id_all) {
132 if (sample_type & PERF_SAMPLE_TID) {
133 MoveToBinaryFormat(tid_data, p);
134 }
135 if (sample_type & PERF_SAMPLE_TIME) {
136 MoveToBinaryFormat(time_data, p);
137 }
138 if (sample_type & PERF_SAMPLE_ID) {
139 MoveToBinaryFormat(id_data, p);
140 }
141 if (sample_type & PERF_SAMPLE_STREAM_ID) {
142 MoveToBinaryFormat(stream_id_data, p);
143 }
144 if (sample_type & PERF_SAMPLE_CPU) {
145 MoveToBinaryFormat(cpu_data, p);
146 }
147 }
148 }
149
Dump(size_t indent) const150 void SampleId::Dump(size_t indent) const {
151 if (sample_id_all) {
152 if (sample_type & PERF_SAMPLE_TID) {
153 PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid, tid_data.tid);
154 }
155 if (sample_type & PERF_SAMPLE_TIME) {
156 PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
157 }
158 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
159 PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
160 }
161 if (sample_type & PERF_SAMPLE_STREAM_ID) {
162 PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", stream_id_data.stream_id);
163 }
164 if (sample_type & PERF_SAMPLE_CPU) {
165 PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
166 }
167 }
168 }
169
Size() const170 size_t SampleId::Size() const {
171 size_t size = 0;
172 if (sample_id_all) {
173 if (sample_type & PERF_SAMPLE_TID) {
174 size += sizeof(PerfSampleTidType);
175 }
176 if (sample_type & PERF_SAMPLE_TIME) {
177 size += sizeof(PerfSampleTimeType);
178 }
179 if (sample_type & PERF_SAMPLE_ID) {
180 size += sizeof(PerfSampleIdType);
181 }
182 if (sample_type & PERF_SAMPLE_STREAM_ID) {
183 size += sizeof(PerfSampleStreamIdType);
184 }
185 if (sample_type & PERF_SAMPLE_CPU) {
186 size += sizeof(PerfSampleCpuType);
187 }
188 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
189 size += sizeof(PerfSampleIdType);
190 }
191 }
192 return size;
193 }
194
Record(Record && other)195 Record::Record(Record&& other) noexcept {
196 header = other.header;
197 sample_id = other.sample_id;
198 binary_ = other.binary_;
199 own_binary_ = other.own_binary_;
200 other.binary_ = nullptr;
201 other.own_binary_ = false;
202 }
203
ParseHeader(char * & p,char * & end)204 bool Record::ParseHeader(char*& p, char*& end) {
205 binary_ = p;
206 CHECK(end != nullptr);
207 CHECK_SIZE(p, end, sizeof(perf_event_header));
208 header = RecordHeader(p);
209 CHECK_SIZE(p, end, header.size);
210 end = p + header.size;
211 p += sizeof(perf_event_header);
212 return true;
213 }
214
Dump(size_t indent) const215 void Record::Dump(size_t indent) const {
216 PrintIndented(indent, "record %s: type %u, misc 0x%x, size %u\n",
217 RecordTypeToString(type()).c_str(), type(), misc(), size());
218 DumpData(indent + 1);
219 sample_id.Dump(indent + 1);
220 }
221
Timestamp() const222 uint64_t Record::Timestamp() const {
223 return sample_id.time_data.time;
224 }
Cpu() const225 uint32_t Record::Cpu() const {
226 return sample_id.cpu_data.cpu;
227 }
Id() const228 uint64_t Record::Id() const {
229 return sample_id.id_data.id;
230 }
231
UpdateBinary(char * new_binary)232 void Record::UpdateBinary(char* new_binary) {
233 if (own_binary_) {
234 delete[] binary_;
235 }
236 own_binary_ = true;
237 binary_ = new_binary;
238 }
239
Parse(const perf_event_attr & attr,char * p,char * end)240 bool MmapRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
241 if (!ParseHeader(p, end)) {
242 return false;
243 }
244 data = reinterpret_cast<const MmapRecordDataType*>(p);
245 CHECK_SIZE(p, end, sizeof(*data));
246 p += sizeof(*data);
247 size_t size = Align(SafeStrlen(p, end) + 1, 8);
248 CHECK_SIZE(p, end, size);
249 filename = p;
250 p += size;
251 return sample_id.ReadFromBinaryFormat(attr, p, end);
252 }
253
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)254 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
255 uint64_t addr, uint64_t len, uint64_t pgoff, const std::string& filename,
256 uint64_t event_id, uint64_t time) {
257 SetTypeAndMisc(PERF_RECORD_MMAP, in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
258 sample_id.CreateContent(attr, event_id);
259 sample_id.time_data.time = time;
260 MmapRecordDataType data;
261 data.pid = pid;
262 data.tid = tid;
263 data.addr = addr;
264 data.len = len;
265 data.pgoff = pgoff;
266 SetDataAndFilename(data, filename);
267 }
268
SetDataAndFilename(const MmapRecordDataType & data,const std::string & filename)269 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data, const std::string& filename) {
270 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) + sample_id.Size());
271 char* new_binary = new char[size()];
272 char* p = new_binary;
273 MoveToBinaryFormat(header, p);
274 this->data = reinterpret_cast<MmapRecordDataType*>(p);
275 MoveToBinaryFormat(data, p);
276 this->filename = p;
277 strcpy(p, filename.c_str());
278 p += Align(filename.size() + 1, 8);
279 sample_id.WriteToBinaryFormat(p);
280 UpdateBinary(new_binary);
281 }
282
DumpData(size_t indent) const283 void MmapRecord::DumpData(size_t indent) const {
284 PrintIndented(indent, "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", data->pid,
285 data->tid, data->addr, data->len);
286 PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff, filename);
287 }
288
Parse(const perf_event_attr & attr,char * p,char * end)289 bool Mmap2Record::Parse(const perf_event_attr& attr, char* p, char* end) {
290 if (!ParseHeader(p, end)) {
291 return false;
292 }
293 data = reinterpret_cast<const Mmap2RecordDataType*>(p);
294 CHECK_SIZE(p, end, sizeof(*data));
295 p += sizeof(*data);
296 size_t size = Align(SafeStrlen(p, end) + 1, 8);
297 CHECK_SIZE(p, end, size);
298 filename = p;
299 p += size;
300 return sample_id.ReadFromBinaryFormat(attr, p, end);
301 }
302
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)303 Mmap2Record::Mmap2Record(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
304 uint64_t addr, uint64_t len, uint64_t pgoff, uint32_t prot,
305 const std::string& filename, uint64_t event_id, uint64_t time) {
306 SetTypeAndMisc(PERF_RECORD_MMAP2, in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
307 sample_id.CreateContent(attr, event_id);
308 sample_id.time_data.time = time;
309 Mmap2RecordDataType data;
310 data.pid = pid;
311 data.tid = tid;
312 data.addr = addr;
313 data.len = len;
314 data.pgoff = pgoff;
315 data.prot = prot;
316 SetDataAndFilename(data, filename);
317 }
318
SetDataAndFilename(const Mmap2RecordDataType & data,const std::string & filename)319 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data, const std::string& filename) {
320 SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) + sample_id.Size());
321 char* new_binary = new char[size()];
322 char* p = new_binary;
323 MoveToBinaryFormat(header, p);
324 this->data = reinterpret_cast<Mmap2RecordDataType*>(p);
325 MoveToBinaryFormat(data, p);
326 this->filename = p;
327 strcpy(p, filename.c_str());
328 p += Align(filename.size() + 1, 8);
329 sample_id.WriteToBinaryFormat(p);
330 UpdateBinary(new_binary);
331 }
332
DumpData(size_t indent) const333 void Mmap2Record::DumpData(size_t indent) const {
334 PrintIndented(indent, "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", data->pid,
335 data->tid, data->addr, data->len);
336 PrintIndented(
337 indent, "pgoff 0x%" PRIx64 ", maj %u, min %u, ino %" PRId64 ", ino_generation %" PRIu64 "\n",
338 data->pgoff, data->maj, data->min, data->ino, data->ino_generation);
339 PrintIndented(indent, "prot %u, flags %u, filename %s\n", data->prot, data->flags, filename);
340 }
341
Parse(const perf_event_attr & attr,char * p,char * end)342 bool CommRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
343 if (!ParseHeader(p, end)) {
344 return false;
345 }
346 data = reinterpret_cast<const CommRecordDataType*>(p);
347 CHECK_SIZE(p, end, sizeof(*data));
348 p += sizeof(*data);
349 size_t size = Align(SafeStrlen(p, end) + 1, 8);
350 CHECK_SIZE(p, end, size);
351 comm = p;
352 p += size;
353 return sample_id.ReadFromBinaryFormat(attr, p, end);
354 }
355
CommRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,const std::string & comm,uint64_t event_id,uint64_t time)356 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
357 const std::string& comm, uint64_t event_id, uint64_t time) {
358 SetTypeAndMisc(PERF_RECORD_COMM, 0);
359 CommRecordDataType data;
360 data.pid = pid;
361 data.tid = tid;
362 size_t sample_id_size = sample_id.CreateContent(attr, event_id);
363 sample_id.time_data.time = time;
364 SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) + sample_id_size);
365 char* new_binary = new char[size()];
366 char* p = new_binary;
367 MoveToBinaryFormat(header, p);
368 this->data = reinterpret_cast<CommRecordDataType*>(p);
369 MoveToBinaryFormat(data, p);
370 this->comm = p;
371 strcpy(p, comm.c_str());
372 p += Align(comm.size() + 1, 8);
373 sample_id.WriteToBinaryFormat(p);
374 UpdateBinary(new_binary);
375 }
376
SetCommandName(const std::string & name)377 void CommRecord::SetCommandName(const std::string& name) {
378 if (name.compare(comm) == 0) {
379 return;
380 }
381 // The kernel uses a 8-byte aligned space to store command name. Follow it here to allow the same
382 // reading code.
383 size_t old_name_len = Align(strlen(comm) + 1, 8);
384 size_t new_name_len = Align(name.size() + 1, 8);
385 size_t new_size = size() - old_name_len + new_name_len;
386 char* new_binary = new char[new_size];
387 char* p = new_binary;
388 header.size = new_size;
389 MoveToBinaryFormat(header, p);
390 MoveToBinaryFormat(*data, p);
391 data = reinterpret_cast<CommRecordDataType*>(p - sizeof(CommRecordDataType));
392 comm = p;
393 strcpy(p, name.c_str());
394 p += new_name_len;
395 sample_id.WriteToBinaryFormat(p);
396 CHECK_EQ(p, new_binary + new_size);
397 UpdateBinary(new_binary);
398 }
399
DumpData(size_t indent) const400 void CommRecord::DumpData(size_t indent) const {
401 PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid, comm);
402 }
403
Parse(const perf_event_attr & attr,char * p,char * end)404 bool ExitOrForkRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
405 if (!ParseHeader(p, end)) {
406 return false;
407 }
408 data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
409 CHECK_SIZE(p, end, sizeof(*data));
410 p += sizeof(*data);
411 return sample_id.ReadFromBinaryFormat(attr, p, end);
412 }
413
DumpData(size_t indent) const414 void ExitOrForkRecord::DumpData(size_t indent) const {
415 PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid, data->ppid, data->tid,
416 data->ptid);
417 }
418
ForkRecord(const perf_event_attr & attr,uint32_t pid,uint32_t tid,uint32_t ppid,uint32_t ptid,uint64_t event_id)419 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, uint32_t ppid,
420 uint32_t ptid, uint64_t event_id) {
421 SetTypeAndMisc(PERF_RECORD_FORK, 0);
422 ExitOrForkRecordDataType data;
423 data.pid = pid;
424 data.ppid = ppid;
425 data.tid = tid;
426 data.ptid = ptid;
427 data.time = 0;
428 size_t sample_id_size = sample_id.CreateContent(attr, event_id);
429 SetSize(header_size() + sizeof(data) + sample_id_size);
430 char* new_binary = new char[size()];
431 char* p = new_binary;
432 MoveToBinaryFormat(header, p);
433 this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p);
434 MoveToBinaryFormat(data, p);
435 sample_id.WriteToBinaryFormat(p);
436 UpdateBinary(new_binary);
437 }
438
Parse(const perf_event_attr & attr,char * p,char * end)439 bool LostRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
440 if (!ParseHeader(p, end)) {
441 return false;
442 }
443 CHECK_SIZE_U64(p, end, 2);
444 MoveFromBinaryFormat(id, p);
445 MoveFromBinaryFormat(lost, p);
446 return sample_id.ReadFromBinaryFormat(attr, p, end);
447 }
448
DumpData(size_t indent) const449 void LostRecord::DumpData(size_t indent) const {
450 PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
451 }
452
Parse(const perf_event_attr & attr,char * p,char * end)453 bool SampleRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
454 if (!ParseHeader(p, end)) {
455 return false;
456 }
457 sample_type = attr.sample_type;
458 read_format = attr.read_format;
459 const uint64_t sample_mask = PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | PERF_SAMPLE_TID |
460 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | PERF_SAMPLE_ID |
461 PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD;
462 CHECK_SIZE_U64(p, end, __builtin_popcountll(sample_type & sample_mask));
463
464 // Set a default id value to report correctly even if ID is not recorded.
465 id_data.id = 0;
466 if (sample_type & PERF_SAMPLE_IDENTIFIER) {
467 MoveFromBinaryFormat(id_data, p);
468 }
469 if (sample_type & PERF_SAMPLE_IP) {
470 MoveFromBinaryFormat(ip_data, p);
471 }
472 if (sample_type & PERF_SAMPLE_TID) {
473 MoveFromBinaryFormat(tid_data, p);
474 }
475 if (sample_type & PERF_SAMPLE_TIME) {
476 MoveFromBinaryFormat(time_data, p);
477 }
478 if (sample_type & PERF_SAMPLE_ADDR) {
479 MoveFromBinaryFormat(addr_data, p);
480 }
481 if (sample_type & PERF_SAMPLE_ID) {
482 MoveFromBinaryFormat(id_data, p);
483 }
484 if (sample_type & PERF_SAMPLE_STREAM_ID) {
485 MoveFromBinaryFormat(stream_id_data, p);
486 }
487 if (sample_type & PERF_SAMPLE_CPU) {
488 MoveFromBinaryFormat(cpu_data, p);
489 }
490 if (sample_type & PERF_SAMPLE_PERIOD) {
491 MoveFromBinaryFormat(period_data, p);
492 }
493 if (sample_type & PERF_SAMPLE_READ) {
494 uint64_t nr = 1;
495 if (read_format & PERF_FORMAT_GROUP) {
496 CHECK_SIZE_U64(p, end, 1);
497 MoveFromBinaryFormat(nr, p);
498 }
499 size_t u64_count = (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) ? 1 : 0;
500 u64_count += (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) ? 1 : 0;
501 u64_count += ((read_format & PERF_FORMAT_ID) ? 2 : 1) * nr;
502 CHECK_SIZE_U64(p, end, u64_count);
503 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
504 MoveFromBinaryFormat(read_data.time_enabled, p);
505 }
506 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
507 MoveFromBinaryFormat(read_data.time_running, p);
508 }
509 read_data.counts.resize(nr);
510 if (read_format & PERF_FORMAT_ID) {
511 read_data.ids.resize(nr);
512 }
513 for (uint64_t i = 0; i < nr; i++) {
514 MoveFromBinaryFormat(read_data.counts[i], p);
515 if (read_format & PERF_FORMAT_ID) {
516 MoveFromBinaryFormat(read_data.ids[i], p);
517 }
518 }
519 }
520 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
521 CHECK_SIZE_U64(p, end, 1);
522 MoveFromBinaryFormat(callchain_data.ip_nr, p);
523 CHECK_SIZE_U64(p, end, callchain_data.ip_nr);
524 callchain_data.ips = reinterpret_cast<uint64_t*>(p);
525 p += callchain_data.ip_nr * sizeof(uint64_t);
526 }
527 if (sample_type & PERF_SAMPLE_RAW) {
528 CHECK_SIZE(p, end, sizeof(uint32_t));
529 MoveFromBinaryFormat(raw_data.size, p);
530 CHECK_SIZE(p, end, raw_data.size);
531 raw_data.data = p;
532 p += raw_data.size;
533 }
534 if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
535 CHECK_SIZE_U64(p, end, 1);
536 MoveFromBinaryFormat(branch_stack_data.stack_nr, p);
537 CHECK_SIZE(p, end, branch_stack_data.stack_nr * sizeof(BranchStackItemType));
538 branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(p);
539 p += branch_stack_data.stack_nr * sizeof(BranchStackItemType);
540 }
541 if (sample_type & PERF_SAMPLE_REGS_USER) {
542 CHECK_SIZE_U64(p, end, 1);
543 MoveFromBinaryFormat(regs_user_data.abi, p);
544 if (regs_user_data.abi == 0) {
545 regs_user_data.reg_mask = 0;
546 } else {
547 regs_user_data.reg_mask = attr.sample_regs_user;
548 size_t bit_nr = __builtin_popcountll(regs_user_data.reg_mask);
549 CHECK_SIZE_U64(p, end, bit_nr);
550 regs_user_data.reg_nr = bit_nr;
551 regs_user_data.regs = reinterpret_cast<uint64_t*>(p);
552 p += bit_nr * sizeof(uint64_t);
553 }
554 }
555 if (sample_type & PERF_SAMPLE_STACK_USER) {
556 CHECK_SIZE_U64(p, end, 1);
557 MoveFromBinaryFormat(stack_user_data.size, p);
558 if (stack_user_data.size == 0) {
559 stack_user_data.dyn_size = 0;
560 } else {
561 CHECK_SIZE(p, end, stack_user_data.size + sizeof(uint64_t));
562 stack_user_data.data = p;
563 p += stack_user_data.size;
564 MoveFromBinaryFormat(stack_user_data.dyn_size, p);
565 }
566 }
567 // TODO: Add parsing of other PERF_SAMPLE_*.
568 if (UNLIKELY(p < end)) {
569 LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
570 }
571 return true;
572 }
573
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 PerfSampleReadType & read_data,const std::vector<uint64_t> & ips,const std::vector<char> & stack,uint64_t dyn_stack_size)574 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id, uint64_t ip, uint32_t pid,
575 uint32_t tid, uint64_t time, uint32_t cpu, uint64_t period,
576 const PerfSampleReadType& read_data, const std::vector<uint64_t>& ips,
577 const std::vector<char>& stack, uint64_t dyn_stack_size) {
578 SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER);
579 sample_type = attr.sample_type;
580 read_format = attr.read_format;
581 CHECK_EQ(0u,
582 sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
583 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | PERF_SAMPLE_READ |
584 PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER));
585 ip_data.ip = ip;
586 tid_data.pid = pid;
587 tid_data.tid = tid;
588 time_data.time = time;
589 id_data.id = id;
590 cpu_data.cpu = cpu;
591 cpu_data.res = 0;
592 period_data.period = period;
593 this->read_data = read_data;
594 callchain_data.ip_nr = ips.size();
595 raw_data.size = 0;
596 branch_stack_data.stack_nr = 0;
597 regs_user_data.abi = 0;
598 regs_user_data.reg_mask = 0;
599 regs_user_data.reg_nr = 0;
600 stack_user_data.size = stack.size();
601 stack_user_data.dyn_size = dyn_stack_size;
602
603 uint32_t size = header_size();
604 if (sample_type & PERF_SAMPLE_IP) {
605 size += sizeof(ip_data);
606 }
607 if (sample_type & PERF_SAMPLE_TID) {
608 size += sizeof(tid_data);
609 }
610 if (sample_type & PERF_SAMPLE_TIME) {
611 size += sizeof(time_data);
612 }
613 if (sample_type & PERF_SAMPLE_ID) {
614 size += sizeof(id_data);
615 }
616 if (sample_type & PERF_SAMPLE_CPU) {
617 size += sizeof(cpu_data);
618 }
619 if (sample_type & PERF_SAMPLE_PERIOD) {
620 size += sizeof(period_data);
621 }
622 if (sample_type & PERF_SAMPLE_READ) {
623 size_t u64_count = (read_format & PERF_FORMAT_GROUP) ? 1 : 0;
624 u64_count += (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) ? 1 : 0;
625 u64_count += (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) ? 1 : 0;
626 u64_count += read_data.counts.size() + read_data.ids.size();
627 size += sizeof(uint64_t) * u64_count;
628 }
629 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
630 size += sizeof(uint64_t) * (ips.size() + 1);
631 }
632 if (sample_type & PERF_SAMPLE_REGS_USER) {
633 size += sizeof(uint64_t);
634 }
635 if (sample_type & PERF_SAMPLE_STACK_USER) {
636 size += sizeof(uint64_t) + (stack.empty() ? 0 : stack.size() + sizeof(uint64_t));
637 }
638
639 SetSize(size);
640 char* new_binary = new char[size];
641 char* p = new_binary;
642 MoveToBinaryFormat(header, p);
643 if (sample_type & PERF_SAMPLE_IP) {
644 MoveToBinaryFormat(ip_data, p);
645 }
646 if (sample_type & PERF_SAMPLE_TID) {
647 MoveToBinaryFormat(tid_data, p);
648 }
649 if (sample_type & PERF_SAMPLE_TIME) {
650 MoveToBinaryFormat(time_data, p);
651 }
652 if (sample_type & PERF_SAMPLE_ID) {
653 MoveToBinaryFormat(id_data, p);
654 }
655 if (sample_type & PERF_SAMPLE_CPU) {
656 MoveToBinaryFormat(cpu_data, p);
657 }
658 if (sample_type & PERF_SAMPLE_PERIOD) {
659 MoveToBinaryFormat(period_data, p);
660 }
661 if (sample_type & PERF_SAMPLE_READ) {
662 if (read_format & PERF_FORMAT_GROUP) {
663 uint64_t nr = read_data.counts.size();
664 MoveToBinaryFormat(nr, p);
665 }
666 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
667 MoveToBinaryFormat(read_data.time_enabled, p);
668 }
669 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
670 MoveToBinaryFormat(read_data.time_running, p);
671 }
672 for (size_t i = 0; i < read_data.counts.size(); i++) {
673 MoveToBinaryFormat(read_data.counts[i], p);
674 if (read_format & PERF_FORMAT_ID) {
675 MoveToBinaryFormat(read_data.ids[i], p);
676 }
677 }
678 }
679 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
680 MoveToBinaryFormat(callchain_data.ip_nr, p);
681 callchain_data.ips = reinterpret_cast<uint64_t*>(p);
682 MoveToBinaryFormat(ips.data(), ips.size(), p);
683 }
684 if (sample_type & PERF_SAMPLE_REGS_USER) {
685 MoveToBinaryFormat(regs_user_data.abi, p);
686 }
687 if (sample_type & PERF_SAMPLE_STACK_USER) {
688 MoveToBinaryFormat(stack_user_data.size, p);
689 if (stack_user_data.size > 0) {
690 stack_user_data.data = p;
691 MoveToBinaryFormat(stack.data(), stack_user_data.size, p);
692 MoveToBinaryFormat(stack_user_data.dyn_size, p);
693 }
694 }
695 CHECK_EQ(p, new_binary + size);
696 UpdateBinary(new_binary);
697 }
698
ReplaceRegAndStackWithCallChain(const std::vector<uint64_t> & ips)699 void SampleRecord::ReplaceRegAndStackWithCallChain(const std::vector<uint64_t>& ips) {
700 uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1);
701 uint32_t size_reduced_in_reg_stack =
702 regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size + sizeof(uint64_t);
703 uint32_t new_size = size() + size_added_in_callchain - size_reduced_in_reg_stack;
704 BuildBinaryWithNewCallChain(new_size, ips);
705 }
706
ExcludeKernelCallChain()707 bool SampleRecord::ExcludeKernelCallChain() {
708 if (!(sample_type & PERF_SAMPLE_CALLCHAIN)) {
709 return true;
710 }
711 size_t i;
712 for (i = 0; i < callchain_data.ip_nr; ++i) {
713 if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
714 break;
715 }
716 // Erase kernel callchain.
717 callchain_data.ips[i] = PERF_CONTEXT_USER;
718 }
719 while (++i < callchain_data.ip_nr) {
720 if (callchain_data.ips[i] < PERF_CONTEXT_MAX) {
721 // Change the sample to make it hit the user space ip address.
722 ip_data.ip = callchain_data.ips[i];
723 if (sample_type & PERF_SAMPLE_IP) {
724 *reinterpret_cast<uint64_t*>(binary_ + header_size()) = ip_data.ip;
725 }
726 header.misc = (header.misc & ~PERF_RECORD_MISC_CPUMODE_MASK) | PERF_RECORD_MISC_USER;
727 reinterpret_cast<perf_event_header*>(binary_)->misc = header.misc;
728 return true;
729 }
730 }
731 return false;
732 }
733
HasUserCallChain() const734 bool SampleRecord::HasUserCallChain() const {
735 if ((sample_type & PERF_SAMPLE_CALLCHAIN) == 0) {
736 return false;
737 }
738 bool in_user_context = !InKernel();
739 for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
740 if (in_user_context && callchain_data.ips[i] < PERF_CONTEXT_MAX) {
741 return true;
742 }
743 if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
744 in_user_context = true;
745 }
746 }
747 return false;
748 }
749
UpdateUserCallChain(const std::vector<uint64_t> & user_ips)750 void SampleRecord::UpdateUserCallChain(const std::vector<uint64_t>& user_ips) {
751 size_t kernel_ip_count = 0;
752 for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
753 if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
754 break;
755 }
756 kernel_ip_count++;
757 }
758 if (kernel_ip_count + 1 + user_ips.size() <= callchain_data.ip_nr) {
759 // Callchain isn't changed.
760 return;
761 }
762 size_t new_size =
763 size() + (kernel_ip_count + 1 + user_ips.size() - callchain_data.ip_nr) * sizeof(uint64_t);
764 callchain_data.ip_nr = kernel_ip_count;
765 BuildBinaryWithNewCallChain(new_size, user_ips);
766 }
767
BuildBinaryWithNewCallChain(uint32_t new_size,const std::vector<uint64_t> & ips)768 void SampleRecord::BuildBinaryWithNewCallChain(uint32_t new_size,
769 const std::vector<uint64_t>& ips) {
770 size_t callchain_pos = reinterpret_cast<char*>(callchain_data.ips) - binary_ - sizeof(uint64_t);
771 char* new_binary = binary_;
772 if (new_size > size()) {
773 new_binary = new char[new_size];
774 memcpy(new_binary, binary_, callchain_pos);
775 }
776 char* p = new_binary;
777 SetSize(new_size);
778 MoveToBinaryFormat(header, p);
779 p = new_binary + new_size;
780 if (sample_type & PERF_SAMPLE_STACK_USER) {
781 stack_user_data.size = 0;
782 p -= sizeof(uint64_t);
783 memcpy(p, &stack_user_data.size, sizeof(uint64_t));
784 }
785 if (sample_type & PERF_SAMPLE_REGS_USER) {
786 regs_user_data.abi = 0;
787 p -= sizeof(uint64_t);
788 memcpy(p, ®s_user_data.abi, sizeof(uint64_t));
789 }
790 if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
791 p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType);
792 memcpy(p, branch_stack_data.stack, branch_stack_data.stack_nr * sizeof(BranchStackItemType));
793 branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(p);
794 p -= sizeof(uint64_t);
795 memcpy(p, &branch_stack_data.stack_nr, sizeof(uint64_t));
796 }
797 if (sample_type & PERF_SAMPLE_RAW) {
798 p -= raw_data.size;
799 memcpy(p, raw_data.data, raw_data.size);
800 raw_data.data = p;
801 p -= sizeof(uint32_t);
802 memcpy(p, &raw_data.size, sizeof(uint32_t));
803 }
804 uint64_t* p64 = reinterpret_cast<uint64_t*>(p);
805 p64 -= ips.size();
806 memcpy(p64, ips.data(), ips.size() * sizeof(uint64_t));
807 *--p64 = PERF_CONTEXT_USER;
808 if (callchain_data.ip_nr > 0) {
809 p64 -= callchain_data.ip_nr;
810 memcpy(p64, callchain_data.ips, callchain_data.ip_nr * sizeof(uint64_t));
811 }
812 callchain_data.ips = p64;
813 callchain_data.ip_nr += 1 + ips.size();
814 *--p64 = callchain_data.ip_nr;
815 CHECK_EQ(callchain_pos, static_cast<size_t>(reinterpret_cast<char*>(p64) - new_binary))
816 << "record time " << time_data.time;
817 if (new_binary != binary_) {
818 UpdateBinary(new_binary);
819 }
820 }
821
DumpData(size_t indent) const822 void SampleRecord::DumpData(size_t indent) const {
823 PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
824 if (sample_type & PERF_SAMPLE_IP) {
825 PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
826 }
827 if (sample_type & PERF_SAMPLE_TID) {
828 PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
829 }
830 if (sample_type & PERF_SAMPLE_TIME) {
831 PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
832 }
833 if (sample_type & PERF_SAMPLE_ADDR) {
834 PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
835 }
836 if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
837 PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
838 }
839 if (sample_type & PERF_SAMPLE_STREAM_ID) {
840 PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
841 }
842 if (sample_type & PERF_SAMPLE_CPU) {
843 PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
844 }
845 if (sample_type & PERF_SAMPLE_PERIOD) {
846 PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
847 }
848 if (sample_type & PERF_SAMPLE_READ) {
849 PrintIndented(indent, "read nr=%zu\n", read_data.counts.size());
850 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
851 PrintIndented(indent + 1, "time_enabled %" PRIu64 "\n", read_data.time_enabled);
852 }
853 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
854 PrintIndented(indent + 1, "time_running %" PRIu64 "\n", read_data.time_running);
855 }
856 for (size_t i = 0; i < read_data.counts.size(); i++) {
857 PrintIndented(indent + 1, "count[%zu] %" PRIu64 "\n", i, read_data.counts[i]);
858 if (read_format & PERF_FORMAT_ID) {
859 PrintIndented(indent + 1, "id[%zu] %" PRIu64 "\n", i, read_data.ids[i]);
860 }
861 }
862 }
863 if (sample_type & PERF_SAMPLE_CALLCHAIN) {
864 PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr);
865 for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
866 PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]);
867 }
868 }
869 if (sample_type & PERF_SAMPLE_RAW) {
870 PrintIndented(indent, "raw size=%zu\n", raw_data.size);
871 const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data);
872 size_t size = raw_data.size / sizeof(uint32_t);
873 for (size_t i = 0; i < size; ++i) {
874 PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
875 }
876 }
877 if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
878 PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n", branch_stack_data.stack_nr);
879 for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) {
880 auto& item = branch_stack_data.stack[i];
881 PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64 ", flags 0x%" PRIx64 "\n",
882 item.from, item.to, item.flags);
883 }
884 }
885 if (sample_type & PERF_SAMPLE_REGS_USER) {
886 PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
887 RegSet regs(regs_user_data.abi, regs_user_data.reg_mask, regs_user_data.regs);
888 for (size_t i = 0; i < 64; ++i) {
889 uint64_t value;
890 if (regs.GetRegValue(i, &value)) {
891 PrintIndented(indent + 1, "reg (%s) 0x%016" PRIx64 "\n", GetRegName(i, regs.arch).c_str(),
892 value);
893 }
894 }
895 }
896 if (sample_type & PERF_SAMPLE_STACK_USER) {
897 PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n", stack_user_data.size,
898 stack_user_data.dyn_size);
899 const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
900 const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
901 while (p < end) {
902 PrintIndented(indent + 1, "");
903 for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
904 printf(" %016" PRIx64, *p);
905 }
906 printf("\n");
907 }
908 printf("\n");
909 }
910 }
911
Timestamp() const912 uint64_t SampleRecord::Timestamp() const {
913 return time_data.time;
914 }
Cpu() const915 uint32_t SampleRecord::Cpu() const {
916 return cpu_data.cpu;
917 }
Id() const918 uint64_t SampleRecord::Id() const {
919 return id_data.id;
920 }
921
AdjustCallChainGeneratedByKernel()922 void SampleRecord::AdjustCallChainGeneratedByKernel() {
923 // The kernel stores return addrs in the callchain, but we want the addrs of call instructions
924 // along the callchain.
925 uint64_t* ips = callchain_data.ips;
926 uint64_t context =
927 header.misc == PERF_RECORD_MISC_KERNEL ? PERF_CONTEXT_KERNEL : PERF_CONTEXT_USER;
928 bool first_frame = true;
929 for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
930 if (ips[i] < PERF_CONTEXT_MAX) {
931 if (first_frame) {
932 first_frame = false;
933 } else {
934 if (ips[i] < 2) {
935 // A wrong ip address, erase it.
936 ips[i] = context;
937 } else {
938 // Here we want to change the return addr to the addr of the previous instruction. We
939 // don't need to find the exact start addr of the previous instruction. A location in
940 // [start_addr_of_call_inst, start_addr_of_next_inst) is enough.
941 #if defined(__arm__) || defined(__aarch64__)
942 // If we are built for arm/aarch64, this may be a callchain of thumb code. For thumb code,
943 // the real instruction addr is (ip & ~1), and ip - 2 can used to hit the address range
944 // of the previous instruction. For non thumb code, any addr in [ip - 4, ip - 1] is fine.
945 ips[i] -= 2;
946 #else
947 ips[i]--;
948 #endif
949 }
950 }
951 } else {
952 context = ips[i];
953 }
954 }
955 }
956
GetCallChain(size_t * kernel_ip_count) const957 std::vector<uint64_t> SampleRecord::GetCallChain(size_t* kernel_ip_count) const {
958 std::vector<uint64_t> ips;
959 bool in_kernel = InKernel();
960 ips.push_back(ip_data.ip);
961 *kernel_ip_count = in_kernel ? 1 : 0;
962 if ((sample_type & PERF_SAMPLE_CALLCHAIN) == 0) {
963 return ips;
964 }
965 bool first_ip = true;
966 for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
967 uint64_t ip = callchain_data.ips[i];
968 if (ip >= PERF_CONTEXT_MAX) {
969 switch (ip) {
970 case PERF_CONTEXT_KERNEL:
971 in_kernel = true;
972 break;
973 case PERF_CONTEXT_USER:
974 in_kernel = false;
975 break;
976 default:
977 LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex << ip << std::dec;
978 }
979 } else {
980 if (first_ip) {
981 first_ip = false;
982 // Remove duplication with sample ip.
983 if (ip == ip_data.ip) {
984 continue;
985 }
986 }
987 ips.push_back(ip);
988 if (in_kernel) {
989 ++*kernel_ip_count;
990 }
991 }
992 }
993 return ips;
994 }
995
Parse(const perf_event_attr & attr,char * p,char * end)996 bool AuxRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
997 if (!ParseHeader(p, end)) {
998 return false;
999 }
1000 data = reinterpret_cast<DataType*>(p);
1001 CHECK_SIZE(p, end, sizeof(*data));
1002 p += sizeof(*data);
1003 return sample_id.ReadFromBinaryFormat(attr, p, end);
1004 }
1005
DumpData(size_t indent) const1006 void AuxRecord::DumpData(size_t indent) const {
1007 PrintIndented(indent, "aux_offset %" PRIu64 "\n", data->aux_offset);
1008 PrintIndented(indent, "aux_size %" PRIu64 "\n", data->aux_size);
1009 PrintIndented(indent, "flags 0x%" PRIx64 "\n", data->flags);
1010 }
1011
Parse(const perf_event_attr & attr,char * p,char * end)1012 bool SwitchRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
1013 if (!ParseHeader(p, end)) {
1014 return false;
1015 }
1016 return sample_id.ReadFromBinaryFormat(attr, p, end);
1017 }
1018
Parse(const perf_event_attr & attr,char * p,char * end)1019 bool SwitchCpuWideRecord::Parse(const perf_event_attr& attr, char* p, char* end) {
1020 if (!ParseHeader(p, end)) {
1021 return false;
1022 }
1023 CHECK_SIZE(p, end, sizeof(tid_data));
1024 MoveFromBinaryFormat(tid_data, p);
1025 return sample_id.ReadFromBinaryFormat(attr, p, end);
1026 }
1027
DumpData(size_t indent) const1028 void SwitchCpuWideRecord::DumpData(size_t indent) const {
1029 if (header.misc & PERF_RECORD_MISC_SWITCH_OUT) {
1030 PrintIndented(indent, "next_pid %u, next_tid %u\n", tid_data.pid, tid_data.tid);
1031 } else {
1032 PrintIndented(indent, "prev_pid %u, prev_tid %u\n", tid_data.pid, tid_data.tid);
1033 }
1034 }
1035
Parse(const perf_event_attr &,char * p,char * end)1036 bool BuildIdRecord::Parse(const perf_event_attr&, char* p, char* end) {
1037 if (!ParseHeader(p, end)) {
1038 return false;
1039 }
1040 size_t size = Align(BUILD_ID_SIZE, 8);
1041 CHECK_SIZE(p, end, sizeof(uint32_t) + size);
1042 MoveFromBinaryFormat(pid, p);
1043 build_id = BuildId(p, BUILD_ID_SIZE);
1044 p += size;
1045 size = Align(SafeStrlen(p, end) + 1, 64);
1046 CHECK_SIZE(p, end, size);
1047 filename = p;
1048 p += size;
1049 return p == end;
1050 }
1051
DumpData(size_t indent) const1052 void BuildIdRecord::DumpData(size_t indent) const {
1053 PrintIndented(indent, "pid %u\n", pid);
1054 PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
1055 PrintIndented(indent, "filename %s\n", filename);
1056 }
1057
BuildIdRecord(bool in_kernel,uint32_t pid,const BuildId & build_id,const std::string & filename)1058 BuildIdRecord::BuildIdRecord(bool in_kernel, uint32_t pid, const BuildId& build_id,
1059 const std::string& filename) {
1060 SetTypeAndMisc(PERF_RECORD_BUILD_ID, in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
1061 this->pid = pid;
1062 this->build_id = build_id;
1063 SetSize(header_size() + sizeof(this->pid) + Align(build_id.Size(), 8) +
1064 Align(filename.size() + 1, 64));
1065 char* new_binary = new char[size()];
1066 char* p = new_binary;
1067 MoveToBinaryFormat(header, p);
1068 MoveToBinaryFormat(this->pid, p);
1069 memcpy(p, build_id.Data(), build_id.Size());
1070 p += Align(build_id.Size(), 8);
1071 this->filename = p;
1072 strcpy(p, filename.c_str());
1073 UpdateBinary(new_binary);
1074 }
1075
Parse(const perf_event_attr &,char * p,char * end)1076 bool AuxTraceInfoRecord::Parse(const perf_event_attr&, char* p, char* end) {
1077 if (!ParseHeader(p, end)) {
1078 return false;
1079 }
1080 data = reinterpret_cast<DataType*>(p);
1081 CHECK_SIZE(p, end, sizeof(*data));
1082 p += sizeof(*data);
1083 if (data->aux_type != AUX_TYPE_ETM || data->version != 1) {
1084 return false;
1085 }
1086 for (uint32_t i = 0; i < data->nr_cpu; ++i) {
1087 uint64_t magic = *reinterpret_cast<uint64_t*>(p);
1088 if (magic == MAGIC_ETM4) {
1089 CHECK_SIZE(p, end, sizeof(ETM4Info));
1090 p += sizeof(ETM4Info);
1091 } else if (magic == MAGIC_ETE) {
1092 CHECK_SIZE(p, end, sizeof(ETEInfo));
1093 p += sizeof(ETEInfo);
1094 } else {
1095 return false;
1096 }
1097 }
1098 return p == end;
1099 }
1100
AuxTraceInfoRecord(const DataType & data,const std::vector<ETEInfo> & ete_info)1101 AuxTraceInfoRecord::AuxTraceInfoRecord(const DataType& data, const std::vector<ETEInfo>& ete_info) {
1102 SetTypeAndMisc(PERF_RECORD_AUXTRACE_INFO, 0);
1103
1104 uint32_t size = header_size() + sizeof(DataType);
1105 for (auto& ete : ete_info) {
1106 size += (ete.trcdevarch == 0) ? sizeof(ETM4Info) : sizeof(ETEInfo);
1107 }
1108 SetSize(size);
1109 char* new_binary = new char[size];
1110 char* p = new_binary;
1111 MoveToBinaryFormat(header, p);
1112 this->data = reinterpret_cast<DataType*>(p);
1113 MoveToBinaryFormat(data, p);
1114 for (auto& ete : ete_info) {
1115 if (ete.trcdevarch == 0) {
1116 ETM4Info etm4;
1117 static_assert(sizeof(ETM4Info) + sizeof(uint64_t) == sizeof(ETEInfo));
1118 memcpy(&etm4, &ete, sizeof(ETM4Info));
1119 MoveToBinaryFormat(etm4, p);
1120 } else {
1121 MoveToBinaryFormat(ete, p);
1122 }
1123 }
1124 UpdateBinary(new_binary);
1125 }
1126
DumpData(size_t indent) const1127 void AuxTraceInfoRecord::DumpData(size_t indent) const {
1128 PrintIndented(indent, "aux_type %u\n", data->aux_type);
1129 PrintIndented(indent, "version %" PRIu64 "\n", data->version);
1130 PrintIndented(indent, "nr_cpu %u\n", data->nr_cpu);
1131 PrintIndented(indent, "pmu_type %u\n", data->pmu_type);
1132 PrintIndented(indent, "snapshot %" PRIu64 "\n", data->snapshot);
1133 indent++;
1134 uint64_t* info = data->info;
1135
1136 for (int i = 0; i < data->nr_cpu; i++) {
1137 if (info[0] == MAGIC_ETM4) {
1138 ETM4Info& e = *reinterpret_cast<ETM4Info*>(info);
1139 PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
1140 PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
1141 PrintIndented(indent, "nrtrcparams %" PRIu64 "\n", e.nrtrcparams);
1142 PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
1143 PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
1144 PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
1145 PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
1146 PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
1147 PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
1148 PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
1149 info = reinterpret_cast<uint64_t*>(&e + 1);
1150 } else {
1151 CHECK_EQ(info[0], MAGIC_ETE);
1152 ETEInfo& e = *reinterpret_cast<ETEInfo*>(info);
1153 PrintIndented(indent, "magic 0x%" PRIx64 "\n", e.magic);
1154 PrintIndented(indent, "cpu %" PRIu64 "\n", e.cpu);
1155 PrintIndented(indent, "nrtrcparams %" PRIu64 "\n", e.nrtrcparams);
1156 PrintIndented(indent, "trcconfigr 0x%" PRIx64 "\n", e.trcconfigr);
1157 PrintIndented(indent, "trctraceidr 0x%" PRIx64 "\n", e.trctraceidr);
1158 PrintIndented(indent, "trcidr0 0x%" PRIx64 "\n", e.trcidr0);
1159 PrintIndented(indent, "trcidr1 0x%" PRIx64 "\n", e.trcidr1);
1160 PrintIndented(indent, "trcidr2 0x%" PRIx64 "\n", e.trcidr2);
1161 PrintIndented(indent, "trcidr8 0x%" PRIx64 "\n", e.trcidr8);
1162 PrintIndented(indent, "trcauthstatus 0x%" PRIx64 "\n", e.trcauthstatus);
1163 PrintIndented(indent, "trcdevarch 0x%" PRIx64 "\n", e.trcdevarch);
1164 info = reinterpret_cast<uint64_t*>(&e + 1);
1165 }
1166 }
1167 }
1168
Parse(const perf_event_attr &,char * p,char * end)1169 bool AuxTraceRecord::Parse(const perf_event_attr&, char* p, char* end) {
1170 if (!ParseHeader(p, end)) {
1171 return false;
1172 }
1173 data = reinterpret_cast<DataType*>(p);
1174 CHECK_SIZE(p, end, sizeof(*data));
1175 p += sizeof(*data);
1176 return p == end;
1177 }
1178
AuxTraceRecord(uint64_t aux_size,uint64_t offset,uint32_t idx,uint32_t tid,uint32_t cpu)1179 AuxTraceRecord::AuxTraceRecord(uint64_t aux_size, uint64_t offset, uint32_t idx, uint32_t tid,
1180 uint32_t cpu) {
1181 SetTypeAndMisc(PERF_RECORD_AUXTRACE, 0);
1182 SetSize(header_size() + sizeof(DataType));
1183 char* new_binary = new char[size()];
1184 char* p = new_binary;
1185 MoveToBinaryFormat(header, p);
1186 data = reinterpret_cast<DataType*>(p);
1187 data->aux_size = aux_size;
1188 data->offset = offset;
1189 data->reserved0 = 0;
1190 data->idx = idx;
1191 data->tid = tid;
1192 data->cpu = cpu;
1193 data->reserved1 = 0;
1194 UpdateBinary(new_binary);
1195 }
1196
DumpData(size_t indent) const1197 void AuxTraceRecord::DumpData(size_t indent) const {
1198 PrintIndented(indent, "aux_size %" PRIu64 "\n", data->aux_size);
1199 PrintIndented(indent, "offset %" PRIu64 "\n", data->offset);
1200 PrintIndented(indent, "idx %u\n", data->idx);
1201 PrintIndented(indent, "tid %u\n", data->tid);
1202 PrintIndented(indent, "cpu %u\n", data->cpu);
1203 PrintIndented(indent, "location.file_offset %" PRIu64 "\n", location.file_offset);
1204 }
1205
Parse(const perf_event_attr &,char * p,char * end)1206 bool KernelSymbolRecord::Parse(const perf_event_attr&, char* p, char* end) {
1207 if (!ParseHeader(p, end)) {
1208 return false;
1209 }
1210 CHECK_SIZE(p, end, sizeof(uint32_t));
1211 MoveFromBinaryFormat(kallsyms_size, p);
1212 size_t size = Align(kallsyms_size, 8);
1213 CHECK_SIZE(p, end, size);
1214 kallsyms = p;
1215 p += size;
1216 return p == end;
1217 }
1218
DumpData(size_t indent) const1219 void KernelSymbolRecord::DumpData(size_t indent) const {
1220 PrintIndented(indent, "kallsyms: %s\n", std::string(kallsyms, kallsyms + kallsyms_size).c_str());
1221 }
1222
KernelSymbolRecord(const std::string & kallsyms)1223 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) {
1224 SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0);
1225 kallsyms_size = kallsyms.size();
1226 SetSize(header_size() + 4 + Align(kallsyms.size(), 8));
1227 char* new_binary = new char[size()];
1228 char* p = new_binary;
1229 MoveToBinaryFormat(header, p);
1230 MoveToBinaryFormat(kallsyms_size, p);
1231 this->kallsyms = p;
1232 memcpy(p, kallsyms.data(), kallsyms_size);
1233 UpdateBinary(new_binary);
1234 }
1235
Parse(const perf_event_attr &,char * p,char * end)1236 bool DsoRecord::Parse(const perf_event_attr&, char* p, char* end) {
1237 if (!ParseHeader(p, end)) {
1238 return false;
1239 }
1240 CHECK_SIZE_U64(p, end, 3);
1241 MoveFromBinaryFormat(dso_type, p);
1242 MoveFromBinaryFormat(dso_id, p);
1243 MoveFromBinaryFormat(min_vaddr, p);
1244 size_t size = Align(SafeStrlen(p, end) + 1, 8);
1245 dso_name = p;
1246 p += size;
1247 return p == end;
1248 }
1249
DsoRecord(uint64_t dso_type,uint64_t dso_id,const std::string & dso_name,uint64_t min_vaddr)1250 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id, const std::string& dso_name,
1251 uint64_t min_vaddr) {
1252 SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0);
1253 this->dso_type = dso_type;
1254 this->dso_id = dso_id;
1255 this->min_vaddr = min_vaddr;
1256 SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8));
1257 char* new_binary = new char[size()];
1258 char* p = new_binary;
1259 MoveToBinaryFormat(header, p);
1260 MoveToBinaryFormat(dso_type, p);
1261 MoveToBinaryFormat(dso_id, p);
1262 MoveToBinaryFormat(min_vaddr, p);
1263 this->dso_name = p;
1264 strcpy(p, dso_name.c_str());
1265 UpdateBinary(new_binary);
1266 }
1267
DumpData(size_t indent) const1268 void DsoRecord::DumpData(size_t indent) const {
1269 PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n",
1270 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type);
1271 PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
1272 PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr);
1273 PrintIndented(indent, "dso_name: %s\n", dso_name);
1274 }
1275
Parse(const perf_event_attr &,char * p,char * end)1276 bool SymbolRecord::Parse(const perf_event_attr&, char* p, char* end) {
1277 if (!ParseHeader(p, end)) {
1278 return false;
1279 }
1280 CHECK_SIZE_U64(p, end, 3);
1281 MoveFromBinaryFormat(addr, p);
1282 MoveFromBinaryFormat(len, p);
1283 MoveFromBinaryFormat(dso_id, p);
1284 size_t size = Align(SafeStrlen(p, end) + 1, 8);
1285 name = p;
1286 p += size;
1287 return p == end;
1288 }
1289
SymbolRecord(uint64_t addr,uint64_t len,const std::string & name,uint64_t dso_id)1290 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name, uint64_t dso_id) {
1291 SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
1292 this->addr = addr;
1293 this->len = len;
1294 this->dso_id = dso_id;
1295 SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8));
1296 char* new_binary = new char[size()];
1297 char* p = new_binary;
1298 MoveToBinaryFormat(header, p);
1299 MoveToBinaryFormat(addr, p);
1300 MoveToBinaryFormat(len, p);
1301 MoveToBinaryFormat(dso_id, p);
1302 this->name = p;
1303 strcpy(p, name.c_str());
1304 UpdateBinary(new_binary);
1305 }
1306
DumpData(size_t indent) const1307 void SymbolRecord::DumpData(size_t indent) const {
1308 PrintIndented(indent, "name: %s\n", name);
1309 PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr);
1310 PrintIndented(indent, "len: 0x%" PRIx64 "\n", len);
1311 PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
1312 }
1313
Parse(const perf_event_attr &,char * p,char * end)1314 bool TracingDataRecord::Parse(const perf_event_attr&, char* p, char* end) {
1315 if (!ParseHeader(p, end)) {
1316 return false;
1317 }
1318 CHECK_SIZE(p, end, sizeof(uint32_t));
1319 MoveFromBinaryFormat(data_size, p);
1320 size_t size = Align(data_size, 64);
1321 CHECK_SIZE(p, end, size);
1322 data = p;
1323 p += size;
1324 return p == end;
1325 }
1326
TracingDataRecord(const std::vector<char> & tracing_data)1327 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
1328 SetTypeAndMisc(SIMPLE_PERF_RECORD_TRACING_DATA, 0);
1329 data_size = tracing_data.size();
1330 SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
1331 char* new_binary = new char[size()];
1332 char* p = new_binary;
1333 MoveToBinaryFormat(header, p);
1334 MoveToBinaryFormat(data_size, p);
1335 data = p;
1336 memcpy(p, tracing_data.data(), data_size);
1337 UpdateBinary(new_binary);
1338 }
1339
DumpData(size_t indent) const1340 void TracingDataRecord::DumpData(size_t indent) const {
1341 Tracing tracing(std::vector<char>(data, data + data_size));
1342 tracing.Dump(indent);
1343 }
1344
Parse(const perf_event_attr &,char * p,char * end)1345 bool EventIdRecord::Parse(const perf_event_attr&, char* p, char* end) {
1346 if (!ParseHeader(p, end)) {
1347 return false;
1348 }
1349 CHECK_SIZE_U64(p, end, 1);
1350 MoveFromBinaryFormat(count, p);
1351 data = reinterpret_cast<const EventIdData*>(p);
1352 CHECK_SIZE(p, end, sizeof(data[0]) * count);
1353 p += sizeof(data[0]) * count;
1354 return p == end;
1355 }
1356
EventIdRecord(const std::vector<uint64_t> & data)1357 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) {
1358 SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0);
1359 SetSize(header_size() + sizeof(uint64_t) * (1 + data.size()));
1360 char* new_binary = new char[size()];
1361 char* p = new_binary;
1362 MoveToBinaryFormat(header, p);
1363 count = data.size() / 2;
1364 MoveToBinaryFormat(count, p);
1365 this->data = reinterpret_cast<EventIdData*>(p);
1366 memcpy(p, data.data(), sizeof(uint64_t) * data.size());
1367 UpdateBinary(new_binary);
1368 }
1369
DumpData(size_t indent) const1370 void EventIdRecord::DumpData(size_t indent) const {
1371 PrintIndented(indent, "count: %" PRIu64 "\n", count);
1372 for (size_t i = 0; i < count; ++i) {
1373 PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i, data[i].attr_id);
1374 PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i, data[i].event_id);
1375 }
1376 }
1377
Parse(const perf_event_attr &,char * p,char * end)1378 bool CallChainRecord::Parse(const perf_event_attr&, char* p, char* end) {
1379 if (!ParseHeader(p, end)) {
1380 return false;
1381 }
1382 CHECK_SIZE_U64(p, end, 4);
1383 MoveFromBinaryFormat(pid, p);
1384 MoveFromBinaryFormat(tid, p);
1385 MoveFromBinaryFormat(chain_type, p);
1386 MoveFromBinaryFormat(time, p);
1387 MoveFromBinaryFormat(ip_nr, p);
1388 CHECK_SIZE_U64(p, end, ip_nr * 2);
1389 ips = reinterpret_cast<uint64_t*>(p);
1390 p += ip_nr * sizeof(uint64_t);
1391 sps = reinterpret_cast<uint64_t*>(p);
1392 p += ip_nr * sizeof(uint64_t);
1393 return p == end;
1394 }
1395
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)1396 CallChainRecord::CallChainRecord(pid_t pid, pid_t tid, CallChainJoiner::ChainType type,
1397 uint64_t time, const std::vector<uint64_t>& ips,
1398 const std::vector<uint64_t>& sps) {
1399 CHECK_EQ(ips.size(), sps.size());
1400 SetTypeAndMisc(SIMPLE_PERF_RECORD_CALLCHAIN, 0);
1401 this->pid = pid;
1402 this->tid = tid;
1403 this->chain_type = static_cast<int>(type);
1404 this->time = time;
1405 this->ip_nr = ips.size();
1406 SetSize(header_size() + (4 + ips.size() * 2) * sizeof(uint64_t));
1407 char* new_binary = new char[size()];
1408 char* p = new_binary;
1409 MoveToBinaryFormat(header, p);
1410 MoveToBinaryFormat(this->pid, p);
1411 MoveToBinaryFormat(this->tid, p);
1412 MoveToBinaryFormat(this->chain_type, p);
1413 MoveToBinaryFormat(this->time, p);
1414 MoveToBinaryFormat(this->ip_nr, p);
1415 this->ips = reinterpret_cast<uint64_t*>(p);
1416 MoveToBinaryFormat(ips.data(), ips.size(), p);
1417 this->sps = reinterpret_cast<uint64_t*>(p);
1418 MoveToBinaryFormat(sps.data(), sps.size(), p);
1419 UpdateBinary(new_binary);
1420 }
1421
DumpData(size_t indent) const1422 void CallChainRecord::DumpData(size_t indent) const {
1423 const char* type_name = "";
1424 switch (chain_type) {
1425 case CallChainJoiner::ORIGINAL_OFFLINE:
1426 type_name = "ORIGINAL_OFFLINE";
1427 break;
1428 case CallChainJoiner::ORIGINAL_REMOTE:
1429 type_name = "ORIGINAL_REMOTE";
1430 break;
1431 case CallChainJoiner::JOINED_OFFLINE:
1432 type_name = "JOINED_OFFLINE";
1433 break;
1434 case CallChainJoiner::JOINED_REMOTE:
1435 type_name = "JOINED_REMOTE";
1436 break;
1437 }
1438 PrintIndented(indent, "pid %u\n", pid);
1439 PrintIndented(indent, "tid %u\n", tid);
1440 PrintIndented(indent, "chain_type %s\n", type_name);
1441 PrintIndented(indent, "time %" PRIu64 "\n", time);
1442 PrintIndented(indent, "ip_nr %" PRIu64 "\n", ip_nr);
1443 for (size_t i = 0; i < ip_nr; ++i) {
1444 PrintIndented(indent + 1, "ip 0x%" PRIx64 ", sp 0x%" PRIx64 "\n", ips[i], sps[i]);
1445 }
1446 }
1447
Parse(const perf_event_attr &,char * p,char * end)1448 bool UnwindingResultRecord::Parse(const perf_event_attr&, char* p, char* end) {
1449 if (!ParseHeader(p, end)) {
1450 return false;
1451 }
1452 CHECK_SIZE_U64(p, end, 8);
1453 MoveFromBinaryFormat(time, p);
1454 MoveFromBinaryFormat(unwinding_result.used_time, p);
1455 MoveFromBinaryFormat(unwinding_result.error_code, p);
1456 MoveFromBinaryFormat(unwinding_result.error_addr, p);
1457 MoveFromBinaryFormat(unwinding_result.stack_start, p);
1458 MoveFromBinaryFormat(unwinding_result.stack_end, p);
1459
1460 // regs_user_data
1461 MoveFromBinaryFormat(regs_user_data.abi, p);
1462 MoveFromBinaryFormat(regs_user_data.reg_mask, p);
1463 size_t bit_nr = __builtin_popcountll(regs_user_data.reg_mask);
1464 CHECK_SIZE_U64(p, end, bit_nr);
1465 regs_user_data.reg_nr = bit_nr;
1466 regs_user_data.regs = reinterpret_cast<uint64_t*>(p);
1467 p += bit_nr * sizeof(uint64_t);
1468
1469 // stack_user_data
1470 CHECK_SIZE_U64(p, end, 1);
1471 MoveFromBinaryFormat(stack_user_data.size, p);
1472 if (stack_user_data.size == 0) {
1473 stack_user_data.dyn_size = 0;
1474 } else {
1475 CHECK_SIZE(p, end, stack_user_data.size + sizeof(uint64_t));
1476 stack_user_data.data = p;
1477 p += stack_user_data.size;
1478 MoveFromBinaryFormat(stack_user_data.dyn_size, p);
1479 }
1480
1481 // callchain
1482 if (p < end) {
1483 CHECK_SIZE_U64(p, end, 1);
1484 MoveFromBinaryFormat(callchain.length, p);
1485 CHECK_SIZE_U64(p, end, callchain.length * 2);
1486 callchain.ips = reinterpret_cast<uint64_t*>(p);
1487 p += callchain.length * sizeof(uint64_t);
1488 callchain.sps = reinterpret_cast<uint64_t*>(p);
1489 p += callchain.length * sizeof(uint64_t);
1490 }
1491 return true;
1492 }
1493
UnwindingResultRecord(uint64_t time,const UnwindingResult & unwinding_result,const PerfSampleRegsUserType & regs_user_data,const PerfSampleStackUserType & stack_user_data,const std::vector<uint64_t> & ips,const std::vector<uint64_t> & sps)1494 UnwindingResultRecord::UnwindingResultRecord(uint64_t time, const UnwindingResult& unwinding_result,
1495 const PerfSampleRegsUserType& regs_user_data,
1496 const PerfSampleStackUserType& stack_user_data,
1497 const std::vector<uint64_t>& ips,
1498 const std::vector<uint64_t>& sps) {
1499 SetTypeAndMisc(SIMPLE_PERF_RECORD_UNWINDING_RESULT, 0);
1500 uint32_t size = header_size() + 6 * sizeof(uint64_t);
1501 size += (2 + regs_user_data.reg_nr) * sizeof(uint64_t);
1502 size +=
1503 stack_user_data.size == 0 ? sizeof(uint64_t) : (2 * sizeof(uint64_t) + stack_user_data.size);
1504 CHECK_EQ(ips.size(), sps.size());
1505 size += (1 + ips.size() * 2) * sizeof(uint64_t);
1506 SetSize(size);
1507 this->time = time;
1508 this->unwinding_result = unwinding_result;
1509 char* new_binary = new char[size];
1510 char* p = new_binary;
1511 MoveToBinaryFormat(header, p);
1512 MoveToBinaryFormat(this->time, p);
1513 MoveToBinaryFormat(unwinding_result.used_time, p);
1514 MoveToBinaryFormat(unwinding_result.error_code, p);
1515 MoveToBinaryFormat(unwinding_result.error_addr, p);
1516 MoveToBinaryFormat(unwinding_result.stack_start, p);
1517 MoveToBinaryFormat(unwinding_result.stack_end, p);
1518 MoveToBinaryFormat(regs_user_data.abi, p);
1519 MoveToBinaryFormat(regs_user_data.reg_mask, p);
1520 if (regs_user_data.reg_nr > 0) {
1521 MoveToBinaryFormat(regs_user_data.regs, regs_user_data.reg_nr, p);
1522 }
1523 MoveToBinaryFormat(stack_user_data.size, p);
1524 if (stack_user_data.size > 0) {
1525 MoveToBinaryFormat(stack_user_data.data, stack_user_data.size, p);
1526 MoveToBinaryFormat(stack_user_data.dyn_size, p);
1527 }
1528 MoveToBinaryFormat(static_cast<uint64_t>(ips.size()), p);
1529 MoveToBinaryFormat(ips.data(), ips.size(), p);
1530 MoveToBinaryFormat(sps.data(), sps.size(), p);
1531 CHECK_EQ(p, new_binary + size);
1532 UpdateBinary(new_binary);
1533 }
1534
DumpData(size_t indent) const1535 void UnwindingResultRecord::DumpData(size_t indent) const {
1536 PrintIndented(indent, "time %" PRIu64 "\n", time);
1537 PrintIndented(indent, "used_time %" PRIu64 "\n", unwinding_result.used_time);
1538 PrintIndented(indent, "error_code %" PRIu64 "\n", unwinding_result.error_code);
1539 PrintIndented(indent, "error_addr 0x%" PRIx64 "\n", unwinding_result.error_addr);
1540 PrintIndented(indent, "stack_start 0x%" PRIx64 "\n", unwinding_result.stack_start);
1541 PrintIndented(indent, "stack_end 0x%" PRIx64 "\n", unwinding_result.stack_end);
1542 if (regs_user_data.reg_nr > 0) {
1543 PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
1544 RegSet regs(regs_user_data.abi, regs_user_data.reg_mask, regs_user_data.regs);
1545 for (size_t i = 0; i < 64; ++i) {
1546 uint64_t value;
1547 if (regs.GetRegValue(i, &value)) {
1548 PrintIndented(indent + 1, "reg (%s) 0x%016" PRIx64 "\n", GetRegName(i, regs.arch).c_str(),
1549 value);
1550 }
1551 }
1552 }
1553 if (stack_user_data.size > 0) {
1554 PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n", stack_user_data.size,
1555 stack_user_data.dyn_size);
1556 const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
1557 const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
1558 while (p < end) {
1559 PrintIndented(indent + 1, "");
1560 for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
1561 printf(" %016" PRIx64, *p);
1562 }
1563 printf("\n");
1564 }
1565 printf("\n");
1566 }
1567 if (callchain.length > 0) {
1568 PrintIndented(indent, "callchain length=%" PRIu64 ":\n", callchain.length);
1569 for (uint64_t i = 0; i < callchain.length; i++) {
1570 PrintIndented(indent + 1, "ip_%" PRIu64 ": 0x%" PRIx64 "\n", i + 1, callchain.ips[i]);
1571 PrintIndented(indent + 1, "sp_%" PRIu64 ": 0x%" PRIx64 "\n", i + 1, callchain.sps[i]);
1572 }
1573 }
1574 }
1575
Parse(const perf_event_attr &,char * p,char * end)1576 bool UnknownRecord::Parse(const perf_event_attr&, char* p, char* end) {
1577 if (!ParseHeader(p, end)) {
1578 return false;
1579 }
1580 data = p;
1581 return true;
1582 }
1583
DumpData(size_t) const1584 void UnknownRecord::DumpData(size_t) const {}
1585
ReadRecordFromBuffer(const perf_event_attr & attr,uint32_t type,char * p,char * end)1586 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32_t type, char* p,
1587 char* end) {
1588 std::unique_ptr<Record> r;
1589 switch (type) {
1590 case PERF_RECORD_MMAP:
1591 r.reset(new MmapRecord);
1592 break;
1593 case PERF_RECORD_MMAP2:
1594 r.reset(new Mmap2Record);
1595 break;
1596 case PERF_RECORD_COMM:
1597 r.reset(new CommRecord);
1598 break;
1599 case PERF_RECORD_EXIT:
1600 r.reset(new ExitRecord);
1601 break;
1602 case PERF_RECORD_FORK:
1603 r.reset(new ForkRecord);
1604 break;
1605 case PERF_RECORD_LOST:
1606 r.reset(new LostRecord);
1607 break;
1608 case PERF_RECORD_SAMPLE:
1609 r.reset(new SampleRecord);
1610 break;
1611 case PERF_RECORD_AUX:
1612 r.reset(new AuxRecord);
1613 break;
1614 case PERF_RECORD_SWITCH:
1615 r.reset(new SwitchRecord);
1616 break;
1617 case PERF_RECORD_SWITCH_CPU_WIDE:
1618 r.reset(new SwitchCpuWideRecord);
1619 break;
1620 case PERF_RECORD_TRACING_DATA:
1621 r.reset(new TracingDataRecord);
1622 break;
1623 case PERF_RECORD_AUXTRACE_INFO:
1624 r.reset(new AuxTraceInfoRecord);
1625 break;
1626 case PERF_RECORD_AUXTRACE:
1627 r.reset(new AuxTraceRecord);
1628 break;
1629 case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
1630 r.reset(new KernelSymbolRecord);
1631 break;
1632 case SIMPLE_PERF_RECORD_DSO:
1633 r.reset(new DsoRecord);
1634 break;
1635 case SIMPLE_PERF_RECORD_SYMBOL:
1636 r.reset(new SymbolRecord);
1637 break;
1638 case SIMPLE_PERF_RECORD_EVENT_ID:
1639 r.reset(new EventIdRecord);
1640 break;
1641 case SIMPLE_PERF_RECORD_CALLCHAIN:
1642 r.reset(new CallChainRecord);
1643 break;
1644 case SIMPLE_PERF_RECORD_UNWINDING_RESULT:
1645 r.reset(new UnwindingResultRecord);
1646 break;
1647 case SIMPLE_PERF_RECORD_TRACING_DATA:
1648 r.reset(new TracingDataRecord);
1649 break;
1650 default:
1651 r.reset(new UnknownRecord);
1652 break;
1653 }
1654 if (UNLIKELY(!r->Parse(attr, p, end))) {
1655 LOG(ERROR) << "failed to parse record " << RecordTypeToString(type);
1656 return nullptr;
1657 }
1658 return r;
1659 }
1660
ReadRecordsFromBuffer(const perf_event_attr & attr,char * buf,size_t buf_size)1661 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(const perf_event_attr& attr, char* buf,
1662 size_t buf_size) {
1663 std::vector<std::unique_ptr<Record>> result;
1664 char* p = buf;
1665 char* end = buf + buf_size;
1666 while (p < end) {
1667 std::unique_ptr<Record> r = ReadRecordFromBuffer(attr, p, end);
1668 if (!r) {
1669 return {};
1670 }
1671 p += r->size();
1672 result.emplace_back(std::move(r));
1673 }
1674 return result;
1675 }
1676
ReadRecordFromBuffer(const perf_event_attr & attr,char * p,char * end)1677 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, char* p, char* end) {
1678 auto header = reinterpret_cast<const perf_event_header*>(p);
1679 return ReadRecordFromBuffer(attr, header->type, p, end);
1680 }
1681
1682 } // namespace simpleperf
1683