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
原文地址:https://www.cnblogs.com/aspirs/p/15634670.html