18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * thread-stack.c: Synthesize a thread's stack using call / return events
48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/rbtree.h>
88c2ecf20Sopenharmony_ci#include <linux/list.h>
98c2ecf20Sopenharmony_ci#include <linux/log2.h>
108c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
118c2ecf20Sopenharmony_ci#include <errno.h>
128c2ecf20Sopenharmony_ci#include <stdlib.h>
138c2ecf20Sopenharmony_ci#include <string.h>
148c2ecf20Sopenharmony_ci#include "thread.h"
158c2ecf20Sopenharmony_ci#include "event.h"
168c2ecf20Sopenharmony_ci#include "machine.h"
178c2ecf20Sopenharmony_ci#include "env.h"
188c2ecf20Sopenharmony_ci#include "debug.h"
198c2ecf20Sopenharmony_ci#include "symbol.h"
208c2ecf20Sopenharmony_ci#include "comm.h"
218c2ecf20Sopenharmony_ci#include "call-path.h"
228c2ecf20Sopenharmony_ci#include "thread-stack.h"
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define STACK_GROWTH 2048
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * State of retpoline detection.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * RETPOLINE_NONE: no retpoline detection
308c2ecf20Sopenharmony_ci * X86_RETPOLINE_POSSIBLE: x86 retpoline possible
318c2ecf20Sopenharmony_ci * X86_RETPOLINE_DETECTED: x86 retpoline detected
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_cienum retpoline_state_t {
348c2ecf20Sopenharmony_ci	RETPOLINE_NONE,
358c2ecf20Sopenharmony_ci	X86_RETPOLINE_POSSIBLE,
368c2ecf20Sopenharmony_ci	X86_RETPOLINE_DETECTED,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/**
408c2ecf20Sopenharmony_ci * struct thread_stack_entry - thread stack entry.
418c2ecf20Sopenharmony_ci * @ret_addr: return address
428c2ecf20Sopenharmony_ci * @timestamp: timestamp (if known)
438c2ecf20Sopenharmony_ci * @ref: external reference (e.g. db_id of sample)
448c2ecf20Sopenharmony_ci * @branch_count: the branch count when the entry was created
458c2ecf20Sopenharmony_ci * @insn_count: the instruction count when the entry was created
468c2ecf20Sopenharmony_ci * @cyc_count the cycle count when the entry was created
478c2ecf20Sopenharmony_ci * @db_id: id used for db-export
488c2ecf20Sopenharmony_ci * @cp: call path
498c2ecf20Sopenharmony_ci * @no_call: a 'call' was not seen
508c2ecf20Sopenharmony_ci * @trace_end: a 'call' but trace ended
518c2ecf20Sopenharmony_ci * @non_call: a branch but not a 'call' to the start of a different symbol
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_cistruct thread_stack_entry {
548c2ecf20Sopenharmony_ci	u64 ret_addr;
558c2ecf20Sopenharmony_ci	u64 timestamp;
568c2ecf20Sopenharmony_ci	u64 ref;
578c2ecf20Sopenharmony_ci	u64 branch_count;
588c2ecf20Sopenharmony_ci	u64 insn_count;
598c2ecf20Sopenharmony_ci	u64 cyc_count;
608c2ecf20Sopenharmony_ci	u64 db_id;
618c2ecf20Sopenharmony_ci	struct call_path *cp;
628c2ecf20Sopenharmony_ci	bool no_call;
638c2ecf20Sopenharmony_ci	bool trace_end;
648c2ecf20Sopenharmony_ci	bool non_call;
658c2ecf20Sopenharmony_ci};
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/**
688c2ecf20Sopenharmony_ci * struct thread_stack - thread stack constructed from 'call' and 'return'
698c2ecf20Sopenharmony_ci *                       branch samples.
708c2ecf20Sopenharmony_ci * @stack: array that holds the stack
718c2ecf20Sopenharmony_ci * @cnt: number of entries in the stack
728c2ecf20Sopenharmony_ci * @sz: current maximum stack size
738c2ecf20Sopenharmony_ci * @trace_nr: current trace number
748c2ecf20Sopenharmony_ci * @branch_count: running branch count
758c2ecf20Sopenharmony_ci * @insn_count: running  instruction count
768c2ecf20Sopenharmony_ci * @cyc_count running  cycle count
778c2ecf20Sopenharmony_ci * @kernel_start: kernel start address
788c2ecf20Sopenharmony_ci * @last_time: last timestamp
798c2ecf20Sopenharmony_ci * @crp: call/return processor
808c2ecf20Sopenharmony_ci * @comm: current comm
818c2ecf20Sopenharmony_ci * @arr_sz: size of array if this is the first element of an array
828c2ecf20Sopenharmony_ci * @rstate: used to detect retpolines
838c2ecf20Sopenharmony_ci * @br_stack_rb: branch stack (ring buffer)
848c2ecf20Sopenharmony_ci * @br_stack_sz: maximum branch stack size
858c2ecf20Sopenharmony_ci * @br_stack_pos: current position in @br_stack_rb
868c2ecf20Sopenharmony_ci * @mispred_all: mark all branches as mispredicted
878c2ecf20Sopenharmony_ci */
888c2ecf20Sopenharmony_cistruct thread_stack {
898c2ecf20Sopenharmony_ci	struct thread_stack_entry *stack;
908c2ecf20Sopenharmony_ci	size_t cnt;
918c2ecf20Sopenharmony_ci	size_t sz;
928c2ecf20Sopenharmony_ci	u64 trace_nr;
938c2ecf20Sopenharmony_ci	u64 branch_count;
948c2ecf20Sopenharmony_ci	u64 insn_count;
958c2ecf20Sopenharmony_ci	u64 cyc_count;
968c2ecf20Sopenharmony_ci	u64 kernel_start;
978c2ecf20Sopenharmony_ci	u64 last_time;
988c2ecf20Sopenharmony_ci	struct call_return_processor *crp;
998c2ecf20Sopenharmony_ci	struct comm *comm;
1008c2ecf20Sopenharmony_ci	unsigned int arr_sz;
1018c2ecf20Sopenharmony_ci	enum retpoline_state_t rstate;
1028c2ecf20Sopenharmony_ci	struct branch_stack *br_stack_rb;
1038c2ecf20Sopenharmony_ci	unsigned int br_stack_sz;
1048c2ecf20Sopenharmony_ci	unsigned int br_stack_pos;
1058c2ecf20Sopenharmony_ci	bool mispred_all;
1068c2ecf20Sopenharmony_ci};
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci/*
1098c2ecf20Sopenharmony_ci * Assume pid == tid == 0 identifies the idle task as defined by
1108c2ecf20Sopenharmony_ci * perf_session__register_idle_thread(). The idle task is really 1 task per cpu,
1118c2ecf20Sopenharmony_ci * and therefore requires a stack for each cpu.
1128c2ecf20Sopenharmony_ci */
1138c2ecf20Sopenharmony_cistatic inline bool thread_stack__per_cpu(struct thread *thread)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	return !(thread->tid || thread->pid_);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int thread_stack__grow(struct thread_stack *ts)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct thread_stack_entry *new_stack;
1218c2ecf20Sopenharmony_ci	size_t sz, new_sz;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	new_sz = ts->sz + STACK_GROWTH;
1248c2ecf20Sopenharmony_ci	sz = new_sz * sizeof(struct thread_stack_entry);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	new_stack = realloc(ts->stack, sz);
1278c2ecf20Sopenharmony_ci	if (!new_stack)
1288c2ecf20Sopenharmony_ci		return -ENOMEM;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ts->stack = new_stack;
1318c2ecf20Sopenharmony_ci	ts->sz = new_sz;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return 0;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic int thread_stack__init(struct thread_stack *ts, struct thread *thread,
1378c2ecf20Sopenharmony_ci			      struct call_return_processor *crp,
1388c2ecf20Sopenharmony_ci			      bool callstack, unsigned int br_stack_sz)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	int err;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (callstack) {
1438c2ecf20Sopenharmony_ci		err = thread_stack__grow(ts);
1448c2ecf20Sopenharmony_ci		if (err)
1458c2ecf20Sopenharmony_ci			return err;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	if (br_stack_sz) {
1498c2ecf20Sopenharmony_ci		size_t sz = sizeof(struct branch_stack);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		sz += br_stack_sz * sizeof(struct branch_entry);
1528c2ecf20Sopenharmony_ci		ts->br_stack_rb = zalloc(sz);
1538c2ecf20Sopenharmony_ci		if (!ts->br_stack_rb)
1548c2ecf20Sopenharmony_ci			return -ENOMEM;
1558c2ecf20Sopenharmony_ci		ts->br_stack_sz = br_stack_sz;
1568c2ecf20Sopenharmony_ci	}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	if (thread->maps && thread->maps->machine) {
1598c2ecf20Sopenharmony_ci		struct machine *machine = thread->maps->machine;
1608c2ecf20Sopenharmony_ci		const char *arch = perf_env__arch(machine->env);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci		ts->kernel_start = machine__kernel_start(machine);
1638c2ecf20Sopenharmony_ci		if (!strcmp(arch, "x86"))
1648c2ecf20Sopenharmony_ci			ts->rstate = X86_RETPOLINE_POSSIBLE;
1658c2ecf20Sopenharmony_ci	} else {
1668c2ecf20Sopenharmony_ci		ts->kernel_start = 1ULL << 63;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	ts->crp = crp;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic struct thread_stack *thread_stack__new(struct thread *thread, int cpu,
1748c2ecf20Sopenharmony_ci					      struct call_return_processor *crp,
1758c2ecf20Sopenharmony_ci					      bool callstack,
1768c2ecf20Sopenharmony_ci					      unsigned int br_stack_sz)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread->ts, *new_ts;
1798c2ecf20Sopenharmony_ci	unsigned int old_sz = ts ? ts->arr_sz : 0;
1808c2ecf20Sopenharmony_ci	unsigned int new_sz = 1;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (thread_stack__per_cpu(thread) && cpu > 0)
1838c2ecf20Sopenharmony_ci		new_sz = roundup_pow_of_two(cpu + 1);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (!ts || new_sz > old_sz) {
1868c2ecf20Sopenharmony_ci		new_ts = calloc(new_sz, sizeof(*ts));
1878c2ecf20Sopenharmony_ci		if (!new_ts)
1888c2ecf20Sopenharmony_ci			return NULL;
1898c2ecf20Sopenharmony_ci		if (ts)
1908c2ecf20Sopenharmony_ci			memcpy(new_ts, ts, old_sz * sizeof(*ts));
1918c2ecf20Sopenharmony_ci		new_ts->arr_sz = new_sz;
1928c2ecf20Sopenharmony_ci		zfree(&thread->ts);
1938c2ecf20Sopenharmony_ci		thread->ts = new_ts;
1948c2ecf20Sopenharmony_ci		ts = new_ts;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (thread_stack__per_cpu(thread) && cpu > 0 &&
1988c2ecf20Sopenharmony_ci	    (unsigned int)cpu < ts->arr_sz)
1998c2ecf20Sopenharmony_ci		ts += cpu;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (!ts->stack &&
2028c2ecf20Sopenharmony_ci	    thread_stack__init(ts, thread, crp, callstack, br_stack_sz))
2038c2ecf20Sopenharmony_ci		return NULL;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return ts;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic struct thread_stack *thread__cpu_stack(struct thread *thread, int cpu)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread->ts;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	if (cpu < 0)
2138c2ecf20Sopenharmony_ci		cpu = 0;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (!ts || (unsigned int)cpu >= ts->arr_sz)
2168c2ecf20Sopenharmony_ci		return NULL;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	ts += cpu;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!ts->stack)
2218c2ecf20Sopenharmony_ci		return NULL;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	return ts;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic inline struct thread_stack *thread__stack(struct thread *thread,
2278c2ecf20Sopenharmony_ci						    int cpu)
2288c2ecf20Sopenharmony_ci{
2298c2ecf20Sopenharmony_ci	if (!thread)
2308c2ecf20Sopenharmony_ci		return NULL;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (thread_stack__per_cpu(thread))
2338c2ecf20Sopenharmony_ci		return thread__cpu_stack(thread, cpu);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	return thread->ts;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int thread_stack__push(struct thread_stack *ts, u64 ret_addr,
2398c2ecf20Sopenharmony_ci			      bool trace_end)
2408c2ecf20Sopenharmony_ci{
2418c2ecf20Sopenharmony_ci	int err = 0;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (ts->cnt == ts->sz) {
2448c2ecf20Sopenharmony_ci		err = thread_stack__grow(ts);
2458c2ecf20Sopenharmony_ci		if (err) {
2468c2ecf20Sopenharmony_ci			pr_warning("Out of memory: discarding thread stack\n");
2478c2ecf20Sopenharmony_ci			ts->cnt = 0;
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	ts->stack[ts->cnt].trace_end = trace_end;
2528c2ecf20Sopenharmony_ci	ts->stack[ts->cnt++].ret_addr = ret_addr;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return err;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
2588c2ecf20Sopenharmony_ci{
2598c2ecf20Sopenharmony_ci	size_t i;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/*
2628c2ecf20Sopenharmony_ci	 * In some cases there may be functions which are not seen to return.
2638c2ecf20Sopenharmony_ci	 * For example when setjmp / longjmp has been used.  Or the perf context
2648c2ecf20Sopenharmony_ci	 * switch in the kernel which doesn't stop and start tracing in exactly
2658c2ecf20Sopenharmony_ci	 * the same code path.  When that happens the return address will be
2668c2ecf20Sopenharmony_ci	 * further down the stack.  If the return address is not found at all,
2678c2ecf20Sopenharmony_ci	 * we assume the opposite (i.e. this is a return for a call that wasn't
2688c2ecf20Sopenharmony_ci	 * seen for some reason) and leave the stack alone.
2698c2ecf20Sopenharmony_ci	 */
2708c2ecf20Sopenharmony_ci	for (i = ts->cnt; i; ) {
2718c2ecf20Sopenharmony_ci		if (ts->stack[--i].ret_addr == ret_addr) {
2728c2ecf20Sopenharmony_ci			ts->cnt = i;
2738c2ecf20Sopenharmony_ci			return;
2748c2ecf20Sopenharmony_ci		}
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic void thread_stack__pop_trace_end(struct thread_stack *ts)
2798c2ecf20Sopenharmony_ci{
2808c2ecf20Sopenharmony_ci	size_t i;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	for (i = ts->cnt; i; ) {
2838c2ecf20Sopenharmony_ci		if (ts->stack[--i].trace_end)
2848c2ecf20Sopenharmony_ci			ts->cnt = i;
2858c2ecf20Sopenharmony_ci		else
2868c2ecf20Sopenharmony_ci			return;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic bool thread_stack__in_kernel(struct thread_stack *ts)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	if (!ts->cnt)
2938c2ecf20Sopenharmony_ci		return false;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	return ts->stack[ts->cnt - 1].cp->in_kernel;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int thread_stack__call_return(struct thread *thread,
2998c2ecf20Sopenharmony_ci				     struct thread_stack *ts, size_t idx,
3008c2ecf20Sopenharmony_ci				     u64 timestamp, u64 ref, bool no_return)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct call_return_processor *crp = ts->crp;
3038c2ecf20Sopenharmony_ci	struct thread_stack_entry *tse;
3048c2ecf20Sopenharmony_ci	struct call_return cr = {
3058c2ecf20Sopenharmony_ci		.thread = thread,
3068c2ecf20Sopenharmony_ci		.comm = ts->comm,
3078c2ecf20Sopenharmony_ci		.db_id = 0,
3088c2ecf20Sopenharmony_ci	};
3098c2ecf20Sopenharmony_ci	u64 *parent_db_id;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	tse = &ts->stack[idx];
3128c2ecf20Sopenharmony_ci	cr.cp = tse->cp;
3138c2ecf20Sopenharmony_ci	cr.call_time = tse->timestamp;
3148c2ecf20Sopenharmony_ci	cr.return_time = timestamp;
3158c2ecf20Sopenharmony_ci	cr.branch_count = ts->branch_count - tse->branch_count;
3168c2ecf20Sopenharmony_ci	cr.insn_count = ts->insn_count - tse->insn_count;
3178c2ecf20Sopenharmony_ci	cr.cyc_count = ts->cyc_count - tse->cyc_count;
3188c2ecf20Sopenharmony_ci	cr.db_id = tse->db_id;
3198c2ecf20Sopenharmony_ci	cr.call_ref = tse->ref;
3208c2ecf20Sopenharmony_ci	cr.return_ref = ref;
3218c2ecf20Sopenharmony_ci	if (tse->no_call)
3228c2ecf20Sopenharmony_ci		cr.flags |= CALL_RETURN_NO_CALL;
3238c2ecf20Sopenharmony_ci	if (no_return)
3248c2ecf20Sopenharmony_ci		cr.flags |= CALL_RETURN_NO_RETURN;
3258c2ecf20Sopenharmony_ci	if (tse->non_call)
3268c2ecf20Sopenharmony_ci		cr.flags |= CALL_RETURN_NON_CALL;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/*
3298c2ecf20Sopenharmony_ci	 * The parent db_id must be assigned before exporting the child. Note
3308c2ecf20Sopenharmony_ci	 * it is not possible to export the parent first because its information
3318c2ecf20Sopenharmony_ci	 * is not yet complete because its 'return' has not yet been processed.
3328c2ecf20Sopenharmony_ci	 */
3338c2ecf20Sopenharmony_ci	parent_db_id = idx ? &(tse - 1)->db_id : NULL;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	return crp->process(&cr, parent_db_id, crp->data);
3368c2ecf20Sopenharmony_ci}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic int __thread_stack__flush(struct thread *thread, struct thread_stack *ts)
3398c2ecf20Sopenharmony_ci{
3408c2ecf20Sopenharmony_ci	struct call_return_processor *crp = ts->crp;
3418c2ecf20Sopenharmony_ci	int err;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	if (!crp) {
3448c2ecf20Sopenharmony_ci		ts->cnt = 0;
3458c2ecf20Sopenharmony_ci		ts->br_stack_pos = 0;
3468c2ecf20Sopenharmony_ci		if (ts->br_stack_rb)
3478c2ecf20Sopenharmony_ci			ts->br_stack_rb->nr = 0;
3488c2ecf20Sopenharmony_ci		return 0;
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	while (ts->cnt) {
3528c2ecf20Sopenharmony_ci		err = thread_stack__call_return(thread, ts, --ts->cnt,
3538c2ecf20Sopenharmony_ci						ts->last_time, 0, true);
3548c2ecf20Sopenharmony_ci		if (err) {
3558c2ecf20Sopenharmony_ci			pr_err("Error flushing thread stack!\n");
3568c2ecf20Sopenharmony_ci			ts->cnt = 0;
3578c2ecf20Sopenharmony_ci			return err;
3588c2ecf20Sopenharmony_ci		}
3598c2ecf20Sopenharmony_ci	}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return 0;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ciint thread_stack__flush(struct thread *thread)
3658c2ecf20Sopenharmony_ci{
3668c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread->ts;
3678c2ecf20Sopenharmony_ci	unsigned int pos;
3688c2ecf20Sopenharmony_ci	int err = 0;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	if (ts) {
3718c2ecf20Sopenharmony_ci		for (pos = 0; pos < ts->arr_sz; pos++) {
3728c2ecf20Sopenharmony_ci			int ret = __thread_stack__flush(thread, ts + pos);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci			if (ret)
3758c2ecf20Sopenharmony_ci				err = ret;
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	return err;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic void thread_stack__update_br_stack(struct thread_stack *ts, u32 flags,
3838c2ecf20Sopenharmony_ci					  u64 from_ip, u64 to_ip)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	struct branch_stack *bs = ts->br_stack_rb;
3868c2ecf20Sopenharmony_ci	struct branch_entry *be;
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	if (!ts->br_stack_pos)
3898c2ecf20Sopenharmony_ci		ts->br_stack_pos = ts->br_stack_sz;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	ts->br_stack_pos -= 1;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	be              = &bs->entries[ts->br_stack_pos];
3948c2ecf20Sopenharmony_ci	be->from        = from_ip;
3958c2ecf20Sopenharmony_ci	be->to          = to_ip;
3968c2ecf20Sopenharmony_ci	be->flags.value = 0;
3978c2ecf20Sopenharmony_ci	be->flags.abort = !!(flags & PERF_IP_FLAG_TX_ABORT);
3988c2ecf20Sopenharmony_ci	be->flags.in_tx = !!(flags & PERF_IP_FLAG_IN_TX);
3998c2ecf20Sopenharmony_ci	/* No support for mispredict */
4008c2ecf20Sopenharmony_ci	be->flags.mispred = ts->mispred_all;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	if (bs->nr < ts->br_stack_sz)
4038c2ecf20Sopenharmony_ci		bs->nr += 1;
4048c2ecf20Sopenharmony_ci}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ciint thread_stack__event(struct thread *thread, int cpu, u32 flags, u64 from_ip,
4078c2ecf20Sopenharmony_ci			u64 to_ip, u16 insn_len, u64 trace_nr, bool callstack,
4088c2ecf20Sopenharmony_ci			unsigned int br_stack_sz, bool mispred_all)
4098c2ecf20Sopenharmony_ci{
4108c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if (!thread)
4138c2ecf20Sopenharmony_ci		return -EINVAL;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (!ts) {
4168c2ecf20Sopenharmony_ci		ts = thread_stack__new(thread, cpu, NULL, callstack, br_stack_sz);
4178c2ecf20Sopenharmony_ci		if (!ts) {
4188c2ecf20Sopenharmony_ci			pr_warning("Out of memory: no thread stack\n");
4198c2ecf20Sopenharmony_ci			return -ENOMEM;
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci		ts->trace_nr = trace_nr;
4228c2ecf20Sopenharmony_ci		ts->mispred_all = mispred_all;
4238c2ecf20Sopenharmony_ci	}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	/*
4268c2ecf20Sopenharmony_ci	 * When the trace is discontinuous, the trace_nr changes.  In that case
4278c2ecf20Sopenharmony_ci	 * the stack might be completely invalid.  Better to report nothing than
4288c2ecf20Sopenharmony_ci	 * to report something misleading, so flush the stack.
4298c2ecf20Sopenharmony_ci	 */
4308c2ecf20Sopenharmony_ci	if (trace_nr != ts->trace_nr) {
4318c2ecf20Sopenharmony_ci		if (ts->trace_nr)
4328c2ecf20Sopenharmony_ci			__thread_stack__flush(thread, ts);
4338c2ecf20Sopenharmony_ci		ts->trace_nr = trace_nr;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (br_stack_sz)
4378c2ecf20Sopenharmony_ci		thread_stack__update_br_stack(ts, flags, from_ip, to_ip);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	/*
4408c2ecf20Sopenharmony_ci	 * Stop here if thread_stack__process() is in use, or not recording call
4418c2ecf20Sopenharmony_ci	 * stack.
4428c2ecf20Sopenharmony_ci	 */
4438c2ecf20Sopenharmony_ci	if (ts->crp || !callstack)
4448c2ecf20Sopenharmony_ci		return 0;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (flags & PERF_IP_FLAG_CALL) {
4478c2ecf20Sopenharmony_ci		u64 ret_addr;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci		if (!to_ip)
4508c2ecf20Sopenharmony_ci			return 0;
4518c2ecf20Sopenharmony_ci		ret_addr = from_ip + insn_len;
4528c2ecf20Sopenharmony_ci		if (ret_addr == to_ip)
4538c2ecf20Sopenharmony_ci			return 0; /* Zero-length calls are excluded */
4548c2ecf20Sopenharmony_ci		return thread_stack__push(ts, ret_addr,
4558c2ecf20Sopenharmony_ci					  flags & PERF_IP_FLAG_TRACE_END);
4568c2ecf20Sopenharmony_ci	} else if (flags & PERF_IP_FLAG_TRACE_BEGIN) {
4578c2ecf20Sopenharmony_ci		/*
4588c2ecf20Sopenharmony_ci		 * If the caller did not change the trace number (which would
4598c2ecf20Sopenharmony_ci		 * have flushed the stack) then try to make sense of the stack.
4608c2ecf20Sopenharmony_ci		 * Possibly, tracing began after returning to the current
4618c2ecf20Sopenharmony_ci		 * address, so try to pop that. Also, do not expect a call made
4628c2ecf20Sopenharmony_ci		 * when the trace ended, to return, so pop that.
4638c2ecf20Sopenharmony_ci		 */
4648c2ecf20Sopenharmony_ci		thread_stack__pop(ts, to_ip);
4658c2ecf20Sopenharmony_ci		thread_stack__pop_trace_end(ts);
4668c2ecf20Sopenharmony_ci	} else if ((flags & PERF_IP_FLAG_RETURN) && from_ip) {
4678c2ecf20Sopenharmony_ci		thread_stack__pop(ts, to_ip);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return 0;
4718c2ecf20Sopenharmony_ci}
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_civoid thread_stack__set_trace_nr(struct thread *thread, int cpu, u64 trace_nr)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (!ts)
4788c2ecf20Sopenharmony_ci		return;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	if (trace_nr != ts->trace_nr) {
4818c2ecf20Sopenharmony_ci		if (ts->trace_nr)
4828c2ecf20Sopenharmony_ci			__thread_stack__flush(thread, ts);
4838c2ecf20Sopenharmony_ci		ts->trace_nr = trace_nr;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void __thread_stack__free(struct thread *thread, struct thread_stack *ts)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	__thread_stack__flush(thread, ts);
4908c2ecf20Sopenharmony_ci	zfree(&ts->stack);
4918c2ecf20Sopenharmony_ci	zfree(&ts->br_stack_rb);
4928c2ecf20Sopenharmony_ci}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cistatic void thread_stack__reset(struct thread *thread, struct thread_stack *ts)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	unsigned int arr_sz = ts->arr_sz;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	__thread_stack__free(thread, ts);
4998c2ecf20Sopenharmony_ci	memset(ts, 0, sizeof(*ts));
5008c2ecf20Sopenharmony_ci	ts->arr_sz = arr_sz;
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_civoid thread_stack__free(struct thread *thread)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread->ts;
5068c2ecf20Sopenharmony_ci	unsigned int pos;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (ts) {
5098c2ecf20Sopenharmony_ci		for (pos = 0; pos < ts->arr_sz; pos++)
5108c2ecf20Sopenharmony_ci			__thread_stack__free(thread, ts + pos);
5118c2ecf20Sopenharmony_ci		zfree(&thread->ts);
5128c2ecf20Sopenharmony_ci	}
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic inline u64 callchain_context(u64 ip, u64 kernel_start)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	return ip < kernel_start ? PERF_CONTEXT_USER : PERF_CONTEXT_KERNEL;
5188c2ecf20Sopenharmony_ci}
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_civoid thread_stack__sample(struct thread *thread, int cpu,
5218c2ecf20Sopenharmony_ci			  struct ip_callchain *chain,
5228c2ecf20Sopenharmony_ci			  size_t sz, u64 ip, u64 kernel_start)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
5258c2ecf20Sopenharmony_ci	u64 context = callchain_context(ip, kernel_start);
5268c2ecf20Sopenharmony_ci	u64 last_context;
5278c2ecf20Sopenharmony_ci	size_t i, j;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	if (sz < 2) {
5308c2ecf20Sopenharmony_ci		chain->nr = 0;
5318c2ecf20Sopenharmony_ci		return;
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	chain->ips[0] = context;
5358c2ecf20Sopenharmony_ci	chain->ips[1] = ip;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	if (!ts) {
5388c2ecf20Sopenharmony_ci		chain->nr = 2;
5398c2ecf20Sopenharmony_ci		return;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	last_context = context;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	for (i = 2, j = 1; i < sz && j <= ts->cnt; i++, j++) {
5458c2ecf20Sopenharmony_ci		ip = ts->stack[ts->cnt - j].ret_addr;
5468c2ecf20Sopenharmony_ci		context = callchain_context(ip, kernel_start);
5478c2ecf20Sopenharmony_ci		if (context != last_context) {
5488c2ecf20Sopenharmony_ci			if (i >= sz - 1)
5498c2ecf20Sopenharmony_ci				break;
5508c2ecf20Sopenharmony_ci			chain->ips[i++] = context;
5518c2ecf20Sopenharmony_ci			last_context = context;
5528c2ecf20Sopenharmony_ci		}
5538c2ecf20Sopenharmony_ci		chain->ips[i] = ip;
5548c2ecf20Sopenharmony_ci	}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	chain->nr = i;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci/*
5608c2ecf20Sopenharmony_ci * Hardware sample records, created some time after the event occurred, need to
5618c2ecf20Sopenharmony_ci * have subsequent addresses removed from the call chain.
5628c2ecf20Sopenharmony_ci */
5638c2ecf20Sopenharmony_civoid thread_stack__sample_late(struct thread *thread, int cpu,
5648c2ecf20Sopenharmony_ci			       struct ip_callchain *chain, size_t sz,
5658c2ecf20Sopenharmony_ci			       u64 sample_ip, u64 kernel_start)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
5688c2ecf20Sopenharmony_ci	u64 sample_context = callchain_context(sample_ip, kernel_start);
5698c2ecf20Sopenharmony_ci	u64 last_context, context, ip;
5708c2ecf20Sopenharmony_ci	size_t nr = 0, j;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (sz < 2) {
5738c2ecf20Sopenharmony_ci		chain->nr = 0;
5748c2ecf20Sopenharmony_ci		return;
5758c2ecf20Sopenharmony_ci	}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	if (!ts)
5788c2ecf20Sopenharmony_ci		goto out;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	/*
5818c2ecf20Sopenharmony_ci	 * When tracing kernel space, kernel addresses occur at the top of the
5828c2ecf20Sopenharmony_ci	 * call chain after the event occurred but before tracing stopped.
5838c2ecf20Sopenharmony_ci	 * Skip them.
5848c2ecf20Sopenharmony_ci	 */
5858c2ecf20Sopenharmony_ci	for (j = 1; j <= ts->cnt; j++) {
5868c2ecf20Sopenharmony_ci		ip = ts->stack[ts->cnt - j].ret_addr;
5878c2ecf20Sopenharmony_ci		context = callchain_context(ip, kernel_start);
5888c2ecf20Sopenharmony_ci		if (context == PERF_CONTEXT_USER ||
5898c2ecf20Sopenharmony_ci		    (context == sample_context && ip == sample_ip))
5908c2ecf20Sopenharmony_ci			break;
5918c2ecf20Sopenharmony_ci	}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci	last_context = sample_ip; /* Use sample_ip as an invalid context */
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for (; nr < sz && j <= ts->cnt; nr++, j++) {
5968c2ecf20Sopenharmony_ci		ip = ts->stack[ts->cnt - j].ret_addr;
5978c2ecf20Sopenharmony_ci		context = callchain_context(ip, kernel_start);
5988c2ecf20Sopenharmony_ci		if (context != last_context) {
5998c2ecf20Sopenharmony_ci			if (nr >= sz - 1)
6008c2ecf20Sopenharmony_ci				break;
6018c2ecf20Sopenharmony_ci			chain->ips[nr++] = context;
6028c2ecf20Sopenharmony_ci			last_context = context;
6038c2ecf20Sopenharmony_ci		}
6048c2ecf20Sopenharmony_ci		chain->ips[nr] = ip;
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ciout:
6078c2ecf20Sopenharmony_ci	if (nr) {
6088c2ecf20Sopenharmony_ci		chain->nr = nr;
6098c2ecf20Sopenharmony_ci	} else {
6108c2ecf20Sopenharmony_ci		chain->ips[0] = sample_context;
6118c2ecf20Sopenharmony_ci		chain->ips[1] = sample_ip;
6128c2ecf20Sopenharmony_ci		chain->nr = 2;
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_civoid thread_stack__br_sample(struct thread *thread, int cpu,
6178c2ecf20Sopenharmony_ci			     struct branch_stack *dst, unsigned int sz)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
6208c2ecf20Sopenharmony_ci	const size_t bsz = sizeof(struct branch_entry);
6218c2ecf20Sopenharmony_ci	struct branch_stack *src;
6228c2ecf20Sopenharmony_ci	struct branch_entry *be;
6238c2ecf20Sopenharmony_ci	unsigned int nr;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	dst->nr = 0;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (!ts)
6288c2ecf20Sopenharmony_ci		return;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci	src = ts->br_stack_rb;
6318c2ecf20Sopenharmony_ci	if (!src->nr)
6328c2ecf20Sopenharmony_ci		return;
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci	dst->nr = min((unsigned int)src->nr, sz);
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	be = &dst->entries[0];
6378c2ecf20Sopenharmony_ci	nr = min(ts->br_stack_sz - ts->br_stack_pos, (unsigned int)dst->nr);
6388c2ecf20Sopenharmony_ci	memcpy(be, &src->entries[ts->br_stack_pos], bsz * nr);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	if (src->nr >= ts->br_stack_sz) {
6418c2ecf20Sopenharmony_ci		sz -= nr;
6428c2ecf20Sopenharmony_ci		be = &dst->entries[nr];
6438c2ecf20Sopenharmony_ci		nr = min(ts->br_stack_pos, sz);
6448c2ecf20Sopenharmony_ci		memcpy(be, &src->entries[0], bsz * ts->br_stack_pos);
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci}
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci/* Start of user space branch entries */
6498c2ecf20Sopenharmony_cistatic bool us_start(struct branch_entry *be, u64 kernel_start, bool *start)
6508c2ecf20Sopenharmony_ci{
6518c2ecf20Sopenharmony_ci	if (!*start)
6528c2ecf20Sopenharmony_ci		*start = be->to && be->to < kernel_start;
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	return *start;
6558c2ecf20Sopenharmony_ci}
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci/*
6588c2ecf20Sopenharmony_ci * Start of branch entries after the ip fell in between 2 branches, or user
6598c2ecf20Sopenharmony_ci * space branch entries.
6608c2ecf20Sopenharmony_ci */
6618c2ecf20Sopenharmony_cistatic bool ks_start(struct branch_entry *be, u64 sample_ip, u64 kernel_start,
6628c2ecf20Sopenharmony_ci		     bool *start, struct branch_entry *nb)
6638c2ecf20Sopenharmony_ci{
6648c2ecf20Sopenharmony_ci	if (!*start) {
6658c2ecf20Sopenharmony_ci		*start = (nb && sample_ip >= be->to && sample_ip <= nb->from) ||
6668c2ecf20Sopenharmony_ci			 be->from < kernel_start ||
6678c2ecf20Sopenharmony_ci			 (be->to && be->to < kernel_start);
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	return *start;
6718c2ecf20Sopenharmony_ci}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci/*
6748c2ecf20Sopenharmony_ci * Hardware sample records, created some time after the event occurred, need to
6758c2ecf20Sopenharmony_ci * have subsequent addresses removed from the branch stack.
6768c2ecf20Sopenharmony_ci */
6778c2ecf20Sopenharmony_civoid thread_stack__br_sample_late(struct thread *thread, int cpu,
6788c2ecf20Sopenharmony_ci				  struct branch_stack *dst, unsigned int sz,
6798c2ecf20Sopenharmony_ci				  u64 ip, u64 kernel_start)
6808c2ecf20Sopenharmony_ci{
6818c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
6828c2ecf20Sopenharmony_ci	struct branch_entry *d, *s, *spos, *ssz;
6838c2ecf20Sopenharmony_ci	struct branch_stack *src;
6848c2ecf20Sopenharmony_ci	unsigned int nr = 0;
6858c2ecf20Sopenharmony_ci	bool start = false;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	dst->nr = 0;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	if (!ts)
6908c2ecf20Sopenharmony_ci		return;
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	src = ts->br_stack_rb;
6938c2ecf20Sopenharmony_ci	if (!src->nr)
6948c2ecf20Sopenharmony_ci		return;
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	spos = &src->entries[ts->br_stack_pos];
6978c2ecf20Sopenharmony_ci	ssz  = &src->entries[ts->br_stack_sz];
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	d = &dst->entries[0];
7008c2ecf20Sopenharmony_ci	s = spos;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	if (ip < kernel_start) {
7038c2ecf20Sopenharmony_ci		/*
7048c2ecf20Sopenharmony_ci		 * User space sample: start copying branch entries when the
7058c2ecf20Sopenharmony_ci		 * branch is in user space.
7068c2ecf20Sopenharmony_ci		 */
7078c2ecf20Sopenharmony_ci		for (s = spos; s < ssz && nr < sz; s++) {
7088c2ecf20Sopenharmony_ci			if (us_start(s, kernel_start, &start)) {
7098c2ecf20Sopenharmony_ci				*d++ = *s;
7108c2ecf20Sopenharmony_ci				nr += 1;
7118c2ecf20Sopenharmony_ci			}
7128c2ecf20Sopenharmony_ci		}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		if (src->nr >= ts->br_stack_sz) {
7158c2ecf20Sopenharmony_ci			for (s = &src->entries[0]; s < spos && nr < sz; s++) {
7168c2ecf20Sopenharmony_ci				if (us_start(s, kernel_start, &start)) {
7178c2ecf20Sopenharmony_ci					*d++ = *s;
7188c2ecf20Sopenharmony_ci					nr += 1;
7198c2ecf20Sopenharmony_ci				}
7208c2ecf20Sopenharmony_ci			}
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci	} else {
7238c2ecf20Sopenharmony_ci		struct branch_entry *nb = NULL;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci		/*
7268c2ecf20Sopenharmony_ci		 * Kernel space sample: start copying branch entries when the ip
7278c2ecf20Sopenharmony_ci		 * falls in between 2 branches (or the branch is in user space
7288c2ecf20Sopenharmony_ci		 * because then the start must have been missed).
7298c2ecf20Sopenharmony_ci		 */
7308c2ecf20Sopenharmony_ci		for (s = spos; s < ssz && nr < sz; s++) {
7318c2ecf20Sopenharmony_ci			if (ks_start(s, ip, kernel_start, &start, nb)) {
7328c2ecf20Sopenharmony_ci				*d++ = *s;
7338c2ecf20Sopenharmony_ci				nr += 1;
7348c2ecf20Sopenharmony_ci			}
7358c2ecf20Sopenharmony_ci			nb = s;
7368c2ecf20Sopenharmony_ci		}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci		if (src->nr >= ts->br_stack_sz) {
7398c2ecf20Sopenharmony_ci			for (s = &src->entries[0]; s < spos && nr < sz; s++) {
7408c2ecf20Sopenharmony_ci				if (ks_start(s, ip, kernel_start, &start, nb)) {
7418c2ecf20Sopenharmony_ci					*d++ = *s;
7428c2ecf20Sopenharmony_ci					nr += 1;
7438c2ecf20Sopenharmony_ci				}
7448c2ecf20Sopenharmony_ci				nb = s;
7458c2ecf20Sopenharmony_ci			}
7468c2ecf20Sopenharmony_ci		}
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	dst->nr = nr;
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cistruct call_return_processor *
7538c2ecf20Sopenharmony_cicall_return_processor__new(int (*process)(struct call_return *cr, u64 *parent_db_id, void *data),
7548c2ecf20Sopenharmony_ci			   void *data)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	struct call_return_processor *crp;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	crp = zalloc(sizeof(struct call_return_processor));
7598c2ecf20Sopenharmony_ci	if (!crp)
7608c2ecf20Sopenharmony_ci		return NULL;
7618c2ecf20Sopenharmony_ci	crp->cpr = call_path_root__new();
7628c2ecf20Sopenharmony_ci	if (!crp->cpr)
7638c2ecf20Sopenharmony_ci		goto out_free;
7648c2ecf20Sopenharmony_ci	crp->process = process;
7658c2ecf20Sopenharmony_ci	crp->data = data;
7668c2ecf20Sopenharmony_ci	return crp;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ciout_free:
7698c2ecf20Sopenharmony_ci	free(crp);
7708c2ecf20Sopenharmony_ci	return NULL;
7718c2ecf20Sopenharmony_ci}
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_civoid call_return_processor__free(struct call_return_processor *crp)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	if (crp) {
7768c2ecf20Sopenharmony_ci		call_path_root__free(crp->cpr);
7778c2ecf20Sopenharmony_ci		free(crp);
7788c2ecf20Sopenharmony_ci	}
7798c2ecf20Sopenharmony_ci}
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
7828c2ecf20Sopenharmony_ci				 u64 timestamp, u64 ref, struct call_path *cp,
7838c2ecf20Sopenharmony_ci				 bool no_call, bool trace_end)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	struct thread_stack_entry *tse;
7868c2ecf20Sopenharmony_ci	int err;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (!cp)
7898c2ecf20Sopenharmony_ci		return -ENOMEM;
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (ts->cnt == ts->sz) {
7928c2ecf20Sopenharmony_ci		err = thread_stack__grow(ts);
7938c2ecf20Sopenharmony_ci		if (err)
7948c2ecf20Sopenharmony_ci			return err;
7958c2ecf20Sopenharmony_ci	}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	tse = &ts->stack[ts->cnt++];
7988c2ecf20Sopenharmony_ci	tse->ret_addr = ret_addr;
7998c2ecf20Sopenharmony_ci	tse->timestamp = timestamp;
8008c2ecf20Sopenharmony_ci	tse->ref = ref;
8018c2ecf20Sopenharmony_ci	tse->branch_count = ts->branch_count;
8028c2ecf20Sopenharmony_ci	tse->insn_count = ts->insn_count;
8038c2ecf20Sopenharmony_ci	tse->cyc_count = ts->cyc_count;
8048c2ecf20Sopenharmony_ci	tse->cp = cp;
8058c2ecf20Sopenharmony_ci	tse->no_call = no_call;
8068c2ecf20Sopenharmony_ci	tse->trace_end = trace_end;
8078c2ecf20Sopenharmony_ci	tse->non_call = false;
8088c2ecf20Sopenharmony_ci	tse->db_id = 0;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_cistatic int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
8148c2ecf20Sopenharmony_ci				u64 ret_addr, u64 timestamp, u64 ref,
8158c2ecf20Sopenharmony_ci				struct symbol *sym)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	int err;
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci	if (!ts->cnt)
8208c2ecf20Sopenharmony_ci		return 1;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	if (ts->cnt == 1) {
8238c2ecf20Sopenharmony_ci		struct thread_stack_entry *tse = &ts->stack[0];
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci		if (tse->cp->sym == sym)
8268c2ecf20Sopenharmony_ci			return thread_stack__call_return(thread, ts, --ts->cnt,
8278c2ecf20Sopenharmony_ci							 timestamp, ref, false);
8288c2ecf20Sopenharmony_ci	}
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	if (ts->stack[ts->cnt - 1].ret_addr == ret_addr &&
8318c2ecf20Sopenharmony_ci	    !ts->stack[ts->cnt - 1].non_call) {
8328c2ecf20Sopenharmony_ci		return thread_stack__call_return(thread, ts, --ts->cnt,
8338c2ecf20Sopenharmony_ci						 timestamp, ref, false);
8348c2ecf20Sopenharmony_ci	} else {
8358c2ecf20Sopenharmony_ci		size_t i = ts->cnt - 1;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci		while (i--) {
8388c2ecf20Sopenharmony_ci			if (ts->stack[i].ret_addr != ret_addr ||
8398c2ecf20Sopenharmony_ci			    ts->stack[i].non_call)
8408c2ecf20Sopenharmony_ci				continue;
8418c2ecf20Sopenharmony_ci			i += 1;
8428c2ecf20Sopenharmony_ci			while (ts->cnt > i) {
8438c2ecf20Sopenharmony_ci				err = thread_stack__call_return(thread, ts,
8448c2ecf20Sopenharmony_ci								--ts->cnt,
8458c2ecf20Sopenharmony_ci								timestamp, ref,
8468c2ecf20Sopenharmony_ci								true);
8478c2ecf20Sopenharmony_ci				if (err)
8488c2ecf20Sopenharmony_ci					return err;
8498c2ecf20Sopenharmony_ci			}
8508c2ecf20Sopenharmony_ci			return thread_stack__call_return(thread, ts, --ts->cnt,
8518c2ecf20Sopenharmony_ci							 timestamp, ref, false);
8528c2ecf20Sopenharmony_ci		}
8538c2ecf20Sopenharmony_ci	}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	return 1;
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_cistatic int thread_stack__bottom(struct thread_stack *ts,
8598c2ecf20Sopenharmony_ci				struct perf_sample *sample,
8608c2ecf20Sopenharmony_ci				struct addr_location *from_al,
8618c2ecf20Sopenharmony_ci				struct addr_location *to_al, u64 ref)
8628c2ecf20Sopenharmony_ci{
8638c2ecf20Sopenharmony_ci	struct call_path_root *cpr = ts->crp->cpr;
8648c2ecf20Sopenharmony_ci	struct call_path *cp;
8658c2ecf20Sopenharmony_ci	struct symbol *sym;
8668c2ecf20Sopenharmony_ci	u64 ip;
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	if (sample->ip) {
8698c2ecf20Sopenharmony_ci		ip = sample->ip;
8708c2ecf20Sopenharmony_ci		sym = from_al->sym;
8718c2ecf20Sopenharmony_ci	} else if (sample->addr) {
8728c2ecf20Sopenharmony_ci		ip = sample->addr;
8738c2ecf20Sopenharmony_ci		sym = to_al->sym;
8748c2ecf20Sopenharmony_ci	} else {
8758c2ecf20Sopenharmony_ci		return 0;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
8798c2ecf20Sopenharmony_ci				ts->kernel_start);
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return thread_stack__push_cp(ts, ip, sample->time, ref, cp,
8828c2ecf20Sopenharmony_ci				     true, false);
8838c2ecf20Sopenharmony_ci}
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_cistatic int thread_stack__pop_ks(struct thread *thread, struct thread_stack *ts,
8868c2ecf20Sopenharmony_ci				struct perf_sample *sample, u64 ref)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	u64 tm = sample->time;
8898c2ecf20Sopenharmony_ci	int err;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	/* Return to userspace, so pop all kernel addresses */
8928c2ecf20Sopenharmony_ci	while (thread_stack__in_kernel(ts)) {
8938c2ecf20Sopenharmony_ci		err = thread_stack__call_return(thread, ts, --ts->cnt,
8948c2ecf20Sopenharmony_ci						tm, ref, true);
8958c2ecf20Sopenharmony_ci		if (err)
8968c2ecf20Sopenharmony_ci			return err;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	return 0;
9008c2ecf20Sopenharmony_ci}
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_cistatic int thread_stack__no_call_return(struct thread *thread,
9038c2ecf20Sopenharmony_ci					struct thread_stack *ts,
9048c2ecf20Sopenharmony_ci					struct perf_sample *sample,
9058c2ecf20Sopenharmony_ci					struct addr_location *from_al,
9068c2ecf20Sopenharmony_ci					struct addr_location *to_al, u64 ref)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	struct call_path_root *cpr = ts->crp->cpr;
9098c2ecf20Sopenharmony_ci	struct call_path *root = &cpr->call_path;
9108c2ecf20Sopenharmony_ci	struct symbol *fsym = from_al->sym;
9118c2ecf20Sopenharmony_ci	struct symbol *tsym = to_al->sym;
9128c2ecf20Sopenharmony_ci	struct call_path *cp, *parent;
9138c2ecf20Sopenharmony_ci	u64 ks = ts->kernel_start;
9148c2ecf20Sopenharmony_ci	u64 addr = sample->addr;
9158c2ecf20Sopenharmony_ci	u64 tm = sample->time;
9168c2ecf20Sopenharmony_ci	u64 ip = sample->ip;
9178c2ecf20Sopenharmony_ci	int err;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	if (ip >= ks && addr < ks) {
9208c2ecf20Sopenharmony_ci		/* Return to userspace, so pop all kernel addresses */
9218c2ecf20Sopenharmony_ci		err = thread_stack__pop_ks(thread, ts, sample, ref);
9228c2ecf20Sopenharmony_ci		if (err)
9238c2ecf20Sopenharmony_ci			return err;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci		/* If the stack is empty, push the userspace address */
9268c2ecf20Sopenharmony_ci		if (!ts->cnt) {
9278c2ecf20Sopenharmony_ci			cp = call_path__findnew(cpr, root, tsym, addr, ks);
9288c2ecf20Sopenharmony_ci			return thread_stack__push_cp(ts, 0, tm, ref, cp, true,
9298c2ecf20Sopenharmony_ci						     false);
9308c2ecf20Sopenharmony_ci		}
9318c2ecf20Sopenharmony_ci	} else if (thread_stack__in_kernel(ts) && ip < ks) {
9328c2ecf20Sopenharmony_ci		/* Return to userspace, so pop all kernel addresses */
9338c2ecf20Sopenharmony_ci		err = thread_stack__pop_ks(thread, ts, sample, ref);
9348c2ecf20Sopenharmony_ci		if (err)
9358c2ecf20Sopenharmony_ci			return err;
9368c2ecf20Sopenharmony_ci	}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (ts->cnt)
9398c2ecf20Sopenharmony_ci		parent = ts->stack[ts->cnt - 1].cp;
9408c2ecf20Sopenharmony_ci	else
9418c2ecf20Sopenharmony_ci		parent = root;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	if (parent->sym == from_al->sym) {
9448c2ecf20Sopenharmony_ci		/*
9458c2ecf20Sopenharmony_ci		 * At the bottom of the stack, assume the missing 'call' was
9468c2ecf20Sopenharmony_ci		 * before the trace started. So, pop the current symbol and push
9478c2ecf20Sopenharmony_ci		 * the 'to' symbol.
9488c2ecf20Sopenharmony_ci		 */
9498c2ecf20Sopenharmony_ci		if (ts->cnt == 1) {
9508c2ecf20Sopenharmony_ci			err = thread_stack__call_return(thread, ts, --ts->cnt,
9518c2ecf20Sopenharmony_ci							tm, ref, false);
9528c2ecf20Sopenharmony_ci			if (err)
9538c2ecf20Sopenharmony_ci				return err;
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		if (!ts->cnt) {
9578c2ecf20Sopenharmony_ci			cp = call_path__findnew(cpr, root, tsym, addr, ks);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci			return thread_stack__push_cp(ts, addr, tm, ref, cp,
9608c2ecf20Sopenharmony_ci						     true, false);
9618c2ecf20Sopenharmony_ci		}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci		/*
9648c2ecf20Sopenharmony_ci		 * Otherwise assume the 'return' is being used as a jump (e.g.
9658c2ecf20Sopenharmony_ci		 * retpoline) and just push the 'to' symbol.
9668c2ecf20Sopenharmony_ci		 */
9678c2ecf20Sopenharmony_ci		cp = call_path__findnew(cpr, parent, tsym, addr, ks);
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci		err = thread_stack__push_cp(ts, 0, tm, ref, cp, true, false);
9708c2ecf20Sopenharmony_ci		if (!err)
9718c2ecf20Sopenharmony_ci			ts->stack[ts->cnt - 1].non_call = true;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci		return err;
9748c2ecf20Sopenharmony_ci	}
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	/*
9778c2ecf20Sopenharmony_ci	 * Assume 'parent' has not yet returned, so push 'to', and then push and
9788c2ecf20Sopenharmony_ci	 * pop 'from'.
9798c2ecf20Sopenharmony_ci	 */
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	cp = call_path__findnew(cpr, parent, tsym, addr, ks);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	err = thread_stack__push_cp(ts, addr, tm, ref, cp, true, false);
9848c2ecf20Sopenharmony_ci	if (err)
9858c2ecf20Sopenharmony_ci		return err;
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	cp = call_path__findnew(cpr, cp, fsym, ip, ks);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	err = thread_stack__push_cp(ts, ip, tm, ref, cp, true, false);
9908c2ecf20Sopenharmony_ci	if (err)
9918c2ecf20Sopenharmony_ci		return err;
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	return thread_stack__call_return(thread, ts, --ts->cnt, tm, ref, false);
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_cistatic int thread_stack__trace_begin(struct thread *thread,
9978c2ecf20Sopenharmony_ci				     struct thread_stack *ts, u64 timestamp,
9988c2ecf20Sopenharmony_ci				     u64 ref)
9998c2ecf20Sopenharmony_ci{
10008c2ecf20Sopenharmony_ci	struct thread_stack_entry *tse;
10018c2ecf20Sopenharmony_ci	int err;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	if (!ts->cnt)
10048c2ecf20Sopenharmony_ci		return 0;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	/* Pop trace end */
10078c2ecf20Sopenharmony_ci	tse = &ts->stack[ts->cnt - 1];
10088c2ecf20Sopenharmony_ci	if (tse->trace_end) {
10098c2ecf20Sopenharmony_ci		err = thread_stack__call_return(thread, ts, --ts->cnt,
10108c2ecf20Sopenharmony_ci						timestamp, ref, false);
10118c2ecf20Sopenharmony_ci		if (err)
10128c2ecf20Sopenharmony_ci			return err;
10138c2ecf20Sopenharmony_ci	}
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return 0;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic int thread_stack__trace_end(struct thread_stack *ts,
10198c2ecf20Sopenharmony_ci				   struct perf_sample *sample, u64 ref)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct call_path_root *cpr = ts->crp->cpr;
10228c2ecf20Sopenharmony_ci	struct call_path *cp;
10238c2ecf20Sopenharmony_ci	u64 ret_addr;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	/* No point having 'trace end' on the bottom of the stack */
10268c2ecf20Sopenharmony_ci	if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
10278c2ecf20Sopenharmony_ci		return 0;
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
10308c2ecf20Sopenharmony_ci				ts->kernel_start);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	ret_addr = sample->ip + sample->insn_len;
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci	return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
10358c2ecf20Sopenharmony_ci				     false, true);
10368c2ecf20Sopenharmony_ci}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_cistatic bool is_x86_retpoline(const char *name)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	const char *p = strstr(name, "__x86_indirect_thunk_");
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	return p == name || !strcmp(name, "__indirect_thunk_start");
10438c2ecf20Sopenharmony_ci}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci/*
10468c2ecf20Sopenharmony_ci * x86 retpoline functions pollute the call graph. This function removes them.
10478c2ecf20Sopenharmony_ci * This does not handle function return thunks, nor is there any improvement
10488c2ecf20Sopenharmony_ci * for the handling of inline thunks or extern thunks.
10498c2ecf20Sopenharmony_ci */
10508c2ecf20Sopenharmony_cistatic int thread_stack__x86_retpoline(struct thread_stack *ts,
10518c2ecf20Sopenharmony_ci				       struct perf_sample *sample,
10528c2ecf20Sopenharmony_ci				       struct addr_location *to_al)
10538c2ecf20Sopenharmony_ci{
10548c2ecf20Sopenharmony_ci	struct thread_stack_entry *tse = &ts->stack[ts->cnt - 1];
10558c2ecf20Sopenharmony_ci	struct call_path_root *cpr = ts->crp->cpr;
10568c2ecf20Sopenharmony_ci	struct symbol *sym = tse->cp->sym;
10578c2ecf20Sopenharmony_ci	struct symbol *tsym = to_al->sym;
10588c2ecf20Sopenharmony_ci	struct call_path *cp;
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ci	if (sym && is_x86_retpoline(sym->name)) {
10618c2ecf20Sopenharmony_ci		/*
10628c2ecf20Sopenharmony_ci		 * This is a x86 retpoline fn. It pollutes the call graph by
10638c2ecf20Sopenharmony_ci		 * showing up everywhere there is an indirect branch, but does
10648c2ecf20Sopenharmony_ci		 * not itself mean anything. Here the top-of-stack is removed,
10658c2ecf20Sopenharmony_ci		 * by decrementing the stack count, and then further down, the
10668c2ecf20Sopenharmony_ci		 * resulting top-of-stack is replaced with the actual target.
10678c2ecf20Sopenharmony_ci		 * The result is that the retpoline functions will no longer
10688c2ecf20Sopenharmony_ci		 * appear in the call graph. Note this only affects the call
10698c2ecf20Sopenharmony_ci		 * graph, since all the original branches are left unchanged.
10708c2ecf20Sopenharmony_ci		 */
10718c2ecf20Sopenharmony_ci		ts->cnt -= 1;
10728c2ecf20Sopenharmony_ci		sym = ts->stack[ts->cnt - 2].cp->sym;
10738c2ecf20Sopenharmony_ci		if (sym && sym == tsym && to_al->addr != tsym->start) {
10748c2ecf20Sopenharmony_ci			/*
10758c2ecf20Sopenharmony_ci			 * Target is back to the middle of the symbol we came
10768c2ecf20Sopenharmony_ci			 * from so assume it is an indirect jmp and forget it
10778c2ecf20Sopenharmony_ci			 * altogether.
10788c2ecf20Sopenharmony_ci			 */
10798c2ecf20Sopenharmony_ci			ts->cnt -= 1;
10808c2ecf20Sopenharmony_ci			return 0;
10818c2ecf20Sopenharmony_ci		}
10828c2ecf20Sopenharmony_ci	} else if (sym && sym == tsym) {
10838c2ecf20Sopenharmony_ci		/*
10848c2ecf20Sopenharmony_ci		 * Target is back to the symbol we came from so assume it is an
10858c2ecf20Sopenharmony_ci		 * indirect jmp and forget it altogether.
10868c2ecf20Sopenharmony_ci		 */
10878c2ecf20Sopenharmony_ci		ts->cnt -= 1;
10888c2ecf20Sopenharmony_ci		return 0;
10898c2ecf20Sopenharmony_ci	}
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	cp = call_path__findnew(cpr, ts->stack[ts->cnt - 2].cp, tsym,
10928c2ecf20Sopenharmony_ci				sample->addr, ts->kernel_start);
10938c2ecf20Sopenharmony_ci	if (!cp)
10948c2ecf20Sopenharmony_ci		return -ENOMEM;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	/* Replace the top-of-stack with the actual target */
10978c2ecf20Sopenharmony_ci	ts->stack[ts->cnt - 1].cp = cp;
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	return 0;
11008c2ecf20Sopenharmony_ci}
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ciint thread_stack__process(struct thread *thread, struct comm *comm,
11038c2ecf20Sopenharmony_ci			  struct perf_sample *sample,
11048c2ecf20Sopenharmony_ci			  struct addr_location *from_al,
11058c2ecf20Sopenharmony_ci			  struct addr_location *to_al, u64 ref,
11068c2ecf20Sopenharmony_ci			  struct call_return_processor *crp)
11078c2ecf20Sopenharmony_ci{
11088c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, sample->cpu);
11098c2ecf20Sopenharmony_ci	enum retpoline_state_t rstate;
11108c2ecf20Sopenharmony_ci	int err = 0;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	if (ts && !ts->crp) {
11138c2ecf20Sopenharmony_ci		/* Supersede thread_stack__event() */
11148c2ecf20Sopenharmony_ci		thread_stack__reset(thread, ts);
11158c2ecf20Sopenharmony_ci		ts = NULL;
11168c2ecf20Sopenharmony_ci	}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (!ts) {
11198c2ecf20Sopenharmony_ci		ts = thread_stack__new(thread, sample->cpu, crp, true, 0);
11208c2ecf20Sopenharmony_ci		if (!ts)
11218c2ecf20Sopenharmony_ci			return -ENOMEM;
11228c2ecf20Sopenharmony_ci		ts->comm = comm;
11238c2ecf20Sopenharmony_ci	}
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	rstate = ts->rstate;
11268c2ecf20Sopenharmony_ci	if (rstate == X86_RETPOLINE_DETECTED)
11278c2ecf20Sopenharmony_ci		ts->rstate = X86_RETPOLINE_POSSIBLE;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	/* Flush stack on exec */
11308c2ecf20Sopenharmony_ci	if (ts->comm != comm && thread->pid_ == thread->tid) {
11318c2ecf20Sopenharmony_ci		err = __thread_stack__flush(thread, ts);
11328c2ecf20Sopenharmony_ci		if (err)
11338c2ecf20Sopenharmony_ci			return err;
11348c2ecf20Sopenharmony_ci		ts->comm = comm;
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	/* If the stack is empty, put the current symbol on the stack */
11388c2ecf20Sopenharmony_ci	if (!ts->cnt) {
11398c2ecf20Sopenharmony_ci		err = thread_stack__bottom(ts, sample, from_al, to_al, ref);
11408c2ecf20Sopenharmony_ci		if (err)
11418c2ecf20Sopenharmony_ci			return err;
11428c2ecf20Sopenharmony_ci	}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	ts->branch_count += 1;
11458c2ecf20Sopenharmony_ci	ts->insn_count += sample->insn_cnt;
11468c2ecf20Sopenharmony_ci	ts->cyc_count += sample->cyc_cnt;
11478c2ecf20Sopenharmony_ci	ts->last_time = sample->time;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	if (sample->flags & PERF_IP_FLAG_CALL) {
11508c2ecf20Sopenharmony_ci		bool trace_end = sample->flags & PERF_IP_FLAG_TRACE_END;
11518c2ecf20Sopenharmony_ci		struct call_path_root *cpr = ts->crp->cpr;
11528c2ecf20Sopenharmony_ci		struct call_path *cp;
11538c2ecf20Sopenharmony_ci		u64 ret_addr;
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		if (!sample->ip || !sample->addr)
11568c2ecf20Sopenharmony_ci			return 0;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci		ret_addr = sample->ip + sample->insn_len;
11598c2ecf20Sopenharmony_ci		if (ret_addr == sample->addr)
11608c2ecf20Sopenharmony_ci			return 0; /* Zero-length calls are excluded */
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci		cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
11638c2ecf20Sopenharmony_ci					to_al->sym, sample->addr,
11648c2ecf20Sopenharmony_ci					ts->kernel_start);
11658c2ecf20Sopenharmony_ci		err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
11668c2ecf20Sopenharmony_ci					    cp, false, trace_end);
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		/*
11698c2ecf20Sopenharmony_ci		 * A call to the same symbol but not the start of the symbol,
11708c2ecf20Sopenharmony_ci		 * may be the start of a x86 retpoline.
11718c2ecf20Sopenharmony_ci		 */
11728c2ecf20Sopenharmony_ci		if (!err && rstate == X86_RETPOLINE_POSSIBLE && to_al->sym &&
11738c2ecf20Sopenharmony_ci		    from_al->sym == to_al->sym &&
11748c2ecf20Sopenharmony_ci		    to_al->addr != to_al->sym->start)
11758c2ecf20Sopenharmony_ci			ts->rstate = X86_RETPOLINE_DETECTED;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	} else if (sample->flags & PERF_IP_FLAG_RETURN) {
11788c2ecf20Sopenharmony_ci		if (!sample->addr) {
11798c2ecf20Sopenharmony_ci			u32 return_from_kernel = PERF_IP_FLAG_SYSCALLRET |
11808c2ecf20Sopenharmony_ci						 PERF_IP_FLAG_INTERRUPT;
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci			if (!(sample->flags & return_from_kernel))
11838c2ecf20Sopenharmony_ci				return 0;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci			/* Pop kernel stack */
11868c2ecf20Sopenharmony_ci			return thread_stack__pop_ks(thread, ts, sample, ref);
11878c2ecf20Sopenharmony_ci		}
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci		if (!sample->ip)
11908c2ecf20Sopenharmony_ci			return 0;
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_ci		/* x86 retpoline 'return' doesn't match the stack */
11938c2ecf20Sopenharmony_ci		if (rstate == X86_RETPOLINE_DETECTED && ts->cnt > 2 &&
11948c2ecf20Sopenharmony_ci		    ts->stack[ts->cnt - 1].ret_addr != sample->addr)
11958c2ecf20Sopenharmony_ci			return thread_stack__x86_retpoline(ts, sample, to_al);
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci		err = thread_stack__pop_cp(thread, ts, sample->addr,
11988c2ecf20Sopenharmony_ci					   sample->time, ref, from_al->sym);
11998c2ecf20Sopenharmony_ci		if (err) {
12008c2ecf20Sopenharmony_ci			if (err < 0)
12018c2ecf20Sopenharmony_ci				return err;
12028c2ecf20Sopenharmony_ci			err = thread_stack__no_call_return(thread, ts, sample,
12038c2ecf20Sopenharmony_ci							   from_al, to_al, ref);
12048c2ecf20Sopenharmony_ci		}
12058c2ecf20Sopenharmony_ci	} else if (sample->flags & PERF_IP_FLAG_TRACE_BEGIN) {
12068c2ecf20Sopenharmony_ci		err = thread_stack__trace_begin(thread, ts, sample->time, ref);
12078c2ecf20Sopenharmony_ci	} else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
12088c2ecf20Sopenharmony_ci		err = thread_stack__trace_end(ts, sample, ref);
12098c2ecf20Sopenharmony_ci	} else if (sample->flags & PERF_IP_FLAG_BRANCH &&
12108c2ecf20Sopenharmony_ci		   from_al->sym != to_al->sym && to_al->sym &&
12118c2ecf20Sopenharmony_ci		   to_al->addr == to_al->sym->start) {
12128c2ecf20Sopenharmony_ci		struct call_path_root *cpr = ts->crp->cpr;
12138c2ecf20Sopenharmony_ci		struct call_path *cp;
12148c2ecf20Sopenharmony_ci
12158c2ecf20Sopenharmony_ci		/*
12168c2ecf20Sopenharmony_ci		 * The compiler might optimize a call/ret combination by making
12178c2ecf20Sopenharmony_ci		 * it a jmp. Make that visible by recording on the stack a
12188c2ecf20Sopenharmony_ci		 * branch to the start of a different symbol. Note, that means
12198c2ecf20Sopenharmony_ci		 * when a ret pops the stack, all jmps must be popped off first.
12208c2ecf20Sopenharmony_ci		 */
12218c2ecf20Sopenharmony_ci		cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
12228c2ecf20Sopenharmony_ci					to_al->sym, sample->addr,
12238c2ecf20Sopenharmony_ci					ts->kernel_start);
12248c2ecf20Sopenharmony_ci		err = thread_stack__push_cp(ts, 0, sample->time, ref, cp, false,
12258c2ecf20Sopenharmony_ci					    false);
12268c2ecf20Sopenharmony_ci		if (!err)
12278c2ecf20Sopenharmony_ci			ts->stack[ts->cnt - 1].non_call = true;
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	return err;
12318c2ecf20Sopenharmony_ci}
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_cisize_t thread_stack__depth(struct thread *thread, int cpu)
12348c2ecf20Sopenharmony_ci{
12358c2ecf20Sopenharmony_ci	struct thread_stack *ts = thread__stack(thread, cpu);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	if (!ts)
12388c2ecf20Sopenharmony_ci		return 0;
12398c2ecf20Sopenharmony_ci	return ts->cnt;
12408c2ecf20Sopenharmony_ci}
1241