LCOV - code coverage report
Current view: top level - arch/arm/probes/kprobes - actions-arm.c (source / functions) Hit Total Coverage
Test: Real Lines: 0 121 0.0 %
Date: 2020-10-17 15:46:43 Functions: 0 8 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * arch/arm/probes/kprobes/actions-arm.c
       4                 :            :  *
       5                 :            :  * Copyright (C) 2006, 2007 Motorola Inc.
       6                 :            :  */
       7                 :            : 
       8                 :            : /*
       9                 :            :  * We do not have hardware single-stepping on ARM, This
      10                 :            :  * effort is further complicated by the ARM not having a
      11                 :            :  * "next PC" register.  Instructions that change the PC
      12                 :            :  * can't be safely single-stepped in a MP environment, so
      13                 :            :  * we have a lot of work to do:
      14                 :            :  *
      15                 :            :  * In the prepare phase:
      16                 :            :  *   *) If it is an instruction that does anything
      17                 :            :  *      with the CPU mode, we reject it for a kprobe.
      18                 :            :  *      (This is out of laziness rather than need.  The
      19                 :            :  *      instructions could be simulated.)
      20                 :            :  *
      21                 :            :  *   *) Otherwise, decode the instruction rewriting its
      22                 :            :  *      registers to take fixed, ordered registers and
      23                 :            :  *      setting a handler for it to run the instruction.
      24                 :            :  *
      25                 :            :  * In the execution phase by an instruction's handler:
      26                 :            :  *
      27                 :            :  *   *) If the PC is written to by the instruction, the
      28                 :            :  *      instruction must be fully simulated in software.
      29                 :            :  *
      30                 :            :  *   *) Otherwise, a modified form of the instruction is
      31                 :            :  *      directly executed.  Its handler calls the
      32                 :            :  *      instruction in insn[0].  In insn[1] is a
      33                 :            :  *      "mov pc, lr" to return.
      34                 :            :  *
      35                 :            :  *      Before calling, load up the reordered registers
      36                 :            :  *      from the original instruction's registers.  If one
      37                 :            :  *      of the original input registers is the PC, compute
      38                 :            :  *      and adjust the appropriate input register.
      39                 :            :  *
      40                 :            :  *      After call completes, copy the output registers to
      41                 :            :  *      the original instruction's original registers.
      42                 :            :  *
      43                 :            :  * We don't use a real breakpoint instruction since that
      44                 :            :  * would have us in the kernel go from SVC mode to SVC
      45                 :            :  * mode losing the link register.  Instead we use an
      46                 :            :  * undefined instruction.  To simplify processing, the
      47                 :            :  * undefined instruction used for kprobes must be reserved
      48                 :            :  * exclusively for kprobes use.
      49                 :            :  *
      50                 :            :  * TODO: ifdef out some instruction decoding based on architecture.
      51                 :            :  */
      52                 :            : 
      53                 :            : #include <linux/kernel.h>
      54                 :            : #include <linux/kprobes.h>
      55                 :            : #include <linux/ptrace.h>
      56                 :            : 
      57                 :            : #include "../decode-arm.h"
      58                 :            : #include "core.h"
      59                 :            : #include "checkers.h"
      60                 :            : 
      61                 :            : #if  __LINUX_ARM_ARCH__ >= 6
      62                 :            : #define BLX(reg)        "blx       "reg"         \n\t"
      63                 :            : #else
      64                 :            : #define BLX(reg)        "mov       lr, pc          \n\t"      \
      65                 :            :                         "mov       pc, "reg"     \n\t"
      66                 :            : #endif
      67                 :            : 
      68                 :            : static void __kprobes
      69                 :          0 : emulate_ldrdstrd(probes_opcode_t insn,
      70                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
      71                 :            : {
      72                 :          0 :         unsigned long pc = regs->ARM_pc + 4;
      73                 :          0 :         int rt = (insn >> 12) & 0xf;
      74                 :          0 :         int rn = (insn >> 16) & 0xf;
      75                 :          0 :         int rm = insn & 0xf;
      76                 :            : 
      77                 :          0 :         register unsigned long rtv asm("r0") = regs->uregs[rt];
      78                 :          0 :         register unsigned long rt2v asm("r1") = regs->uregs[rt+1];
      79                 :          0 :         register unsigned long rnv asm("r2") = (rn == 15) ? pc
      80                 :          0 :                                                           : regs->uregs[rn];
      81                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
      82                 :            : 
      83                 :          0 :         __asm__ __volatile__ (
      84                 :            :                 BLX("%[fn]")
      85                 :            :                 : "=r" (rtv), "=r" (rt2v), "=r" (rnv)
      86                 :            :                 : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv),
      87                 :          0 :                   [fn] "r" (asi->insn_fn)
      88                 :            :                 : "lr", "memory", "cc"
      89                 :            :         );
      90                 :            : 
      91                 :          0 :         regs->uregs[rt] = rtv;
      92                 :          0 :         regs->uregs[rt+1] = rt2v;
      93                 :          0 :         if (is_writeback(insn))
      94                 :          0 :                 regs->uregs[rn] = rnv;
      95                 :          0 : }
      96                 :            : 
      97                 :            : static void __kprobes
      98                 :          0 : emulate_ldr(probes_opcode_t insn,
      99                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
     100                 :            : {
     101                 :          0 :         unsigned long pc = regs->ARM_pc + 4;
     102                 :          0 :         int rt = (insn >> 12) & 0xf;
     103                 :          0 :         int rn = (insn >> 16) & 0xf;
     104                 :          0 :         int rm = insn & 0xf;
     105                 :            : 
     106                 :            :         register unsigned long rtv asm("r0");
     107                 :          0 :         register unsigned long rnv asm("r2") = (rn == 15) ? pc
     108                 :          0 :                                                           : regs->uregs[rn];
     109                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
     110                 :            : 
     111                 :          0 :         __asm__ __volatile__ (
     112                 :            :                 BLX("%[fn]")
     113                 :            :                 : "=r" (rtv), "=r" (rnv)
     114                 :          0 :                 : "1" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
     115                 :            :                 : "lr", "memory", "cc"
     116                 :            :         );
     117                 :            : 
     118                 :          0 :         if (rt == 15)
     119                 :          0 :                 load_write_pc(rtv, regs);
     120                 :            :         else
     121                 :          0 :                 regs->uregs[rt] = rtv;
     122                 :            : 
     123                 :          0 :         if (is_writeback(insn))
     124                 :          0 :                 regs->uregs[rn] = rnv;
     125                 :          0 : }
     126                 :            : 
     127                 :            : static void __kprobes
     128                 :          0 : emulate_str(probes_opcode_t insn,
     129                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
     130                 :            : {
     131                 :          0 :         unsigned long rtpc = regs->ARM_pc - 4 + str_pc_offset;
     132                 :            :         unsigned long rnpc = regs->ARM_pc + 4;
     133                 :          0 :         int rt = (insn >> 12) & 0xf;
     134                 :          0 :         int rn = (insn >> 16) & 0xf;
     135                 :          0 :         int rm = insn & 0xf;
     136                 :            : 
     137                 :          0 :         register unsigned long rtv asm("r0") = (rt == 15) ? rtpc
     138                 :          0 :                                                           : regs->uregs[rt];
     139                 :          0 :         register unsigned long rnv asm("r2") = (rn == 15) ? rnpc
     140                 :          0 :                                                           : regs->uregs[rn];
     141                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
     142                 :            : 
     143                 :          0 :         __asm__ __volatile__ (
     144                 :            :                 BLX("%[fn]")
     145                 :            :                 : "=r" (rnv)
     146                 :          0 :                 : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (asi->insn_fn)
     147                 :            :                 : "lr", "memory", "cc"
     148                 :            :         );
     149                 :            : 
     150                 :          0 :         if (is_writeback(insn))
     151                 :          0 :                 regs->uregs[rn] = rnv;
     152                 :          0 : }
     153                 :            : 
     154                 :            : static void __kprobes
     155                 :          0 : emulate_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
     156                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
     157                 :            : {
     158                 :          0 :         unsigned long pc = regs->ARM_pc + 4;
     159                 :          0 :         int rd = (insn >> 12) & 0xf;
     160                 :          0 :         int rn = (insn >> 16) & 0xf;
     161                 :          0 :         int rm = insn & 0xf;
     162                 :          0 :         int rs = (insn >> 8) & 0xf;
     163                 :            : 
     164                 :          0 :         register unsigned long rdv asm("r0") = regs->uregs[rd];
     165                 :          0 :         register unsigned long rnv asm("r2") = (rn == 15) ? pc
     166                 :          0 :                                                           : regs->uregs[rn];
     167                 :          0 :         register unsigned long rmv asm("r3") = (rm == 15) ? pc
     168                 :          0 :                                                           : regs->uregs[rm];
     169                 :          0 :         register unsigned long rsv asm("r1") = regs->uregs[rs];
     170                 :          0 :         unsigned long cpsr = regs->ARM_cpsr;
     171                 :            : 
     172                 :          0 :         __asm__ __volatile__ (
     173                 :            :                 "msr       cpsr_fs, %[cpsr]        \n\t"
     174                 :            :                 BLX("%[fn]")
     175                 :            :                 "mrs       %[cpsr], cpsr           \n\t"
     176                 :            :                 : "=r" (rdv), [cpsr] "=r" (cpsr)
     177                 :            :                 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
     178                 :          0 :                   "1" (cpsr), [fn] "r" (asi->insn_fn)
     179                 :            :                 : "lr", "memory", "cc"
     180                 :            :         );
     181                 :            : 
     182                 :          0 :         if (rd == 15)
     183                 :          0 :                 alu_write_pc(rdv, regs);
     184                 :            :         else
     185                 :          0 :                 regs->uregs[rd] = rdv;
     186                 :          0 :         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
     187                 :          0 : }
     188                 :            : 
     189                 :            : static void __kprobes
     190                 :          0 : emulate_rd12rn16rm0_rwflags_nopc(probes_opcode_t insn,
     191                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
     192                 :            : {
     193                 :          0 :         int rd = (insn >> 12) & 0xf;
     194                 :          0 :         int rn = (insn >> 16) & 0xf;
     195                 :          0 :         int rm = insn & 0xf;
     196                 :            : 
     197                 :          0 :         register unsigned long rdv asm("r0") = regs->uregs[rd];
     198                 :          0 :         register unsigned long rnv asm("r2") = regs->uregs[rn];
     199                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
     200                 :          0 :         unsigned long cpsr = regs->ARM_cpsr;
     201                 :            : 
     202                 :          0 :         __asm__ __volatile__ (
     203                 :            :                 "msr       cpsr_fs, %[cpsr]        \n\t"
     204                 :            :                 BLX("%[fn]")
     205                 :            :                 "mrs       %[cpsr], cpsr           \n\t"
     206                 :            :                 : "=r" (rdv), [cpsr] "=r" (cpsr)
     207                 :            :                 : "0" (rdv), "r" (rnv), "r" (rmv),
     208                 :          0 :                   "1" (cpsr), [fn] "r" (asi->insn_fn)
     209                 :            :                 : "lr", "memory", "cc"
     210                 :            :         );
     211                 :            : 
     212                 :          0 :         regs->uregs[rd] = rdv;
     213                 :          0 :         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
     214                 :          0 : }
     215                 :            : 
     216                 :            : static void __kprobes
     217                 :          0 : emulate_rd16rn12rm0rs8_rwflags_nopc(probes_opcode_t insn,
     218                 :            :         struct arch_probes_insn *asi,
     219                 :            :         struct pt_regs *regs)
     220                 :            : {
     221                 :          0 :         int rd = (insn >> 16) & 0xf;
     222                 :          0 :         int rn = (insn >> 12) & 0xf;
     223                 :          0 :         int rm = insn & 0xf;
     224                 :          0 :         int rs = (insn >> 8) & 0xf;
     225                 :            : 
     226                 :          0 :         register unsigned long rdv asm("r2") = regs->uregs[rd];
     227                 :          0 :         register unsigned long rnv asm("r0") = regs->uregs[rn];
     228                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
     229                 :          0 :         register unsigned long rsv asm("r1") = regs->uregs[rs];
     230                 :          0 :         unsigned long cpsr = regs->ARM_cpsr;
     231                 :            : 
     232                 :          0 :         __asm__ __volatile__ (
     233                 :            :                 "msr       cpsr_fs, %[cpsr]        \n\t"
     234                 :            :                 BLX("%[fn]")
     235                 :            :                 "mrs       %[cpsr], cpsr           \n\t"
     236                 :            :                 : "=r" (rdv), [cpsr] "=r" (cpsr)
     237                 :            :                 : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv),
     238                 :          0 :                   "1" (cpsr), [fn] "r" (asi->insn_fn)
     239                 :            :                 : "lr", "memory", "cc"
     240                 :            :         );
     241                 :            : 
     242                 :          0 :         regs->uregs[rd] = rdv;
     243                 :          0 :         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
     244                 :          0 : }
     245                 :            : 
     246                 :            : static void __kprobes
     247                 :          0 : emulate_rd12rm0_noflags_nopc(probes_opcode_t insn,
     248                 :            :         struct arch_probes_insn *asi, struct pt_regs *regs)
     249                 :            : {
     250                 :          0 :         int rd = (insn >> 12) & 0xf;
     251                 :          0 :         int rm = insn & 0xf;
     252                 :            : 
     253                 :          0 :         register unsigned long rdv asm("r0") = regs->uregs[rd];
     254                 :          0 :         register unsigned long rmv asm("r3") = regs->uregs[rm];
     255                 :            : 
     256                 :          0 :         __asm__ __volatile__ (
     257                 :            :                 BLX("%[fn]")
     258                 :            :                 : "=r" (rdv)
     259                 :          0 :                 : "0" (rdv), "r" (rmv), [fn] "r" (asi->insn_fn)
     260                 :            :                 : "lr", "memory", "cc"
     261                 :            :         );
     262                 :            : 
     263                 :          0 :         regs->uregs[rd] = rdv;
     264                 :          0 : }
     265                 :            : 
     266                 :            : static void __kprobes
     267                 :          0 : emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(probes_opcode_t insn,
     268                 :            :         struct arch_probes_insn *asi,
     269                 :            :         struct pt_regs *regs)
     270                 :            : {
     271                 :          0 :         int rdlo = (insn >> 12) & 0xf;
     272                 :          0 :         int rdhi = (insn >> 16) & 0xf;
     273                 :          0 :         int rn = insn & 0xf;
     274                 :          0 :         int rm = (insn >> 8) & 0xf;
     275                 :            : 
     276                 :          0 :         register unsigned long rdlov asm("r0") = regs->uregs[rdlo];
     277                 :          0 :         register unsigned long rdhiv asm("r2") = regs->uregs[rdhi];
     278                 :          0 :         register unsigned long rnv asm("r3") = regs->uregs[rn];
     279                 :          0 :         register unsigned long rmv asm("r1") = regs->uregs[rm];
     280                 :          0 :         unsigned long cpsr = regs->ARM_cpsr;
     281                 :            : 
     282                 :          0 :         __asm__ __volatile__ (
     283                 :            :                 "msr       cpsr_fs, %[cpsr]        \n\t"
     284                 :            :                 BLX("%[fn]")
     285                 :            :                 "mrs       %[cpsr], cpsr           \n\t"
     286                 :            :                 : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr)
     287                 :            :                 : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv),
     288                 :          0 :                   "2" (cpsr), [fn] "r" (asi->insn_fn)
     289                 :            :                 : "lr", "memory", "cc"
     290                 :            :         );
     291                 :            : 
     292                 :          0 :         regs->uregs[rdlo] = rdlov;
     293                 :          0 :         regs->uregs[rdhi] = rdhiv;
     294                 :          0 :         regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK);
     295                 :          0 : }
     296                 :            : 
     297                 :            : const union decode_action kprobes_arm_actions[NUM_PROBES_ARM_ACTIONS] = {
     298                 :            :         [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
     299                 :            :         [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
     300                 :            :         [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
     301                 :            :         [PROBES_MRS] = {.handler = simulate_mrs},
     302                 :            :         [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
     303                 :            :         [PROBES_CLZ] = {.handler = emulate_rd12rm0_noflags_nopc},
     304                 :            :         [PROBES_SATURATING_ARITHMETIC] = {
     305                 :            :                 .handler = emulate_rd12rn16rm0_rwflags_nopc},
     306                 :            :         [PROBES_MUL1] = {.handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
     307                 :            :         [PROBES_MUL2] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
     308                 :            :         [PROBES_SWP] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
     309                 :            :         [PROBES_LDRSTRD] = {.handler = emulate_ldrdstrd},
     310                 :            :         [PROBES_LOAD_EXTRA] = {.handler = emulate_ldr},
     311                 :            :         [PROBES_LOAD] = {.handler = emulate_ldr},
     312                 :            :         [PROBES_STORE_EXTRA] = {.handler = emulate_str},
     313                 :            :         [PROBES_STORE] = {.handler = emulate_str},
     314                 :            :         [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
     315                 :            :         [PROBES_DATA_PROCESSING_REG] = {
     316                 :            :                 .handler = emulate_rd12rn16rm0rs8_rwflags},
     317                 :            :         [PROBES_DATA_PROCESSING_IMM] = {
     318                 :            :                 .handler = emulate_rd12rn16rm0rs8_rwflags},
     319                 :            :         [PROBES_MOV_HALFWORD] = {.handler = emulate_rd12rm0_noflags_nopc},
     320                 :            :         [PROBES_SEV] = {.handler = probes_emulate_none},
     321                 :            :         [PROBES_WFE] = {.handler = probes_simulate_nop},
     322                 :            :         [PROBES_SATURATE] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
     323                 :            :         [PROBES_REV] = {.handler = emulate_rd12rm0_noflags_nopc},
     324                 :            :         [PROBES_MMI] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
     325                 :            :         [PROBES_PACK] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
     326                 :            :         [PROBES_EXTEND] = {.handler = emulate_rd12rm0_noflags_nopc},
     327                 :            :         [PROBES_EXTEND_ADD] = {.handler = emulate_rd12rn16rm0_rwflags_nopc},
     328                 :            :         [PROBES_MUL_ADD_LONG] = {
     329                 :            :                 .handler = emulate_rdlo12rdhi16rn0rm8_rwflags_nopc},
     330                 :            :         [PROBES_MUL_ADD] = {.handler = emulate_rd16rn12rm0rs8_rwflags_nopc},
     331                 :            :         [PROBES_BITFIELD] = {.handler = emulate_rd12rm0_noflags_nopc},
     332                 :            :         [PROBES_BRANCH] = {.handler = simulate_bbl},
     333                 :            :         [PROBES_LDMSTM] = {.decoder = kprobe_decode_ldmstm}
     334                 :            : };
     335                 :            : 
     336                 :            : const struct decode_checker *kprobes_arm_checkers[] = {arm_stack_checker, arm_regs_checker, NULL};
    

Generated by: LCOV version 1.14