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