This source file includes following definitions.
- dbg_set_reg
- dbg_get_reg
- arch_kgdb_breakpoint
- kgdb_call_nmi_hook
- compute_signal
- sleeping_thread_to_gdb_regs
- kgdb_arch_set_pc
- kgdb_mips_notify
- kgdb_ll_trap
- kgdb_arch_handle_exception
- kgdb_arch_init
- kgdb_arch_exit
   1 
   2 
   3 
   4 
   5 
   6 
   7 
   8 
   9 
  10 
  11 
  12 
  13 
  14 
  15 
  16 
  17 
  18 
  19 
  20 
  21 
  22 
  23 
  24 
  25 #include <linux/ptrace.h>               
  26 #include <linux/kgdb.h>
  27 #include <linux/kdebug.h>
  28 #include <linux/sched.h>
  29 #include <linux/smp.h>
  30 #include <asm/inst.h>
  31 #include <asm/fpu.h>
  32 #include <asm/cacheflush.h>
  33 #include <asm/processor.h>
  34 #include <asm/sigcontext.h>
  35 #include <linux/uaccess.h>
  36 #include <asm/irq_regs.h>
  37 
  38 static struct hard_trap_info {
  39         unsigned char tt;       
  40         unsigned char signo;    
  41 } hard_trap_info[] = {
  42         { 6, SIGBUS },          
  43         { 7, SIGBUS },          
  44         { 9, SIGTRAP },         
  45       
  46         { 12, SIGFPE },         
  47         { 13, SIGTRAP },        
  48         { 14, SIGSEGV },        
  49         { 15, SIGFPE },         
  50         { 23, SIGSEGV },        
  51         { 31, SIGSEGV },        
  52         { 0, 0}                 
  53 };
  54 
  55 struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] =
  56 {
  57         { "zero", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0]) },
  58         { "at", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1]) },
  59         { "v0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2]) },
  60         { "v1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3]) },
  61         { "a0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4]) },
  62         { "a1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5]) },
  63         { "a2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6]) },
  64         { "a3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7]) },
  65         { "t0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8]) },
  66         { "t1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9]) },
  67         { "t2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10]) },
  68         { "t3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11]) },
  69         { "t4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12]) },
  70         { "t5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13]) },
  71         { "t6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14]) },
  72         { "t7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15]) },
  73         { "s0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16]) },
  74         { "s1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17]) },
  75         { "s2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18]) },
  76         { "s3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19]) },
  77         { "s4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20]) },
  78         { "s5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21]) },
  79         { "s6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22]) },
  80         { "s7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23]) },
  81         { "t8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24]) },
  82         { "t9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25]) },
  83         { "k0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26]) },
  84         { "k1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27]) },
  85         { "gp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28]) },
  86         { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29]) },
  87         { "s8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30]) },
  88         { "ra", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31]) },
  89         { "sr", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_status) },
  90         { "lo", GDB_SIZEOF_REG, offsetof(struct pt_regs, lo) },
  91         { "hi", GDB_SIZEOF_REG, offsetof(struct pt_regs, hi) },
  92         { "bad", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_badvaddr) },
  93         { "cause", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_cause) },
  94         { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, cp0_epc) },
  95         { "f0", GDB_SIZEOF_REG, 0 },
  96         { "f1", GDB_SIZEOF_REG, 1 },
  97         { "f2", GDB_SIZEOF_REG, 2 },
  98         { "f3", GDB_SIZEOF_REG, 3 },
  99         { "f4", GDB_SIZEOF_REG, 4 },
 100         { "f5", GDB_SIZEOF_REG, 5 },
 101         { "f6", GDB_SIZEOF_REG, 6 },
 102         { "f7", GDB_SIZEOF_REG, 7 },
 103         { "f8", GDB_SIZEOF_REG, 8 },
 104         { "f9", GDB_SIZEOF_REG, 9 },
 105         { "f10", GDB_SIZEOF_REG, 10 },
 106         { "f11", GDB_SIZEOF_REG, 11 },
 107         { "f12", GDB_SIZEOF_REG, 12 },
 108         { "f13", GDB_SIZEOF_REG, 13 },
 109         { "f14", GDB_SIZEOF_REG, 14 },
 110         { "f15", GDB_SIZEOF_REG, 15 },
 111         { "f16", GDB_SIZEOF_REG, 16 },
 112         { "f17", GDB_SIZEOF_REG, 17 },
 113         { "f18", GDB_SIZEOF_REG, 18 },
 114         { "f19", GDB_SIZEOF_REG, 19 },
 115         { "f20", GDB_SIZEOF_REG, 20 },
 116         { "f21", GDB_SIZEOF_REG, 21 },
 117         { "f22", GDB_SIZEOF_REG, 22 },
 118         { "f23", GDB_SIZEOF_REG, 23 },
 119         { "f24", GDB_SIZEOF_REG, 24 },
 120         { "f25", GDB_SIZEOF_REG, 25 },
 121         { "f26", GDB_SIZEOF_REG, 26 },
 122         { "f27", GDB_SIZEOF_REG, 27 },
 123         { "f28", GDB_SIZEOF_REG, 28 },
 124         { "f29", GDB_SIZEOF_REG, 29 },
 125         { "f30", GDB_SIZEOF_REG, 30 },
 126         { "f31", GDB_SIZEOF_REG, 31 },
 127         { "fsr", GDB_SIZEOF_REG, 0 },
 128         { "fir", GDB_SIZEOF_REG, 0 },
 129 };
 130 
 131 int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
 132 {
 133         int fp_reg;
 134 
 135         if (regno < 0 || regno >= DBG_MAX_REG_NUM)
 136                 return -EINVAL;
 137 
 138         if (dbg_reg_def[regno].offset != -1 && regno < 38) {
 139                 memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
 140                        dbg_reg_def[regno].size);
 141         } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
 142                 
 143                 if (!(regs->cp0_status & ST0_CU1))
 144                         return 0;
 145                 if (regno == 70) {
 146                         
 147                         memcpy((void *)¤t->thread.fpu.fcr31, mem,
 148                                dbg_reg_def[regno].size);
 149                         goto out_save;
 150                 } else if (regno == 71) {
 151                         
 152                         goto out_save;
 153                 }
 154                 fp_reg = dbg_reg_def[regno].offset;
 155                 memcpy((void *)¤t->thread.fpu.fpr[fp_reg], mem,
 156                        dbg_reg_def[regno].size);
 157 out_save:
 158                 restore_fp(current);
 159         }
 160 
 161         return 0;
 162 }
 163 
 164 char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
 165 {
 166         int fp_reg;
 167 
 168         if (regno >= DBG_MAX_REG_NUM || regno < 0)
 169                 return NULL;
 170 
 171         if (dbg_reg_def[regno].offset != -1 && regno < 38) {
 172                 
 173                 memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
 174                        dbg_reg_def[regno].size);
 175         } else if (current && dbg_reg_def[regno].offset != -1 && regno < 72) {
 176                 
 177                 if (!(regs->cp0_status & ST0_CU1))
 178                         goto out;
 179                 save_fp(current);
 180                 if (regno == 70) {
 181                         
 182                         memcpy(mem, (void *)¤t->thread.fpu.fcr31,
 183                                dbg_reg_def[regno].size);
 184                         goto out;
 185                 } else if (regno == 71) {
 186                         
 187                         memset(mem, 0, dbg_reg_def[regno].size);
 188                         goto out;
 189                 }
 190                 fp_reg = dbg_reg_def[regno].offset;
 191                 memcpy(mem, (void *)¤t->thread.fpu.fpr[fp_reg],
 192                        dbg_reg_def[regno].size);
 193         }
 194 
 195 out:
 196         return dbg_reg_def[regno].name;
 197 
 198 }
 199 
 200 void arch_kgdb_breakpoint(void)
 201 {
 202         __asm__ __volatile__(
 203                 ".globl breakinst\n\t"
 204                 ".set\tnoreorder\n\t"
 205                 "nop\n"
 206                 "breakinst:\tbreak\n\t"
 207                 "nop\n\t"
 208                 ".set\treorder");
 209 }
 210 
 211 void kgdb_call_nmi_hook(void *ignored)
 212 {
 213         mm_segment_t old_fs;
 214 
 215         old_fs = get_fs();
 216         set_fs(KERNEL_DS);
 217 
 218         kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
 219 
 220         set_fs(old_fs);
 221 }
 222 
 223 static int compute_signal(int tt)
 224 {
 225         struct hard_trap_info *ht;
 226 
 227         for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
 228                 if (ht->tt == tt)
 229                         return ht->signo;
 230 
 231         return SIGHUP;          
 232 }
 233 
 234 
 235 
 236 
 237 
 238 void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
 239 {
 240         int reg;
 241 #if (KGDB_GDB_REG_SIZE == 32)
 242         u32 *ptr = (u32 *)gdb_regs;
 243 #else
 244         u64 *ptr = (u64 *)gdb_regs;
 245 #endif
 246 
 247         for (reg = 0; reg < 16; reg++)
 248                 *(ptr++) = 0;
 249 
 250         
 251         *(ptr++) = p->thread.reg16;
 252         *(ptr++) = p->thread.reg17;
 253         *(ptr++) = p->thread.reg18;
 254         *(ptr++) = p->thread.reg19;
 255         *(ptr++) = p->thread.reg20;
 256         *(ptr++) = p->thread.reg21;
 257         *(ptr++) = p->thread.reg22;
 258         *(ptr++) = p->thread.reg23;
 259 
 260         for (reg = 24; reg < 28; reg++)
 261                 *(ptr++) = 0;
 262 
 263         
 264         *(ptr++) = (long)p;
 265         *(ptr++) = p->thread.reg29;
 266         *(ptr++) = p->thread.reg30;
 267         *(ptr++) = p->thread.reg31;
 268 
 269         *(ptr++) = p->thread.cp0_status;
 270 
 271         
 272         *(ptr++) = 0;
 273         *(ptr++) = 0;
 274 
 275         
 276 
 277 
 278 
 279 
 280         *(ptr++) = 0;
 281         *(ptr++) = 0;
 282 
 283         
 284 
 285 
 286 
 287         *(ptr++) = p->thread.reg31;
 288 }
 289 
 290 void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
 291 {
 292         regs->cp0_epc = pc;
 293 }
 294 
 295 
 296 
 297 
 298 
 299 static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
 300                             void *ptr)
 301 {
 302         struct die_args *args = (struct die_args *)ptr;
 303         struct pt_regs *regs = args->regs;
 304         int trap = (regs->cp0_cause & 0x7c) >> 2;
 305         mm_segment_t old_fs;
 306 
 307 #ifdef CONFIG_KPROBES
 308         
 309 
 310 
 311 
 312         if (cmd == DIE_PAGE_FAULT)
 313                 return NOTIFY_DONE;
 314 #endif 
 315 
 316         
 317         if (user_mode(regs))
 318                 return NOTIFY_DONE;
 319 
 320         
 321         old_fs = get_fs();
 322         set_fs(KERNEL_DS);
 323 
 324         if (atomic_read(&kgdb_active) != -1)
 325                 kgdb_nmicallback(smp_processor_id(), regs);
 326 
 327         if (kgdb_handle_exception(trap, compute_signal(trap), cmd, regs)) {
 328                 set_fs(old_fs);
 329                 return NOTIFY_DONE;
 330         }
 331 
 332         if (atomic_read(&kgdb_setting_breakpoint))
 333                 if ((trap == 9) && (regs->cp0_epc == (unsigned long)breakinst))
 334                         regs->cp0_epc += 4;
 335 
 336         
 337         local_irq_enable();
 338         __flush_cache_all();
 339 
 340         set_fs(old_fs);
 341         return NOTIFY_STOP;
 342 }
 343 
 344 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
 345 int kgdb_ll_trap(int cmd, const char *str,
 346                  struct pt_regs *regs, long err, int trap, int sig)
 347 {
 348         struct die_args args = {
 349                 .regs   = regs,
 350                 .str    = str,
 351                 .err    = err,
 352                 .trapnr = trap,
 353                 .signr  = sig,
 354 
 355         };
 356 
 357         if (!kgdb_io_module_registered)
 358                 return NOTIFY_DONE;
 359 
 360         return kgdb_mips_notify(NULL, cmd, &args);
 361 }
 362 #endif 
 363 
 364 static struct notifier_block kgdb_notifier = {
 365         .notifier_call = kgdb_mips_notify,
 366 };
 367 
 368 
 369 
 370 
 371 int kgdb_arch_handle_exception(int vector, int signo, int err_code,
 372                                char *remcom_in_buffer, char *remcom_out_buffer,
 373                                struct pt_regs *regs)
 374 {
 375         char *ptr;
 376         unsigned long address;
 377 
 378         switch (remcom_in_buffer[0]) {
 379         case 'c':
 380                 
 381                 ptr = &remcom_in_buffer[1];
 382                 if (kgdb_hex2long(&ptr, &address))
 383                         regs->cp0_epc = address;
 384 
 385                 return 0;
 386         }
 387 
 388         return -1;
 389 }
 390 
 391 const struct kgdb_arch arch_kgdb_ops = {
 392 #ifdef CONFIG_CPU_BIG_ENDIAN
 393         .gdb_bpt_instr = { spec_op << 2, 0x00, 0x00, break_op },
 394 #else
 395         .gdb_bpt_instr = { break_op, 0x00, 0x00, spec_op << 2 },
 396 #endif
 397 };
 398 
 399 int kgdb_arch_init(void)
 400 {
 401         register_die_notifier(&kgdb_notifier);
 402 
 403         return 0;
 404 }
 405 
 406 
 407 
 408 
 409 
 410 
 411 
 412 void kgdb_arch_exit(void)
 413 {
 414         unregister_die_notifier(&kgdb_notifier);
 415 }