linux/arch/arc/kernel/kgdb.c
<<
>>
Prefs
   1/*
   2 * kgdb support for ARC
   3 *
   4 * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/kgdb.h>
  12#include <linux/sched.h>
  13#include <asm/disasm.h>
  14#include <asm/cacheflush.h>
  15
  16static void to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
  17                        struct callee_regs *cregs)
  18{
  19        int regno;
  20
  21        for (regno = 0; regno <= 26; regno++)
  22                gdb_regs[_R0 + regno] = get_reg(regno, kernel_regs, cregs);
  23
  24        for (regno = 27; regno < GDB_MAX_REGS; regno++)
  25                gdb_regs[regno] = 0;
  26
  27        gdb_regs[_FP]           = kernel_regs->fp;
  28        gdb_regs[__SP]          = kernel_regs->sp;
  29        gdb_regs[_BLINK]        = kernel_regs->blink;
  30        gdb_regs[_RET]          = kernel_regs->ret;
  31        gdb_regs[_STATUS32]     = kernel_regs->status32;
  32        gdb_regs[_LP_COUNT]     = kernel_regs->lp_count;
  33        gdb_regs[_LP_END]       = kernel_regs->lp_end;
  34        gdb_regs[_LP_START]     = kernel_regs->lp_start;
  35        gdb_regs[_BTA]          = kernel_regs->bta;
  36        gdb_regs[_STOP_PC]      = kernel_regs->ret;
  37}
  38
  39static void from_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
  40                        struct callee_regs *cregs)
  41{
  42        int regno;
  43
  44        for (regno = 0; regno <= 26; regno++)
  45                set_reg(regno, gdb_regs[regno + _R0], kernel_regs, cregs);
  46
  47        kernel_regs->fp         = gdb_regs[_FP];
  48        kernel_regs->sp         = gdb_regs[__SP];
  49        kernel_regs->blink      = gdb_regs[_BLINK];
  50        kernel_regs->ret        = gdb_regs[_RET];
  51        kernel_regs->status32   = gdb_regs[_STATUS32];
  52        kernel_regs->lp_count   = gdb_regs[_LP_COUNT];
  53        kernel_regs->lp_end     = gdb_regs[_LP_END];
  54        kernel_regs->lp_start   = gdb_regs[_LP_START];
  55        kernel_regs->bta        = gdb_regs[_BTA];
  56}
  57
  58
  59void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
  60{
  61        to_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  62                current->thread.callee_reg);
  63}
  64
  65void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
  66{
  67        from_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  68                current->thread.callee_reg);
  69}
  70
  71void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
  72                                 struct task_struct *task)
  73{
  74        if (task)
  75                to_gdb_regs(gdb_regs, task_pt_regs(task),
  76                        (struct callee_regs *) task->thread.callee_reg);
  77}
  78
  79struct single_step_data_t {
  80        uint16_t opcode[2];
  81        unsigned long address[2];
  82        int is_branch;
  83        int armed;
  84} single_step_data;
  85
  86static void undo_single_step(struct pt_regs *regs)
  87{
  88        if (single_step_data.armed) {
  89                int i;
  90
  91                for (i = 0; i < (single_step_data.is_branch ? 2 : 1); i++) {
  92                        memcpy((void *) single_step_data.address[i],
  93                                &single_step_data.opcode[i],
  94                                BREAK_INSTR_SIZE);
  95
  96                        flush_icache_range(single_step_data.address[i],
  97                                single_step_data.address[i] +
  98                                BREAK_INSTR_SIZE);
  99                }
 100                single_step_data.armed = 0;
 101        }
 102}
 103
 104static void place_trap(unsigned long address, void *save)
 105{
 106        memcpy(save, (void *) address, BREAK_INSTR_SIZE);
 107        memcpy((void *) address, &arch_kgdb_ops.gdb_bpt_instr,
 108                BREAK_INSTR_SIZE);
 109        flush_icache_range(address, address + BREAK_INSTR_SIZE);
 110}
 111
 112static void do_single_step(struct pt_regs *regs)
 113{
 114        single_step_data.is_branch = disasm_next_pc((unsigned long)
 115                regs->ret, regs, (struct callee_regs *)
 116                current->thread.callee_reg,
 117                &single_step_data.address[0],
 118                &single_step_data.address[1]);
 119
 120        place_trap(single_step_data.address[0], &single_step_data.opcode[0]);
 121
 122        if (single_step_data.is_branch) {
 123                place_trap(single_step_data.address[1],
 124                        &single_step_data.opcode[1]);
 125        }
 126
 127        single_step_data.armed++;
 128}
 129
 130int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
 131                               char *remcomInBuffer, char *remcomOutBuffer,
 132                               struct pt_regs *regs)
 133{
 134        unsigned long addr;
 135        char *ptr;
 136
 137        undo_single_step(regs);
 138
 139        switch (remcomInBuffer[0]) {
 140        case 's':
 141        case 'c':
 142                ptr = &remcomInBuffer[1];
 143                if (kgdb_hex2long(&ptr, &addr))
 144                        regs->ret = addr;
 145
 146        case 'D':
 147        case 'k':
 148                atomic_set(&kgdb_cpu_doing_single_step, -1);
 149
 150                if (remcomInBuffer[0] == 's') {
 151                        do_single_step(regs);
 152                        atomic_set(&kgdb_cpu_doing_single_step,
 153                                   smp_processor_id());
 154                }
 155
 156                return 0;
 157        }
 158        return -1;
 159}
 160
 161unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs)
 162{
 163        return instruction_pointer(regs);
 164}
 165
 166int kgdb_arch_init(void)
 167{
 168        single_step_data.armed = 0;
 169        return 0;
 170}
 171
 172void kgdb_trap(struct pt_regs *regs)
 173{
 174        /* trap_s 3 is used for breakpoints that overwrite existing
 175         * instructions, while trap_s 4 is used for compiled breakpoints.
 176         *
 177         * with trap_s 3 breakpoints the original instruction needs to be
 178         * restored and continuation needs to start at the location of the
 179         * breakpoint.
 180         *
 181         * with trap_s 4 (compiled) breakpoints, continuation needs to
 182         * start after the breakpoint.
 183         */
 184        if (regs->ecr_param == 3)
 185                instruction_pointer(regs) -= BREAK_INSTR_SIZE;
 186
 187        kgdb_handle_exception(1, SIGTRAP, 0, regs);
 188}
 189
 190void kgdb_arch_exit(void)
 191{
 192}
 193
 194void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 195{
 196        instruction_pointer(regs) = ip;
 197}
 198
 199struct kgdb_arch arch_kgdb_ops = {
 200        /* breakpoint instruction: TRAP_S 0x3 */
 201#ifdef CONFIG_CPU_BIG_ENDIAN
 202        .gdb_bpt_instr          = {0x78, 0x7e},
 203#else
 204        .gdb_bpt_instr          = {0x7e, 0x78},
 205#endif
 206};
 207