天天看点

kernel crash 发生后的那些事(二)

__do_kernel_fault主要包含两个函数show_pte and die.

void show_pte(struct mm_struct *mm, unsigned long addr)

{

    pgd_t *pgd;

    if (!mm)

        mm = &init_mm;

    printk(KERN_ALERT "pgd = %p\n", mm->pgd);

    pgd = pgd_offset(mm, addr);

    printk(KERN_ALERT "[%08lx] *pgd=%08llx",

            addr, (long long)pgd_val(*pgd));

    do {

        pud_t *pud;

        pmd_t *pmd;

        pte_t *pte;

        if (pgd_none(*pgd)){

            printk(KERN_ALERT "pgd_none\n");

            break;

        }

    }while(0);

    printk("\n");

}

这里涉及页表目录和页表项的操作。

对arm体系结构而言,相关的宏包含在文件arch/arm/include/asm/pgtable.h中,如以下:

#define pgd_index(addr)        ((addr) >> PGDIR_SHIFT)

#define pgd_offset(mm, addr)    ((mm)->pgd + pgd_index(addr))

#define pgd_val(x)    ((x).pgd[0])

在文件arch/arm/include/asm/pgtable.h中包含

#ifdef CONFIG_ARM_LPAE

#include <asm/pgtable-3level.h>

#else

#include <asm/pgtable-2level.h>

#endif

根据.config 文件,可知没有定义CONFIG_ARM_LPAE,固包含头文件

arch/arm/include/asm/pgtable-2level-types.h

arch/arm/include/asm/pgtable-2level.h

比如PGDIR_SHIFT在这些文件中定义。

从crash的分析结果中,可以明确看出 pgd_t,pud_t,pmd_t,pte_t的定义。

crash> whatis pgd_t

typedef unsigned int [2] pgd_t;

SIZE: 8

crash> whatis pud_t

typedef struct {

    pgd_t pgd;

} pud_t;

SIZE: 8

crash> whatis pmd_t

typedef unsigned int pmd_t;

SIZE: 4

crash> whatis pte_t

typedef unsigned int pte_t;

SIZE: 4

对该例而言,pgd = e6390000

crash> rd 0xe6390000 16

e6390000:  00000000 00000000 00000000 00000000

如打印显示的那样:

Unable to handle kernel NULL pointer dereference at virtual address 00000000

pgd = e6390000

[00000000] *pgd=00000000

这里应该弄清楚,arm中为什么pgd_t占8个字节?

task_struct/ mm_struct/ thread_info/ sp 等之间的关系。待续---

继续阅读