linux kernel debug 之 CallTrace

本文针对UWB无线调试中出现的Kernel警告问题进行了深入分析,并提供了具体的解决方案,包括Kernel中断请求与释放、内存页分配与释放及内核锁等方面的内容。

这篇文章是基于上次UWB(WUSB) wireless debug 的一个问题,然后引申出来的一个话题,对kenel有一定理解的同学可能会有一定的帮助。

--其实这个问题,个人认为,这个个CallTrace会一起down机,cpuhold的等问题,还是一个很大的问题。不过从一般意义上来讲,他是个warning我们可以不用管他。但谁让自己是做技术的呢,没办法,眼里容不得沙子。来吧干货。

1.      Kernel int request & free

Call Trace:

Apr  7 10:44:56 magic kernel: ------------[ cuthere ]------------

Apr  7 10:44:56 magic kernel: WARNING: atkernel/softirq.c:159 local_bh_enable_ip+0x7d/0xb0() (Tainted: P           ---------------   )

Apr  7 10:44:56 magic kernel: Hardware name: HPZ420 Workstation

Apr  7 10:44:56 magic kernel: Modules linked in:usb_skeleton(U) wusb_cbaf(U) elok_s(P)(U) tun bridge iptable_mangle iptable_natnf_nat nf_conntrack_ipv4 nf_conntrack nf_defrag_ipv4 iptable_filter ip_tablessunrpc bnx2fc cnic uio fcoe libfcoe 8021q garp stp libfc llc scsi_transport_fcscsi_tgt cpufreq_ondemand acpi_cpufreq freq_table mperf ipv6 rcim2usb(U)psysdrv(P)(U) esdcan_pci200(P)(U) realtek_uwb(U) vfat fat hwa_hc(U) wusb_wa(U)ext3 wusbcore(U) jbd hwa_rc(U) uwb(U) wmi xhci_hcd nvidia(P)(U) igb dca ptppps_core sg microcode serio_raw i2c_i801 i2c_core iTCO_wdt iTCO_vendor_supportsnd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdepsnd_seq snd_seq_device snd_pcm snd_timer snd soundcore snd_page_alloc e1000eshpchp ext4 mbcache jbd2 sd_mod crc_t10dif sr_mod cdrom firewire_ohcifirewire_core crc_itu_t isci libsas mpt2sas scsi_transport_sas raid_class ahcipata_acpi ata_generic dm_mirror dm_region_hash dm_log dm_mod [last unloaded:scsi_wait_scan]

Apr  7 10:44:56 magic kernel: Pid: 6127, comm:java Tainted: P          ---------------   2.6.32-358.11.1.el6.x86_64 #1

Apr  7 10:44:56 magic kernel: Call Trace:

Apr  7 10:44:56 magic kernel: <IRQ>  [<ffffffff8106e2e7>] ? warn_slowpath_common+0x87/0xc0

Apr  7 10:44:56 magic kernel:[<ffffffff8106e33a>] ? warn_slowpath_null+0x1a/0x20

Apr  7 10:44:56 magic kernel:[<ffffffff810778dd>] ? local_bh_enable_ip+0x7d/0xb0

Apr  7 10:44:56 magic kernel:[<ffffffff815106db>] ? _spin_unlock_bh+0x1b/0x20

Apr  7 10:44:56 magic kernel:[<ffffffffa0bcd8f7>] ? uwb_rc_set_drp_cmd_done+0x67/0x100 [uwb]

Apr  7 10:44:56 magic kernel:[<ffffffff8108107d>] ? del_timer+0x7d/0xe0

Apr  7 10:44:56 magic kernel:[<ffffffffa0bd0e95>] ? uwb_rc_neh_cb+0x25/0x40 [uwb]

Apr  7 10:44:56 magic kernel:[<ffffffffa0bd11a2>] ? uwb_rc_neh_grok+0x252/0x4d0 [uwb]

Apr  7 10:44:56 magic kernel:[<ffffffffa01e6e39>] ? hwarc_neep_cb+0x59/0x168 [hwa_rc]

Apr  7 10:44:56 magic kernel:[<ffffffff813b4ad4>] ? usb_hcd_giveback_urb+0x64/0xe0

Apr  7 10:44:56 magic kernel:[<ffffffffa0c6a26e>] ? xhci_irq+0x4be/0x17f0 [xhci_hcd]

Apr  7 10:44:56 magic kernel:[<ffffffff81082128>] ? add_timer+0x18/0x30

Apr  7 10:44:56 magic kernel:[<ffffffff810e70ea>] ? __rcu_process_callbacks+0x25a/0x350

Apr  7 10:44:56 magic kernel:[<ffffffffa0c6b5d1>] ? xhci_msi_irq+0x31/0x40 [xhci_hcd]

Apr  7 10:44:56 magic kernel:[<ffffffff810e1670>] ? handle_IRQ_event+0x60/0x170

Apr  7 10:44:56 magic kernel:[<ffffffff8107700f>] ? __do_softirq+0x11f/0x1e0

Apr  7 10:44:56 magic kernel:[<ffffffff810e3dbe>] ? handle_edge_irq+0xde/0x180

Apr  7 10:44:56 magic kernel:[<ffffffff8100de89>] ? handle_irq+0x49/0xa0

Apr  7 10:44:56 magic kernel:[<ffffffff815171bc>] ? do_IRQ+0x6c/0xf0

Apr  7 10:44:56 magic kernel: [<ffffffff8100b9d3>]? ret_from_intr+0x0/0x11

Apr  7 10:44:56 magic kernel: <EOI>

Apr  7 10:44:56 magic kernel: ---[ end trace580801de7dc9f3db ]---

Apr  7 10:44:56 magic kernel: in uwb_rsv_timer

结合Call Trace,我们上相应内核代码:

static inline void _local_bh_enable_ip(unsignedlong ip)

{

         WARN_ON_ONCE(in_irq()|| irqs_disabled());

#ifdef CONFIG_TRACE_IRQFLAGS

         local_irq_disable();

#endif

         /*

          * Are softirqs going to be turned on now:

          */

         if(softirq_count() == SOFTIRQ_DISABLE_OFFSET)

                   trace_softirqs_on(ip);

         /*

          * Keep preemption disabled until we are donewith

          * softirq processing:

         */

         sub_preempt_count(SOFTIRQ_DISABLE_OFFSET- 1);

 

         if(unlikely(!in_interrupt() && local_softirq_pending()))

                   do_softirq();

 

         dec_preempt_count();

#ifdef CONFIG_TRACE_IRQFLAGS

         local_irq_enable();

#endif

         preempt_check_resched();

}

 

warning是由WARN_ON_ONCE(in_irq()|| irqs_disabled());代码产生的

 

解决方法

解决了disconnect CallTrace

/drivers/usb/host/hwa-hc.c

static void hwahc_disconnect(structusb_interface *usb_iface)

{

       struct usb_hcd *usb_hcd;

       struct wusbhc *wusbhc;

       struct hwahc *hwahc;

 

       printk("in hwahc_disconnect\n");

 

       usb_hcd = usb_get_intfdata(usb_iface);

       wusbhc = usb_hcd_to_wusbhc(usb_hcd);

       hwahc = container_of(wusbhc, struct hwahc, wusbhc);

 

 

       wusbhc_b_destroy(&hwahc->wusbhc);

       usb_remove_hcd(usb_hcd);

       hwahc_destroy(hwahc);

       usb_put_hcd(usb_hcd);

}

 

static int hwahc_probe(struct usb_interface*usb_iface,

                       const structusb_device_id *id)

{

                   …

                   usb_hcd->wireless= 1;

       usb_hcd->irq= -1;

                  

}

 

以上解决了disconnect的问题。

2.      Memory page alloc & free

Call Trace

Jun 11 03:09:14magic kernel: [  263.849177]  [<ffffffff81137d09>] ?free_pages+0x49/0x50

Jun 11 03:09:14magic kernel: [  263.849186]  [<ffffffffa01949b2>] ? hwarc_neep_release+0x32/0x40[hwa_rc]

Jun 11 03:09:14magic kernel: [  263.849202]  [<ffffffffa0359f7b>] ? uwb_rc_rm+0x3b/0xd0 [uwb]

Jun 11 03:09:14magic kernel: [  263.849211]  [<ffffffffa01940a1>] ?hwarc_disconnect+0x41/0x70 [hwa_rc]

Jun 11 03:09:14magic kernel: [  263.849225]  [<ffffffff813d5998>] ?usb_unbind_interface+0x78/0x160

Jun 11 03:09:14magic kernel: [  263.849235]  [<ffffffff8137407f>] ?__device_release_driver+0x6f/0xe0

Jun 11 03:09:14magic kernel: [  263.849241]  [<ffffffff813741ed>] ?device_release_driver+0x2d/0x40

Jun 11 03:09:14magic kernel: [  263.849248]  [<ffffffff813730f3>] ?bus_remove_device+0xa3/0x110

Jun 11 03:09:14magic kernel: [  263.849258]  [<ffffffff81370b2d>] ?device_del+0x12d/0x1e0

Jun 11 03:09:14magic kernel: [  263.849266]  [<ffffffff813d1c50>] ?usb_disable_device+0xb0/0x2b0

Jun 11 03:09:14magic kernel: [  263.849273]  [<ffffffff813ca862>] ?usb_disconnect+0xa2/0x1c0

Jun 11 03:09:14magic kernel: [  263.849280]  [<ffffffff813cc6fe>] ?hub_thread+0x75e/0x1820

Jun 11 03:09:14magic kernel: [  263.849291]  [<ffffffff8100969d>] ?__switch_to+0x7d/0x340

Jun 11 03:09:14magic kernel: [  263.849304]  [<ffffffff810a1460>] ?autoremove_wake_function+0x0/0x40

Jun 11 03:09:14magic kernel: [  263.849311]  [<ffffffff813cbfa0>] ?hub_thread+0x0/0x1820

Jun 11 03:09:14magic kernel: [  263.849320]  [<ffffffff810a0fce>] ?kthread+0x9e/0xc0

Jun 11 03:09:14magic kernel: [  263.849327]  [<ffffffff8100c28a>] ?child_rip+0xa/0x20

Jun 11 03:09:14 magickernel: [  263.849336]  [<ffffffff810a0f30>] ? kthread+0x0/0xc0

Jun 11 03:09:14magic kernel: [  263.849341]  [<ffffffff8100c280>] ?child_rip+0x0/0x20

Jun 11 03:09:14magic kernel: [  263.849345] Disablinglock debugging due to kernel taint

 

/drivers/uwb /hwa-rc.c

staticvoid hwarc_neep_release(struct uwb_rc *rc)

{

        struct hwarc *hwarc = rc->priv;

 

        usb_kill_urb(hwarc->neep_urb);

        usb_free_urb(hwarc->neep_urb);

        printk("%srd_buffer=%p\n",__func__, hwarc->rd_buffer);

        if (hwarc->rd_buffer != NULL){

                printk("%srd_buffer=%p\n",__func__, hwarc->rd_buffer);

                free_page((unsigned long)hwarc->rd_buffer);

                hwarc->rd_buffer = NULL;

        }

}

 

 

staticint hwarc_post_reset(struct usb_interface *iface)

{

        struct hwarc *hwarc = NULL;

        ssleep(1);

        hwarc = usb_get_intfdata(iface);

        if(hwarc == NULL){

                printk("hwarc_post_reset:ERROR hwarc is NULL in hwarc_post_reset\n");

                return 0;

        }

        struct uwb_rc *uwb_rc =hwarc->uwb_rc;

 

        return uwb_rc_post_reset(uwb_rc);

}

以上解决了内核Page free的问题。

 

3.      Kernellock

Call Trace

About the Spin lock. Kernel lock:mutex_lock  semaphore_lock  spin_lock atomic_lock

/drivers/uwb/drp.c  +913

static voiduwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,

                                    structuwb_rceb *reply, ssize_t reply_size)

{

        struct uwb_rc_evt_set_drp_ie *r =(struct uwb_rc_evt_set_drp_ie *)reply;

        unsigned long flags;

        printk("inuwb_rc_set_drp_cmd_done!!!!!!!!\n");

 

        if (r != NULL) {

                if (r->bResultCode !=UWB_RC_RES_SUCCESS)

                       dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s(%d)\n",

                                uwb_rc_strerror(r->bResultCode),r->bResultCode);

        } else

               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");

 

        //spin_lock_bh(&rc->rsvs_lock);

       spin_lock_irqsave(&rc->rsvs_lock, flags);

        if (rc->set_drp_ie_pending > 1) {

                rc->set_drp_ie_pending = 0;

                uwb_rsv_queue_update(rc);

        } else {

                rc->set_drp_ie_pending = 0;

        }

        spin_unlock_irqrestore(&rc->rsvs_lock, flags);

        //spin_unlock_bh(&rc->rsvs_lock);

}

 

以上解决了内核锁嵌套问题!

<think> 我们面对的是一个Linux内核崩溃的报错日志。用户的问题核心在于:根据提供的报错信息,判断问题最先产生的位置是RIP、CR2还是Call Trace。 分析步骤: 1. **理解三个关键概念**: - **RIP (Instruction Pointer Register)**:64位系统中的指令指针寄存器(32位为EIP),存放着下一条即将执行的指令的地址。当发生异常时,RIP指向触发异常的指令地址。 - **CR2 (Control Register 2)**:存储引发缺页异常(Page Fault)的线性地址(虚拟地址)。只有当异常是缺页异常时,CR2才有效。 - **Call Trace**:函数调用堆栈,展示了从异常发生点开始回溯的函数调用链。最内层(栈顶)的函数是直接触发异常的函数。 2. **报错信息关键部分提取**: - Call Trace部分展示了函数调用栈。 - 日志中出现了CR2的值:`CR2: 000000000000000e`(两处重复) - RIP的值:`RIP: 0010:tcp_v4_rcy+0x786/0x1380` - 最后一行日志:`Code: ...` 显示了崩溃点附近的机器码。 3. **问题产生的顺序**: 内核崩溃通常由CPU异常触发(例如缺页、非法指令等)。当CPU执行到一条非法指令时(比如访问无效内存地址),会触发异常。此时: - CPU会首先将导致异常的指令地址存入RIP(实际上,异常发生时RIP指向的是触发异常的指令)。 - 如果异常是缺页(Page Fault),则导致缺页的线性地址会被存入CR2寄存器。 - 然后,CPU会切换到内核异常处理流程,内核会记录下当前的调用栈(Call Trace)。 因此,从时间顺序上: - **最先产生**的是触发异常的指令(由RIP指向)。 - 如果是缺页异常,紧接着会设置CR2(存储触发缺页的地址)。 - 然后内核异常处理程序收集调用栈(Call Trace)信息。 4. **当前报错信息分析**: - **CR2值为0xe**(即十进制的14),这是一个非常小的地址,通常属于内核空间的最低地址范围。这样的地址通常无效(因为内核不会映射这么低的地址给用户空间,而内核自身使用也很少会用到这么低的地址),所以很可能是空指针解引用或者指针计算错误。 - **RIP指向的指令**:`tcp_v4_rcy`函数内部的偏移`0x786`处。这个函数是TCPv4协议接收数据包的处理函数之一。 - **Call Trace**:从下往上看(因为堆栈是从高地址向低地址增长,打印时通常从内层函数开始),最内层(最后调用)的函数是`tcp_v4_rcy`,说明异常发生在这个函数内部。 5. **结论**: - 问题最先产生的位置是**RIP指向的指令**(即`tcp_v4_rcy+0x786`这条指令)。因为CPU执行这条指令时触发异常(很可能是缺页异常,因为CR2有值)。 - 同时,CR2的值(0xe)告诉我们,这条指令试图访问一个无效的虚拟地址(0xe),这导致了缺页异常。 - Call Trace是异常发生后记录的函数调用链,用于回溯代码路径,但它本身并不是问题最初触发点。 因此,回答用户:问题最先产生的位置是RIP指向的指令(即`tcp_v4_rcy+0x786`),该指令试图访问一个无效的内存地址(CR2: 0xe),导致缺页异常。 补充说明: - 根据引用[1],Call Trace中的函数地址格式为`函数名+偏移量/函数长度`。这里RIP的格式也是类似的。 - 根据引用[2],CR2记录了缺页异常的线性地址,这里为0xe,是一个很小的地址,通常意味着空指针引用或指针计算错误。 建议的排查方向: - 检查`tcp_v4_rcy`函数中偏移0x786处的代码,查看其访问内存的指令(例如,是不是访问了某个结构体成员,而该结构体指针为空或者无效)。 - 结合内核源码版本,定位到具体代码行。 生成的相关问题: §§相关问题§§ 1. 如何通过RIP值定位内核崩溃的具体代码行? 2. Linux内核中CR2值为0xe通常意味着什么类型的错误? 3. 在Linux内核调试中,如何分析Call Trace信息? 4. 如何根据内核崩溃日志分析TCP/IP协议栈的问题? 5. 如何避免内核中出现空指针解引用? </think> ### 问题最先产生位置的判断分析 通过分析给定的内核报错信息,问题的源头产生顺序和定位依据如下: #### 1. **问题产生的逻辑顺序** 在 Linux 内核崩溃时,硬件和内核协同记录信息的顺序为: 1. **CPU 执行到错误指令** → 2. **RIP 记录错误指令地址** → 3. **CR2 捕获内存地址** → 4. **内核生成 Call Trace** 因此,**RIP 指向的位置是问题最先产生的位置**,因为它记录了触发异常的指令地址[^1][^2]。 #### 2. **关键证据分析** 在报错信息中: ```log 3733.469332] RIP: 0010:tcp_v4_rcy+0x786/0x1380 ``` - `tcp_v4_rcy`:出错的函数(TCPv4 接收处理) - `0x786`:函数内出错指令的偏移量 - `0x1380`:该函数的总长度 这明确指出了 CPU 执行到 `tcp_v4_rcy` 函数内偏移 0x786 处的指令时触发了异常[^1]。 #### 3. **CR2 的作用** ```log 3733.461868] CR2: 000000000000000e ``` - CR2 存储了触发缺页异常的**虚拟内存地址**(此处为 0x0e) - 这表明 RIP 指向的指令试图访问无效地址 0x0e(可能是空指针解引用) - 但 CR2 **不是问题起点**,而是 RIP 指令操作引发的后果[^2][^3]。 #### 4. **Call Trace 的作用** Call Trace 显示了函数调用栈: ```log 3733.452303] Call Trace: 3733.452309] <TASK> 3733.452327] ip_protocol_deliver_rcu+0x3c/0x290 ... 3733.452971] __napi_poll+0x33/0x1a0 3733.454806] ret_from_fork+0x22/0x30 ``` - 从下往上读:`ret_from_fork` → `__napi_poll` → ... → `tcp_v4_rcy` - 这是异常发生后内核记录的**调用路径回溯**,用于定位代码调用链,并非问题起点[^1]。 #### 5. **结论:问题根源定位** 1. **最先触发点**:`RIP: tcp_v4_rcy+0x786` (CPU 执行该指令时崩溃) 2. **直接原因**:该指令访问了无效地址 `CR2: 0x0e` (空指针或已释放内存) 3. **调用路径**:通过 Call Trace 回溯到网络包接收路径 (从 `ret_from_fork` → 网络中断处理 → TCP 接收) ### 排查建议 1. **源码定位**: ```bash addr2line -e vmlinux tcp_v4_rcy+0x786 ``` 定位到内核源码中具体出错的行[^1]。 2. **重点检查**: - TCP 接收路径中对指针的校验(特别是 skb 或 socket 结构) - 内存释放后仍被访问的可能性(use-after-free) - 驱动 `e1000` 的 DMA 操作是否越界(Call Trace 中可见) 3. **辅助验证**: - 检查内核配置 `CONFIG_DEBUG_KERNEL` 是否启用 - 使用 `kprobe` 在 `tcp_v4_rcy+0x786` 设断点捕获现场 > **根本原因推测**:TCP 接收路径中未校验指针直接访问内存地址 0x0e,可能是网络包解析时未处理畸形数据包或内存释放时序错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值