Re: [PATCH] *(int*)0 = 0 & variations

Andi Kleen (ak@muc.de)
23 Jun 1999 19:44:06 +0200


masp0008@stud.uni-sb.de (Manfred Spraul) writes:

> > The following functions more like the userland version:
> >
> >#ifndef NDEBUG
> ># define kassert(cond) \
> > if (!(cond)) { \
> > printk (KERN_ERR "kassert failed in function %s, file %s, line %d:
> >%s\n", \
> > __FUNCTION__, \
> > __FILE__, \
> > __LINE__, \
> > __STRING(cond)); \
> > *(int*)0 = 0; \ <<<<<<<<<<<<<<<<<<<<<<<<<<<<
> > }
>
>
> we should split show_registers() into show_callchain() and
> the rest. Don't force an oops.

I did this some time ago, even loadable as a module (with some
minor changes the ksyms.c to export the necessary symbols). It also
does a better job with modules than the standard backtracer.

An even better job does kdb.

-Andi

/* For i386. Based on the code in i386/kernel/traps.c, but with accurate
module checking and does not require an exception frame.
Hacked by Andi Kleen and subject to the GPL.
*/
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <asm/pgtable.h>
#include <linux/kernel.h>
#include <linux/module.h>

// these two are not exported in a standard kernel
extern unsigned long _etext, _stext;
extern struct module *module_list;

#define MODULE_RANGE (8*1024*1024)

int backtrace_stack_depth = 24;

static inline void print_trace(unsigned long *stack)
{
int i;
unsigned long module_start,module_end,addr;
const char *mname = NULL;

static inline char * module_end_addr(struct module *mp) {
return ((char *)mp) + mp->size;
}

static inline int valid_addr(unsigned long addr) {
return (((addr >= (unsigned long) &_stext) &&
(addr <= (unsigned long) &_etext)) ||
((addr >= module_start) && (addr <= module_end)));
}

static inline const char * in_module(unsigned long addr) {
struct module *mp;
for (mp = module_list; mp; mp = mp->next) {
static int warned;
// be paranoid
if (!valid_addr((unsigned long) mp) ||
!valid_addr((unsigned long) module_end_addr(mp))) {
if (!warned++)
printk("corrupted module pointer %p\n", mp);
break;
}
if (addr >= (unsigned long) (mp+1) &&
addr <= (unsigned long) module_end_addr(mp))
return mp->name;
}
return 0;
}

printk(KERN_DEBUG "Call Trace: ");

module_start = PAGE_OFFSET + (max_mapnr << PAGE_SHIFT);
module_start = ((module_start + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
module_end = module_start + MODULE_RANGE;

i = 1;
while (((long) stack & 4095) != 0) {
const char *omname = mname;
addr = *stack++;
if (valid_addr(addr) &&
(mname = in_module(addr))) {
if (i && ((i % 8) == 0))
printk("\n ");
printk("[<%08lx>] ", addr);
if (mname && mname != omname)
printk(" (%s) ", mname);
i++;
}
if (i > 30) {
printk("...");
break;
}
}
printk("\n");
}

static inline void print_stack(unsigned long *stack)
{
int i;
printk(KERN_DEBUG "Stack: ");
for(i=0; i < backtrace_stack_depth; i++) {
if (((long) stack & 4095) == 0)
break;
if (i && ((i % 8) == 0))
printk("\n ");
printk("%08lx ", *stack++);
}
printk("\n");
}

static inline void print_code(unsigned char *eip)
{
int i;
printk(KERN_DEBUG "Code: ");
for(i = 0; i < 20; i++)
printk("%02x ", *eip++);
printk("\n");
}

void backtrace(void)
{
unsigned char *esp;

asm("movl %%esp,%0\n" : "=r" (esp));

print_stack((unsigned long *) esp);
print_trace((unsigned long *) esp);
print_code((unsigned char *) __builtin_return_address(0));
}

EXPORT_SYMBOL(backtrace);

#ifdef MODULE
int init_module(void)
{
#ifdef TEST
printk(KERN_DEBUG "test\n");
backtrace();
#endif
return 0;
}
void cleanup_module() { }
#endif


-- 
This is like TV. I don't like TV.

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/