1 #include <linux/interrupt.h>
2 #include <linux/kdebug.h>
3 #include <linux/kmemcheck.h>
4 #include <linux/kernel.h>
5 #include <linux/types.h>
6 #include <linux/ptrace.h>
7 #include <linux/stacktrace.h>
8 #include <linux/string.h>
13 enum kmemcheck_error_type
{
14 KMEMCHECK_ERROR_INVALID_ACCESS
,
18 #define SHADOW_COPY_SIZE (1 << CONFIG_KMEMCHECK_SHADOW_COPY_SHIFT)
20 struct kmemcheck_error
{
21 enum kmemcheck_error_type type
;
24 /* KMEMCHECK_ERROR_INVALID_ACCESS */
26 /* Kind of access that caused the error */
27 enum kmemcheck_shadow state
;
28 /* Address and size of the erroneous read */
29 unsigned long address
;
35 struct stack_trace trace
;
36 unsigned long trace_entries
[32];
38 /* We compress it to a char. */
39 unsigned char shadow_copy
[SHADOW_COPY_SIZE
];
40 unsigned char memory_copy
[SHADOW_COPY_SIZE
];
44 * Create a ring queue of errors to output. We can't call printk() directly
45 * from the kmemcheck traps, since this may call the console drivers and
46 * result in a recursive fault.
48 static struct kmemcheck_error error_fifo
[CONFIG_KMEMCHECK_QUEUE_SIZE
];
49 static unsigned int error_count
;
50 static unsigned int error_rd
;
51 static unsigned int error_wr
;
52 static unsigned int error_missed_count
;
54 static struct kmemcheck_error
*error_next_wr(void)
56 struct kmemcheck_error
*e
;
58 if (error_count
== ARRAY_SIZE(error_fifo
)) {
63 e
= &error_fifo
[error_wr
];
64 if (++error_wr
== ARRAY_SIZE(error_fifo
))
70 static struct kmemcheck_error
*error_next_rd(void)
72 struct kmemcheck_error
*e
;
77 e
= &error_fifo
[error_rd
];
78 if (++error_rd
== ARRAY_SIZE(error_fifo
))
84 void kmemcheck_error_recall(void)
86 static const char *desc
[] = {
87 [KMEMCHECK_SHADOW_UNALLOCATED
] = "unallocated",
88 [KMEMCHECK_SHADOW_UNINITIALIZED
] = "uninitialized",
89 [KMEMCHECK_SHADOW_INITIALIZED
] = "initialized",
90 [KMEMCHECK_SHADOW_FREED
] = "freed",
93 static const char short_desc
[] = {
94 [KMEMCHECK_SHADOW_UNALLOCATED
] = 'a',
95 [KMEMCHECK_SHADOW_UNINITIALIZED
] = 'u',
96 [KMEMCHECK_SHADOW_INITIALIZED
] = 'i',
97 [KMEMCHECK_SHADOW_FREED
] = 'f',
100 struct kmemcheck_error
*e
;
108 case KMEMCHECK_ERROR_INVALID_ACCESS
:
109 printk(KERN_ERR
"WARNING: kmemcheck: Caught %d-bit read "
110 "from %s memory (%p)\n",
111 8 * e
->size
, e
->state
< ARRAY_SIZE(desc
) ?
112 desc
[e
->state
] : "(invalid shadow state)",
113 (void *) e
->address
);
116 for (i
= 0; i
< SHADOW_COPY_SIZE
; ++i
)
117 printk("%02x", e
->memory_copy
[i
]);
121 for (i
= 0; i
< SHADOW_COPY_SIZE
; ++i
) {
122 if (e
->shadow_copy
[i
] < ARRAY_SIZE(short_desc
))
123 printk(" %c", short_desc
[e
->shadow_copy
[i
]]);
128 printk(KERN_INFO
"%*c\n", 2 + 2
129 * (int) (e
->address
& (SHADOW_COPY_SIZE
- 1)), '^');
131 case KMEMCHECK_ERROR_BUG
:
132 printk(KERN_EMERG
"ERROR: kmemcheck: Fatal error\n");
136 __show_regs(&e
->regs
, 1);
137 print_stack_trace(&e
->trace
, 0);
140 static void do_wakeup(unsigned long data
)
142 while (error_count
> 0)
143 kmemcheck_error_recall();
145 if (error_missed_count
> 0) {
146 printk(KERN_WARNING
"kmemcheck: Lost %d error reports because "
147 "the queue was too small\n", error_missed_count
);
148 error_missed_count
= 0;
152 static DECLARE_TASKLET(kmemcheck_tasklet
, &do_wakeup
, 0);
155 * Save the context of an error report.
157 void kmemcheck_error_save(enum kmemcheck_shadow state
,
158 unsigned long address
, unsigned int size
, struct pt_regs
*regs
)
160 static unsigned long prev_ip
;
162 struct kmemcheck_error
*e
;
166 /* Don't report several adjacent errors from the same EIP. */
167 if (regs
->ip
== prev_ip
)
175 e
->type
= KMEMCHECK_ERROR_INVALID_ACCESS
;
178 e
->address
= address
;
182 memcpy(&e
->regs
, regs
, sizeof(*regs
));
184 /* Save stack trace */
185 e
->trace
.nr_entries
= 0;
186 e
->trace
.entries
= e
->trace_entries
;
187 e
->trace
.max_entries
= ARRAY_SIZE(e
->trace_entries
);
189 save_stack_trace_bp(&e
->trace
, regs
->bp
);
191 /* Round address down to nearest 16 bytes */
192 shadow_copy
= kmemcheck_shadow_lookup(address
193 & ~(SHADOW_COPY_SIZE
- 1));
194 BUG_ON(!shadow_copy
);
196 memcpy(e
->shadow_copy
, shadow_copy
, SHADOW_COPY_SIZE
);
198 kmemcheck_show_addr(address
);
199 memory_copy
= (void *) (address
& ~(SHADOW_COPY_SIZE
- 1));
200 memcpy(e
->memory_copy
, memory_copy
, SHADOW_COPY_SIZE
);
201 kmemcheck_hide_addr(address
);
203 tasklet_hi_schedule_first(&kmemcheck_tasklet
);
207 * Save the context of a kmemcheck bug.
209 void kmemcheck_error_save_bug(struct pt_regs
*regs
)
211 struct kmemcheck_error
*e
;
217 e
->type
= KMEMCHECK_ERROR_BUG
;
219 memcpy(&e
->regs
, regs
, sizeof(*regs
));
221 e
->trace
.nr_entries
= 0;
222 e
->trace
.entries
= e
->trace_entries
;
223 e
->trace
.max_entries
= ARRAY_SIZE(e
->trace_entries
);
225 save_stack_trace(&e
->trace
);
227 tasklet_hi_schedule_first(&kmemcheck_tasklet
);