Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128/* SPDX-License-Identifier: GPL-2.0 */#include "sample.h"#include "debug.h"#include "thread.h"#include <elf.h>#ifndef EM_CSKY#define EM_CSKY 252#endif#ifndef EM_LOONGARCH#define EM_LOONGARCH 258#endif#include <linux/zalloc.h>#include <stdlib.h>#include <string.h>#include "../../arch/x86/include/asm/insn.h"
void perf_sample__init(struct perf_sample *sample, bool all){ if (all) { memset(sample, 0, sizeof(*sample)); } else { sample->evsel = NULL; sample->user_regs = NULL; sample->intr_regs = NULL; sample->merged_callchain = false; sample->callchain = NULL; }}
void perf_sample__exit(struct perf_sample *sample){ zfree(&sample->user_regs); zfree(&sample->intr_regs); if (sample->merged_callchain) { zfree(&sample->callchain); sample->merged_callchain = false; }}
struct regs_dump *perf_sample__user_regs(struct perf_sample *sample){ if (!sample->user_regs) { sample->user_regs = zalloc(sizeof(*sample->user_regs)); if (!sample->user_regs) pr_err("Failure to allocate sample user_regs"); } return sample->user_regs;}
struct regs_dump *perf_sample__intr_regs(struct perf_sample *sample){ if (!sample->intr_regs) { sample->intr_regs = zalloc(sizeof(*sample->intr_regs)); if (!sample->intr_regs) pr_err("Failure to allocate sample intr_regs"); } return sample->intr_regs;}
static int elf_machine_max_instruction_length(uint16_t e_machine){ switch (e_machine) { /* Fixed 4-byte (32-bit) architectures */ case EM_AARCH64: case EM_PPC: case EM_PPC64: case EM_MIPS: case EM_SPARC: case EM_SPARCV9: case EM_ALPHA: case EM_LOONGARCH: case EM_PARISC: case EM_SH: return 4;
/* Variable length or mixed-mode architectures */ case EM_ARM: /* Variable due to Thumb/Thumb-2 */ case EM_RISCV: /* Variable due to Compressed (C) extension */ case EM_CSKY: /* Variable (16 or 32 bit) */ case EM_ARC: /* Variable (ARCompact) */ return 4; case EM_S390: /* Variable (2, 4, or 6 bytes) */ return 6; case EM_68K: return 10; case EM_386: case EM_X86_64: return 15; case EM_XTENSA: /* Variable (FLIX) */ return 16; default: return MAX_INSN; }}
void perf_sample__fetch_insn(struct perf_sample *sample, struct thread *thread, struct machine *machine){ int ret, len; bool is64bit = false; uint16_t e_machine;
if (!sample->ip || sample->insn_len != 0) return;
e_machine = thread__e_machine(thread, machine, /*e_flags=*/NULL); len = elf_machine_max_instruction_length(e_machine); len = thread__memcpy(thread, machine, sample->insn, sample->ip, len, &is64bit); if (len <= 0) return;
sample->insn_len = len;
if (e_machine == EM_386 || e_machine == EM_X86_64) { /* Refine the x86 instruction length with the decoder. */ struct insn insn;
ret = insn_decode(&insn, sample->insn, len, is64bit ? INSN_MODE_64 : INSN_MODE_32); if (ret >= 0 && insn.length <= len) sample->insn_len = insn.length; }}