zoukankan      html  css  js  c++  java
  • kernel BUG_ON macro的实现以及brk指令触发异常后的异常处理callstack

    kernel BUG_ON macro的实现以及brk指令触发异常后的异常处理callstack

    kernel里的两个macro

    BUG_ON(condition),如果condition条件满足,判断为真,则会造成一个debug exception;

    BUG(),这个没有条件判断,调用它则会直接造成一个debug exception,可以在code里在某种error的情形下调用。BUG_ON()也是调用的这个macro,只是多一个判断条件。

    BUG() macro的实现

    arch/arm64/include/asm/asm-bug.h

    #ifdef CONFIG_DEBUG_BUGVERBOSE
    #define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line)
    #define __BUGVERBOSE_LOCATION(file, line)            \
            .pushsection .rodata.str,"aMS",@progbits,1;    \
        14472:    .string file;                    \ #这里.string存储__FILE__ string,会自动以/0字符结尾
            .popsection;                    \
                                    \
            .long 14472b - 14470b;                \  #这里存储的是上面.string字串在bug_entry struct里的offset,后面根据bug_entry struct的起始地址再加上这个offset即可以得到这个string的起始地址
            .short line;   #存储的是__LINE__
    #else
    #define _BUGVERBOSE_LOCATION(file, line)
    #endif
    
    #ifdef CONFIG_GENERIC_BUG
    
    #define __BUG_ENTRY(flags)                 \
            .pushsection __bug_table,"aw";        \
            .align 2;                \
        14470:    .long 14471f - 14470b;            \   #这里是两个label地址相减,这个对应bug_entry struct里的bug_addr_disp,即这个struct的size
    _BUGVERBOSE_LOCATION(__FILE__, __LINE__)        \
            .short flags;                 \
            .popsection;                \
        14471:
    #else
    #define __BUG_ENTRY(flags)
    #endif
    
    #define ASM_BUG_FLAGS(flags)                \
        __BUG_ENTRY(flags)                \
        brk    BUG_BRK_IMM
    
    #define ASM_BUG()    ASM_BUG_FLAGS(0)

    注意上面__BUG_ENTRY macro里看起来是有5个field,但是它是对应如下struct bug_entry的,这个struct里只define了4个field,所以看起来上面__BUG_ENTRY里的.string是不包含在struct bug_entry里的

    include/asm-generic/bug.h

    #ifdef CONFIG_GENERIC_BUG
    struct bug_entry {
    #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
        unsigned long    bug_addr;
    #else
        signed int    bug_addr_disp;
    #endif
    #ifdef CONFIG_DEBUG_BUGVERBOSE
    #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
        const char    *file;
    #else
        signed int    file_disp;
    #endif
        unsigned short    line;
    #endif
        unsigned short    flags;
    };
    #endif    /* CONFIG_GENERIC_BUG */

    arch/arm64/kernel/traps.c

    static int bug_handler(struct pt_regs *regs, unsigned int esr)
    {
        if (user_mode(regs))
            return DBG_HOOK_ERROR;
    
        switch (report_bug(regs->pc, regs)) {
        case BUG_TRAP_TYPE_BUG:
            die("Oops - BUG", regs, 0);
            break;
    
        case BUG_TRAP_TYPE_WARN:
            break;
    
        default:
            /* unknown/unrecognised bug trap type */
            return DBG_HOOK_ERROR;
        }
    
        /* If thread survives, skip over the BUG instruction and continue: */
        arm64_skip_faulting_instruction(regs, AARCH64_INSN_SIZE);
        return DBG_HOOK_HANDLED;
    }
    4.19/lib/bug.c
    enum
    bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs) { struct bug_entry *bug; const char *file; unsigned line, warning, once, done; if (!is_valid_bugaddr(bugaddr)) return BUG_TRAP_TYPE_NONE; bug = find_bug(bugaddr); ... if (file) pr_crit("kernel BUG at %s:%u!\n", file, line); else pr_crit("Kernel BUG at %pB [verbose debug info unavailable]\n", (void *)bugaddr);

    4.19/lib/bug.c

    static inline unsigned long bug_addr(const struct bug_entry *bug)
    {
    #ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
        return bug->bug_addr;
    #else
        return (unsigned long)bug + bug->bug_addr_disp;
    #endif
    }

    ASM_BUG_FLAGS里包含了__BUG_ENTRY(flags)以及一条brk BUG_BRK_IMM指令,

    __BUG_ENTRY相当于define了一个struct bug_entry,所以是在这个struct后面紧跟了一个brk BUG_BRK_IMM指令,所以上述(unsigned long)bug + bug->bug_addr_disp即表示这条brk指令的地址,这个地址和发生brk异常时的PC值比较,如果相等,则找到了对应的bug_entry struct,并将调用BUG_ON()所在文件以及行数打印出来

    看一下BUG_ON() 是如何实现的

    include/asm-generic/bug.h
    #ifndef HAVE_ARCH_BUG_ON
    #define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
    #endif
    
    4.19/arch/arm64/include/asm/bug.h
    #define BUG() do {                    \
        __BUG_FLAGS(0);                    \
        unreachable();                    \
    } while (0)
    
    #define __BUG_FLAGS(flags)                \
        asm volatile (__stringify(ASM_BUG_FLAGS(flags)));

    所以每一个BUG_ON最终的编译结果会包含一个brk指令,如果BUG_ON的条件成立(条件判断为1),则会执行到这条brk指令触发异常,处理这个异常的callstack如下:

    <2>[ 1409.592923] kernel BUG at block/blk-core.c:3238!
    
    <0>[ 1409.592929] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP
    
    KERNEL-PANIC
    
    dump process path
    
    [HwBinder:2904_2, 3479]
    
    dump backtrace
    
    [<0000000080c43ddd>] kmsg_dump+0xa4/0x284
    
    [<000000000affdfa0>] panic+0x1c0/0x4e4
    
    [<000000009de7d86d>] die+0x5d8/0x5ec
    
    [<000000000b44dbbb>] bug_handler+0x50/0xa4
    
    [<0000000014428671>] brk_handler+0xe0/0x21c
    
    [<0000000056de13f5>] do_debug_exception+0x154/0x2a4
    
    [<000000006312a774>] el1_dbg+0x18/0xa8
    
    [<00000000723f061b>] blk_finish_request+0x22c/0x230
    
    [<0000000036ccd665>] scsi_end_request+0x288/0x588
    
    [<000000002223f37c>] scsi_io_completion+0x8c/0x90c
    
    [<00000000404d6d57>] scsi_finish_command+0x12c/0x184
    
    [<00000000323c7119>] scsi_softirq_done+0x118/0x14c
    
    [<000000007f25ecd3>] blk_done_softirq+0xcc/0x130
    
    [<00000000414d4713>] __do_softirq+0x1f8/0x490
    
    [<000000003feb2504>] irq_exit+0x1d4/0x244
    
    [<00000000df9c9f02>] handle_IPI+0x2cc/0x6b8
    
    [<000000005f9611a3>] gic_handle_irq+0xa4/0xbc
    
    [<00000000fe8e935c>] el1_irq+0xe8/0x190
    
    [<00000000f48fe71e>] binder_ioctl_write_read+0x2868/0x3214
    
    [<000000000c8156f9>] binder_ioctl+0x370/0xd30
    
    [<0000000047fd89c2>] do_vfs_ioctl+0x718/0xf0c
    
    [<0000000072e174c9>] __arm64_sys_ioctl+0xcc/0x104
    
    [<00000000b02b22b0>] el0_svc_common+0xb8/0x1b8
    
    [<0000000016fc6b90>] el0_svc_handler+0x74/0x90
    
    [<00000000255fbc3e>] el0_svc+0x8/0x340
    
    [<0000000074c12ba5>] 0xffffffffffffffff
  • 相关阅读:
    文件光标移动
    python的版本的差别 "2","3"
    java通过jdbc操作Excel
    qt通过odbc操作Excel
    qt读取oracle表数据
    virtual box安装oracle_rac_10g
    oracle rac +standby
    rac不完全恢复
    rac完全恢复学习
    oracle rac搭建(三)--安装中的问题
  • 原文地址:https://www.cnblogs.com/aspirs/p/15634670.html
Copyright © 2011-2022 走看看