待机时反复按Power键概率性重启-定位问题
android@c0490:~/log/6601/20151218-KE$ arm-linux-androideabi-gdb vmlinux SYS_MINI_RDUMP
GNU gdb (GDB) 7.6
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
For bug reporting instructions, please see:
<http://source.android.com/source/report-bugs.html>...
Reading symbols from /home/android/log/6601/20151218-KE/vmlinux...done.
[New LWP 100]
[New LWP 1]
[New LWP 2]
[New LWP 3]
[New LWP 4]
[New LWP 5]
[New LWP 6]
[New LWP 7]
[New LWP 8]
Core was generated by `console=tty0 console=ttyMT0,921600n1 root=/dev/ram vmalloc=496M slub_max_order='.
#0 device_prepare (dev=<optimized out>, state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1483
1483 callback = dev->bus->pm->prepare;
(gdb) list
1478 } else if (dev->class && dev->class->pm) {
1479 info = "preparing class ";
1480 callback = dev->class->pm->prepare;
1481 } else if (dev->bus && dev->bus->pm) {
1482 info = "preparing bus ";
1483 callback = dev->bus->pm->prepare;
1484 }
1485
1486 if (!callback && dev->driver && dev->driver->pm) {
1487 info = "preparing driver ";
(gdb) bt
#0 device_prepare (dev=<optimized out>, state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1483
#1 dpm_prepare (state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1520
#2 0xc0327cc8 in dpm_suspend_start (state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1556
#3 0xc0090390 in suspend_devices_and_enter (state=0) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/power/suspend.c:273
#4 0xc0090a50 in enter_state (state=3) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/power/suspend.c:426
#5 0xc0090ac0 in pm_suspend (state=0) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/power/suspend.c:464
#6 0xc0098b24 in try_to_suspend (work=<optimized out>) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/power/autosleep.c:81
#7 0xc0042b60 in process_one_work (worker=0xd79a9600, work=0xc0e056e4 <suspend_work>)at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/workqueue.c:2216
#8 0xc0043098 in worker_thread (__worker=0x0 <__vectors_start>) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/workqueue.c:2348
#9 0xc004c0bc in kthread (_create=0xdb1ffdf0) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/kernel/kthread.c:200
#10 0xc000f308 in ret_from_fork () at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/arch/arm/kernel/entry-common.S:91
#11 0xc000f308 in ret_from_fork () at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/arch/arm/kernel/entry-common.S:91
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)
从调用栈可以看到进程跑到进程在 kernel-3.10/drivers/base/power/main.c:1483 位置发生KE了,看看具体源代码 :
static int device_prepare(struct device *dev, pm_message_t state)
{int (*callback)(struct device *) = NULL;char *info = NULL;int error = 0;if (dev->power.syscore)return 0;/** If a device's parent goes into runtime suspend at the wrong time,* it won't be possible to resume the device. To prevent this we* block runtime suspend here, during the prepare phase, and allow* it again during the complete phase.*/pm_runtime_get_noresume(dev);device_lock(dev);dev->power.wakeup_path = device_may_wakeup(dev);if (dev->pm_domain) {info = "preparing power domain ";callback = dev->pm_domain->ops.prepare;} else if (dev->type && dev->type->pm) {info = "preparing type ";callback = dev->type->pm->prepare;} else if (dev->class && dev->class->pm) {info = "preparing class ";callback = dev->class->pm->prepare;} else if (dev->bus && dev->bus->pm) {info = "preparing bus ";callback = dev->bus->pm->prepare;}
(gdb) disassemble
Dump of assembler code for function dpm_prepare:
...0xc0327ba8 <+252>: mov r0, r80xc0327bac <+256>: bl 0xc0998e1c <mutex_unlock>0xc0327bb0 <+260>: b 0xc0327ad4 <dpm_prepare+40>0xc0327bb4 <+264>: ldr r3, [r4, #-128] ; 0x800xc0327bb8 <+268>: cmp r3, #00xc0327bbc <+272>: beq 0xc0327c18 <dpm_prepare+364>0xc0327bc0 <+276>: ldr r3, [r3, #20]0xc0327bc4 <+280>: cmp r3, #00xc0327bc8 <+284>: beq 0xc0327c18 <dpm_prepare+364>
=> 0xc0327bcc <+288>: ldr r9, [r3]0xc0327bd0 <+292>: cmp r9, #00xc0327bd4 <+296>: bne 0xc0327b98 <dpm_prepare+236>0xc0327bd8 <+300>: ldr r3, [r4, #-48] ; 0x300xc0327bdc <+304>: cmp r3, #00xc0327be0 <+308>: beq 0xc0327ba8 <dpm_prepare+252>0xc0327be4 <+312>: ldr r3, [r3, #52] ; 0x34
---Type <return> to continue, or q <return> to quit---q
Quit
汇编指令打印出来有点长,但我们只看关键的部分,如上的 => 提示指令:
=> 0xc0327bcc <+288>: ldr r9, [r3]
gdb 工具已标记出进程是运行到这条 ldr(Memory Access) 指令时挂了!这个时候我们需要知道此刻的各个寄存器内容才能判断分析KE的原因:
(gdb) info reg
r0 0x0 0
r1 0x0 0
r2 0x0 0
r3 0x6b6b6b6b 1802201963
r4 0xd90680b0 3641082032
r5 0xd9068000 3641081856
r6 0xc0e1c280 3236020864
r7 0xc0e1c2e0 3236020960
r8 0xd9068034 3641081908
r9 0x0 0
r10 0xc0f07f3c 3236986684
r11 0xd7b83d1c 3619175708
r12 0xd7b83c88 3619175560
sp 0xd7b83cf0 0xd7b83cf0
lr 0xc099767c 3231282812
pc 0xc0327bcc 0xc0327bcc <dpm_prepare+288>
cpsr 0x200e0013 537788435
(gdb)
从当前寄存器值可以看出,r3 的 值是 0x6b6b6b6b ==> 非kernel虚拟内存范围(从 0xc0008000 开始),执行 Memroy access 操作会导致MMU报 page translation fault(缺页异常),MMU首先会自己尝试处理缺页异常,通常是试图从Low level的memroy(如disk)中重新 load 数据进来,然后再次执行 TTW (Translation table walk) 地址转换,最后发现处理不了就只能执行 __die() ==> panic ==> 发生Kernel exception,所以此题死机重启的原因就是 野指针 导致!
1481 } else if (dev->bus && dev->bus->pm) {0xc0327c30 <+388>: ldr r3, [r4, #-52] ; 0x340xc0327c34 <+392>: cmp r3, #00xc0327c38 <+396>: beq 0xc0327bd8 <dpm_prepare+300>0xc0327c3c <+400>: ldr r3, [r3, #52] ; 0x340xc0327c40 <+404>: cmp r3, #00xc0327c44 <+408>: bne 0xc0327bcc <dpm_prepare+288>0xc0327c48 <+412>: b 0xc0327bd8 <dpm_prepare+300>1482 info = "preparing bus ";
1483 callback = dev->bus->pm->prepare;
=> 0xc0327bcc <+288>: ldr r9, [r3]
上面两句ldr指令加上下面的cmp指令,很明显就是代表上面 if(dev->bus && dev->bus->pm) 的描述,所以这里就可以判断出:
dev->bus ==> r4 - #52 == 0xd906807c
dev->bus->pm ==> r4 == 0xd90680b0
(gdb) p dev
$2 = (struct device *) 0xd9068000
(gdb) p &dev->bus
$3 = (struct bus_type **) 0xd906807c
(gdb) p &dev->bus->pm
$4 = (const struct dev_pm_ops **) 0x34
(gdb) f 0
#0 device_prepare (dev=<optimized out>, state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1483
1483 callback = dev->bus->pm->prepare;
(gdb) p dev
$1 = <optimized out>
(gdb) f 1
#1 dpm_prepare (state=...) at /home/android/work/prj/6601-32bit-kernel/baseline/kernel-3.10/drivers/base/power/main.c:1520
1520 error = device_prepare(dev, state);
(gdb) list
1515 struct device *dev = to_device(dpm_list.next);
1516
1517 get_device(dev);
1518 mutex_unlock(&dpm_list_mtx);
1519
1520 error = device_prepare(dev, state);
1521
1522 mutex_lock(&dpm_list_mtx);
1523 if (error) {
1524 if (error == -EAGAIN) {
(gdb) p dev
$2 = (struct device *) 0xd9068000
(gdb) p &dev->bus
$3 = (struct bus_type **) 0xd906807c
(gdb) p &dev->bus->pm
$4 = (const struct dev_pm_ops **) 0x34
(gdb) p dpm_list
$5 = {next = 0xd90680b0, prev = 0xdb1df5b0}
int dpm_prepare(pm_message_t state)
{int error = 0;might_sleep();mutex_lock(&dpm_list_mtx);while (!list_empty(&dpm_list)) {struct device *dev = to_device(dpm_list.next);get_device(dev);mutex_unlock(&dpm_list_mtx);error = device_prepare(dev, state);mutex_lock(&dpm_list_mtx);if (error) {if (error == -EAGAIN) {put_device(dev);error = 0;continue;}printk(KERN_INFO "PM: Device %s not prepared ""for power transition: code %d\n",dev_name(dev), error);put_device(dev);break;}dev->power.is_prepared = true;if (!list_empty(&dev->power.entry))list_move_tail(&dev->power.entry, &dpm_prepared_list);put_device(dev);}mutex_unlock(&dpm_list_mtx);return error;
}
从上面代码可知:dev是从dmp_list得来的,继续追踪代码可以追踪发现其实是在开机的时候从 device_pm_add 函数加载的:
/*** device_pm_add - Add a device to the PM core's list of active devices.* @dev: Device to add to the list.*/
void device_pm_add(struct device *dev)
{pr_debug("PM: Adding info for %s:%s\n",dev->bus ? dev->bus->name : "No Bus", dev_name(dev));mutex_lock(&dpm_list_mtx);if (dev->parent && dev->parent->power.is_prepared)dev_warn(dev, "parent %s should not be sleeping\n",dev_name(dev->parent));list_add_tail(&dev->power.entry, &dpm_list);mutex_unlock(&dpm_list_mtx);
}
上面代码中,dev->power.entry的地址作为成员添加到dmp_list中,猜想&dev->power.entry 其实和 &dev->bus->pm 是同一个东西,dmp_list就是以各个dev的bus->pm成员的链表。既然dev是从这里加载来的,那么就可以在这里加打印,抓开机log抓出导致KE的真凶!
void device_pm_add(struct device *dev)
{pr_debug("PM: Adding info for %s:%s\n",dev->bus ? dev->bus->name : "No Bus", dev_name(dev));pr_debug("[KE],[%s],[0x%lx],[0x%lx],[0x%lx],[0x%lx],[%s]\n",__func__, (long)dev, (long)&dev->bus,(long)&dev->bus->pm, (long)&dev->power.entry,dev_name(dev));</span>mutex_lock(&dpm_list_mtx);if (dev->parent && dev->parent->power.is_prepared)dev_warn(dev, "parent %s should not be sleeping\n",dev_name(dev->parent));list_add_tail(&dev->power.entry, &dpm_list);mutex_unlock(&dpm_list_mtx);
}
编译kernel、烧机、抓开机log :
[ 21.491480]<2>.(2)[1:swapper/0]PM: Adding info for No Bus:silead_fp_dev
[ 21.492349]<2>.(2)[1:swapper/0][KE],[device_pm_add],[0xd9068000],[0xd906807c],[0x34],[0xd90680b0],[silead_fp_dev]
看到这个结果,心情马上就好了^_^ ! 因为造成死机重启的真凶露面了!------>>>> silead_fp_dev
void device_pm_add(struct device *dev)
{pr_debug("PM: Adding info for %s:%s\n",dev->bus ? dev->bus->name : "No Bus", dev_name(dev));pr_debug("[KE],[%s],[0x%lx],[0x%lx],[0x%lx],[0x%lx],[%s]\n",__func__, (long)dev, (long)&dev->bus,(long)&dev->bus->pm, (long)&dev->power.entry,dev_name(dev));if(strcmp(dev_name(dev), "silead_fp_dev") == 0) {pr_debug("[KE]:[0x%lx]\n",(long)dev);dump_stack(); }mutex_lock(&dpm_list_mtx);if (dev->parent && dev->parent->power.is_prepared)dev_warn(dev, "parent %s should not be sleeping\n",dev_name(dev->parent));list_add_tail(&dev->power.entry, &dpm_list);mutex_unlock(&dpm_list_mtx);
}
编译kernel、烧机、抓开机log :
[ 21.493949]<2>.(2)[1:swapper/0][KE]:[0xd9068000]
[ 21.494539]Backtrace:
[ 21.494883]<2>.(2)[1:swapper/0][<c0013a48>] (dump_backtrace+0x0/0x110) from [<c0984660>] (dump_stack+0x18/0x1c)
[ 21.496161] r6:d9068000 r5:d90680b0 r4:d9068000 r3:dbc3d000
[ 21.496891]<2>.(2)[1:swapper/0][<c0984648>] (dump_stack+0x0/0x1c) from [<c032713c>] (device_pm_add+0x118/0x120)
[ 21.498191]<2>.(2)[1:swapper/0][<c0327024>] (device_pm_add+0x0/0x120) from [<c031c958>] (device_add+0x4e0/0x5d0)
[ 21.499470] r5:c0df60c8 r4:d9068008
[ 21.499945]<2>.(2)[1:swapper/0][<c031c478>] (device_add+0x0/0x5d0) from [<c031d278>] (device_create_vargs+0xa8/0xc0)
[ 21.501304]<2>.(2)[1:swapper/0][<c031d1d0>] (device_create_vargs+0x0/0xc0) from [<c031d2b8>] (device_create+0x28/0x30)
[ 21.502648] r9:00000000 r8:c14698c0 r7:dbcd72a8 r6:c165b144 r5:d9046a00
r4:dbcd7280
[ 21.503754]<2>.(2)[1:swapper/0][<c031d290>] (device_create+0x0/0x30) from [<c0678bb0>] (spidev_probe+0x2fc/0x528)
[ 21.505076]<2>.(2)[1:swapper/0][<c06788b4>] (spidev_probe+0x0/0x528) from [<c06954f0>] (spi_drv_probe+0x20/0x24)
[ 21.505076]<2>.(2)[1:swapper/0][<c06788b4>] (spidev_probe+0x0/0x528) from [<c06954f0>] (spi_drv_probe+0x20/0x24)
结合addr2Line工具可以解析出backtrace对于的函数所在文件行号,然后直接去源代码搜索相关函数就可以了.
待机时反复按Power键概率性重启-定位问题相关推荐
- ios html 全选文本框,【前端】IOS input输入框按删除键删除字符,删除最后一个字符时,概率性出现光标前面多余一个字符...
IOS input输入框按删除键删除字符,删除最后一个字符时,概率性出现光标前面多余一个字符,并且placeholder文字也能显示出来 回答 删除最后一个字符时延迟一毫秒 我用了vue,input[ ...
- mt6735 [Audio Common]通话时,概率性出现听筒或喇叭无声问题,如何debug
[DESCRIPTION] 在MT6595之后平台通话时,概率性出现听筒或喇叭无声问题,如何debug~ [SOLUTION] 1. 先抓复现问题的VM LOG,这样就可以定位问题是网络端还是语音算法 ...
- 锁屏时按power键不弹出关机界面
前几天有个国外项目,有个需求是锁屏时按power键不能弹出关机界面. 之前没人改过这个,网上查也没有类似案例,然后只能一步一步跟代码了. 查阅相关的文章和翻代码,发现关机流程在PhoneWindowM ...
- 如何分析按power键熄屏时屏幕又被唤醒了
如何分析按power键熄屏时屏幕又被唤醒了 具体参考以下分析 从log看,唤醒源为keyguard的fingerprint wakeup : 01-01 09:03:20.564 1622 3341 ...
- 增加按键功能(Camera按键)。确认OK键和挂断ENDCALL能在工模按键测试时正常使用。挂断键日常是电源键,监听power键
配好键值后在override/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java ...
- Camera 驱动 读取摄像头ID失败问题、低温下Camera打开花屏或者读不到id、概率性读取不到id
底层驱动读不到摄像头的ID,可以从以下几个方面做检查 首先检查硬件方面,多拿几个摄像头模组来做试验.因为会存在打样模组有问题的情况,在原理图上对清摄像头的各个脚是否都对应上了.模组是否都扣好等.这个是 ...
- 使Android Home键,Power键等按钮失效
通常情况下,用户按Home键,Power键,Search 键,会退出当前应用的运行,这对于某些情况会造成问题,这个手机端程序需要一旦运行后,只有管理员或是用户登出时,才可以主动退出运行,其它情况不能退 ...
- DTI预处理及概率性纤维束追踪
一.什么是DTI? 弥散张量成像(DTI)是在弥散加权成像(DWI)基础上发展而来的一种新的磁共振成像技术,它主要利用大脑中水分子弥散信息来成像.弥散张量成像(DTI)是在弥散加权成像基础上发展而来的 ...
- Android 5.1 长按power键流程分析
安全模式简述 android平台,在长按power / menu键时会快速进入一个模式选择,部分定制的平台是直接进入安装模式,也可以定制成公司需要的一些特定功能模式,比如报警 ... power 也属 ...
最新文章
- Mac安装Dart的SDK
- 七牛大数据平台的演进与大数据分析实践--转
- Understanding G1 GC Logs--转载
- 【实用】SAP修改记录表开发
- SAP配置webdynpro完全手册 .
- Java中的HashMap和HashTable到底哪不同?(原文参考来自码农网)
- php 判断3个数谁最小,Python编程学习之如何判断3个数的大小
- jzoj4598. 【NOIP2016模拟7.9】准备食物
- python脚本监控mysql数据库_Python脚本监控mysql数据库,Python脚本监控mongo数据库
- linux 按列提取文件名,Linux展示按文件名降序文件
- presentViewController:navigationController animated:YES completion:^(void)
- linux 查看网口实时流速_Linux查看实时带宽流量情况
- springboot整合高德地图获取经纬度和地址
- 一年级下册计算机教学计划,一年级科学下册教学计划
- XSS篇——javascript:伪协议
- 芭比波朗品牌的男性市场
- 第六十七章 方法关键字 - Language
- Problem T 分数拆分问题(第四讲)
- git describe 生成版本号
- 《程序员升职记》2.繁忙的收发室
热门文章
- 车载以太网 > 百兆100BaseT1转TX盒子拆解(包含3类产品)
- 大麦路由器dw22d不拆机刷breed和openwrt
- 产品必备技能(十一):如何写产品分析报告?附实产品分析报告实例(闲鱼)
- golang中定时器ticker
- (附源码)springboot公选课在线选课系统 毕业设计 142011
- 惠普暗影精灵6安装Ubuntu双系统显卡及Wi-Fi问题解决
- 解决Android 8.1 获取不到wifi名称
- 编写一个简单Java程序,计算银行年存款的本息
- Beaver's Calculator(蓝桥杯 算法训练)sort排序
- 隐藏17年的Firefox文件窃取漏洞,可结合WhatsApp钓鱼窃取文件