| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- /* 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->user_regs = NULL;
- sample->intr_regs = NULL;
- }
- }
- void perf_sample__exit(struct perf_sample *sample)
- {
- free(sample->user_regs);
- free(sample->intr_regs);
- }
- 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;
- }
- }
|