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 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 <> 68 void MoveToBinaryFormat(const RecordHeader& data, char*& p) { 69 data.MoveToBinaryFormat(p); 70 } 71 72 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); } 73 74 // Return sample_id size in binary format. 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 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 113 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 133 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 156 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 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 190 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 197 uint64_t Record::Timestamp() const { return sample_id.time_data.time; } 198 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; } 199 uint64_t Record::Id() const { return sample_id.id_data.id; } 200 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 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 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 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 253 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 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 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 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 304 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 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 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 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 372 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 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 387 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 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 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 421 void LostRecord::DumpData(size_t indent) const { 422 PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost); 423 } 424 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 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 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 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 637 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 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 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 725 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 802 uint64_t SampleRecord::Timestamp() const { return time_data.time; } 803 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; } 804 uint64_t SampleRecord::Id() const { return id_data.id; } 805 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 841 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 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 888 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 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 905 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 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 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 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 958 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 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 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 1005 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 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 1023 void KernelSymbolRecord::DumpData(size_t indent) const { 1024 PrintIndented(indent, "kallsyms: %s\n", 1025 std::string(kallsyms, kallsyms + kallsyms_size).c_str()); 1026 } 1027 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 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 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 1070 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 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 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 1107 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 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 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 1136 void TracingDataRecord::DumpData(size_t indent) const { 1137 Tracing tracing(std::vector<char>(data, data + data_size)); 1138 tracing.Dump(indent); 1139 } 1140 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 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 1163 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 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 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 1214 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 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 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 1265 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 1290 UnknownRecord::UnknownRecord(char* p) : Record(p) { 1291 p += header_size(); 1292 data = p; 1293 } 1294 1295 void UnknownRecord::DumpData(size_t) const {} 1296 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 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 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 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