• Al Cooper's avatar
    MIPS: Function tracer: Fix broken function tracing · 58b69401
    Al Cooper authored
    Function tracing is currently broken for all 32 bit MIPS platforms.
    When tracing is enabled, the kernel immediately hangs on boot.
    This is a result of commit b732d439
    that changes the kernel/trace/Kconfig file so that is no longer
    forces FRAME_POINTER when FUNCTION_TRACING is enabled.
    
    MIPS frame pointers are generally considered to be useless because
    they cannot be used to unwind the stack. Unfortunately the MIPS
    function tracing code has bugs that are masked by the use of frame
    pointers. This commit fixes the bugs so that MIPS frame pointers
    don't need to be enabled.
    
    The bugs are a result of the odd calling sequence used to call the trace
    routine. This calling sequence is inserted into every traceable function
    when the tracing CONFIG option is enabled. This sequence is generated
    for 32bit MIPS platforms by the compiler via the "-pg" flag.
    
    Part of the sequence is "addiu sp,sp,-8" in the delay slot after every
    call to the trace routine "_mcount" (some legacy thing where 2 arguments
    used to be pushed on the stack). The _mcount routine is expected to
    adjust the sp by +8 before returning.  So when not disabled, the original
    jalr and addiu will be there, so _mcount has to adjust sp.
    
    The problem is that when tracing is disabled for a function, the
    "jalr _mcount" instruction is replaced with a nop, but the
    "addiu sp,sp,-8" is still executed and the stack pointer is left
    trashed. When frame pointers are enabled the problem is masked
    because any access to the stack is done through the frame
    pointer and the stack pointer is restored from the frame pointer when
    the function returns.
    
    This patch writes two nops starting at the address of the "jalr _mcount"
    instruction whenever tracing is disabled. This means that the
    "addiu sp,sp.-8" will be converted to a nop along with the "jalr".  When
    disabled, there will be two nops.
    
    This is SMP safe because the first time this happens is during
    ftrace_init() which is before any other processor has been started.
    Subsequent calls to enable/disable tracing when other CPUs ARE running
    will still be safe because the enable will only change the first nop
    to a "jalr" and the disable, while writing 2 nops, will only be changing
    the "jalr". This patch also stops using stop_machine() to call the
    tracer enable/disable routines and calls them directly because the
    routines are SMP safe.
    
    When the kernel first boots we have to be able to handle the gcc
    generated jalr, addui sequence until ftrace_init gets a chance to run
    and change the sequence. At this point mcount just adjusts the stack
    and returns. When ftrace_init runs, we convert the jalr/addui to nops.
    Then whenever tracing is enabled we convert the first nop to a "jalr
    mcount+8". The mcount+8 entry point skips the stack adjust.
    
    [ralf@linux-mips.org: Folded in  Steven Rostedt's build fix.]
    Signed-off-by: default avatarAl Cooper <alcooperx@gmail.com>
    Cc: rostedt@goodmis.org
    Cc: ddaney.cavm@gmail.com
    Cc: linux-mips@linux-mips.org
    Cc: linux-kernel@vger.kernel.org
    Patchwork: https://patchwork.linux-mips.org/patch/4806/
    Patchwork: https://patchwork.linux-mips.org/patch/4841/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
    58b69401
ftrace.c 9.37 KB