diff options
-rw-r--r-- | arch/ia64/kernel/traps.c | 33 | ||||
-rw-r--r-- | arch/ia64/mm/fault.c | 8 | ||||
-rw-r--r-- | include/asm-ia64/break.h | 2 | ||||
-rw-r--r-- | include/asm-ia64/kdebug.h | 61 |
4 files changed, 103 insertions, 1 deletions
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index 1861173bd4f6..e7e520d90f03 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c | |||
@@ -21,12 +21,26 @@ | |||
21 | #include <asm/intrinsics.h> | 21 | #include <asm/intrinsics.h> |
22 | #include <asm/processor.h> | 22 | #include <asm/processor.h> |
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | #include <asm/kdebug.h> | ||
24 | 25 | ||
25 | extern spinlock_t timerlist_lock; | 26 | extern spinlock_t timerlist_lock; |
26 | 27 | ||
27 | fpswa_interface_t *fpswa_interface; | 28 | fpswa_interface_t *fpswa_interface; |
28 | EXPORT_SYMBOL(fpswa_interface); | 29 | EXPORT_SYMBOL(fpswa_interface); |
29 | 30 | ||
31 | struct notifier_block *ia64die_chain; | ||
32 | static DEFINE_SPINLOCK(die_notifier_lock); | ||
33 | |||
34 | int register_die_notifier(struct notifier_block *nb) | ||
35 | { | ||
36 | int err = 0; | ||
37 | unsigned long flags; | ||
38 | spin_lock_irqsave(&die_notifier_lock, flags); | ||
39 | err = notifier_chain_register(&ia64die_chain, nb); | ||
40 | spin_unlock_irqrestore(&die_notifier_lock, flags); | ||
41 | return err; | ||
42 | } | ||
43 | |||
30 | void __init | 44 | void __init |
31 | trap_init (void) | 45 | trap_init (void) |
32 | { | 46 | { |
@@ -137,6 +151,10 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) | |||
137 | 151 | ||
138 | switch (break_num) { | 152 | switch (break_num) { |
139 | case 0: /* unknown error (used by GCC for __builtin_abort()) */ | 153 | case 0: /* unknown error (used by GCC for __builtin_abort()) */ |
154 | if (notify_die(DIE_BREAK, "break 0", regs, break_num, TRAP_BRKPT, SIGTRAP) | ||
155 | == NOTIFY_STOP) { | ||
156 | return; | ||
157 | } | ||
140 | die_if_kernel("bugcheck!", regs, break_num); | 158 | die_if_kernel("bugcheck!", regs, break_num); |
141 | sig = SIGILL; code = ILL_ILLOPC; | 159 | sig = SIGILL; code = ILL_ILLOPC; |
142 | break; | 160 | break; |
@@ -189,6 +207,15 @@ ia64_bad_break (unsigned long break_num, struct pt_regs *regs) | |||
189 | sig = SIGILL; code = __ILL_BNDMOD; | 207 | sig = SIGILL; code = __ILL_BNDMOD; |
190 | break; | 208 | break; |
191 | 209 | ||
210 | case 0x80200: | ||
211 | case 0x80300: | ||
212 | if (notify_die(DIE_BREAK, "kprobe", regs, break_num, TRAP_BRKPT, SIGTRAP) | ||
213 | == NOTIFY_STOP) { | ||
214 | return; | ||
215 | } | ||
216 | sig = SIGTRAP; code = TRAP_BRKPT; | ||
217 | break; | ||
218 | |||
192 | default: | 219 | default: |
193 | if (break_num < 0x40000 || break_num > 0x100000) | 220 | if (break_num < 0x40000 || break_num > 0x100000) |
194 | die_if_kernel("Bad break", regs, break_num); | 221 | die_if_kernel("Bad break", regs, break_num); |
@@ -548,7 +575,11 @@ ia64_fault (unsigned long vector, unsigned long isr, unsigned long ifa, | |||
548 | #endif | 575 | #endif |
549 | break; | 576 | break; |
550 | case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; | 577 | case 35: siginfo.si_code = TRAP_BRANCH; ifa = 0; break; |
551 | case 36: siginfo.si_code = TRAP_TRACE; ifa = 0; break; | 578 | case 36: |
579 | if (notify_die(DIE_SS, "ss", ®s, vector, | ||
580 | vector, SIGTRAP) == NOTIFY_STOP) | ||
581 | return; | ||
582 | siginfo.si_code = TRAP_TRACE; ifa = 0; break; | ||
552 | } | 583 | } |
553 | siginfo.si_signo = SIGTRAP; | 584 | siginfo.si_signo = SIGTRAP; |
554 | siginfo.si_errno = 0; | 585 | siginfo.si_errno = 0; |
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c index 4174ec999dde..ff62551eb3a1 100644 --- a/arch/ia64/mm/fault.c +++ b/arch/ia64/mm/fault.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
15 | #include <asm/system.h> | 15 | #include <asm/system.h> |
16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
17 | #include <asm/kdebug.h> | ||
17 | 18 | ||
18 | extern void die (char *, struct pt_regs *, long); | 19 | extern void die (char *, struct pt_regs *, long); |
19 | 20 | ||
@@ -102,6 +103,13 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re | |||
102 | goto bad_area_no_up; | 103 | goto bad_area_no_up; |
103 | #endif | 104 | #endif |
104 | 105 | ||
106 | /* | ||
107 | * This is to handle the kprobes on user space access instructions | ||
108 | */ | ||
109 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, code, TRAP_BRKPT, | ||
110 | SIGSEGV) == NOTIFY_STOP) | ||
111 | return; | ||
112 | |||
105 | down_read(&mm->mmap_sem); | 113 | down_read(&mm->mmap_sem); |
106 | 114 | ||
107 | vma = find_vma_prev(mm, address, &prev_vma); | 115 | vma = find_vma_prev(mm, address, &prev_vma); |
diff --git a/include/asm-ia64/break.h b/include/asm-ia64/break.h index 97c7b2d79600..8167828edc4b 100644 --- a/include/asm-ia64/break.h +++ b/include/asm-ia64/break.h | |||
@@ -12,6 +12,8 @@ | |||
12 | * OS-specific debug break numbers: | 12 | * OS-specific debug break numbers: |
13 | */ | 13 | */ |
14 | #define __IA64_BREAK_KDB 0x80100 | 14 | #define __IA64_BREAK_KDB 0x80100 |
15 | #define __IA64_BREAK_KPROBE 0x80200 | ||
16 | #define __IA64_BREAK_JPROBE 0x80300 | ||
15 | 17 | ||
16 | /* | 18 | /* |
17 | * OS-specific break numbers: | 19 | * OS-specific break numbers: |
diff --git a/include/asm-ia64/kdebug.h b/include/asm-ia64/kdebug.h new file mode 100644 index 000000000000..4d376e1663f7 --- /dev/null +++ b/include/asm-ia64/kdebug.h | |||
@@ -0,0 +1,61 @@ | |||
1 | #ifndef _IA64_KDEBUG_H | ||
2 | #define _IA64_KDEBUG_H 1 | ||
3 | /* | ||
4 | * include/asm-ia64/kdebug.h | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | * Copyright (C) Intel Corporation, 2005 | ||
21 | * | ||
22 | * 2005-Apr Rusty Lynch <rusty.lynch@intel.com> and Anil S Keshavamurthy | ||
23 | * <anil.s.keshavamurthy@intel.com> adopted from | ||
24 | * include/asm-x86_64/kdebug.h | ||
25 | */ | ||
26 | #include <linux/notifier.h> | ||
27 | |||
28 | struct pt_regs; | ||
29 | |||
30 | struct die_args { | ||
31 | struct pt_regs *regs; | ||
32 | const char *str; | ||
33 | long err; | ||
34 | int trapnr; | ||
35 | int signr; | ||
36 | }; | ||
37 | |||
38 | int register_die_notifier(struct notifier_block *nb); | ||
39 | extern struct notifier_block *ia64die_chain; | ||
40 | |||
41 | enum die_val { | ||
42 | DIE_BREAK = 1, | ||
43 | DIE_SS, | ||
44 | DIE_PAGE_FAULT, | ||
45 | }; | ||
46 | |||
47 | static inline int notify_die(enum die_val val, char *str, struct pt_regs *regs, | ||
48 | long err, int trap, int sig) | ||
49 | { | ||
50 | struct die_args args = { | ||
51 | .regs = regs, | ||
52 | .str = str, | ||
53 | .err = err, | ||
54 | .trapnr = trap, | ||
55 | .signr = sig | ||
56 | }; | ||
57 | |||
58 | return notifier_call_chain(&ia64die_chain, val, &args); | ||
59 | } | ||
60 | |||
61 | #endif | ||