📄 ia64-lite.patch
字号:
+ printk(KERN_INFO "do_init_hw_break: %d exceeds max %d\n",+ (int)HW_BREAKPOINT, (int)MAX_HW_BREAKPOINT);++ while ((HW_BREAKPOINT > MAX_HW_BREAKPOINT)+ && hw_break_total_ibr != 1)+ hw_break_total_ibr--;+ while (HW_BREAKPOINT > MAX_HW_BREAKPOINT)+ hw_break_total_dbr--;+ }++ breakinfo = hwbreaks;++ memset(breakinfo, 0, HW_BREAKPOINT * sizeof(struct hw_breakpoint));++ for (i = 0; i < hw_break_total_dbr; i++)+ breakinfo[i].capable = HWCAP_DBR;++ for (; i < HW_BREAKPOINT; i++)+ breakinfo[i].capable = HWCAP_IBR;++ return;+}++void kgdb_correct_hw_break(void)+{+ int breakno;++ if (!breakinfo)+ return;++ for (breakno = 0; breakno < HW_BREAKPOINT; breakno++) {+ if (breakinfo[breakno].enabled) {+ if (breakinfo[breakno].capable & HWCAP_IBR) {+ int ibreakno = breakno - hw_break_total_dbr;+ ia64_set_ibr(ibreakno << 1,+ breakinfo[breakno].addr);+ ia64_set_ibr((ibreakno << 1) + 1,+ (~breakinfo[breakno].mask &+ ((1UL << 56UL) - 1)) |+ (1UL << 56UL) | (1UL << 63UL));+ } else {+ ia64_set_dbr(breakno << 1,+ breakinfo[breakno].addr);+ ia64_set_dbr((breakno << 1) + 1,+ (~breakinfo[breakno].+ mask & ((1UL << 56UL) - 1)) |+ (1UL << 56UL) |+ (breakinfo[breakno].type << 62UL));+ }+ } else {+ if (breakinfo[breakno].capable & HWCAP_IBR)+ ia64_set_ibr(((breakno -+ hw_break_total_dbr) << 1) + 1,+ 0);+ else+ ia64_set_dbr((breakno << 1) + 1, 0);+ }+ }++ return;+}++int hardware_breakpoint(unsigned long addr, int length, int type, int action)+{+ int breakno, found, watch;+ unsigned long mask;+ extern unsigned long _start[];++ if (!hw_breakpoint_init)+ do_init_hw_break();++ if (!breakinfo)+ return 0;+ else if (addr == (unsigned long)_start)+ return 1;++ if (type == WATCH_ACCESS)+ mask = HWCAP_DBR;+ else+ mask = 1UL << type;++ for (watch = 0, found = 0, breakno = 0; breakno < HW_BREAKPOINT;+ breakno++) {+ if (action) {+ if (breakinfo[breakno].enabled+ || !(breakinfo[breakno].capable & mask))+ continue;+ breakinfo[breakno].enabled = 1;+ breakinfo[breakno].type = type;+ breakinfo[breakno].mask = length - 1;+ breakinfo[breakno].addr = addr;+ watch = breakno;+ } else if (breakinfo[breakno].enabled &&+ ((length < 0 && breakinfo[breakno].addr == addr) ||+ ((breakinfo[breakno].capable & mask) &&+ (breakinfo[breakno].mask == (length - 1)) &&+ (breakinfo[breakno].addr == addr)))) {+ breakinfo[breakno].enabled = 0;+ breakinfo[breakno].type = 0UL;+ } else+ continue;+ found++;+ if (type != WATCH_ACCESS)+ break;+ else if (found == 2)+ break;+ else+ mask = HWCAP_IBR;+ }++ if (type == WATCH_ACCESS && found == 1) {+ breakinfo[watch].enabled = 0;+ found = 0;+ }++ mb();+ return found;+}++int kgdb_arch_set_hw_breakpoint(unsigned long addr, int len,+ enum kgdb_bptype type)+{+ return hardware_breakpoint(addr, len, type - '1', 1);+}++int kgdb_arch_remove_hw_breakpoint(unsigned long addr, int len,+ enum kgdb_bptype type)+{+ return hardware_breakpoint(addr, len, type - '1', 0);+}++int kgdb_remove_hw_break(unsigned long addr)+{+ return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 0);++}++void kgdb_remove_all_hw_break(void)+{+ int i;++ for (i = 0; i < HW_BREAKPOINT; i++)+ memset(&breakinfo[i], 0, sizeof(struct hw_breakpoint));+}++int kgdb_set_hw_break(unsigned long addr)+{+ return hardware_breakpoint(addr, 8, WATCH_INSTRUCTION, 1);+}++void kgdb_disable_hw_debug(struct pt_regs *regs)+{+ unsigned long hw_breakpoint_status;++ hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);+ if (hw_breakpoint_status & IA64_PSR_DB)+ ia64_setreg(_IA64_REG_PSR_L,+ hw_breakpoint_status ^ IA64_PSR_DB);+}++volatile static struct smp_unw {+ struct unw_frame_info *unw;+ struct task_struct *task;+} smp_unw[NR_CPUS];++static int inline kgdb_get_blocked_state(struct task_struct *p,+ struct unw_frame_info *unw)+{+ unsigned long ip;+ int count = 0;++ unw_init_from_blocked_task(unw, p);+ ip = 0UL;+ do {+ if (unw_unwind(unw) < 0)+ return -1;+ unw_get_ip(unw, &ip);+ if (!in_sched_functions(ip))+ break;+ } while (count++ < 16);++ if (!ip)+ return -1;+ else+ return 0;+}++static void inline kgdb_wait(struct pt_regs *regs)+{+ unsigned long hw_breakpoint_status = ia64_getreg(_IA64_REG_PSR);+ if (hw_breakpoint_status & IA64_PSR_DB)+ ia64_setreg(_IA64_REG_PSR_L,+ hw_breakpoint_status ^ IA64_PSR_DB);+ kgdb_nmihook(smp_processor_id(), regs);+ if (hw_breakpoint_status & IA64_PSR_DB)+ ia64_setreg(_IA64_REG_PSR_L, hw_breakpoint_status);++ return;+}++static void inline normalize(struct unw_frame_info *running,+ struct pt_regs *regs)+{+ unsigned long sp;++ do {+ unw_get_sp(running, &sp);+ if ((sp + 0x10) >= (unsigned long)regs)+ break;+ } while (unw_unwind(running) >= 0);++ return;+}++static void kgdb_init_running(struct unw_frame_info *unw, void *data)+{+ struct pt_regs *regs;++ regs = data;+ normalize(unw, regs);+ smp_unw[smp_processor_id()].unw = unw;+ kgdb_wait(regs);+}++void kgdb_wait_ipi(struct pt_regs *regs)+{+ struct unw_frame_info unw;++ smp_unw[smp_processor_id()].task = current;++ if (user_mode(regs)) {+ smp_unw[smp_processor_id()].unw = (struct unw_frame_info *)1;+ kgdb_wait(regs);+ } else {+ if (current->state == TASK_RUNNING)+ unw_init_running(kgdb_init_running, regs);+ else {+ if (kgdb_get_blocked_state(current, &unw))+ smp_unw[smp_processor_id()].unw =+ (struct unw_frame_info *)1;+ else+ smp_unw[smp_processor_id()].unw = &unw;+ kgdb_wait(regs);+ }+ }++ smp_unw[smp_processor_id()].unw = NULL;+ return;+}++void kgdb_roundup_cpus(unsigned long flags)+{+ if (num_online_cpus() > 1)+ smp_send_nmi_allbutself();+}++static volatile int kgdb_hwbreak_sstep[NR_CPUS];++static int kgdb_notify(struct notifier_block *self, unsigned long cmd,+ void *ptr)+{+ struct die_args *args = ptr;+ struct pt_regs *regs = args->regs;+ unsigned long err = args->err;++ switch (cmd) {+ default:+ return NOTIFY_DONE;+ case DIE_PAGE_FAULT_NO_CONTEXT:+ if (atomic_read(&debugger_active) && kgdb_may_fault) {+ kgdb_fault_longjmp(kgdb_fault_jmp_regs);+ return NOTIFY_STOP;+ }+ break;+ case DIE_BREAK:+ if (user_mode(regs) || err == 0x80001)+ return NOTIFY_DONE;+ break;+ case DIE_FAULT:+ if (user_mode(regs))+ return NOTIFY_DONE;+ else if (err == 36 && kgdb_hwbreak_sstep[smp_processor_id()]) {+ kgdb_hwbreak_sstep[smp_processor_id()] = 0;+ regs->cr_ipsr &= ~IA64_PSR_SS;+ return NOTIFY_STOP;+ }+ case DIE_MCA_MONARCH_PROCESS:+ case DIE_INIT_MONARCH_PROCESS:+ break;+ }++ kgdb_handle_exception(args->trapnr, args->signr, args->err, regs);+ return NOTIFY_STOP;+}++static struct notifier_block kgdb_notifier = {+ .notifier_call = kgdb_notify,+};++int kgdb_arch_init(void)+{+ notifier_chain_register(&ia64die_chain, &kgdb_notifier);+ return 0;+}++static void do_kgdb_handle_exception(struct unw_frame_info *, void *data);++struct kgdb_state {+ int e_vector;+ int signo;+ unsigned long err_code;+ struct pt_regs *regs;+ struct unw_frame_info *unw;+ char *inbuf;+ char *outbuf;+ int unwind;+ int ret;+};++static void inline kgdb_pc(struct pt_regs *regs, unsigned long pc)+{+ regs->cr_iip = pc & ~0xf;+ ia64_psr(regs)->ri = pc & 0x3;+ return;+}++int kgdb_arch_handle_exception(int e_vector, int signo,+ int err_code, char *remcom_in_buffer,+ char *remcom_out_buffer,+ struct pt_regs *linux_regs)+{+ struct kgdb_state info;++ info.e_vector = e_vector;+ info.signo = signo;+ info.err_code = err_code;+ info.unw = (void *)0;+ info.inbuf = remcom_in_buffer;+ info.outbuf = remcom_out_buffer;+ info.unwind = 0;+ info.ret = -1;++ if (remcom_in_buffer[0] == 'c' || remcom_in_buffer[0] == 's') {+ info.regs = linux_regs;+ do_kgdb_handle_exception(NULL, &info);+ } else if (kgdb_usethread == current) {+ info.regs = linux_regs;+ info.unwind = 1;+ unw_init_running(do_kgdb_handle_exception, &info);+ } else if (kgdb_usethread->state != TASK_RUNNING) {+ struct unw_frame_info unw_info;++ if (kgdb_get_blocked_state(kgdb_usethread, &unw_info)) {+ info.ret = 1;+ goto bad;+ }+ info.regs = NULL;+ do_kgdb_handle_exception(&unw_info, &info);+ } else {+ int i;++ for (i = 0; i < NR_CPUS; i++)+ if (smp_unw[i].task == kgdb_usethread && smp_unw[i].unw+ && smp_unw[i].unw != (struct unw_frame_info *)1) {+ info.regs = NULL;+ do_kgdb_handle_exception(smp_unw[i].unw, &info);+ break;+ } else {+ info.ret = 1;+ goto bad;+ }+ }++ bad:+ if (info.ret != -1 && remcom_in_buffer[0] == 'p') {+ unsigned long bad = 0xbad4badbadbadbadUL;++ printk("kgdb_arch_handle_exception: p packet bad (%s)\n",+ remcom_in_buffer);+ kgdb_mem2hex((char *)&bad, remcom_out_buffer, sizeof(bad));+ remcom_out_buffer[sizeof(bad) * 2] = 0;+ info.ret = -1;+ }+ return info.ret;+}++/*+ * This is done because I evidently made an incorrect 'p' encoding+ * when my patch for gdb was committed. It was later corrected. This+ * check supports both my wrong encoding of the register number and+ * the correct encoding. Eventually this should be eliminated and+ * kgdb_hex2long should be demarshalling the regnum.+ */+static inline int check_packet(unsigned int regnum, char *packet)+{+ static int check_done, swap;+ unsigned long reglong;++ if (likely(check_done)) {+ if (swap) {+ kgdb_hex2long(&packet, ®long);+ regnum = (int) reglong;+ }++ } else {+ if (regnum > NUM_REGS) {+ kgdb_hex2long(&packet, ®long);+ regnum = (int) reglong;+ swap = 1;+ }+ check_done = 1;+ }+ return regnum;+}++static void do_kgdb_handle_exception(struct unw_frame_info *unw_info,+ void *data)+{+ long addr;+ char *ptr;+ unsigned long newPC;+ int e_vector, signo;+ unsigned long err_code;+ struct pt_regs *linux_regs;+ struct kgdb_state *info;+ char *remcom_in_buffer, *remcom_out_buffer;++ info = data;+ info->unw = unw_info;+ e_vector = info->e_vector;+ signo = info->signo;+ err_code = info->err_code;+ remcom_in_buffer = info->inbuf;+ remcom_out_buffer = info->outbuf;+ linux_regs = info->regs;++ if (info->unwind)+ normalize(unw_info, linux_regs);++ switch (remcom_in_buffer[0]) {+ case 'p':+ {+ unsigned int regnum;++ kgdb_hex2mem(&remcom_in_buffer[1], (char *)®num,+ sizeof(regnum));+ regnum = check_packet(regnum, &remcom_in_buffer[1]);+ if (regnum >= NUM_REGS) {+ remcom_out_buffer[0] = 'E';+ remcom_out_buffer[1] = 0;+ } else+ kgdb_get_reg(remcom_out_buffer, regnum,+ unw_info, linux_regs);+ break;+ }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -