1 // SPDX-License-Identifier: GPL-2.0-only
3 * thread-stack.c: Synthesize a thread's stack using call / return events
4 * Copyright (c) 2014, Intel Corporation.
7 #include <linux/rbtree.h>
8 #include <linux/list.h>
9 #include <linux/log2.h>
19 #include "call-path.h"
20 #include "thread-stack.h"
22 #define STACK_GROWTH 2048
25 * State of retpoline detection.
27 * RETPOLINE_NONE: no retpoline detection
28 * X86_RETPOLINE_POSSIBLE: x86 retpoline possible
29 * X86_RETPOLINE_DETECTED: x86 retpoline detected
31 enum retpoline_state_t
{
33 X86_RETPOLINE_POSSIBLE
,
34 X86_RETPOLINE_DETECTED
,
38 * struct thread_stack_entry - thread stack entry.
39 * @ret_addr: return address
40 * @timestamp: timestamp (if known)
41 * @ref: external reference (e.g. db_id of sample)
42 * @branch_count: the branch count when the entry was created
43 * @insn_count: the instruction count when the entry was created
44 * @cyc_count the cycle count when the entry was created
45 * @db_id: id used for db-export
47 * @no_call: a 'call' was not seen
48 * @trace_end: a 'call' but trace ended
49 * @non_call: a branch but not a 'call' to the start of a different symbol
51 struct thread_stack_entry
{
66 * struct thread_stack - thread stack constructed from 'call' and 'return'
68 * @stack: array that holds the stack
69 * @cnt: number of entries in the stack
70 * @sz: current maximum stack size
71 * @trace_nr: current trace number
72 * @branch_count: running branch count
73 * @insn_count: running instruction count
74 * @cyc_count running cycle count
75 * @kernel_start: kernel start address
76 * @last_time: last timestamp
77 * @crp: call/return processor
79 * @arr_sz: size of array if this is the first element of an array
80 * @rstate: used to detect retpolines
83 struct thread_stack_entry
*stack
;
92 struct call_return_processor
*crp
;
95 enum retpoline_state_t rstate
;
99 * Assume pid == tid == 0 identifies the idle task as defined by
100 * perf_session__register_idle_thread(). The idle task is really 1 task per cpu,
101 * and therefore requires a stack for each cpu.
103 static inline bool thread_stack__per_cpu(struct thread
*thread
)
105 return !(thread
->tid
|| thread
->pid_
);
108 static int thread_stack__grow(struct thread_stack
*ts
)
110 struct thread_stack_entry
*new_stack
;
113 new_sz
= ts
->sz
+ STACK_GROWTH
;
114 sz
= new_sz
* sizeof(struct thread_stack_entry
);
116 new_stack
= realloc(ts
->stack
, sz
);
120 ts
->stack
= new_stack
;
126 static int thread_stack__init(struct thread_stack
*ts
, struct thread
*thread
,
127 struct call_return_processor
*crp
)
131 err
= thread_stack__grow(ts
);
135 if (thread
->mg
&& thread
->mg
->machine
) {
136 struct machine
*machine
= thread
->mg
->machine
;
137 const char *arch
= perf_env__arch(machine
->env
);
139 ts
->kernel_start
= machine__kernel_start(machine
);
140 if (!strcmp(arch
, "x86"))
141 ts
->rstate
= X86_RETPOLINE_POSSIBLE
;
143 ts
->kernel_start
= 1ULL << 63;
150 static struct thread_stack
*thread_stack__new(struct thread
*thread
, int cpu
,
151 struct call_return_processor
*crp
)
153 struct thread_stack
*ts
= thread
->ts
, *new_ts
;
154 unsigned int old_sz
= ts
? ts
->arr_sz
: 0;
155 unsigned int new_sz
= 1;
157 if (thread_stack__per_cpu(thread
) && cpu
> 0)
158 new_sz
= roundup_pow_of_two(cpu
+ 1);
160 if (!ts
|| new_sz
> old_sz
) {
161 new_ts
= calloc(new_sz
, sizeof(*ts
));
165 memcpy(new_ts
, ts
, old_sz
* sizeof(*ts
));
166 new_ts
->arr_sz
= new_sz
;
172 if (thread_stack__per_cpu(thread
) && cpu
> 0 &&
173 (unsigned int)cpu
< ts
->arr_sz
)
177 thread_stack__init(ts
, thread
, crp
))
183 static struct thread_stack
*thread__cpu_stack(struct thread
*thread
, int cpu
)
185 struct thread_stack
*ts
= thread
->ts
;
190 if (!ts
|| (unsigned int)cpu
>= ts
->arr_sz
)
201 static inline struct thread_stack
*thread__stack(struct thread
*thread
,
207 if (thread_stack__per_cpu(thread
))
208 return thread__cpu_stack(thread
, cpu
);
213 static int thread_stack__push(struct thread_stack
*ts
, u64 ret_addr
,
218 if (ts
->cnt
== ts
->sz
) {
219 err
= thread_stack__grow(ts
);
221 pr_warning("Out of memory: discarding thread stack\n");
226 ts
->stack
[ts
->cnt
].trace_end
= trace_end
;
227 ts
->stack
[ts
->cnt
++].ret_addr
= ret_addr
;
232 static void thread_stack__pop(struct thread_stack
*ts
, u64 ret_addr
)
237 * In some cases there may be functions which are not seen to return.
238 * For example when setjmp / longjmp has been used. Or the perf context
239 * switch in the kernel which doesn't stop and start tracing in exactly
240 * the same code path. When that happens the return address will be
241 * further down the stack. If the return address is not found at all,
242 * we assume the opposite (i.e. this is a return for a call that wasn't
243 * seen for some reason) and leave the stack alone.
245 for (i
= ts
->cnt
; i
; ) {
246 if (ts
->stack
[--i
].ret_addr
== ret_addr
) {
253 static void thread_stack__pop_trace_end(struct thread_stack
*ts
)
257 for (i
= ts
->cnt
; i
; ) {
258 if (ts
->stack
[--i
].trace_end
)
265 static bool thread_stack__in_kernel(struct thread_stack
*ts
)
270 return ts
->stack
[ts
->cnt
- 1].cp
->in_kernel
;
273 static int thread_stack__call_return(struct thread
*thread
,
274 struct thread_stack
*ts
, size_t idx
,
275 u64 timestamp
, u64 ref
, bool no_return
)
277 struct call_return_processor
*crp
= ts
->crp
;
278 struct thread_stack_entry
*tse
;
279 struct call_return cr
= {
286 tse
= &ts
->stack
[idx
];
288 cr
.call_time
= tse
->timestamp
;
289 cr
.return_time
= timestamp
;
290 cr
.branch_count
= ts
->branch_count
- tse
->branch_count
;
291 cr
.insn_count
= ts
->insn_count
- tse
->insn_count
;
292 cr
.cyc_count
= ts
->cyc_count
- tse
->cyc_count
;
293 cr
.db_id
= tse
->db_id
;
294 cr
.call_ref
= tse
->ref
;
297 cr
.flags
|= CALL_RETURN_NO_CALL
;
299 cr
.flags
|= CALL_RETURN_NO_RETURN
;
301 cr
.flags
|= CALL_RETURN_NON_CALL
;
304 * The parent db_id must be assigned before exporting the child. Note
305 * it is not possible to export the parent first because its information
306 * is not yet complete because its 'return' has not yet been processed.
308 parent_db_id
= idx
? &(tse
- 1)->db_id
: NULL
;
310 return crp
->process(&cr
, parent_db_id
, crp
->data
);
313 static int __thread_stack__flush(struct thread
*thread
, struct thread_stack
*ts
)
315 struct call_return_processor
*crp
= ts
->crp
;
324 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
325 ts
->last_time
, 0, true);
327 pr_err("Error flushing thread stack!\n");
336 int thread_stack__flush(struct thread
*thread
)
338 struct thread_stack
*ts
= thread
->ts
;
343 for (pos
= 0; pos
< ts
->arr_sz
; pos
++) {
344 int ret
= __thread_stack__flush(thread
, ts
+ pos
);
354 int thread_stack__event(struct thread
*thread
, int cpu
, u32 flags
, u64 from_ip
,
355 u64 to_ip
, u16 insn_len
, u64 trace_nr
)
357 struct thread_stack
*ts
= thread__stack(thread
, cpu
);
363 ts
= thread_stack__new(thread
, cpu
, NULL
);
365 pr_warning("Out of memory: no thread stack\n");
368 ts
->trace_nr
= trace_nr
;
372 * When the trace is discontinuous, the trace_nr changes. In that case
373 * the stack might be completely invalid. Better to report nothing than
374 * to report something misleading, so flush the stack.
376 if (trace_nr
!= ts
->trace_nr
) {
378 __thread_stack__flush(thread
, ts
);
379 ts
->trace_nr
= trace_nr
;
382 /* Stop here if thread_stack__process() is in use */
386 if (flags
& PERF_IP_FLAG_CALL
) {
391 ret_addr
= from_ip
+ insn_len
;
392 if (ret_addr
== to_ip
)
393 return 0; /* Zero-length calls are excluded */
394 return thread_stack__push(ts
, ret_addr
,
395 flags
& PERF_IP_FLAG_TRACE_END
);
396 } else if (flags
& PERF_IP_FLAG_TRACE_BEGIN
) {
398 * If the caller did not change the trace number (which would
399 * have flushed the stack) then try to make sense of the stack.
400 * Possibly, tracing began after returning to the current
401 * address, so try to pop that. Also, do not expect a call made
402 * when the trace ended, to return, so pop that.
404 thread_stack__pop(ts
, to_ip
);
405 thread_stack__pop_trace_end(ts
);
406 } else if ((flags
& PERF_IP_FLAG_RETURN
) && from_ip
) {
407 thread_stack__pop(ts
, to_ip
);
413 void thread_stack__set_trace_nr(struct thread
*thread
, int cpu
, u64 trace_nr
)
415 struct thread_stack
*ts
= thread__stack(thread
, cpu
);
420 if (trace_nr
!= ts
->trace_nr
) {
422 __thread_stack__flush(thread
, ts
);
423 ts
->trace_nr
= trace_nr
;
427 static void __thread_stack__free(struct thread
*thread
, struct thread_stack
*ts
)
429 __thread_stack__flush(thread
, ts
);
433 static void thread_stack__reset(struct thread
*thread
, struct thread_stack
*ts
)
435 unsigned int arr_sz
= ts
->arr_sz
;
437 __thread_stack__free(thread
, ts
);
438 memset(ts
, 0, sizeof(*ts
));
442 void thread_stack__free(struct thread
*thread
)
444 struct thread_stack
*ts
= thread
->ts
;
448 for (pos
= 0; pos
< ts
->arr_sz
; pos
++)
449 __thread_stack__free(thread
, ts
+ pos
);
454 static inline u64
callchain_context(u64 ip
, u64 kernel_start
)
456 return ip
< kernel_start
? PERF_CONTEXT_USER
: PERF_CONTEXT_KERNEL
;
459 void thread_stack__sample(struct thread
*thread
, int cpu
,
460 struct ip_callchain
*chain
,
461 size_t sz
, u64 ip
, u64 kernel_start
)
463 struct thread_stack
*ts
= thread__stack(thread
, cpu
);
464 u64 context
= callchain_context(ip
, kernel_start
);
473 chain
->ips
[0] = context
;
481 last_context
= context
;
483 for (i
= 2, j
= 1; i
< sz
&& j
<= ts
->cnt
; i
++, j
++) {
484 ip
= ts
->stack
[ts
->cnt
- j
].ret_addr
;
485 context
= callchain_context(ip
, kernel_start
);
486 if (context
!= last_context
) {
489 chain
->ips
[i
++] = context
;
490 last_context
= context
;
498 struct call_return_processor
*
499 call_return_processor__new(int (*process
)(struct call_return
*cr
, u64
*parent_db_id
, void *data
),
502 struct call_return_processor
*crp
;
504 crp
= zalloc(sizeof(struct call_return_processor
));
507 crp
->cpr
= call_path_root__new();
510 crp
->process
= process
;
519 void call_return_processor__free(struct call_return_processor
*crp
)
522 call_path_root__free(crp
->cpr
);
527 static int thread_stack__push_cp(struct thread_stack
*ts
, u64 ret_addr
,
528 u64 timestamp
, u64 ref
, struct call_path
*cp
,
529 bool no_call
, bool trace_end
)
531 struct thread_stack_entry
*tse
;
537 if (ts
->cnt
== ts
->sz
) {
538 err
= thread_stack__grow(ts
);
543 tse
= &ts
->stack
[ts
->cnt
++];
544 tse
->ret_addr
= ret_addr
;
545 tse
->timestamp
= timestamp
;
547 tse
->branch_count
= ts
->branch_count
;
548 tse
->insn_count
= ts
->insn_count
;
549 tse
->cyc_count
= ts
->cyc_count
;
551 tse
->no_call
= no_call
;
552 tse
->trace_end
= trace_end
;
553 tse
->non_call
= false;
559 static int thread_stack__pop_cp(struct thread
*thread
, struct thread_stack
*ts
,
560 u64 ret_addr
, u64 timestamp
, u64 ref
,
569 struct thread_stack_entry
*tse
= &ts
->stack
[0];
571 if (tse
->cp
->sym
== sym
)
572 return thread_stack__call_return(thread
, ts
, --ts
->cnt
,
573 timestamp
, ref
, false);
576 if (ts
->stack
[ts
->cnt
- 1].ret_addr
== ret_addr
&&
577 !ts
->stack
[ts
->cnt
- 1].non_call
) {
578 return thread_stack__call_return(thread
, ts
, --ts
->cnt
,
579 timestamp
, ref
, false);
581 size_t i
= ts
->cnt
- 1;
584 if (ts
->stack
[i
].ret_addr
!= ret_addr
||
585 ts
->stack
[i
].non_call
)
588 while (ts
->cnt
> i
) {
589 err
= thread_stack__call_return(thread
, ts
,
596 return thread_stack__call_return(thread
, ts
, --ts
->cnt
,
597 timestamp
, ref
, false);
604 static int thread_stack__bottom(struct thread_stack
*ts
,
605 struct perf_sample
*sample
,
606 struct addr_location
*from_al
,
607 struct addr_location
*to_al
, u64 ref
)
609 struct call_path_root
*cpr
= ts
->crp
->cpr
;
610 struct call_path
*cp
;
617 } else if (sample
->addr
) {
624 cp
= call_path__findnew(cpr
, &cpr
->call_path
, sym
, ip
,
627 return thread_stack__push_cp(ts
, ip
, sample
->time
, ref
, cp
,
631 static int thread_stack__pop_ks(struct thread
*thread
, struct thread_stack
*ts
,
632 struct perf_sample
*sample
, u64 ref
)
634 u64 tm
= sample
->time
;
637 /* Return to userspace, so pop all kernel addresses */
638 while (thread_stack__in_kernel(ts
)) {
639 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
648 static int thread_stack__no_call_return(struct thread
*thread
,
649 struct thread_stack
*ts
,
650 struct perf_sample
*sample
,
651 struct addr_location
*from_al
,
652 struct addr_location
*to_al
, u64 ref
)
654 struct call_path_root
*cpr
= ts
->crp
->cpr
;
655 struct call_path
*root
= &cpr
->call_path
;
656 struct symbol
*fsym
= from_al
->sym
;
657 struct symbol
*tsym
= to_al
->sym
;
658 struct call_path
*cp
, *parent
;
659 u64 ks
= ts
->kernel_start
;
660 u64 addr
= sample
->addr
;
661 u64 tm
= sample
->time
;
665 if (ip
>= ks
&& addr
< ks
) {
666 /* Return to userspace, so pop all kernel addresses */
667 while (thread_stack__in_kernel(ts
)) {
668 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
674 /* If the stack is empty, push the userspace address */
676 cp
= call_path__findnew(cpr
, root
, tsym
, addr
, ks
);
677 return thread_stack__push_cp(ts
, 0, tm
, ref
, cp
, true,
680 } else if (thread_stack__in_kernel(ts
) && ip
< ks
) {
681 /* Return to userspace, so pop all kernel addresses */
682 while (thread_stack__in_kernel(ts
)) {
683 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
691 parent
= ts
->stack
[ts
->cnt
- 1].cp
;
695 if (parent
->sym
== from_al
->sym
) {
697 * At the bottom of the stack, assume the missing 'call' was
698 * before the trace started. So, pop the current symbol and push
702 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
709 cp
= call_path__findnew(cpr
, root
, tsym
, addr
, ks
);
711 return thread_stack__push_cp(ts
, addr
, tm
, ref
, cp
,
716 * Otherwise assume the 'return' is being used as a jump (e.g.
717 * retpoline) and just push the 'to' symbol.
719 cp
= call_path__findnew(cpr
, parent
, tsym
, addr
, ks
);
721 err
= thread_stack__push_cp(ts
, 0, tm
, ref
, cp
, true, false);
723 ts
->stack
[ts
->cnt
- 1].non_call
= true;
729 * Assume 'parent' has not yet returned, so push 'to', and then push and
733 cp
= call_path__findnew(cpr
, parent
, tsym
, addr
, ks
);
735 err
= thread_stack__push_cp(ts
, addr
, tm
, ref
, cp
, true, false);
739 cp
= call_path__findnew(cpr
, cp
, fsym
, ip
, ks
);
741 err
= thread_stack__push_cp(ts
, ip
, tm
, ref
, cp
, true, false);
745 return thread_stack__call_return(thread
, ts
, --ts
->cnt
, tm
, ref
, false);
748 static int thread_stack__trace_begin(struct thread
*thread
,
749 struct thread_stack
*ts
, u64 timestamp
,
752 struct thread_stack_entry
*tse
;
759 tse
= &ts
->stack
[ts
->cnt
- 1];
760 if (tse
->trace_end
) {
761 err
= thread_stack__call_return(thread
, ts
, --ts
->cnt
,
762 timestamp
, ref
, false);
770 static int thread_stack__trace_end(struct thread_stack
*ts
,
771 struct perf_sample
*sample
, u64 ref
)
773 struct call_path_root
*cpr
= ts
->crp
->cpr
;
774 struct call_path
*cp
;
777 /* No point having 'trace end' on the bottom of the stack */
778 if (!ts
->cnt
|| (ts
->cnt
== 1 && ts
->stack
[0].ref
== ref
))
781 cp
= call_path__findnew(cpr
, ts
->stack
[ts
->cnt
- 1].cp
, NULL
, 0,
784 ret_addr
= sample
->ip
+ sample
->insn_len
;
786 return thread_stack__push_cp(ts
, ret_addr
, sample
->time
, ref
, cp
,
790 static bool is_x86_retpoline(const char *name
)
792 const char *p
= strstr(name
, "__x86_indirect_thunk_");
794 return p
== name
|| !strcmp(name
, "__indirect_thunk_start");
798 * x86 retpoline functions pollute the call graph. This function removes them.
799 * This does not handle function return thunks, nor is there any improvement
800 * for the handling of inline thunks or extern thunks.
802 static int thread_stack__x86_retpoline(struct thread_stack
*ts
,
803 struct perf_sample
*sample
,
804 struct addr_location
*to_al
)
806 struct thread_stack_entry
*tse
= &ts
->stack
[ts
->cnt
- 1];
807 struct call_path_root
*cpr
= ts
->crp
->cpr
;
808 struct symbol
*sym
= tse
->cp
->sym
;
809 struct symbol
*tsym
= to_al
->sym
;
810 struct call_path
*cp
;
812 if (sym
&& is_x86_retpoline(sym
->name
)) {
814 * This is a x86 retpoline fn. It pollutes the call graph by
815 * showing up everywhere there is an indirect branch, but does
816 * not itself mean anything. Here the top-of-stack is removed,
817 * by decrementing the stack count, and then further down, the
818 * resulting top-of-stack is replaced with the actual target.
819 * The result is that the retpoline functions will no longer
820 * appear in the call graph. Note this only affects the call
821 * graph, since all the original branches are left unchanged.
824 sym
= ts
->stack
[ts
->cnt
- 2].cp
->sym
;
825 if (sym
&& sym
== tsym
&& to_al
->addr
!= tsym
->start
) {
827 * Target is back to the middle of the symbol we came
828 * from so assume it is an indirect jmp and forget it
834 } else if (sym
&& sym
== tsym
) {
836 * Target is back to the symbol we came from so assume it is an
837 * indirect jmp and forget it altogether.
843 cp
= call_path__findnew(cpr
, ts
->stack
[ts
->cnt
- 2].cp
, tsym
,
844 sample
->addr
, ts
->kernel_start
);
848 /* Replace the top-of-stack with the actual target */
849 ts
->stack
[ts
->cnt
- 1].cp
= cp
;
854 int thread_stack__process(struct thread
*thread
, struct comm
*comm
,
855 struct perf_sample
*sample
,
856 struct addr_location
*from_al
,
857 struct addr_location
*to_al
, u64 ref
,
858 struct call_return_processor
*crp
)
860 struct thread_stack
*ts
= thread__stack(thread
, sample
->cpu
);
861 enum retpoline_state_t rstate
;
864 if (ts
&& !ts
->crp
) {
865 /* Supersede thread_stack__event() */
866 thread_stack__reset(thread
, ts
);
871 ts
= thread_stack__new(thread
, sample
->cpu
, crp
);
878 if (rstate
== X86_RETPOLINE_DETECTED
)
879 ts
->rstate
= X86_RETPOLINE_POSSIBLE
;
881 /* Flush stack on exec */
882 if (ts
->comm
!= comm
&& thread
->pid_
== thread
->tid
) {
883 err
= __thread_stack__flush(thread
, ts
);
889 /* If the stack is empty, put the current symbol on the stack */
891 err
= thread_stack__bottom(ts
, sample
, from_al
, to_al
, ref
);
896 ts
->branch_count
+= 1;
897 ts
->insn_count
+= sample
->insn_cnt
;
898 ts
->cyc_count
+= sample
->cyc_cnt
;
899 ts
->last_time
= sample
->time
;
901 if (sample
->flags
& PERF_IP_FLAG_CALL
) {
902 bool trace_end
= sample
->flags
& PERF_IP_FLAG_TRACE_END
;
903 struct call_path_root
*cpr
= ts
->crp
->cpr
;
904 struct call_path
*cp
;
907 if (!sample
->ip
|| !sample
->addr
)
910 ret_addr
= sample
->ip
+ sample
->insn_len
;
911 if (ret_addr
== sample
->addr
)
912 return 0; /* Zero-length calls are excluded */
914 cp
= call_path__findnew(cpr
, ts
->stack
[ts
->cnt
- 1].cp
,
915 to_al
->sym
, sample
->addr
,
917 err
= thread_stack__push_cp(ts
, ret_addr
, sample
->time
, ref
,
918 cp
, false, trace_end
);
921 * A call to the same symbol but not the start of the symbol,
922 * may be the start of a x86 retpoline.
924 if (!err
&& rstate
== X86_RETPOLINE_POSSIBLE
&& to_al
->sym
&&
925 from_al
->sym
== to_al
->sym
&&
926 to_al
->addr
!= to_al
->sym
->start
)
927 ts
->rstate
= X86_RETPOLINE_DETECTED
;
929 } else if (sample
->flags
& PERF_IP_FLAG_RETURN
) {
931 u32 return_from_kernel
= PERF_IP_FLAG_SYSCALLRET
|
932 PERF_IP_FLAG_INTERRUPT
;
934 if (!(sample
->flags
& return_from_kernel
))
937 /* Pop kernel stack */
938 return thread_stack__pop_ks(thread
, ts
, sample
, ref
);
944 /* x86 retpoline 'return' doesn't match the stack */
945 if (rstate
== X86_RETPOLINE_DETECTED
&& ts
->cnt
> 2 &&
946 ts
->stack
[ts
->cnt
- 1].ret_addr
!= sample
->addr
)
947 return thread_stack__x86_retpoline(ts
, sample
, to_al
);
949 err
= thread_stack__pop_cp(thread
, ts
, sample
->addr
,
950 sample
->time
, ref
, from_al
->sym
);
954 err
= thread_stack__no_call_return(thread
, ts
, sample
,
955 from_al
, to_al
, ref
);
957 } else if (sample
->flags
& PERF_IP_FLAG_TRACE_BEGIN
) {
958 err
= thread_stack__trace_begin(thread
, ts
, sample
->time
, ref
);
959 } else if (sample
->flags
& PERF_IP_FLAG_TRACE_END
) {
960 err
= thread_stack__trace_end(ts
, sample
, ref
);
961 } else if (sample
->flags
& PERF_IP_FLAG_BRANCH
&&
962 from_al
->sym
!= to_al
->sym
&& to_al
->sym
&&
963 to_al
->addr
== to_al
->sym
->start
) {
964 struct call_path_root
*cpr
= ts
->crp
->cpr
;
965 struct call_path
*cp
;
968 * The compiler might optimize a call/ret combination by making
969 * it a jmp. Make that visible by recording on the stack a
970 * branch to the start of a different symbol. Note, that means
971 * when a ret pops the stack, all jmps must be popped off first.
973 cp
= call_path__findnew(cpr
, ts
->stack
[ts
->cnt
- 1].cp
,
974 to_al
->sym
, sample
->addr
,
976 err
= thread_stack__push_cp(ts
, 0, sample
->time
, ref
, cp
, false,
979 ts
->stack
[ts
->cnt
- 1].non_call
= true;
985 size_t thread_stack__depth(struct thread
*thread
, int cpu
)
987 struct thread_stack
*ts
= thread__stack(thread
, cpu
);