int perf_event__parse_sample(const union perf_event *event, u64 type, int sample_size, bool sample_id_all, struct perf_sample *data, bool swapped) { const u64 *array; /* * used for cross-endian analysis. See git commit 65014ab3 * for why this goofiness is needed. */ union { u64 val64; u32 val32[2]; } u; memset(data, 0, sizeof(*data)); data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; data->period = 1; if (event->header.type != PERF_RECORD_SAMPLE) { if (!sample_id_all) return 0; return perf_event__parse_id_sample(event, type, data); } array = event->sample.array; if (sample_size + sizeof(event->header) > event->header.size) return -EFAULT; if (type & PERF_SAMPLE_IP) { data->ip = event->ip.ip; array++; } if (type & PERF_SAMPLE_TID) { u.val64 = *array; if (swapped) { /* undo swap of u64, then swap on individual u32s */ u.val64 = bswap_64(u.val64); u.val32[0] = bswap_32(u.val32[0]); u.val32[1] = bswap_32(u.val32[1]); } data->pid = u.val32[0]; data->tid = u.val32[1]; array++; } if (type & PERF_SAMPLE_TIME) { data->time = *array; array++; } data->addr = 0; if (type & PERF_SAMPLE_ADDR) { data->addr = *array; array++; } data->id = -1ULL; if (type & PERF_SAMPLE_ID) { data->id = *array; array++; } if (type & PERF_SAMPLE_STREAM_ID) { data->stream_id = *array; array++; } if (type & PERF_SAMPLE_CPU) { u.val64 = *array; if (swapped) { /* undo swap of u64, then swap on individual u32s */ u.val64 = bswap_64(u.val64); u.val32[0] = bswap_32(u.val32[0]); } data->cpu = u.val32[0]; array++; } if (type & PERF_SAMPLE_PERIOD) { data->period = *array; array++; } if (type & PERF_SAMPLE_READ) { fprintf(stderr, "PERF_SAMPLE_READ is unsupported for now\n"); return -1; } if (type & PERF_SAMPLE_CALLCHAIN) { if (sample_overlap(event, array, sizeof(data->callchain->nr))) return -EFAULT; data->callchain = (struct ip_callchain *)array; if (sample_overlap(event, array, data->callchain->nr)) return -EFAULT; array += 1 + data->callchain->nr; } if (type & PERF_SAMPLE_RAW) { const u64 *pdata; u.val64 = *array; if (WARN_ONCE(swapped, "Endianness of raw data not corrected!\n")) { /* undo swap of u64, then swap on individual u32s */ u.val64 = bswap_64(u.val64); u.val32[0] = bswap_32(u.val32[0]); u.val32[1] = bswap_32(u.val32[1]); } if (sample_overlap(event, array, sizeof(u32))) return -EFAULT; data->raw_size = u.val32[0]; pdata = (void *) array + sizeof(u32); if (sample_overlap(event, pdata, data->raw_size)) return -EFAULT; data->raw_data = (void *) pdata; } if (type & PERF_SAMPLE_BRANCH_STACK) { u64 sz; data->branch_stack = (struct branch_stack *)array; array++; /* nr */ sz = data->branch_stack->nr * sizeof(struct branch_entry); sz /= sizeof(u64); array += sz; } return 0; }
int perf_event__parse_sample(const union perf_event *event, u64 type, int sample_size, bool sample_id_all, struct perf_sample *data) { const u64 *array; data->cpu = data->pid = data->tid = -1; data->stream_id = data->id = data->time = -1ULL; if (event->header.type != PERF_RECORD_SAMPLE) { if (!sample_id_all) return 0; return perf_event__parse_id_sample(event, type, data); } array = event->sample.array; if (sample_size + sizeof(event->header) > event->header.size) return -EFAULT; if (type & PERF_SAMPLE_IP) { data->ip = event->ip.ip; array++; } if (type & PERF_SAMPLE_TID) { u32 *p = (u32 *)array; data->pid = p[0]; data->tid = p[1]; array++; } if (type & PERF_SAMPLE_TIME) { data->time = *array; array++; } if (type & PERF_SAMPLE_ADDR) { data->addr = *array; array++; } data->id = -1ULL; if (type & PERF_SAMPLE_ID) { data->id = *array; array++; } if (type & PERF_SAMPLE_STREAM_ID) { data->stream_id = *array; array++; } if (type & PERF_SAMPLE_CPU) { u32 *p = (u32 *)array; data->cpu = *p; array++; } if (type & PERF_SAMPLE_PERIOD) { data->period = *array; array++; } if (type & PERF_SAMPLE_READ) { fprintf(stderr, "PERF_SAMPLE_READ is unsuported for now\n"); return -1; } if (type & PERF_SAMPLE_CALLCHAIN) { if (sample_overlap(event, array, sizeof(data->callchain->nr))) return -EFAULT; data->callchain = (struct ip_callchain *)array; if (sample_overlap(event, array, data->callchain->nr)) return -EFAULT; array += 1 + data->callchain->nr; } if (type & PERF_SAMPLE_RAW) { u32 *p = (u32 *)array; if (sample_overlap(event, array, sizeof(u32))) return -EFAULT; data->raw_size = *p; p++; if (sample_overlap(event, p, data->raw_size)) return -EFAULT; data->raw_data = p; } return 0; }