1d2912cb1SThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-only */ 2819e50e2SAKASHI Takahiro/* 3819e50e2SAKASHI Takahiro * arch/arm64/kernel/entry-ftrace.S 4819e50e2SAKASHI Takahiro * 5819e50e2SAKASHI Takahiro * Copyright (C) 2013 Linaro Limited 6819e50e2SAKASHI Takahiro * Author: AKASHI Takahiro <takahiro.akashi@linaro.org> 7819e50e2SAKASHI Takahiro */ 8819e50e2SAKASHI Takahiro 9819e50e2SAKASHI Takahiro#include <linux/linkage.h> 103b23e499STorsten Duwe#include <asm/asm-offsets.h> 11f705d954SArnd Bergmann#include <asm/assembler.h> 12819e50e2SAKASHI Takahiro#include <asm/ftrace.h> 13819e50e2SAKASHI Takahiro#include <asm/insn.h> 14819e50e2SAKASHI Takahiro 153b23e499STorsten Duwe#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS 163b23e499STorsten Duwe/* 173b23e499STorsten Duwe * Due to -fpatchable-function-entry=2, the compiler has placed two NOPs before 183b23e499STorsten Duwe * the regular function prologue. For an enabled callsite, ftrace_init_nop() and 193b23e499STorsten Duwe * ftrace_make_call() have patched those NOPs to: 203b23e499STorsten Duwe * 213b23e499STorsten Duwe * MOV X9, LR 223b23e499STorsten Duwe * BL <entry> 233b23e499STorsten Duwe * 243b23e499STorsten Duwe * ... where <entry> is either ftrace_caller or ftrace_regs_caller. 253b23e499STorsten Duwe * 263b23e499STorsten Duwe * Each instrumented function follows the AAPCS, so here x0-x8 and x19-x30 are 273b23e499STorsten Duwe * live, and x9-x18 are safe to clobber. 283b23e499STorsten Duwe * 293b23e499STorsten Duwe * We save the callsite's context into a pt_regs before invoking any ftrace 303b23e499STorsten Duwe * callbacks. So that we can get a sensible backtrace, we create a stack record 313b23e499STorsten Duwe * for the callsite and the ftrace entry assembly. This is not sufficient for 323b23e499STorsten Duwe * reliable stacktrace: until we create the callsite stack record, its caller 333b23e499STorsten Duwe * is missing from the LR and existing chain of frame records. 343b23e499STorsten Duwe */ 353b23e499STorsten Duwe .macro ftrace_regs_entry, allregs=0 363b23e499STorsten Duwe /* Make room for pt_regs, plus a callee frame */ 373b23e499STorsten Duwe sub sp, sp, #(S_FRAME_SIZE + 16) 383b23e499STorsten Duwe 393b23e499STorsten Duwe /* Save function arguments (and x9 for simplicity) */ 403b23e499STorsten Duwe stp x0, x1, [sp, #S_X0] 413b23e499STorsten Duwe stp x2, x3, [sp, #S_X2] 423b23e499STorsten Duwe stp x4, x5, [sp, #S_X4] 433b23e499STorsten Duwe stp x6, x7, [sp, #S_X6] 443b23e499STorsten Duwe stp x8, x9, [sp, #S_X8] 453b23e499STorsten Duwe 463b23e499STorsten Duwe /* Optionally save the callee-saved registers, always save the FP */ 473b23e499STorsten Duwe .if \allregs == 1 483b23e499STorsten Duwe stp x10, x11, [sp, #S_X10] 493b23e499STorsten Duwe stp x12, x13, [sp, #S_X12] 503b23e499STorsten Duwe stp x14, x15, [sp, #S_X14] 513b23e499STorsten Duwe stp x16, x17, [sp, #S_X16] 523b23e499STorsten Duwe stp x18, x19, [sp, #S_X18] 533b23e499STorsten Duwe stp x20, x21, [sp, #S_X20] 543b23e499STorsten Duwe stp x22, x23, [sp, #S_X22] 553b23e499STorsten Duwe stp x24, x25, [sp, #S_X24] 563b23e499STorsten Duwe stp x26, x27, [sp, #S_X26] 573b23e499STorsten Duwe stp x28, x29, [sp, #S_X28] 583b23e499STorsten Duwe .else 593b23e499STorsten Duwe str x29, [sp, #S_FP] 603b23e499STorsten Duwe .endif 613b23e499STorsten Duwe 623b23e499STorsten Duwe /* Save the callsite's SP and LR */ 633b23e499STorsten Duwe add x10, sp, #(S_FRAME_SIZE + 16) 643b23e499STorsten Duwe stp x9, x10, [sp, #S_LR] 653b23e499STorsten Duwe 663b23e499STorsten Duwe /* Save the PC after the ftrace callsite */ 673b23e499STorsten Duwe str x30, [sp, #S_PC] 683b23e499STorsten Duwe 693b23e499STorsten Duwe /* Create a frame record for the callsite above pt_regs */ 703b23e499STorsten Duwe stp x29, x9, [sp, #S_FRAME_SIZE] 713b23e499STorsten Duwe add x29, sp, #S_FRAME_SIZE 723b23e499STorsten Duwe 733b23e499STorsten Duwe /* Create our frame record within pt_regs. */ 743b23e499STorsten Duwe stp x29, x30, [sp, #S_STACKFRAME] 753b23e499STorsten Duwe add x29, sp, #S_STACKFRAME 763b23e499STorsten Duwe .endm 773b23e499STorsten Duwe 78e434b08bSMark BrownSYM_CODE_START(ftrace_regs_caller) 793b23e499STorsten Duwe ftrace_regs_entry 1 803b23e499STorsten Duwe b ftrace_common 81e434b08bSMark BrownSYM_CODE_END(ftrace_regs_caller) 823b23e499STorsten Duwe 83e434b08bSMark BrownSYM_CODE_START(ftrace_caller) 843b23e499STorsten Duwe ftrace_regs_entry 0 853b23e499STorsten Duwe b ftrace_common 86e434b08bSMark BrownSYM_CODE_END(ftrace_caller) 873b23e499STorsten Duwe 88e434b08bSMark BrownSYM_CODE_START(ftrace_common) 893b23e499STorsten Duwe sub x0, x30, #AARCH64_INSN_SIZE // ip (callsite's BL insn) 903b23e499STorsten Duwe mov x1, x9 // parent_ip (callsite's LR) 913b23e499STorsten Duwe ldr_l x2, function_trace_op // op 923b23e499STorsten Duwe mov x3, sp // regs 933b23e499STorsten Duwe 94e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) 953b23e499STorsten Duwe bl ftrace_stub 963b23e499STorsten Duwe 973b23e499STorsten Duwe#ifdef CONFIG_FUNCTION_GRAPH_TRACER 98e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_graph_call, SYM_L_GLOBAL) // ftrace_graph_caller(); 993b23e499STorsten Duwe nop // If enabled, this will be replaced 1003b23e499STorsten Duwe // "b ftrace_graph_caller" 1013b23e499STorsten Duwe#endif 1023b23e499STorsten Duwe 1033b23e499STorsten Duwe/* 1043b23e499STorsten Duwe * At the callsite x0-x8 and x19-x30 were live. Any C code will have preserved 1053b23e499STorsten Duwe * x19-x29 per the AAPCS, and we created frame records upon entry, so we need 1063b23e499STorsten Duwe * to restore x0-x8, x29, and x30. 1073b23e499STorsten Duwe */ 1083b23e499STorsten Duweftrace_common_return: 1093b23e499STorsten Duwe /* Restore function arguments */ 1103b23e499STorsten Duwe ldp x0, x1, [sp] 1113b23e499STorsten Duwe ldp x2, x3, [sp, #S_X2] 1123b23e499STorsten Duwe ldp x4, x5, [sp, #S_X4] 1133b23e499STorsten Duwe ldp x6, x7, [sp, #S_X6] 1143b23e499STorsten Duwe ldr x8, [sp, #S_X8] 1153b23e499STorsten Duwe 1163b23e499STorsten Duwe /* Restore the callsite's FP, LR, PC */ 1173b23e499STorsten Duwe ldr x29, [sp, #S_FP] 1183b23e499STorsten Duwe ldr x30, [sp, #S_LR] 1193b23e499STorsten Duwe ldr x9, [sp, #S_PC] 1203b23e499STorsten Duwe 1213b23e499STorsten Duwe /* Restore the callsite's SP */ 1223b23e499STorsten Duwe add sp, sp, #S_FRAME_SIZE + 16 1233b23e499STorsten Duwe 1243b23e499STorsten Duwe ret x9 125e434b08bSMark BrownSYM_CODE_END(ftrace_common) 1263b23e499STorsten Duwe 1273b23e499STorsten Duwe#ifdef CONFIG_FUNCTION_GRAPH_TRACER 128e434b08bSMark BrownSYM_CODE_START(ftrace_graph_caller) 1293b23e499STorsten Duwe ldr x0, [sp, #S_PC] 1303b23e499STorsten Duwe sub x0, x0, #AARCH64_INSN_SIZE // ip (callsite's BL insn) 1313b23e499STorsten Duwe add x1, sp, #S_LR // parent_ip (callsite's LR) 1323b23e499STorsten Duwe ldr x2, [sp, #S_FRAME_SIZE] // parent fp (callsite's FP) 1333b23e499STorsten Duwe bl prepare_ftrace_return 1343b23e499STorsten Duwe b ftrace_common_return 135e434b08bSMark BrownSYM_CODE_END(ftrace_graph_caller) 1363b23e499STorsten Duwe#endif 1373b23e499STorsten Duwe 1383b23e499STorsten Duwe#else /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ 1393b23e499STorsten Duwe 140819e50e2SAKASHI Takahiro/* 141819e50e2SAKASHI Takahiro * Gcc with -pg will put the following code in the beginning of each function: 142819e50e2SAKASHI Takahiro * mov x0, x30 143819e50e2SAKASHI Takahiro * bl _mcount 144819e50e2SAKASHI Takahiro * [function's body ...] 145819e50e2SAKASHI Takahiro * "bl _mcount" may be replaced to "bl ftrace_caller" or NOP if dynamic 146819e50e2SAKASHI Takahiro * ftrace is enabled. 147819e50e2SAKASHI Takahiro * 148819e50e2SAKASHI Takahiro * Please note that x0 as an argument will not be used here because we can 149819e50e2SAKASHI Takahiro * get lr(x30) of instrumented function at any time by winding up call stack 150819e50e2SAKASHI Takahiro * as long as the kernel is compiled without -fomit-frame-pointer. 151819e50e2SAKASHI Takahiro * (or CONFIG_FRAME_POINTER, this is forced on arm64) 152819e50e2SAKASHI Takahiro * 153819e50e2SAKASHI Takahiro * stack layout after mcount_enter in _mcount(): 154819e50e2SAKASHI Takahiro * 155819e50e2SAKASHI Takahiro * current sp/fp => 0:+-----+ 156819e50e2SAKASHI Takahiro * in _mcount() | x29 | -> instrumented function's fp 157819e50e2SAKASHI Takahiro * +-----+ 158819e50e2SAKASHI Takahiro * | x30 | -> _mcount()'s lr (= instrumented function's pc) 159819e50e2SAKASHI Takahiro * old sp => +16:+-----+ 160819e50e2SAKASHI Takahiro * when instrumented | | 161819e50e2SAKASHI Takahiro * function calls | ... | 162819e50e2SAKASHI Takahiro * _mcount() | | 163819e50e2SAKASHI Takahiro * | | 164819e50e2SAKASHI Takahiro * instrumented => +xx:+-----+ 165819e50e2SAKASHI Takahiro * function's fp | x29 | -> parent's fp 166819e50e2SAKASHI Takahiro * +-----+ 167819e50e2SAKASHI Takahiro * | x30 | -> instrumented function's lr (= parent's pc) 168819e50e2SAKASHI Takahiro * +-----+ 169819e50e2SAKASHI Takahiro * | ... | 170819e50e2SAKASHI Takahiro */ 171819e50e2SAKASHI Takahiro 172819e50e2SAKASHI Takahiro .macro mcount_enter 173819e50e2SAKASHI Takahiro stp x29, x30, [sp, #-16]! 174819e50e2SAKASHI Takahiro mov x29, sp 175819e50e2SAKASHI Takahiro .endm 176819e50e2SAKASHI Takahiro 177819e50e2SAKASHI Takahiro .macro mcount_exit 178819e50e2SAKASHI Takahiro ldp x29, x30, [sp], #16 179819e50e2SAKASHI Takahiro ret 180819e50e2SAKASHI Takahiro .endm 181819e50e2SAKASHI Takahiro 182819e50e2SAKASHI Takahiro .macro mcount_adjust_addr rd, rn 183819e50e2SAKASHI Takahiro sub \rd, \rn, #AARCH64_INSN_SIZE 184819e50e2SAKASHI Takahiro .endm 185819e50e2SAKASHI Takahiro 186819e50e2SAKASHI Takahiro /* for instrumented function's parent */ 187819e50e2SAKASHI Takahiro .macro mcount_get_parent_fp reg 188819e50e2SAKASHI Takahiro ldr \reg, [x29] 189819e50e2SAKASHI Takahiro ldr \reg, [\reg] 190819e50e2SAKASHI Takahiro .endm 191819e50e2SAKASHI Takahiro 192819e50e2SAKASHI Takahiro /* for instrumented function */ 193819e50e2SAKASHI Takahiro .macro mcount_get_pc0 reg 194819e50e2SAKASHI Takahiro mcount_adjust_addr \reg, x30 195819e50e2SAKASHI Takahiro .endm 196819e50e2SAKASHI Takahiro 197819e50e2SAKASHI Takahiro .macro mcount_get_pc reg 198819e50e2SAKASHI Takahiro ldr \reg, [x29, #8] 199819e50e2SAKASHI Takahiro mcount_adjust_addr \reg, \reg 200819e50e2SAKASHI Takahiro .endm 201819e50e2SAKASHI Takahiro 202819e50e2SAKASHI Takahiro .macro mcount_get_lr reg 203819e50e2SAKASHI Takahiro ldr \reg, [x29] 204819e50e2SAKASHI Takahiro ldr \reg, [\reg, #8] 205819e50e2SAKASHI Takahiro .endm 206819e50e2SAKASHI Takahiro 207819e50e2SAKASHI Takahiro .macro mcount_get_lr_addr reg 208819e50e2SAKASHI Takahiro ldr \reg, [x29] 209819e50e2SAKASHI Takahiro add \reg, \reg, #8 210819e50e2SAKASHI Takahiro .endm 211819e50e2SAKASHI Takahiro 212bd7d38dbSAKASHI Takahiro#ifndef CONFIG_DYNAMIC_FTRACE 213819e50e2SAKASHI Takahiro/* 214819e50e2SAKASHI Takahiro * void _mcount(unsigned long return_address) 215819e50e2SAKASHI Takahiro * @return_address: return address to instrumented function 216819e50e2SAKASHI Takahiro * 217819e50e2SAKASHI Takahiro * This function makes calls, if enabled, to: 218819e50e2SAKASHI Takahiro * - tracer function to probe instrumented function's entry, 219819e50e2SAKASHI Takahiro * - ftrace_graph_caller to set up an exit hook 220819e50e2SAKASHI Takahiro */ 221e2d591d2SMark BrownSYM_FUNC_START(_mcount) 222819e50e2SAKASHI Takahiro mcount_enter 223819e50e2SAKASHI Takahiro 224829d2bd1SMark Rutland ldr_l x2, ftrace_trace_function 225819e50e2SAKASHI Takahiro adr x0, ftrace_stub 226819e50e2SAKASHI Takahiro cmp x0, x2 // if (ftrace_trace_function 227819e50e2SAKASHI Takahiro b.eq skip_ftrace_call // != ftrace_stub) { 228819e50e2SAKASHI Takahiro 229819e50e2SAKASHI Takahiro mcount_get_pc x0 // function's pc 230819e50e2SAKASHI Takahiro mcount_get_lr x1 // function's lr (= parent's pc) 231819e50e2SAKASHI Takahiro blr x2 // (*ftrace_trace_function)(pc, lr); 232819e50e2SAKASHI Takahiro 233d125bffcSJulien Thierryskip_ftrace_call: // } 234d125bffcSJulien Thierry#ifdef CONFIG_FUNCTION_GRAPH_TRACER 235829d2bd1SMark Rutland ldr_l x2, ftrace_graph_return 236f1ba46eeSArd Biesheuvel cmp x0, x2 // if ((ftrace_graph_return 237f1ba46eeSArd Biesheuvel b.ne ftrace_graph_caller // != ftrace_stub) 238819e50e2SAKASHI Takahiro 239829d2bd1SMark Rutland ldr_l x2, ftrace_graph_entry // || (ftrace_graph_entry 240829d2bd1SMark Rutland adr_l x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub)) 241819e50e2SAKASHI Takahiro cmp x0, x2 242819e50e2SAKASHI Takahiro b.ne ftrace_graph_caller // ftrace_graph_caller(); 243819e50e2SAKASHI Takahiro#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 244d125bffcSJulien Thierry mcount_exit 245e2d591d2SMark BrownSYM_FUNC_END(_mcount) 246dbd31962SMark RutlandEXPORT_SYMBOL(_mcount) 247dbd31962SMark RutlandNOKPROBE(_mcount) 248819e50e2SAKASHI Takahiro 249bd7d38dbSAKASHI Takahiro#else /* CONFIG_DYNAMIC_FTRACE */ 250bd7d38dbSAKASHI Takahiro/* 251bd7d38dbSAKASHI Takahiro * _mcount() is used to build the kernel with -pg option, but all the branch 252bd7d38dbSAKASHI Takahiro * instructions to _mcount() are replaced to NOP initially at kernel start up, 253bd7d38dbSAKASHI Takahiro * and later on, NOP to branch to ftrace_caller() when enabled or branch to 254bd7d38dbSAKASHI Takahiro * NOP when disabled per-function base. 255bd7d38dbSAKASHI Takahiro */ 256e2d591d2SMark BrownSYM_FUNC_START(_mcount) 257bd7d38dbSAKASHI Takahiro ret 258e2d591d2SMark BrownSYM_FUNC_END(_mcount) 259dbd31962SMark RutlandEXPORT_SYMBOL(_mcount) 260dbd31962SMark RutlandNOKPROBE(_mcount) 261bd7d38dbSAKASHI Takahiro 262bd7d38dbSAKASHI Takahiro/* 263bd7d38dbSAKASHI Takahiro * void ftrace_caller(unsigned long return_address) 264bd7d38dbSAKASHI Takahiro * @return_address: return address to instrumented function 265bd7d38dbSAKASHI Takahiro * 266bd7d38dbSAKASHI Takahiro * This function is a counterpart of _mcount() in 'static' ftrace, and 267bd7d38dbSAKASHI Takahiro * makes calls to: 268bd7d38dbSAKASHI Takahiro * - tracer function to probe instrumented function's entry, 269bd7d38dbSAKASHI Takahiro * - ftrace_graph_caller to set up an exit hook 270bd7d38dbSAKASHI Takahiro */ 271e2d591d2SMark BrownSYM_FUNC_START(ftrace_caller) 272bd7d38dbSAKASHI Takahiro mcount_enter 273bd7d38dbSAKASHI Takahiro 274bd7d38dbSAKASHI Takahiro mcount_get_pc0 x0 // function's pc 275bd7d38dbSAKASHI Takahiro mcount_get_lr x1 // function's lr 276bd7d38dbSAKASHI Takahiro 277e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) // tracer(pc, lr); 278bd7d38dbSAKASHI Takahiro nop // This will be replaced with "bl xxx" 279bd7d38dbSAKASHI Takahiro // where xxx can be any kind of tracer. 280bd7d38dbSAKASHI Takahiro 281bd7d38dbSAKASHI Takahiro#ifdef CONFIG_FUNCTION_GRAPH_TRACER 282e2d591d2SMark BrownSYM_INNER_LABEL(ftrace_graph_call) // ftrace_graph_caller(); 283bd7d38dbSAKASHI Takahiro nop // If enabled, this will be replaced 284bd7d38dbSAKASHI Takahiro // "b ftrace_graph_caller" 285bd7d38dbSAKASHI Takahiro#endif 286bd7d38dbSAKASHI Takahiro 287bd7d38dbSAKASHI Takahiro mcount_exit 288e2d591d2SMark BrownSYM_FUNC_END(ftrace_caller) 28970927d02SMark Rutland#endif /* CONFIG_DYNAMIC_FTRACE */ 290819e50e2SAKASHI Takahiro 291819e50e2SAKASHI Takahiro#ifdef CONFIG_FUNCTION_GRAPH_TRACER 292819e50e2SAKASHI Takahiro/* 293819e50e2SAKASHI Takahiro * void ftrace_graph_caller(void) 294819e50e2SAKASHI Takahiro * 295819e50e2SAKASHI Takahiro * Called from _mcount() or ftrace_caller() when function_graph tracer is 296819e50e2SAKASHI Takahiro * selected. 297819e50e2SAKASHI Takahiro * This function w/ prepare_ftrace_return() fakes link register's value on 298819e50e2SAKASHI Takahiro * the call stack in order to intercept instrumented function's return path 299819e50e2SAKASHI Takahiro * and run return_to_handler() later on its exit. 300819e50e2SAKASHI Takahiro */ 301e2d591d2SMark BrownSYM_FUNC_START(ftrace_graph_caller) 3027dc48bf9SMark Rutland mcount_get_pc x0 // function's pc 3037dc48bf9SMark Rutland mcount_get_lr_addr x1 // pointer to function's saved lr 304819e50e2SAKASHI Takahiro mcount_get_parent_fp x2 // parent's fp 3057dc48bf9SMark Rutland bl prepare_ftrace_return // prepare_ftrace_return(pc, &lr, fp) 306819e50e2SAKASHI Takahiro 307819e50e2SAKASHI Takahiro mcount_exit 308e2d591d2SMark BrownSYM_FUNC_END(ftrace_graph_caller) 3093b23e499STorsten Duwe#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 3103b23e499STorsten Duwe#endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ 311819e50e2SAKASHI Takahiro 312e2d591d2SMark BrownSYM_FUNC_START(ftrace_stub) 3133b23e499STorsten Duwe ret 314e2d591d2SMark BrownSYM_FUNC_END(ftrace_stub) 3153b23e499STorsten Duwe 3163b23e499STorsten Duwe#ifdef CONFIG_FUNCTION_GRAPH_TRACER 317819e50e2SAKASHI Takahiro/* 318819e50e2SAKASHI Takahiro * void return_to_handler(void) 319819e50e2SAKASHI Takahiro * 320819e50e2SAKASHI Takahiro * Run ftrace_return_to_handler() before going back to parent. 3215c176affSMark Rutland * @fp is checked against the value passed by ftrace_graph_caller(). 322819e50e2SAKASHI Takahiro */ 3231e4729edSMark BrownSYM_CODE_START(return_to_handler) 32449e258e0SMark Rutland /* save return value regs */ 32549e258e0SMark Rutland sub sp, sp, #64 32649e258e0SMark Rutland stp x0, x1, [sp] 32749e258e0SMark Rutland stp x2, x3, [sp, #16] 32849e258e0SMark Rutland stp x4, x5, [sp, #32] 32949e258e0SMark Rutland stp x6, x7, [sp, #48] 33049e258e0SMark Rutland 331819e50e2SAKASHI Takahiro mov x0, x29 // parent's fp 332819e50e2SAKASHI Takahiro bl ftrace_return_to_handler// addr = ftrace_return_to_hander(fp); 333819e50e2SAKASHI Takahiro mov x30, x0 // restore the original return address 33449e258e0SMark Rutland 33549e258e0SMark Rutland /* restore return value regs */ 33649e258e0SMark Rutland ldp x0, x1, [sp] 33749e258e0SMark Rutland ldp x2, x3, [sp, #16] 33849e258e0SMark Rutland ldp x4, x5, [sp, #32] 33949e258e0SMark Rutland ldp x6, x7, [sp, #48] 34049e258e0SMark Rutland add sp, sp, #64 34149e258e0SMark Rutland 342819e50e2SAKASHI Takahiro ret 3431e4729edSMark BrownSYM_CODE_END(return_to_handler) 344819e50e2SAKASHI Takahiro#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 345