162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <string.h>
362306a36Sopenharmony_ci#include "perf_regs.h"
462306a36Sopenharmony_ci#include "thread.h"
562306a36Sopenharmony_ci#include "map.h"
662306a36Sopenharmony_ci#include "maps.h"
762306a36Sopenharmony_ci#include "event.h"
862306a36Sopenharmony_ci#include "debug.h"
962306a36Sopenharmony_ci#include "tests/tests.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define STACK_SIZE 8192
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic int sample_ustack(struct perf_sample *sample,
1462306a36Sopenharmony_ci			 struct thread *thread, u64 *regs)
1562306a36Sopenharmony_ci{
1662306a36Sopenharmony_ci	struct stack_dump *stack = &sample->user_stack;
1762306a36Sopenharmony_ci	struct map *map;
1862306a36Sopenharmony_ci	unsigned long sp;
1962306a36Sopenharmony_ci	u64 stack_size, *buf;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci	buf = malloc(STACK_SIZE);
2262306a36Sopenharmony_ci	if (!buf) {
2362306a36Sopenharmony_ci		pr_debug("failed to allocate sample uregs data\n");
2462306a36Sopenharmony_ci		return -1;
2562306a36Sopenharmony_ci	}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	sp = (unsigned long) regs[PERF_REG_X86_SP];
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	map = maps__find(thread__maps(thread), (u64)sp);
3062306a36Sopenharmony_ci	if (!map) {
3162306a36Sopenharmony_ci		pr_debug("failed to get stack map\n");
3262306a36Sopenharmony_ci		free(buf);
3362306a36Sopenharmony_ci		return -1;
3462306a36Sopenharmony_ci	}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	stack_size = map__end(map) - sp;
3762306a36Sopenharmony_ci	stack_size = stack_size > STACK_SIZE ? STACK_SIZE : stack_size;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	memcpy(buf, (void *) sp, stack_size);
4062306a36Sopenharmony_ci#ifdef MEMORY_SANITIZER
4162306a36Sopenharmony_ci	/*
4262306a36Sopenharmony_ci	 * Copying the stack may copy msan poison, avoid false positives in the
4362306a36Sopenharmony_ci	 * unwinder by removing the poison here.
4462306a36Sopenharmony_ci	 */
4562306a36Sopenharmony_ci	__msan_unpoison(buf, stack_size);
4662306a36Sopenharmony_ci#endif
4762306a36Sopenharmony_ci	stack->data = (char *) buf;
4862306a36Sopenharmony_ci	stack->size = stack_size;
4962306a36Sopenharmony_ci	return 0;
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ciint test__arch_unwind_sample(struct perf_sample *sample,
5362306a36Sopenharmony_ci			     struct thread *thread)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct regs_dump *regs = &sample->user_regs;
5662306a36Sopenharmony_ci	u64 *buf;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	buf = malloc(sizeof(u64) * PERF_REGS_MAX);
5962306a36Sopenharmony_ci	if (!buf) {
6062306a36Sopenharmony_ci		pr_debug("failed to allocate sample uregs data\n");
6162306a36Sopenharmony_ci		return -1;
6262306a36Sopenharmony_ci	}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci#ifdef MEMORY_SANITIZER
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * Assignments to buf in the assembly function perf_regs_load aren't
6762306a36Sopenharmony_ci	 * seen by memory sanitizer. Zero the memory to convince memory
6862306a36Sopenharmony_ci	 * sanitizer the memory is initialized.
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	memset(buf, 0, sizeof(u64) * PERF_REGS_MAX);
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci	perf_regs_load(buf);
7362306a36Sopenharmony_ci	regs->abi  = PERF_SAMPLE_REGS_ABI;
7462306a36Sopenharmony_ci	regs->regs = buf;
7562306a36Sopenharmony_ci	regs->mask = PERF_REGS_MASK;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	return sample_ustack(sample, thread, buf);
7862306a36Sopenharmony_ci}
79