【内核配置】CONFIG_DEBUG_USER 配置项原理分析

背景

应用反馈设备运行过程中,应用APP出现运行报错,但是没有堆栈信息。

排查

1、尝试复现问题

针对这个现象,首先是做了对比测试,简单做了一个应用踩空地址的oops_demo:

#include <stdio.h>
#include <stdlib.h>

int main() {
int *null_ptr = NULL;
int value;

printf("空指针测试程序启动\n");

// 故意解引用空指针,触发段错误
value = *null_ptr;

printf("这行永远不会被执行: %d\n", value);

return 0;
}

然后如果是交查编译环境,则通过交叉编译工具链编译:

.../arm-ca9-linux-uclibcgnueabihf-gcc oops_demo.c -o oops_demo

将编译成功后的成果物,拷贝到设备上运行。

出现现象如下:

# echo 7 4 1 7 > /proc/sys/kernel/printk
# ./oops_demo
空指针测试程序启动
Segmentation fault

确实没有出现堆栈信息。

2、对比其他平台,进一步确认问题

又找了另一个平台设备,做对比测试,发现如下现象:

# echo 7 4 1 7 > /proc/sys/kernel/printk
# ./oops_demo
空指针测试程序启动
<--- cut here ---

oops: unhandled page fault (11) at 0x00000000, code 0x017
pgd = 385e9cea
[00000000] *pgd=013ca831, *pte=00000000, *ppte=00000000
CPU: 0 PID: 448 Comm: oops Tainted: P           O      5.10.168 #6
Hardware name: Novatek Video Platform
PC is at 0x103dc
LR is at 0x76f34717
pc : [<000103dc>]    lr : [<76f34717>]    psr: 00000030
sp : 7e97dad0  ip : 92e9878c  fp : 00000000
r10: 00000000  r9 : 00000000  r8 : 00000000
r7 : 7e97dad0  r6 : 00010305  r5 : 00000000  r4 : 76fcbc0c
r3 : 00000000  r2 : 00000001  r1 : 00000001  r0 : 0000001c
Flags: nzcv  IRQs on  FIQs on  Mode USER_32  ISA Thumb  Segment user
Control: 10c53c7d  Table: 02134059  DAC: 00000055
CPU: 0 PID: 448 Comm: oops Tainted: P           O      5.10.168 #6
Hardware name: Novatek Video Platform
[<80011cc4>] (unwind_backtrace) from [<80010200>] (show_stack+0x10/0x14)
[<80010200>] (show_stack) from [<800122e4>] (__do_user_fault+0x90/0x110)
[<800122e4>] (__do_user_fault) from [<8001265c>] (do_page_fault+0x260/0x26c)
[<8001265c>] (do_page_fault) from [<8001279c>] (do_DataAbort+0x34/0xb4)
[<8001279c>] (do_DataAbort) from [<8000907c>] (__dabt_usr+0x3c/0x40)
Exception stack(0x809bffb0 to 0x809bfff8)
ffa0:                                     0000001c 00000001 00000001 00000000
ffc0: 76fcbc0c 00000000 00010305 7e97dad0 00000000 00000000 00000000 00000000
ffe0: 92e9878c 7e97dad0 76f34717 000103dc 00000030 ffffffff
Segmentation fault

尝试换了一个其他设备测试,发现是能正常打印堆栈信息的。

3、对比内核配置

对比内核配置项,找到关键内核配置:

CONFIG_DEBUG_USER=y

开启该配置项后,应用oops触发时,会打印堆栈信息。

分析

CONFIG_DEBUG_USER 的作用

CONFIG_DEBUG_USER 是一个内核配置选项,专门用于控制用户空间程序发生错误时是否显示详细的调试信息。当你启用这个选项时,内核会在用户空间程序发生段错误等异常时打印详细的调试信息,包括寄存器状态、堆栈跟踪、页表信息等。

原理分析:

在ARM架构上,当用户空间程序尝试访问无效内存地址(如NULL指针)时,会发生以下流程:

硬件异常触发:CPU尝试访问地址0x00000000,触发数据中止异常(Data Abort)
异常处理:CPU跳转到内核的异常向量表,执行__dabt_usr处理函数
内核处理:内核通过do_DataAbort函数处理异常
页面错误处理:调用do_page_fault函数确定错误类型
用户错误处理:最终调用__do_user_fault函数处理用户空间的错误

CONFIG_DEBUG_USER 的影响

CONFIG_DEBUG_USER配置项直接影响__do_user_fault函数的行为。让我们看看内核源码中的实现:

// 在 arch/arm/mm/fault.c 中
#ifdef CONFIG_DEBUG_USER
void __do_user_fault(struct task_struct *tsk, unsigned long addr,
                     unsigned int fsr, unsigned int sig, int code,
                     struct pt_regs *regs)
{
    struct siginfo si;
    
    // 打印详细的调试信息
    printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
           tsk->comm, sig, addr, fsr);
    
    show_pte(tsk->mm, addr);
    show_regs(regs);
    
    // ... 其他调试信息
}
#else
void __do_user_fault(struct task_struct *tsk, unsigned long addr,
                     unsigned int fsr, unsigned int sig, int code,
                     struct pt_regs *regs)
{
    // 不打印调试信息,直接发送信号
    struct siginfo si;
    
    // 只设置信号信息,不打印调试信息
}
#endif

为什么会有两种不同的输出?

当你启用CONFIG_DEBUG_USER=y时:

  • 内核会调用详细的__do_user_fault实现
  • 打印包括寄存器状态、堆栈跟踪、页表信息等详细调试信息
  • 这就是你看到的第一种情况,有完整的堆栈信息

当你禁用CONFIG_DEBUG_USER时(或者未设置):

  • 内核调用简化版的__do_user_fault实现
  • 不打印任何调试信息
  • 直接向进程发送SIGSEGV信号
  • 这就是你看到的第二种情况,只有简单的"Segmentation fault"

结论

CONFIG_DEBUG_USER配置项直接控制内核在处理用户空间程序错误时的详细程度。启用时,内核会打印包括寄存器状态、堆栈跟踪等详细调试信息;禁用时,内核只会简单地终止进程而不打印额外信息。这个设计允许系统管理员根据使用场景(开发或生产)来选择适当的调试级别。

建议:

  • 生产环境:通常禁用此选项,减少不必要的日志输出,提高性能
  • 开发环境:启用此选项,便于调试用户空间程序的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Evan_ZGYF丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值