# HG changeset patch # User yamahata@xxxxxxxxxxxxx # Node ID 0722cc73a7a25ec2fcb1ac31667f2546d7c0a448 # Parent b1068ef4ffb0e37efccf4bec2ed5ae242807add6 implemented cdb for ia64. stolen from kgdb the routine which gets register value. this includes a bug fix of kgdb/ia64. Signed-off-by: Isaku Yamahata diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/Makefile --- a/xen/arch/ia64/Makefile Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/Makefile Tue Jan 10 15:59:11 2006 +0900 @@ -22,6 +22,10 @@ memset.o strlen.o memcpy_mck.o \ __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o + +ifeq ($(crash_debug),y) +OBJS += cdb.o +endif # xen stack unwinder # unwind_decoder.c is included in unwind.c diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/vmx/vmx_process.c --- a/xen/arch/ia64/vmx/vmx_process.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/vmx/vmx_process.c Tue Jan 10 15:59:11 2006 +0900 @@ -41,6 +41,7 @@ #include #include #include +#include //#include #include #include @@ -107,6 +108,13 @@ if (running_on_sim) do_ssc(vcpu_get_gr_nat(current,36), regs); else do_ssc(vcpu_get_gr_nat(current,36), regs); } +#endif +#ifdef CRASH_DEBUG + if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don't care */, regs); + } else #endif if (iim == d->arch.breakimm) { struct ia64_pal_retval y; diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/hyperprivop.S --- a/xen/arch/ia64/xen/hyperprivop.S Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/hyperprivop.S Tue Jan 10 15:59:11 2006 +0900 @@ -12,6 +12,7 @@ #include #include #include +#include #include diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/ivt.S --- a/xen/arch/ia64/xen/ivt.S Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/ivt.S Tue Jan 10 15:59:11 2006 +0900 @@ -15,6 +15,7 @@ #define sys_call_table 0 #define sys_ni_syscall 0 #include +#include #endif /* * arch/ia64/kernel/ivt.S diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/process.c --- a/xen/arch/ia64/xen/process.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/process.c Tue Jan 10 15:59:11 2006 +0900 @@ -31,6 +31,7 @@ #include #include "hpsim_ssc.h" #include +#include extern unsigned long vcpu_get_itir_on_fault(struct vcpu *, UINT64); extern void die_if_kernel(char *str, struct pt_regs *regs, long err); @@ -662,7 +663,7 @@ ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long isr, unsigned long iim) { struct domain *d = (struct domain *) current->domain; - struct vcpu *v = (struct domain *) current; + struct vcpu *v = current; extern unsigned long running_on_sim; if (first_break) { @@ -673,7 +674,14 @@ if (iim == 0x80001 || iim == 0x80002) { //FIXME: don't hardcode constant if (running_on_sim) do_ssc(vcpu_get_gr(current,36), regs); else do_ssc(vcpu_get_gr(current,36), regs); - } + } +#ifdef CRASH_DEBUG + else if ((iim == 0 || iim == CDB_BREAK_NUM) && !user_mode(regs)) { + if (iim == 0) + show_registers(regs); + debugger_trap_fatal(0 /* don't care */, regs); + } +#endif else if (iim == d->arch.breakimm) { /* by default, do not continue */ v->arch.hypercall_continuation = 0; diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/xenmisc.c --- a/xen/arch/ia64/xen/xenmisc.c Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/arch/ia64/xen/xenmisc.c Tue Jan 10 15:59:11 2006 +0900 @@ -18,6 +18,7 @@ #include #include #include +#include efi_memory_desc_t ia64_efi_io_md; EXPORT_SYMBOL(ia64_efi_io_md); @@ -357,6 +358,11 @@ va_end(args); printf(buf); if (regs) show_registers(regs); + if (regs) { + debugger_trap_fatal(0 /* don't care */, regs); + } else { + debugger_trap_immediate(); + } domain_pause_by_systemcontroller(current->domain); v->domain->shutdown_code = SHUTDOWN_crash; set_bit(_DOMF_shutdown, v->domain->domain_flags); diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/include/asm-ia64/debugger.h --- a/xen/include/asm-ia64/debugger.h Tue Jan 10 15:51:03 2006 +0900 +++ b/xen/include/asm-ia64/debugger.h Tue Jan 10 15:59:11 2006 +0900 @@ -24,6 +24,54 @@ #include +// this number is an arbitary number which is not used for any other purpose +// __builtin_trap(), FORCE_CRASH() 0x0 +// ski 0x80001, 0x80002 +// kdb 0x80100, 0x80101 +// kprobe 0x80200, jprobe 0x80300 +// kgdb 0x6665 +// gdb 0x99998 (#define IA64_BREAKPOINT 0x00003333300LL) + +// cdb should handle 0 and CDB_BREAK_NUM. +#define CDB_BREAK_NUM 0x80800 + + +#ifndef __ASSEMBLY__ + +#include + +// NOTE: on xen struct pt_regs = struct cpu_user_regs +// see include/asm-ia64/linux-xen/asm/ptrace.h +#ifdef CRASH_DEBUG +// crash_debug=y + +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +extern int __trap_to_cdb(struct cpu_user_regs *r); +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + (void)__trap_to_cdb(regs); + return 0; +} + +#define ____debugger_trap_immediate(b) __asm__ __volatile__ ("break.m "#b"\n") +#define __debugger_trap_immediate(b) ____debugger_trap_immediate(b) +#define debugger_trap_immediate() __debugger_trap_immediate(CDB_BREAK_NUM) + +//XXX temporal work around +#ifndef CONFIG_SMP +#define smp_send_stop() /* nothing */ +#endif + +#elif defined DOMU_DEBUG +// domu_debug=y +#warning "domu_debug is not implemented yet." /* The main trap handlers use these helper macros which include early bail. */ static inline int debugger_trap_entry( unsigned int vector, struct cpu_user_regs *regs) @@ -37,6 +85,23 @@ return 0; } -#define debugger_trap_immediate() do {} while(0) +#define debugger_trap_immediate() ((void)0) +#else +/* The main trap handlers use these helper macros which include early bail. */ +static inline int debugger_trap_entry( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +static inline int debugger_trap_fatal( + unsigned int vector, struct cpu_user_regs *regs) +{ + return 0; +} + +#define debugger_trap_immediate() ((void)0) +#endif +#endif // __ASSEMBLLY__ #endif /* __ASM_DEBUGGER_H__ */ diff -r b1068ef4ffb0 -r 0722cc73a7a2 xen/arch/ia64/xen/cdb.c --- /dev/null Thu Jan 1 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/cdb.c Tue Jan 10 15:59:11 2006 +0900 @@ -0,0 +1,652 @@ +/* + * ia64-specific cdb routines + * cdb xen/ia64 by Isaku Yamahta + * VA Linux Systems Japan K.K. + * some routines are stolen from kgdb/ia64. + */ +/* + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +/* + * Copyright (C) 2000-2001 VERITAS Software Corporation. + */ +/* + * Contributor: Lake Stevens Instrument Division$ + * Written by: Glenn Engel $ + * Updated by: Amit Kale + * Modified for 386 by Jim Kingdon, Cygnus Support. + * Origianl kgdb, compatibility with 2.1.xx kernel by David Grothe + * + */ + + +#include +#include +#include +#include + +#define USE_UNWIND + +#ifdef USE_UNWIND +#include +#endif + +/* Printk isn't particularly safe just after we've trapped to the + debugger. so avoid it. */ +#define dbg_printk(...) +//#define dbg_printk(...) printk(__VA_ARGS__) + +/* Like copy_from_user, but safe to call with interrupts disabled. + Trust me, and don't look behind the curtain. */ +unsigned +xendbg_arch_copy_from_user(void *dest, const void *src, unsigned len) +{ + int val; + __asm__ __volatile__( + "cmp4.eq p6, p0 = r0, %1\n" + "(p6) br.cond.dptk 2f\n" + "[1:]\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] ld1 %0 = [%3], 1\n" + ";;\n" + ".xdata4 \"__ex_table\", 99f-., 2f-.;\n" + "[99:] st1 [%2] = %0, 1\n" + "adds %1 = -1, %1\n" + ";;\n" + "cmp4.eq p0, p6 = r0, %1\n" + "(p6) br.cond.dptk 1b\n" + "[2:]\n" + : "=r"(val), "=r"(len), "=r"(dest), "=r"(src) + : "1"(len), "2"(dest), "3"(src) + : "memory", "p6"); + return len; +} + +int +xendbg_arch_handle_register_read_command(struct cpu_user_regs *regs, struct xendbg_context *ctx) +{ + return xendbg_send_reply("", ctx); +} + +#define NUM_REGS 590 +#define REGISTER_BYTES (NUM_REGS*8+128*8) +#define REGISTER_BYTE(N) (((N) * 8) + ((N) <= IA64_FR0_REGNUM ? 0 : 8 * (((N) > IA64_FR127_REGNUM) ? 128 : (N) - IA64_FR0_REGNUM))) +#define REGISTER_SIZE(N) (((N) >= IA64_FR0_REGNUM && (N) <= IA64_FR127_REGNUM) ? 16 : 8) + +#define IA64_GR0_REGNUM 0 +#define IA64_FR0_REGNUM 128 +#define IA64_FR127_REGNUM (IA64_FR0_REGNUM+127) +#define IA64_PR0_REGNUM 256 +#define IA64_BR0_REGNUM 320 +#define IA64_VFP_REGNUM 328 +#define IA64_PR_REGNUM 330 +#define IA64_IP_REGNUM 331 +#define IA64_PSR_REGNUM 332 +#define IA64_CFM_REGNUM 333 +#define IA64_AR0_REGNUM 334 +#define IA64_NAT0_REGNUM 462 +#define IA64_NAT31_REGNUM (IA64_NAT0_REGNUM+31) +#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM+32) +#define IA64_RSC_REGNUM (IA64_AR0_REGNUM+16) +#define IA64_BSP_REGNUM (IA64_AR0_REGNUM+17) +#define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM+18) +#define IA64_RNAT_REGNUM (IA64_AR0_REGNUM+19) +#define IA64_FCR_REGNUM (IA64_AR0_REGNUM+21) +#define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM+24) +#define IA64_CSD_REGNUM (IA64_AR0_REGNUM+25) +#define IA64_SSD_REGNUM (IA64_AR0_REGNUM+26) +#define IA64_CFLG_REGNUM (IA64_AR0_REGNUM+27) +#define IA64_FSR_REGNUM (IA64_AR0_REGNUM+28) +#define IA64_FIR_REGNUM (IA64_AR0_REGNUM+29) +#define IA64_FDR_REGNUM (IA64_AR0_REGNUM+30) +#define IA64_CCV_REGNUM (IA64_AR0_REGNUM+32) +#define IA64_UNAT_REGNUM (IA64_AR0_REGNUM+36) +#define IA64_FPSR_REGNUM (IA64_AR0_REGNUM+40) +#define IA64_ITC_REGNUM (IA64_AR0_REGNUM+44) +#define IA64_PFS_REGNUM (IA64_AR0_REGNUM+64) +#define IA64_LC_REGNUM (IA64_AR0_REGNUM+65) +#define IA64_EC_REGNUM (IA64_AR0_REGNUM+66) + +#ifndef USE_UNWIND +struct regs_to_cpu_user_resgs_index { + unsigned int reg; + unsigned int ptregoff; +}; + +#define ptoff(V) ((unsigned int)&((struct cpu_user_regs*)0x0)->V) + +// gr +static const struct regs_to_cpu_user_resgs_index +gr_reg_to_cpu_user_regs_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, + {IA64_GR0_REGNUM + 16, ptoff(r16)}, + {IA64_GR0_REGNUM + 17, ptoff(r17)}, + {IA64_GR0_REGNUM + 18, ptoff(r18)}, + {IA64_GR0_REGNUM + 19, ptoff(r19)}, + {IA64_GR0_REGNUM + 20, ptoff(r20)}, + {IA64_GR0_REGNUM + 21, ptoff(r21)}, + {IA64_GR0_REGNUM + 22, ptoff(r22)}, + {IA64_GR0_REGNUM + 23, ptoff(r23)}, + {IA64_GR0_REGNUM + 24, ptoff(r24)}, + {IA64_GR0_REGNUM + 25, ptoff(r25)}, + {IA64_GR0_REGNUM + 26, ptoff(r26)}, + {IA64_GR0_REGNUM + 27, ptoff(r27)}, + {IA64_GR0_REGNUM + 28, ptoff(r28)}, + {IA64_GR0_REGNUM + 29, ptoff(r29)}, + {IA64_GR0_REGNUM + 30, ptoff(r30)}, + {IA64_GR0_REGNUM + 31, ptoff(r31)}, + + {IA64_GR0_REGNUM + 4, ptoff(r4)}, + {IA64_GR0_REGNUM + 5, ptoff(r5)}, + {IA64_GR0_REGNUM + 6, ptoff(r6)}, + {IA64_GR0_REGNUM + 7, ptoff(r7)}, +}; +static const int gr_reg_to_cpu_user_regs_index_max = + sizeof(gr_reg_to_cpu_user_regs_index) / + sizeof(gr_reg_to_cpu_user_regs_index[0]); + +// br +static const struct regs_to_cpu_user_resgs_index +br_reg_to_cpu_user_regs_index[] = { + {IA64_BR0_REGNUM + 0, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; +static const int br_reg_to_cpu_user_regs_index_max = + sizeof(br_reg_to_cpu_user_regs_index) / + sizeof(br_reg_to_cpu_user_regs_index[0]); + +// f +static const struct regs_to_cpu_user_resgs_index +fr_reg_to_cpu_user_regs_index[] = { + {IA64_FR0_REGNUM + 6, ptoff(f6)}, + {IA64_FR0_REGNUM + 7, ptoff(f7)}, + {IA64_FR0_REGNUM + 8, ptoff(f8)}, + {IA64_FR0_REGNUM + 9, ptoff(f9)}, + {IA64_FR0_REGNUM + 10, ptoff(f10)}, + {IA64_FR0_REGNUM + 11, ptoff(f11)}, +}; +static const int fr_reg_to_cpu_user_regs_index_max = + sizeof(fr_reg_to_cpu_user_regs_index) / + sizeof(fr_reg_to_cpu_user_regs_index[0]); + + +int +xendbg_arch_handle_register_get_command(unsigned long regnum, struct cpu_user_regs *regs, struct xendbg_context *ctx) +{ + unsigned long reg = IA64_IP_REGNUM; + char buf[9]; + int i; + + dbg_printk("Register read regnum = 0x%lx\n", regnum); + if (IA64_GR0_REGNUM <= regnum && regnum <= IA64_GR0_REGNUM + 31) { + for (i = 0; i < gr_reg_to_cpu_user_regs_index_max; i++) { + if (gr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + gr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == gr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_BR0_REGNUM <= regnum && regnum <= IA64_BR0_REGNUM + 7) { + for (i = 0; i < br_reg_to_cpu_user_regs_index_max; i++) { + if (br_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + br_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == br_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (IA64_FR0_REGNUM + 6 <= regnum && regnum <= IA64_FR0_REGNUM + 11) { + for (i = 0; i < fr_reg_to_cpu_user_regs_index_max; i++) { + if (fr_reg_to_cpu_user_regs_index[i].reg == regnum) { + reg = *(unsigned long*)(((char*)regs) + fr_reg_to_cpu_user_regs_index[i].ptregoff); + break; + } + } + if (i == fr_reg_to_cpu_user_regs_index_max) { + goto out_err; + } + } else if (regnum == IA64_CSD_REGNUM) { + reg = regs->ar_csd; + } else if (regnum == IA64_SSD_REGNUM) { + reg = regs->ar_ssd; + } else if (regnum == IA64_PSR_REGNUM) { + reg = regs->cr_ipsr; + } else if (regnum == IA64_IP_REGNUM) { + reg = regs->cr_iip; + } else if (regnum == IA64_CFM_REGNUM) { + reg = regs->cr_ifs; + } else if (regnum == IA64_UNAT_REGNUM) { + reg = regs->ar_unat; + } else if (regnum == IA64_PFS_REGNUM) { + reg = regs->ar_pfs; + } else if (regnum == IA64_RSC_REGNUM) { + reg = regs->ar_rsc; + } else if (regnum == IA64_RNAT_REGNUM) { + reg = regs->ar_rnat; + } else if (regnum == IA64_BSPSTORE_REGNUM) { + reg = regs->ar_bspstore; + } else if (regnum == IA64_PR_REGNUM) { + reg = regs->pr; + } else if (regnum == IA64_FPSR_REGNUM) { + reg = regs->ar_fpsr; + } else if (regnum == IA64_CCV_REGNUM) { + reg = regs->ar_ccv; + } else { + // emul_unat, rfi_pfs + goto out_err; + } + + dbg_printk("Register read regnum = 0x%lx, val = 0x%lx\n", regnum, reg); + sprintf(buf, "%.08lx", swab64(reg)); +out: + return xendbg_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "x"); + goto out; +} +#else + +#define ptoff(V) ((unsigned int) &((struct pt_regs *)0x0)->V) +struct reg_to_ptreg_index { + unsigned int reg; + unsigned int ptregoff; +}; +struct reg_to_ptreg_index gr_reg_to_ptreg_index[] = { + {IA64_GR0_REGNUM + 8, ptoff(r8)}, + {IA64_GR0_REGNUM + 9, ptoff(r9)}, + {IA64_GR0_REGNUM + 10, ptoff(r10)}, + {IA64_GR0_REGNUM + 11, ptoff(r11)}, + {IA64_GR0_REGNUM + 1, ptoff(r1)}, + {IA64_GR0_REGNUM + 12, ptoff(r12)}, + {IA64_GR0_REGNUM + 13, ptoff(r13)}, + {IA64_GR0_REGNUM + 14, ptoff(r14)}, + {IA64_GR0_REGNUM + 15, ptoff(r15)}, + {IA64_GR0_REGNUM + 2, ptoff(r2)}, + {IA64_GR0_REGNUM + 3, ptoff(r3)}, +}; + +struct reg_to_ptreg_index br_reg_to_ptreg_index[] = { + {IA64_BR0_REGNUM, ptoff(b0)}, + {IA64_BR0_REGNUM + 6, ptoff(b6)}, + {IA64_BR0_REGNUM + 7, ptoff(b7)}, +}; + +extern atomic_t cpu_doing_single_step; + +#ifndef XEN +void kgdb_get_reg(char *outbuffer, int regnum, struct unw_frame_info *info, + struct pt_regs *ptregs) +#else +static int +kgdb_get_reg(int regnum, struct unw_frame_info *info, + struct cpu_user_regs* ptregs, + unsigned long* __reg, struct pt_fpreg* __freg) +#endif +{ + unsigned long reg, size = 0, *mem = ® + char nat; +#ifndef XEN + struct ia64_fpreg freg; +#else + struct pt_fpreg freg; +#endif + int i; + + if ((regnum >= IA64_GR0_REGNUM && regnum <= (IA64_GR0_REGNUM + 1)) || + (regnum >= (IA64_GR0_REGNUM + 4) && regnum <= (IA64_GR0_REGNUM + 7)) + || (regnum >= (IA64_GR0_REGNUM + 16) + && regnum <= (IA64_GR0_REGNUM + 31))) { + unw_access_gr(info, regnum - IA64_GR0_REGNUM, ®, &nat, 0); + size = sizeof(reg); + } else + if ((regnum >= (IA64_GR0_REGNUM + 2) + && regnum <= (IA64_GR0_REGNUM + 3)) + || (regnum >= (IA64_GR0_REGNUM + 8) + && regnum <= (IA64_GR0_REGNUM + 15))) { + if (ptregs) { + for (i = 0; i < (sizeof(gr_reg_to_ptreg_index) / + sizeof(gr_reg_to_ptreg_index[0])); i++) + if (gr_reg_to_ptreg_index[i].reg == regnum) { + reg = *((unsigned long *) + (((void *)ptregs) + + gr_reg_to_ptreg_index[i].ptregoff)); + break; + } + } else + unw_access_gr(info, regnum - IA64_GR0_REGNUM, ®, + &nat, 0); + size = sizeof(reg); + } else if (regnum >= IA64_BR0_REGNUM && regnum <= (IA64_BR0_REGNUM + 7)) + switch (regnum) { + case IA64_BR0_REGNUM: + case IA64_BR0_REGNUM + 6: + case IA64_BR0_REGNUM + 7: + if (ptregs) { + for (i = 0; i < (sizeof(br_reg_to_ptreg_index) / + sizeof(br_reg_to_ptreg_index + [0])); i++) + if (br_reg_to_ptreg_index[i].reg == + regnum) { + reg = *((unsigned long *) + (((void *)ptregs) + + br_reg_to_ptreg_index + [i].ptregoff)); + break; + } + } else + unw_access_br(info, regnum - IA64_BR0_REGNUM, + ®, 0); + size = sizeof(reg); + break; + case IA64_BR0_REGNUM + 1: + case IA64_BR0_REGNUM + 2: + case IA64_BR0_REGNUM + 3: + case IA64_BR0_REGNUM + 4: + case IA64_BR0_REGNUM + 5: + unw_access_br(info, regnum - IA64_BR0_REGNUM, ®, 0); + size = sizeof(reg); + break; + } else if (regnum >= IA64_FR0_REGNUM + && regnum <= (IA64_FR0_REGNUM + 127)) + switch (regnum) { + case IA64_FR0_REGNUM + 6: + case IA64_FR0_REGNUM + 7: + case IA64_FR0_REGNUM + 8: + case IA64_FR0_REGNUM + 9: + case IA64_FR0_REGNUM + 10: + case IA64_FR0_REGNUM + 11: + case IA64_FR0_REGNUM + 12: + if (!ptregs) +#ifndef XEN + unw_access_fr(info, regnum - IA64_FR0_REGNUM, + &freg, 0); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + unw_access_fr(info, regnum - IA64_FR0_REGNUM, + (struct ia64_fpreg*)&freg, 0); +#endif + else { + freg = + *(&ptregs->f6 + + (regnum - (IA64_FR0_REGNUM + 6))); + } + size = sizeof(freg); + mem = (unsigned long *)&freg; + break; + default: +#ifndef XEN + unw_access_fr(info, regnum - IA64_FR0_REGNUM, &freg, 0); +#else + //XXX struct ia64_fpreg and struct pt_fpreg are same. + unw_access_fr(info, regnum - IA64_FR0_REGNUM, (struct ia64_fpreg*)&freg, 0); +#endif + break; + } else if (regnum == IA64_IP_REGNUM) { + if (!ptregs) + unw_get_ip(info, ®); + else + reg = ptregs->cr_iip; + size = sizeof(reg); + } else if (regnum == IA64_CFM_REGNUM) { + if (!ptregs) + unw_get_cfm(info, ®); + else + reg = ptregs->cr_ifs; + size = sizeof(reg); + } else if (regnum == IA64_PSR_REGNUM) { +#ifndef XEN + if (!ptregs && kgdb_usethread) + ptregs = (struct pt_regs *) + ((unsigned long)kgdb_usethread + IA64_STK_OFFSET) - + 1; +#endif + if (ptregs) + reg = ptregs->cr_ipsr; + size = sizeof(reg); + } else if (regnum == IA64_PR_REGNUM) { + if (ptregs) + reg = ptregs->pr; + else + unw_access_pr(info, ®, 0); + size = sizeof(reg); + } else if (regnum == IA64_BSP_REGNUM) { + unw_get_bsp(info, ®); + size = sizeof(reg); + } else if (regnum >= IA64_AR0_REGNUM && regnum <= IA64_EC_REGNUM) + switch (regnum) { + case IA64_CSD_REGNUM: + if (ptregs) + reg = ptregs->ar_csd; + else + unw_access_ar(info, UNW_AR_CSD, ®, 0); + size = sizeof(reg); + break; + case IA64_SSD_REGNUM: + if (ptregs) + reg = ptregs->ar_ssd; + else + unw_access_ar(info, UNW_AR_SSD, ®, 0); + size = sizeof(reg); + break; + case IA64_UNAT_REGNUM: + if (ptregs) + reg = ptregs->ar_unat; + else + unw_access_ar(info, UNW_AR_UNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_RNAT_REGNUM: + unw_access_ar(info, UNW_AR_RNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_BSPSTORE_REGNUM: + unw_access_ar(info, UNW_AR_BSPSTORE, ®, 0); + size = sizeof(reg); + break; + case IA64_PFS_REGNUM: + unw_access_ar(info, UNW_AR_PFS, ®, 0); + size = sizeof(reg); + break; + case IA64_LC_REGNUM: + unw_access_ar(info, UNW_AR_LC, ®, 0); + size = sizeof(reg); + break; + case IA64_EC_REGNUM: + unw_access_ar(info, UNW_AR_EC, ®, 0); + size = sizeof(reg); + break; + case IA64_FPSR_REGNUM: + if (ptregs) + reg = ptregs->ar_fpsr; + else + unw_access_ar(info, UNW_AR_FPSR, ®, 0); + size = sizeof(reg); + break; + case IA64_RSC_REGNUM: + if (ptregs) + reg = ptregs->ar_rsc; + else + unw_access_ar(info, UNW_AR_RNAT, ®, 0); + size = sizeof(reg); + break; + case IA64_CCV_REGNUM: + unw_access_ar(info, UNW_AR_CCV, ®, 0); + size = sizeof(reg); + break; + } + +#ifndef XEN + if (size) { + kgdb_mem2hex((char *)mem, outbuffer, size); + outbuffer[size * 2] = 0; + } else + strcpy(outbuffer, "E0"); + + return; +#else + if (size) { + if (size == sizeof(reg)) { + *__reg = reg; + } else { + BUG_ON(size != sizeof(freg)); + *__freg = freg; + } + return 0; + } + + return -1; +#endif +} + + +#ifndef XEN +static int inline kgdb_get_blocked_state(struct task_struct *p, + struct unw_frame_info *unw) +#else +static int +kgdb_get_blocked_state(struct vcpu *p, + struct cpu_user_regs *regs, + struct unw_frame_info *unw) +#endif +{ + unsigned long ip; + int count = 0; + +#ifndef XEN + unw_init_from_blocked_task(unw, p); +#endif + ip = 0UL; + do { + if (unw_unwind(unw) < 0) + return -1; + unw_get_ip(unw, &ip); +#ifndef XEN + if (!in_sched_functions(ip)) + break; +#else + dbg_printk("ip 0x%lx cr_iip 0x%lx\n", ip, regs->cr_iip); + if (ip == regs->cr_iip) + break; +#endif + } while (count++ < 16); + + if (!ip) + return -1; + else + return 0; +} + +struct xendbg_callback_arg +{ + struct cpu_user_regs* regs; + unsigned long regnum; + unsigned long* reg; + struct pt_fpreg* freg; + + int error; + // 1: not supported + // 0: success + // -1: failure +}; + +static void +xendbg_get_reg_callback(struct unw_frame_info* info, void* __arg) +{ + struct xendbg_callback_arg* arg = (struct xendbg_callback_arg*)__arg; + + if (kgdb_get_blocked_state(current, arg->regs, info) < 0) { + dbg_printk("%s: kgdb_get_blocked_state failed\n", __func__); + arg->error = -1; + return; + } + if (kgdb_get_reg(arg->regnum, info, arg->regs, arg->reg, arg->freg) < 0) { + dbg_printk("%s: kgdb_get_reg failed\n", __func__); + arg->error = 1; + return; + } + arg->error = 0; + return; +} + +int +xendbg_arch_handle_register_get_command(unsigned long regnum, + struct cpu_user_regs *regs, + struct xendbg_context *ctx) +{ + struct xendbg_callback_arg arg; + unsigned long reg; + struct pt_fpreg freg; + char buf[16 * 2 + 1]; + + if (regnum >= NUM_REGS) { + dbg_printk("%s: regnum %ld\n", __func__, regnum); + goto out_err; + } + + arg.regs = regs; + arg.regnum = regnum; + arg.reg = ® + arg.freg = &freg; + arg.error = 0; + unw_init_running(&xendbg_get_reg_callback, (void*)&arg); + if (arg.error < 0) { + dbg_printk("%s: xendbg_get_reg_callback failed\n", __func__); + goto out_err; + } + + if (arg.error > 0) { + // notify gdb that this register is not supported. + // see fetch_register_using_p() in gdb/remote.c. + sprintf(buf, "%s", "x"); + } else if (IA64_FR0_REGNUM <= regnum && regnum <= IA64_FR0_REGNUM + 127) { + sprintf(buf, "%.016lx", swab64(freg.u.bits[0])); + sprintf(buf + 16, "%.016lx", swab64(freg.u.bits[1])); + } else { + sprintf(buf, "%.016lx", swab64(reg)); + } +out: + return xendbg_send_reply(buf, ctx); + +out_err: + dbg_printk("Register read unsupported regnum = 0x%lx\n", regnum); + sprintf(buf, "%s", "E0"); + goto out; +} +#endif + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * End: + */