• Debug Hacks


    启动内核转储(core dump)

    ulimit -c     // 查看内核转储功能是否有效
    ulimit -c unlimited    // 不限制大小
    ulimit -c 1073741824    // 设置1G大小

    对于转储文件 core*可以用GDB进行调试

    未设置时,转出文件都在运行目录下,可以设置到固定位置

    # cat /etc/systol.conf
    kernel.core_pattern = /var/core/%t-%e-%p-%c.core
    kernel.core_uses_pid = 0
    # sysctl -p

    将会把文件放到 /var/core/下,文件名为%t-%e-%p-%c.core。含义如表2-1所示。

    对于kernel.core_uses_pid设置成1,那么文件名末尾就会加 .PID。

     自动压缩内核转储文件

    // 可以设置进行压缩
    kernel.core_pattern = |/usr/local/sbin/core_helper %t %e %p %c  
    
    // 看看core_helper到底是啥
    # cat /usr/local/sbin/core_helper 
    
    #!/bin/bash
    exec gzip - > /var/core/$1-$2-$3-$4.core.gz // 直接压缩了

    有时进程多,全都转储会有一定压力,可以通过掩码屏蔽一些类型。如表2-2

    # cat /proc/<PID>/coredump_filter
    00000003                // 转储所有匿名内存区段,若改为1则跳过共享内存区段

    GDB基本使用方法 一

    gdb 文件名    // 启动调试该文件
    b 断点(函数名、行号、文件名:行号、文件名:函数名、+偏移量、-偏移量、*地址) // 设置断点,直接b则在下一行设置断点
    info break      // 查看设置断点处
    run -a        // 开始运行,运行到断点后暂停。
    backtrace/bt        // 显示栈帧,
    p 变量        // 显示值
    p/格式  变量      // 如表2-3所示,按照格式显示值
    info reg        // 显示寄存器
    x/格式 地址      // 可以显示地址下的数据,若格式为i则显示机器语言的语句
    x/NFU ADDR     // ADDR为显示的地址, N为连续显示的个数,F为2-3的格式,U为2-4的单位
    next(n)        // 执行源代码的一行,nexti则会执行汇编语言的一行
    step(p)        // 对于函数调用,可以进入到函数内部,stepi则会执行汇编语言的一行
    continue(c) 次数    // 继续运行程序,遇到断点暂停
    watch <表达式>      // 监视点,表达式则是常量或者变量。表达式变化时暂停
    awatch <表达式>     //  表达式被访问、改变时暂停
    rwatch <表达式>      // 表达式被访问时暂停
    delete <编号>       //删除断点或监视点
    set variable <变量>=<表达式>  // 修改变量的值
    generate-core-file      // 生成内核转储文件

     GDB基本使用方法二

    attach到进程:用于调试守护进程等已经启动的进程。

    attach pid  // attach到pid进程上(在gdb里面进行attach)
    ps aux | grep sleep   // 可以查看sleep命令
    info proc  // 可以用来查看进程信息
    break 断点 if 条件 // 只有条件为真,断点才暂停
    clear    // 删除断点
    disable   // 禁用断点
    enable    // 开启disable禁用的断点
    comand 断点编号 // 断点命令 在遇到该断点编号后自动执行,可以用来显示一些变量
    命令...
    end

     

     GDB基本使用方法三

    p argc // 可以显示argc的值,如表2-6可以显示历史输出的值。
    set $i = 0 // 可以随意定义变量,并设置值
    show history // 可以显示历史命令,默认保存在./.gdb_history文件
    define 命令名  // 可以自定义命令
     命令...
    end
    命令名      // 通过命令名可以直接运行
    document 命令名  // 可以为定义的命令添加说明
     说明...
    end
    help 命令名  // 可以查看命令名的说明

     字节序:低位在低地址就是小端(Little Endian),否则是大端。

     ESP:栈指针

    CS:代码段。DS:数据段。SS:堆栈段。ES/FS/GS:数据段。

    EAX:操作数,结果。EBX:DS段的指针。ECX:计数器。EDX:输入输出指针。

    ESI:DS下的数据指针,作为源。EDI:ES下的数据指针,作为目的。ESP:栈指针(栈顶)。EBP:栈上数据的指针(栈底)

    地址:平坦模式,如图2-9,内存是线性空间。LInux采用该方式。

       分段模式,如图2-10,先寻找段,再找段内偏移。

    ------------------------------TODO 函数调用前后栈的状态 P72-------------------------

     使用GDB操作栈帧

    bt        // 查看栈
    frame     // 选择栈帧
    up/down   // 选择上一层或者下一层栈帧
    i frame 1     // 查看详细的栈帧信息
    i proc mapping // 查看attach的进程的内存映射信息,包含栈的空间
                            // 对于内核转储的文件,可以info /proc/<PID>/maps主动增加该文件
    b func      // 调试函数

    ---------------------------------- TODO 函数调试 P79-------------------------

    crash可以进行反汇编

    crash /boot/vmlinux-2.6.19  // 首先进入crash(常用于分析vmcore)
    crash> dis 文件名    // 反汇编该文件
    crash> bt        // 打印函数栈
    crash> ps       // 查看崩溃时,运行的所有进程

    ----------------------------------TODO oops 105~108--------------------

    netconsole:可以让printk信息通过网络(UDP)发送到远端主机。

          如下图,发送端为10.1.1.100,接收端为10.1.0.200

    文件 /etc/sysconfig/syslog中

    将 SYSLOGD_OPTIONS="-m 0" 修改为 "-m 0 -r"  可用于接收主机日志。

    修改/etc/sysctl.conf

    将 kernel.sysrq = 0修改为 1。并执行sysctl -p可以用于启动SysRq

     SysRq:用于调试内核。SysRq使用了中断,即使无法登陆,按键无响应也可以使用,但内核禁止中断时无法使用。

    make menuconfig

    sysctl -w kernel.sysrq=1  // 1代表所有命令键都可使用,如表3-1为其他配置。48则是允许Sync和重新挂载。

    SysRq : show memory // 显示内存占用

    SysRq : show State      // 显示状态

    disdump:为发生kernel panic 获取转出文件功能。

    /etc/sysconfig/diskdump加入:

    DEVICE = /dev/sda3       // 需要准备一个分区,分区要大于内存大小。

    service disdump initialformat   // 准备启动diskdump
    chkconfig diskdump on
    service diskdump start
    cat /proc/diskdump    // 查看diskdump是否生效

     kdump:获取内核崩溃转储

    makedumpfile:缩小转储文件

    crash常用命令

    // 启动crash
    
    crash vmlinux vmcore   // vmlinux未压缩的镜像,vmcore为转储文件。
    
    crash vmlinux  // 查看当前实时系统。
    // crash内部命令
    
    set 命令     // 指定进程,显示其上下文。不指定则为当前运行进程。
    ascii  命令    // 将16进制转为字符串。
    h 命令      // 显示输入过的命令历史
    bt 命令      // 输出backtrace
    dev命令      // 显示字符设备列表
    dis 命令      // 输出反汇编
    files 命令      // 显示进程打开的文件
    irq 命令       // 显示打开的中断
    kmem 命令     // 显示内存信息
    list 命令      // 按顺序显示地址
    mod 命令      // 加载模块信息,符号信息,调试信息。
    net 命令      // 列出网络设备
    ps 命令      // 显示进程信息
    rd 命令      // 读取内存地址
    runq 命令     // 显示进程调度的运行队列
    .....

    ------------------------- TODO IPMI NMI获取崩溃转储---------------------------

    内核独有汇编指令:

    ud2   // CPU引发的异常,内核执行ud2指令,使CPU接收该异常。
    cli      // 禁止中断
    sli      // 允许中断

    current 宏:获取当前运行进程的task_struct

    task_struct和 thread_finfo  :管理进程task_struct 的结构位于SLAB中。

                 task_struct和thread_info都有对方指针。如图3-6.

    发生SIGSEGV:应用程序非法访问了内存。

            NULL指针访问。指针被破坏,导致非法地址访问。栈溢出,访问超出了分配的空间。

    数据非法访问导致内存破坏:缓冲区溢出后,bt不会显示符号名

                 运行地址的改变有:指定地址并调用。指定了内存区域,保存了跳转地址、ret命令返回时的栈指针被破坏。

                 由于第一类使用的地址都被保存在只读空间,所以通常是后两类。 

                 确定破坏跳转地址值的位置(栈被破坏),如:对于复制字符串的目的地址空间过小,缓冲区溢出。原本是保存返回地址的,保存成了错误地址。如图4-4所示。

    监视点:对于越界的地址可以用监视点,看什么时候访问了该错误的地址。

    malloc和free:双重释放、非法区域释放可能导致问题。

    应用程序停止响应(死锁):对于停止响应,如果用ps看到状态是R,说明还在运行,可能是失控。对于S,说明睡眠,可能是死锁。

                 attach到该进程。i thr(可以看有哪些线程)。thr 2(跳转到2线程)

    应用程序停止响应(死循环):通常有大量相同信息,可以通过top命令、vmstat命令查看cpu利用率。

    kernel panic(空指针引用):首先可以通过crash下的disas进行反汇编,并加载符号需要的模块。

    kernel panic(链表被破坏):在删除时,prev和next有了错误数据。

     -------------------------------------------------TODO 遇到的各种BUG---------------------------

    strace:跟踪进程使用的系统调用,并显示内容。

    strace 可执行文件:可以看到,下图2处,由于没有打开文件权限,导致失败。

    strace -i 可执行文件:可以看到哪里执行了系统调用,有利于GDB调试去设置断点。

    strace -p ·pidof st2· :(pidof st2就获得了进程的pid),attach到正在运行的pid进程上。

    strace -o output.log command :可以将内容输出到文件

    objdump:可以处理带有调试信息的二进制文件。

    valgrind:用于检测内存的非法使用。

         如图所示代码,malloc 20的空间没有释放,HEAP SUMMARY内部显示20字节,分配1次,释放0次。

        除此之外,还能检测:非法内存地址的访问,读取未初始化区域,访问已释放区域,内存双重释放,非法栈操作

        valgrind对于检测非法使用内存很有效果,但不是万能的。

     

     

    valigrind:内存泄漏会根据时间增长,内存使用(VIRT和RES)逐渐增长。VIRT和RES的区别,VIRT包含了被交换(swap)的空间,而RES不包括。

    kprobes:动态插入侦测器获取内核内部信息。

         无需重启内核,就可以执行printk在内的各种调试工作。

    jprobes:将侦测器插入到内核函数的开头,获取内核内部信息。

    KAHO:获取被编译器优化掉的变量的值

     systemtap:调试运行中的内核。

    /proc/<PID>/mem:读取进程的内存内容

    OOM(Out of Memory) Killer:内存和交换区用尽时的强制结束信号。

    参考:Debug Hacks 中文版

  • 相关阅读:
    Dev 之 GridControl 列表 显示底部(包括底部统计)
    DEV 之 有些控件不允许拖动。
    Split 之特殊用法
    WebSerivce与WebAPI的区别
    DevExpress的DateEdit设置显示日期和时间
    indexOf 和 lastIndexOf的区别
    DevExpress GridControl使用教程:之 添加 checkbox 复选框
    APP通用测试用例大全
    Windows下搭建easyMock
    Centos8搭建Easy-Mock详细步骤
  • 原文地址:https://www.cnblogs.com/lmhyhblog/p/12785106.html
Copyright © 2020-2023  润新知