LCOV - code coverage report
Current view: top level - arch/arm/kernel - kgdb.c (source / functions) Hit Total Coverage
Test: gcov_data_raspi2_qemu_modules_combined.info Lines: 0 72 0.0 %
Date: 2020-09-30 20:25:01 Functions: 0 12 0.0 %
Branches: 0 26 0.0 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * arch/arm/kernel/kgdb.c
       4                 :            :  *
       5                 :            :  * ARM KGDB support
       6                 :            :  *
       7                 :            :  * Copyright (c) 2002-2004 MontaVista Software, Inc
       8                 :            :  * Copyright (c) 2008 Wind River Systems, Inc.
       9                 :            :  *
      10                 :            :  * Authors:  George Davis <davis_g@mvista.com>
      11                 :            :  *           Deepak Saxena <dsaxena@plexity.net>
      12                 :            :  */
      13                 :            : #include <linux/irq.h>
      14                 :            : #include <linux/kdebug.h>
      15                 :            : #include <linux/kgdb.h>
      16                 :            : #include <linux/uaccess.h>
      17                 :            : 
      18                 :            : #include <asm/patch.h>
      19                 :            : #include <asm/traps.h>
      20                 :            : 
      21                 :            : struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
      22                 :            : {
      23                 :            :         { "r0", 4, offsetof(struct pt_regs, ARM_r0)},
      24                 :            :         { "r1", 4, offsetof(struct pt_regs, ARM_r1)},
      25                 :            :         { "r2", 4, offsetof(struct pt_regs, ARM_r2)},
      26                 :            :         { "r3", 4, offsetof(struct pt_regs, ARM_r3)},
      27                 :            :         { "r4", 4, offsetof(struct pt_regs, ARM_r4)},
      28                 :            :         { "r5", 4, offsetof(struct pt_regs, ARM_r5)},
      29                 :            :         { "r6", 4, offsetof(struct pt_regs, ARM_r6)},
      30                 :            :         { "r7", 4, offsetof(struct pt_regs, ARM_r7)},
      31                 :            :         { "r8", 4, offsetof(struct pt_regs, ARM_r8)},
      32                 :            :         { "r9", 4, offsetof(struct pt_regs, ARM_r9)},
      33                 :            :         { "r10", 4, offsetof(struct pt_regs, ARM_r10)},
      34                 :            :         { "fp", 4, offsetof(struct pt_regs, ARM_fp)},
      35                 :            :         { "ip", 4, offsetof(struct pt_regs, ARM_ip)},
      36                 :            :         { "sp", 4, offsetof(struct pt_regs, ARM_sp)},
      37                 :            :         { "lr", 4, offsetof(struct pt_regs, ARM_lr)},
      38                 :            :         { "pc", 4, offsetof(struct pt_regs, ARM_pc)},
      39                 :            :         { "f0", 12, -1 },
      40                 :            :         { "f1", 12, -1 },
      41                 :            :         { "f2", 12, -1 },
      42                 :            :         { "f3", 12, -1 },
      43                 :            :         { "f4", 12, -1 },
      44                 :            :         { "f5", 12, -1 },
      45                 :            :         { "f6", 12, -1 },
      46                 :            :         { "f7", 12, -1 },
      47                 :            :         { "fps", 4, -1 },
      48                 :            :         { "cpsr", 4, offsetof(struct pt_regs, ARM_cpsr)},
      49                 :            : };
      50                 :            : 
      51                 :          0 : char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
      52                 :            : {
      53         [ #  # ]:          0 :         if (regno >= DBG_MAX_REG_NUM || regno < 0)
      54                 :            :                 return NULL;
      55                 :            : 
      56         [ #  # ]:          0 :         if (dbg_reg_def[regno].offset != -1)
      57                 :          0 :                 memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
      58                 :          0 :                        dbg_reg_def[regno].size);
      59                 :            :         else
      60                 :          0 :                 memset(mem, 0, dbg_reg_def[regno].size);
      61                 :          0 :         return dbg_reg_def[regno].name;
      62                 :            : }
      63                 :            : 
      64                 :          0 : int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
      65                 :            : {
      66         [ #  # ]:          0 :         if (regno >= DBG_MAX_REG_NUM || regno < 0)
      67                 :            :                 return -EINVAL;
      68                 :            : 
      69         [ #  # ]:          0 :         if (dbg_reg_def[regno].offset != -1)
      70                 :          0 :                 memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
      71                 :          0 :                        dbg_reg_def[regno].size);
      72                 :            :         return 0;
      73                 :            : }
      74                 :            : 
      75                 :            : void
      76                 :          0 : sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
      77                 :            : {
      78                 :            :         struct thread_info *ti;
      79                 :            :         int regno;
      80                 :            : 
      81                 :            :         /* Just making sure... */
      82         [ #  # ]:          0 :         if (task == NULL)
      83                 :          0 :                 return;
      84                 :            : 
      85                 :            :         /* Initialize to zero */
      86         [ #  # ]:          0 :         for (regno = 0; regno < GDB_MAX_REGS; regno++)
      87                 :          0 :                 gdb_regs[regno] = 0;
      88                 :            : 
      89                 :            :         /* Otherwise, we have only some registers from switch_to() */
      90                 :          0 :         ti                      = task_thread_info(task);
      91                 :          0 :         gdb_regs[_R4]           = ti->cpu_context.r4;
      92                 :          0 :         gdb_regs[_R5]           = ti->cpu_context.r5;
      93                 :          0 :         gdb_regs[_R6]           = ti->cpu_context.r6;
      94                 :          0 :         gdb_regs[_R7]           = ti->cpu_context.r7;
      95                 :          0 :         gdb_regs[_R8]           = ti->cpu_context.r8;
      96                 :          0 :         gdb_regs[_R9]           = ti->cpu_context.r9;
      97                 :          0 :         gdb_regs[_R10]          = ti->cpu_context.sl;
      98                 :          0 :         gdb_regs[_FP]           = ti->cpu_context.fp;
      99                 :          0 :         gdb_regs[_SPT]          = ti->cpu_context.sp;
     100                 :          0 :         gdb_regs[_PC]           = ti->cpu_context.pc;
     101                 :            : }
     102                 :            : 
     103                 :          0 : void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
     104                 :            : {
     105                 :          0 :         regs->ARM_pc = pc;
     106                 :          0 : }
     107                 :            : 
     108                 :            : static int compiled_break;
     109                 :            : 
     110                 :          0 : int kgdb_arch_handle_exception(int exception_vector, int signo,
     111                 :            :                                int err_code, char *remcom_in_buffer,
     112                 :            :                                char *remcom_out_buffer,
     113                 :            :                                struct pt_regs *linux_regs)
     114                 :            : {
     115                 :            :         unsigned long addr;
     116                 :            :         char *ptr;
     117                 :            : 
     118         [ #  # ]:          0 :         switch (remcom_in_buffer[0]) {
     119                 :            :         case 'D':
     120                 :            :         case 'k':
     121                 :            :         case 'c':
     122                 :            :                 /*
     123                 :            :                  * Try to read optional parameter, pc unchanged if no parm.
     124                 :            :                  * If this was a compiled breakpoint, we need to move
     125                 :            :                  * to the next instruction or we will just breakpoint
     126                 :            :                  * over and over again.
     127                 :            :                  */
     128                 :          0 :                 ptr = &remcom_in_buffer[1];
     129         [ #  # ]:          0 :                 if (kgdb_hex2long(&ptr, &addr))
     130                 :          0 :                         linux_regs->ARM_pc = addr;
     131         [ #  # ]:          0 :                 else if (compiled_break == 1)
     132                 :          0 :                         linux_regs->ARM_pc += 4;
     133                 :            : 
     134                 :          0 :                 compiled_break = 0;
     135                 :            : 
     136                 :          0 :                 return 0;
     137                 :            :         }
     138                 :            : 
     139                 :            :         return -1;
     140                 :            : }
     141                 :            : 
     142                 :          0 : static int kgdb_brk_fn(struct pt_regs *regs, unsigned int instr)
     143                 :            : {
     144                 :          0 :         kgdb_handle_exception(1, SIGTRAP, 0, regs);
     145                 :            : 
     146                 :          0 :         return 0;
     147                 :            : }
     148                 :            : 
     149                 :          0 : static int kgdb_compiled_brk_fn(struct pt_regs *regs, unsigned int instr)
     150                 :            : {
     151                 :          0 :         compiled_break = 1;
     152                 :          0 :         kgdb_handle_exception(1, SIGTRAP, 0, regs);
     153                 :            : 
     154                 :          0 :         return 0;
     155                 :            : }
     156                 :            : 
     157                 :            : static struct undef_hook kgdb_brkpt_hook = {
     158                 :            :         .instr_mask             = 0xffffffff,
     159                 :            :         .instr_val              = KGDB_BREAKINST,
     160                 :            :         .cpsr_mask              = MODE_MASK,
     161                 :            :         .cpsr_val               = SVC_MODE,
     162                 :            :         .fn                     = kgdb_brk_fn
     163                 :            : };
     164                 :            : 
     165                 :            : static struct undef_hook kgdb_compiled_brkpt_hook = {
     166                 :            :         .instr_mask             = 0xffffffff,
     167                 :            :         .instr_val              = KGDB_COMPILED_BREAK,
     168                 :            :         .cpsr_mask              = MODE_MASK,
     169                 :            :         .cpsr_val               = SVC_MODE,
     170                 :            :         .fn                     = kgdb_compiled_brk_fn
     171                 :            : };
     172                 :            : 
     173                 :            : static int __kgdb_notify(struct die_args *args, unsigned long cmd)
     174                 :            : {
     175                 :          0 :         struct pt_regs *regs = args->regs;
     176                 :            : 
     177         [ #  # ]:          0 :         if (kgdb_handle_exception(1, args->signr, cmd, regs))
     178                 :            :                 return NOTIFY_DONE;
     179                 :            :         return NOTIFY_STOP;
     180                 :            : }
     181                 :            : static int
     182                 :          0 : kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
     183                 :            : {
     184                 :            :         unsigned long flags;
     185                 :            :         int ret;
     186                 :            : 
     187                 :          0 :         local_irq_save(flags);
     188                 :            :         ret = __kgdb_notify(ptr, cmd);
     189         [ #  # ]:          0 :         local_irq_restore(flags);
     190                 :            : 
     191                 :          0 :         return ret;
     192                 :            : }
     193                 :            : 
     194                 :            : static struct notifier_block kgdb_notifier = {
     195                 :            :         .notifier_call  = kgdb_notify,
     196                 :            :         .priority       = -INT_MAX,
     197                 :            : };
     198                 :            : 
     199                 :            : 
     200                 :            : /**
     201                 :            :  *      kgdb_arch_init - Perform any architecture specific initalization.
     202                 :            :  *
     203                 :            :  *      This function will handle the initalization of any architecture
     204                 :            :  *      specific callbacks.
     205                 :            :  */
     206                 :          0 : int kgdb_arch_init(void)
     207                 :            : {
     208                 :          0 :         int ret = register_die_notifier(&kgdb_notifier);
     209                 :            : 
     210         [ #  # ]:          0 :         if (ret != 0)
     211                 :            :                 return ret;
     212                 :            : 
     213                 :          0 :         register_undef_hook(&kgdb_brkpt_hook);
     214                 :          0 :         register_undef_hook(&kgdb_compiled_brkpt_hook);
     215                 :            : 
     216                 :          0 :         return 0;
     217                 :            : }
     218                 :            : 
     219                 :            : /**
     220                 :            :  *      kgdb_arch_exit - Perform any architecture specific uninitalization.
     221                 :            :  *
     222                 :            :  *      This function will handle the uninitalization of any architecture
     223                 :            :  *      specific callbacks, for dynamic registration and unregistration.
     224                 :            :  */
     225                 :          0 : void kgdb_arch_exit(void)
     226                 :            : {
     227                 :          0 :         unregister_undef_hook(&kgdb_brkpt_hook);
     228                 :          0 :         unregister_undef_hook(&kgdb_compiled_brkpt_hook);
     229                 :          0 :         unregister_die_notifier(&kgdb_notifier);
     230                 :          0 : }
     231                 :            : 
     232                 :          0 : int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
     233                 :            : {
     234                 :            :         int err;
     235                 :            : 
     236                 :            :         /* patch_text() only supports int-sized breakpoints */
     237                 :            :         BUILD_BUG_ON(sizeof(int) != BREAK_INSTR_SIZE);
     238                 :            : 
     239                 :          0 :         err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
     240                 :            :                                 BREAK_INSTR_SIZE);
     241         [ #  # ]:          0 :         if (err)
     242                 :            :                 return err;
     243                 :            : 
     244                 :            :         /* Machine is already stopped, so we can use __patch_text() directly */
     245                 :          0 :         __patch_text((void *)bpt->bpt_addr,
     246                 :            :                      *(unsigned int *)arch_kgdb_ops.gdb_bpt_instr);
     247                 :            : 
     248                 :          0 :         return err;
     249                 :            : }
     250                 :            : 
     251                 :          0 : int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
     252                 :            : {
     253                 :            :         /* Machine is already stopped, so we can use __patch_text() directly */
     254                 :          0 :         __patch_text((void *)bpt->bpt_addr, *(unsigned int *)bpt->saved_instr);
     255                 :            : 
     256                 :          0 :         return 0;
     257                 :            : }
     258                 :            : 
     259                 :            : /*
     260                 :            :  * Register our undef instruction hooks with ARM undef core.
     261                 :            :  * We register a hook specifically looking for the KGB break inst
     262                 :            :  * and we handle the normal undef case within the do_undefinstr
     263                 :            :  * handler.
     264                 :            :  */
     265                 :            : const struct kgdb_arch arch_kgdb_ops = {
     266                 :            : #ifndef __ARMEB__
     267                 :            :         .gdb_bpt_instr          = {0xfe, 0xde, 0xff, 0xe7}
     268                 :            : #else /* ! __ARMEB__ */
     269                 :            :         .gdb_bpt_instr          = {0xe7, 0xff, 0xde, 0xfe}
     270                 :            : #endif
     271                 :            : };

Generated by: LCOV version 1.14