Chinaunix首页 | 论坛 | 博客
  • 博客访问: 732684
  • 博文数量: 79
  • 博客积分: 2671
  • 博客等级: 少校
  • 技术积分: 1247
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-02 15:26
个人简介

宅男

文章分类

全部博文(79)

文章存档

2017年(11)

2016年(12)

2015年(6)

2012年(10)

2011年(33)

2010年(7)

分类: Android平台

2016-05-05 19:36:59

上次写了一篇《ftrace function_graph分析》,是为了解决一个bug,所以在不停的撸代码。
最近这个bug终于有了头绪了。
这个bug的现象是在打开ftrace function graph之后,设备老是crash掉。

35.509913: <6> Unable to handle kernel NULL pointer dereference at virtual address 00000071
  1.     35.517215: <6> pgd = ffffffc00007d000
  2.     35.520602: <2> [00000071] *pgd=000000008dd0b003, *pmd=000000008dd0c003, *pte=00e000000b000407
  3. 35.528880: <6> Internal error: Oops: 96000006 [#1] PREEMPT SMP
  4. 36.645457: <2> scm_call 33554690 ffffffc074017bf0 //address of desc
  5.     36.650038: <2> Modules linked in: qdrbg_module(O) qcrypto_module(O)
  6.     36.650073: <6> CPU: 2 PID: 0 Comm: swapper/2 Tainted: G W O 3.10.73-g356530d-05963-ga8723d9-dirty #13
  7.     36.650101: <6> task: ffffffc00ddfb000 ti: ffffffc07400c000 task.ti: ffffffc07400c000
  8.     36.650147: <2> PC is at scm_call2_atomic+0x190/0x1bc
  9.     36.650180: <2> LR is at scm_call2_atomic+0x118/0x1bc
  10.     36.650204: <2> pc : [<ffffffc0003e1904>] lr : [<ffffffc0003e188c>] pstate: 200001c5
  11.     36.650223: <2> sp : ffffffc07400fd90
  12.     36.650282: <2> x29: ffffffc07400fd90 x28: ffffffc000c1f350
  13.     36.650340: <2> x27: ffffffc003e65658 x26: 0000000000000040
  14.     36.650398: <2> x25: ffffffc001588000 x24: ffffffc0016376d0
  15.     36.650455: <2> x23: 0000000000000002 x22: 0000000000000001
  16.     36.650512: <2> x21: ffffffc00149d000 x20: 0000000000000000
  17.     36.650570: <2> x19: 0000000000000001 x18: 0000000000000000
  18.     36.650627: <2> x17: 0000000000000000 x16: 0000000000000000
  19.     36.650684: <2> x15: 0000000000000000 x14: 0000000000000000
  20.     36.650741: <2> x13: 0000000000000000 x12: 0000000004c5d83d
  21.     36.650797: <2> x11: 0000000000000001 x10: 0000000000000000
  22.     36.650856: <2> x9 : ffffffc000084000 x8 : 00000032b5193519
  23.     36.650914: <2> x7 : 000000008007d000 x6 : ffffffc0016640e8
  24.     36.650971: <2> x5 : ffffffc0013c3b40 x4 : ffffffc07400c000
  25.     36.651028: <2> x3 : 0000000075ad7000 x2 : ffffffc076e7c218
  26.     36.651086: <2> x1 : 0000000000000000 x0 : 0000000000000000

  27.     36.656822: <2> Call trace:
  28.     36.656859: <2> [<ffffffc0003e1904>] scm_call2_atomic+0x190/0x1bc
  29.     36.656895: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  30.     36.656928: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  31.    36.656960: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  32.     36.656993: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  33.     36.657026: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  34.     36.657059: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  35.     36.657090: <2> [<ffffffc00008f1ac>] ftrace_graph_caller+0x2c/0x30
  36. 36.657131: <2> [<ffffffc000c0a0f8>] secondary_start_kernel+0x108/0x118
从这个stack dump上看不出太多的信息,每次调用scm call进入PC 的时候,总是crash掉。scm_call2_atomic返回的时候,一个保存在栈中的参数X19被破坏掉了。之前花了一个多月的时候来分析这个问题,但是没什么太大的进展。在搞清楚设备的suspend/resume过程后,尝试给cpu_suspend的子函数全部使用notrace关键字,居然解决掉这个问题。但是一直没有找到这个问题的root cause。
由于这个stack dump中一直出现scm_call2_atomic函数,把我误导了(在此省略一个月的无效调试),一直以为这个问题是出现在scm call进入power collapse失败的时候。最终发现不是,居然是power collapse成功从cpu_resume返回的时候出问题。
还用从ftrace function graph的设计原理来细说。 通过分析代码,发现cpu_suspend调用的很多子函数中都有notrace关键字,为什么要添加这样的关键字呢?
答案就是__cpu_suspend_enter的子函数不允许function graph!

当一个CPU要进入power collapse进入低功耗的时候,
__cpu_suspend
       ->__cpu_suspend_enter
            -> 
                ->scm_call2_atomic
                    ->__scm_call_armv8_32 ---- power collapse 掉电  (PSCI的情况类似)

cpu_resume
        .......
       ->__cpu_suspend中__cpu_suspend_enter函数的下一条指令 (在此省略讲解suspend中如何保持CPU的context,resume的时候如何恢复CPU context 的相关代码
           ->cpus_suspend
每次调用一个非notrace的函数时,ftrace_caller会修改子函数的stack中的LR,将原来的LR保存在task_struct->ret_stack和task_struct->current_ret_stack.

那么如果CPU成功进入power collapse并从cpu_resume返回时,执行完
__cpu_suspend(注意__cpu_suspend本身是打开了ftrace function
graph)的,它的LR已经被修改了,所以__cpu_suspend函数执行完毕返回时,需要从task_struct中去获得
LR。
那么问题来了?如果__cpu_suspend_enter的子函数开启了ftrace function grpah,那么其子函数同样会保持LR到ret_stack数组中,并递加curr_ret_stack.
那么从cpu_resume返回时,
__cpu_suspend执行完毕时,curr_ret_stack被子函数递加过,无法正常返回了。

这就是为什么我们会从上面看到奇怪的stack dump了,scm_call2_atomic完全是误导,因为scm_call2_atomic是一个非notrace的函数。所以cpu_resume返回时,
就获得了从task_struct中获取到了错误的LR。所以__cpu_suspend返回时跳转到了这个错误的LR。

这个问题在ARM PSCI driver同样存在。虽然可以通过在__cpu_suspend_enter的前后加入pause_graph_tracing/unpause_graph_tracing来解决这个问题。
但是我觉得这个问题的根据解决还是通过加notrace。这一点从cpu_suspend的相关代码中可以明显看出痕迹。代码提交者就考虑到了这个问题,所以很多地方用了notrace关键词。
但是PSCI是后来加入的代码,并没有充分考虑到这一点。

好吧,内核4.4已经解决了这个问题 

阅读(2011) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~