kgdb.c (4661B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Nios2 KGDB support 4 * 5 * Copyright (C) 2015 Altera Corporation 6 * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch> 7 * 8 * Based on the code posted by Kazuyasu on the Altera Forum at: 9 * http://www.alteraforum.com/forum/showpost.php?p=77003&postcount=20 10 */ 11#include <linux/ptrace.h> 12#include <linux/kgdb.h> 13#include <linux/kdebug.h> 14#include <linux/io.h> 15 16static int wait_for_remote_debugger; 17 18struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = 19{ 20 { "zero", GDB_SIZEOF_REG, -1 }, 21 { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, r1) }, 22 { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, r2) }, 23 { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, r3) }, 24 { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, r4) }, 25 { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, r5) }, 26 { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, r6) }, 27 { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, r7) }, 28 { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, r8) }, 29 { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, r9) }, 30 { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, r10) }, 31 { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, r11) }, 32 { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, r12) }, 33 { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, r13) }, 34 { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, r14) }, 35 { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, r15) }, 36 { "r16", GDB_SIZEOF_REG, -1 }, 37 { "r17", GDB_SIZEOF_REG, -1 }, 38 { "r18", GDB_SIZEOF_REG, -1 }, 39 { "r19", GDB_SIZEOF_REG, -1 }, 40 { "r20", GDB_SIZEOF_REG, -1 }, 41 { "r21", GDB_SIZEOF_REG, -1 }, 42 { "r22", GDB_SIZEOF_REG, -1 }, 43 { "r23", GDB_SIZEOF_REG, -1 }, 44 { "et", GDB_SIZEOF_REG, -1 }, 45 { "bt", GDB_SIZEOF_REG, -1 }, 46 { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, gp) }, 47 { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp) }, 48 { "fp", GDB_SIZEOF_REG, offsetof(struct pt_regs, fp) }, 49 { "ea", GDB_SIZEOF_REG, -1 }, 50 { "ba", GDB_SIZEOF_REG, -1 }, 51 { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, ra) }, 52 { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, ea) }, 53 { "status", GDB_SIZEOF_REG, -1 }, 54 { "estatus", GDB_SIZEOF_REG, offsetof(struct pt_regs, estatus) }, 55 { "bstatus", GDB_SIZEOF_REG, -1 }, 56 { "ienable", GDB_SIZEOF_REG, -1 }, 57 { "ipending", GDB_SIZEOF_REG, -1}, 58 { "cpuid", GDB_SIZEOF_REG, -1 }, 59 { "ctl6", GDB_SIZEOF_REG, -1 }, 60 { "exception", GDB_SIZEOF_REG, -1 }, 61 { "pteaddr", GDB_SIZEOF_REG, -1 }, 62 { "tlbacc", GDB_SIZEOF_REG, -1 }, 63 { "tlbmisc", GDB_SIZEOF_REG, -1 }, 64 { "eccinj", GDB_SIZEOF_REG, -1 }, 65 { "badaddr", GDB_SIZEOF_REG, -1 }, 66 { "config", GDB_SIZEOF_REG, -1 }, 67 { "mpubase", GDB_SIZEOF_REG, -1 }, 68 { "mpuacc", GDB_SIZEOF_REG, -1 }, 69}; 70 71char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) 72{ 73 if (regno >= DBG_MAX_REG_NUM || regno < 0) 74 return NULL; 75 76 if (dbg_reg_def[regno].offset != -1) 77 memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, 78 dbg_reg_def[regno].size); 79 else 80 memset(mem, 0, dbg_reg_def[regno].size); 81 82 return dbg_reg_def[regno].name; 83} 84 85int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) 86{ 87 if (regno >= DBG_MAX_REG_NUM || regno < 0) 88 return -EINVAL; 89 90 if (dbg_reg_def[regno].offset != -1) 91 memcpy((void *)regs + dbg_reg_def[regno].offset, mem, 92 dbg_reg_def[regno].size); 93 94 return 0; 95} 96 97void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p) 98{ 99 memset((char *)gdb_regs, 0, NUMREGBYTES); 100 gdb_regs[GDB_SP] = p->thread.kregs->sp; 101 gdb_regs[GDB_PC] = p->thread.kregs->ea; 102} 103 104void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) 105{ 106 regs->ea = pc; 107} 108 109int kgdb_arch_handle_exception(int vector, int signo, int err_code, 110 char *remcom_in_buffer, char *remcom_out_buffer, 111 struct pt_regs *regs) 112{ 113 char *ptr; 114 unsigned long addr; 115 116 switch (remcom_in_buffer[0]) { 117 case 's': 118 case 'c': 119 /* handle the optional parameters */ 120 ptr = &remcom_in_buffer[1]; 121 if (kgdb_hex2long(&ptr, &addr)) 122 regs->ea = addr; 123 124 return 0; 125 } 126 127 return -1; /* this means that we do not want to exit from the handler */ 128} 129 130asmlinkage void kgdb_breakpoint_c(struct pt_regs *regs) 131{ 132 /* 133 * The breakpoint entry code has moved the PC on by 4 bytes, so we must 134 * move it back. This could be done on the host but we do it here 135 */ 136 if (!wait_for_remote_debugger) 137 regs->ea -= 4; 138 else /* pass the first trap 30 code */ 139 wait_for_remote_debugger = 0; 140 141 kgdb_handle_exception(30, SIGTRAP, 0, regs); 142} 143 144int kgdb_arch_init(void) 145{ 146 wait_for_remote_debugger = 1; 147 return 0; 148} 149 150void kgdb_arch_exit(void) 151{ 152 /* Nothing to do */ 153} 154 155const struct kgdb_arch arch_kgdb_ops = { 156 /* Breakpoint instruction: trap 30 */ 157 .gdb_bpt_instr = { 0xba, 0x6f, 0x3b, 0x00 }, 158};