Re: [PATCH] MIPS: Ftrace: Fix dynamic tracing of kernel modules

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Petri,

>However, when ftrace is later enabled for a call site, ftrace_make_call()
>does not currently restore the _mcount call correctly for module call sites

I just did some testing on a BMIPS5000 system with a 3.3 kernel and
module tracing worked correctly without these changes. I see that the call
site is being restored correctly by writing a single 0x3c038001 which is what
the compiler originally generated. What are the first 2 instructions of your
modules call site and what version kernel and toolchain are you using?

Al

On Thu, Jul 24, 2014 at 1:55 AM, Petri Gynther <pgynther@xxxxxxxxxx> wrote:
> Dynamic tracing of kernel modules is broken on 32-bit MIPS. When modules
> are loaded, the kernel crashes when dynamic tracing is enabled with:
>  cd /sys/kernel/debug/tracing
>  echo > set_ftrace_filter
>  echo function > current_tracer
>
> 1) arch/mips/kernel/ftrace.c
> When the kernel boots, or when a module is initialized, ftrace_make_nop()
> modifies every _mcount call site to eliminate the ftrace overhead.
> However, when ftrace is later enabled for a call site, ftrace_make_call()
> does not currently restore the _mcount call correctly for module call sites.
> Added ftrace_modify_code_2r() and modified ftrace_make_call() to fix this.
>
> 2) arch/mips/kernel/mcount.S
> _mcount assembly routine is supposed to have the caller's _mcount call site
> address in register a0. However, a0 is currently not calculated correctly for
> module call sites. a0 should be (ra - 20) or (ra - 24), depending on whether
> the kernel was built with KBUILD_MCOUNT_RA_ADDRESS or not.
>
> This fix has been tested on Broadcom BMIPS5000 processor. Dynamic tracing
> now works for both built-in functions and module functions.
>
> Signed-off-by: Petri Gynther <pgynther@xxxxxxxxxx>
> ---
>  arch/mips/kernel/ftrace.c | 56 +++++++++++++++++++++++++++++++++++++++--------
>  arch/mips/kernel/mcount.S | 13 +++++++++++
>  2 files changed, 60 insertions(+), 9 deletions(-)
>
> diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
> index 60e7e5e..2a72208 100644
> --- a/arch/mips/kernel/ftrace.c
> +++ b/arch/mips/kernel/ftrace.c
> @@ -63,7 +63,7 @@ static inline int in_kernel_space(unsigned long ip)
>         ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK)))
>
>  static unsigned int insn_jal_ftrace_caller __read_mostly;
> -static unsigned int insn_lui_v1_hi16_mcount __read_mostly;
> +static unsigned int insn_la_mcount[2] __read_mostly;
>  static unsigned int insn_j_ftrace_graph_caller __maybe_unused __read_mostly;
>
>  static inline void ftrace_dyn_arch_init_insns(void)
> @@ -71,10 +71,10 @@ static inline void ftrace_dyn_arch_init_insns(void)
>         u32 *buf;
>         unsigned int v1;
>
> -       /* lui v1, hi16_mcount */
> +       /* la v1, _mcount */
>         v1 = 3;
> -       buf = (u32 *)&insn_lui_v1_hi16_mcount;
> -       UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR);
> +       buf = (u32 *)&insn_la_mcount[0];
> +       UASM_i_LA(&buf, v1, MCOUNT_ADDR);
>
>         /* jal (ftrace_caller + 8), jump over the first two instruction */
>         buf = (u32 *)&insn_jal_ftrace_caller;
> @@ -111,14 +111,47 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
>                                 unsigned int new_code2)
>  {
>         int faulted;
> +       mm_segment_t old_fs;
>
>         safe_store_code(new_code1, ip, faulted);
>         if (unlikely(faulted))
>                 return -EFAULT;
> -       safe_store_code(new_code2, ip + 4, faulted);
> +
> +       ip += 4;
> +       safe_store_code(new_code2, ip, faulted);
>         if (unlikely(faulted))
>                 return -EFAULT;
> +
> +       ip -= 4;
> +       old_fs = get_fs();
> +       set_fs(get_ds());
>         flush_icache_range(ip, ip + 8);
> +       set_fs(old_fs);
> +
> +       return 0;
> +}
> +
> +static int ftrace_modify_code_2r(unsigned long ip, unsigned int new_code1,
> +                                unsigned int new_code2)
> +{
> +       int faulted;
> +       mm_segment_t old_fs;
> +
> +       ip += 4;
> +       safe_store_code(new_code2, ip, faulted);
> +       if (unlikely(faulted))
> +               return -EFAULT;
> +
> +       ip -= 4;
> +       safe_store_code(new_code1, ip, faulted);
> +       if (unlikely(faulted))
> +               return -EFAULT;
> +
> +       old_fs = get_fs();
> +       set_fs(get_ds());
> +       flush_icache_range(ip, ip + 8);
> +       set_fs(old_fs);
> +
>         return 0;
>  }
>  #endif
> @@ -130,13 +163,14 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
>   *
>   * move at, ra
>   * jal _mcount         --> nop
> + *  sub sp, sp, 8      --> nop  (CONFIG_32BIT)
>   *
>   * 2. For modules:
>   *
>   * 2.1 For KBUILD_MCOUNT_RA_ADDRESS and CONFIG_32BIT
>   *
>   * lui v1, hi_16bit_of_mcount       --> b 1f (0x10000005)
> - * addiu v1, v1, low_16bit_of_mcount
> + * addiu v1, v1, low_16bit_of_mcount --> nop  (CONFIG_32BIT)
>   * move at, ra
>   * move $12, ra_address
>   * jalr v1
> @@ -145,7 +179,7 @@ static int ftrace_modify_code_2(unsigned long ip, unsigned int new_code1,
>   * 2.2 For the Other situations
>   *
>   * lui v1, hi_16bit_of_mcount       --> b 1f (0x10000004)
> - * addiu v1, v1, low_16bit_of_mcount
> + * addiu v1, v1, low_16bit_of_mcount --> nop  (CONFIG_32BIT)
>   * move at, ra
>   * jalr v1
>   *  nop | move $12, ra_address | sub sp, sp, 8
> @@ -184,10 +218,14 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
>         unsigned int new;
>         unsigned long ip = rec->ip;
>
> -       new = in_kernel_space(ip) ? insn_jal_ftrace_caller :
> -               insn_lui_v1_hi16_mcount;
> +       new = in_kernel_space(ip) ? insn_jal_ftrace_caller : insn_la_mcount[0];
>
> +#ifdef CONFIG_64BIT
>         return ftrace_modify_code(ip, new);
> +#else
> +       return ftrace_modify_code_2r(ip, new, in_kernel_space(ip) ?
> +                                               INSN_NOP : insn_la_mcount[1]);
> +#endif
>  }
>
>  #define FTRACE_CALL_IP ((unsigned long)(&ftrace_call))
> diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
> index 539b629..26ceb3c 100644
> --- a/arch/mips/kernel/mcount.S
> +++ b/arch/mips/kernel/mcount.S
> @@ -84,6 +84,19 @@ _mcount:
>  #endif
>
>         PTR_SUBU a0, ra, 8      /* arg1: self address */
> +       PTR_LA   t1, _stext
> +       sltu     t2, a0, t1     /* t2 = (a0 < _stext) */
> +       PTR_LA   t1, _etext
> +       sltu     t3, t1, a0     /* t3 = (a0 > _etext) */
> +       or       t1, t2, t3
> +       beqz     t1, ftrace_call
> +        nop
> +#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
> +       PTR_SUBU a0, a0, 16     /* arg1: adjust to module's recorded callsite */
> +#else
> +       PTR_SUBU a0, a0, 12
> +#endif
> +
>         .globl ftrace_call
>  ftrace_call:
>         nop     /* a placeholder for the call to a real tracing function */
> --
> 2.0.0.526.g5318336
>


[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux