MIPS汇编及KDB入门 czk.

Slides:



Advertisements
Similar presentations
因数与倍数 2 、 5 的倍数的特征
Advertisements

3 的倍数的特征 的倍数有 : 。 5 的倍数有 : 。 既是 2 的倍数又是 5 的倍数有 : 。 12 , 18 , 20 , 48 , 60 , 72 , , 25 , 60 ,
2 、 5 的倍数的特征. 目标 重点 难点 关键词 2 、 5 的倍数的特征 1 、发现 2 和 5 的倍数的特征。 2 、知道什么是奇数和偶数。 能判断一个数是不是 2 或 5 的倍数。 能判断一个数是奇数还是偶数。 奇数、偶数。 返回返回 目录目录 前进前进.
重庆市九龙坡区走马小学 邓华. 一、复习导入,揭示课题 下面哪些数是 2 的倍数?哪些数是 5 的倍数? 2,5的倍数的特征:只看个位上数就能进行判断。 2的倍数:个位上是0,2,4,6,8的数。
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
了解太平天国运动的主要史实,认识农民起义在民主革命时期的作用与局限性。
第二章 指令系统.
B F C D G E B E A 下图是沿20°经线所作的地形剖面示意图
Oracle数据库 Oracle 子程序.
大连理工大学软件学院 软件工程系 赖晓晨 计算机组成与结构 大连理工大学软件学院 软件工程系 赖晓晨
第三节 格林公式及其应用(2) 一、曲线积分与路径无关的定义 二、曲线积分与路径无关的条件 三、二元函数的全微分的求积 四、小结.
在PHP和MYSQL中实现完美的中文显示
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
MIPS 体系结构介绍 张福新.
第2章 计算机指令集结构 曲冠南
走进编程 程序的顺序结构(二).
辅导课程六.
DM81X 视频采集处理 ——简单采集显示例程讲解 广州创龙电子科技有限公司
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
I2C驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
按键驱动 广州创龙电子科技有限公司 Guangzhou Tronlong Electronic Technology Co., Ltd.
第二章 Java语言基础.
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
动态规划(Dynamic Programming)
CPU结构和功能.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
练习: 由三个不同的英文字母和三个不同的阿拉伯数字组成一个六位号码(每位不能重复),并且3个英文字母必须合成一组出现,3个阿拉伯数字必须合成一组出现,一共有多少种方法?
Instructions: Language of the Machine
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
第二章 登录UNIX操作系统.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
第四章 MCS-51定时器/计数器 一、定时器结构 1.定时器结构框图
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
第二章 Java基本语法 讲师:复凡.
VB与Access数据库的连接.
微机原理与接口技术 微机原理与接口技术 朱华贵 2015年11月13日.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Web安全基础教程
第4章 Excel电子表格制作软件 4.4 函数(一).
本节内容 内存复制指令 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第九节 赋值运算符和赋值表达式.
3.16 枚举算法及其程序实现 ——数组的作用.
《手把手教你学STM32-STemWin》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 线性地址的管理 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
College of Computer Science & Technology
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
学习任务三 偏导数 结合一元函数的导数学习二元函数的偏导数是非常有用的. 要求了解二元函数的偏导数的定义, 掌握二元函数偏导数的计算.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Python 环境搭建 基于Anaconda和VSCode.
3. 逻辑运算指令 A、简单逻辑操作指令 CLR A. (不影响CY、AC、 OV标志) CPL A
本节内容 通用寄存器 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
WEB程序设计技术 数据库操作.
24 or 1024? PWN Jawbone Up24 手环.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
<编程达人入门课程> 本节内容 有符号数与无符号数 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
Presentation transcript:

MIPS汇编及KDB入门 czk

目录 通用寄存器及常用CP0寄存器功能介绍 基本汇编指令 Mips汇编中的一些隐式规则 常用kdb命令 使用kdb定位问题的具体方法 杭州迪普科技有限公司

通用寄存器 汇编语言以行为单位,由指令和寄存器组成,mips汇编沿袭c语言赋值语句风格,目标寄存器在左,源操作数在右 Mips共有32个通用寄存器,其中$0,$31这两个寄存器有特殊作用,其它寄存器硬件没有做限制,理论上可以随便使用,但为了可读性和兼容性,基本上所有mips处理器都遵循下面的习惯用法,相应于习惯用法对寄存器有一套命名约定,定义在内核<regdef.h>头文件中,经过这个头文件的预处理后,反汇编后的汇编代码中寄存器就不再是$0,$1…$30,$31这些编号,而是头文件中定义的习惯命名,也叫助记符 杭州迪普科技有限公司

寄存器作用说明 <0>$ 0   : 00000000 5000dc00 00000005 8cdb388e <0>$ 4   : dfd51400 00000000 8ffb3d58 8ffb3e28 <0>$ 8   : da84f394 da84f374 ffffff00 00000000 <0>$12   : 00000000 8c4a9920 bc400000 bfc04800 <0>$16   : 00000000 0000000e 00000014 8cdb3800 <0>$20   : 00000001 00000000 00000005 00000050 <0>$24   : 00000073 dfcc0000 <0>$28   : 8ffb2000 8ffb3d48 db0589f4 dfcc0054 编号 别名 作用 $0 zero 永远返回0 $1 at (assembly temporary)保留给汇编器使用 $2-$3 v0-v1 子程序返回值 $4-$7 a0-a3 (argument)调用子程序时前4个参数 杭州迪普科技有限公司

寄存器作用说明 $8-$15 t0-t7 (temporaries)临时变量,子程序使用时不必保存原值 $16-$23 s0-s7 (stack)子程序使用时必须将原值保存在栈里,在返回调用函数时恢复原值 $24-$25 t8-t9 同t0-t7 $26-$27 k0-k1 保留给异常处理程序使用 $28 gp (global pointer) 一般用于存取static变量,因为mips汇编一条指令是4个字节,存取一个数据的偏移最大只能是2^16(前后32k),这样存取一个数据就需要两条指令,先获取地址高位,再在高位基础上加偏移,gp的作用就是对于一些静态变量,让gp指向静态数据的中间,对于前后32k的数据存取一条指令就可完成 杭州迪普科技有限公司

寄存器作用说明 $29 sp (stack pointer) 堆栈指针,用于子函数存取临时变量和返回调用函数时需要还原的s0-s7寄存器的值,通常每个函数的第一条指令都是压栈操作,即在子程序的入口将sp压至该子程序可能用到的最低点 $30 f8/s8 (frame pointer)帧指针,作用类似于sp,只在当栈底在编译时还不能确定的情况下使用 $31 ra (return address)子程序返回地址,在每个子程序的入口ra自动保存调用函数的返回地址,典型的子程序都以一条jr ra指令结尾,当该子程序又需要嵌套调用其它子程序时,必须先将ra的值压栈 a函数:… b函数:ra = … c函数:ra = … jal b jal c lw t1 vo lw t1 vo …. jr ra 杭州迪普科技有限公司

常用cpo寄存器 异常程序计数器即异常返回地址(EPC):保存异常返回点,即导致异常的指令地址,使用kdb定位问题的入口 原因寄存器(cause):记录异常类型,只有一位比较重要,最高位表示异常发生在分支延迟槽,这时真正导致异常指令应该是epc的下一条指令 状态寄存器(SR):与通常状态寄存器是只读的不同,cpo的SR是可写的,用于控制cpu的工作模式:尾端,协处理器使能,中断使能,大写端配置等 ErrorEPC寄存器:发生cache error时,异常受害指令为ErrorEPC 杭州迪普科技有限公司

基本汇编指令 加载和存储(load/store) ld,lw,lh(lhu),lb(lbu): 加载双字(double 8字节,64位系统才有),字(word),半字(half),字节(byte) lw v0,4(s0)  v0 = *(s0 +4); lhu,lbu(u:unsigned)指加载无符号数,因为mips通用寄存器都是32位的,而判断一个数的正负时,只看最高位,所以在加载半字和一个字节时需要根据加载数的最高位(lhu:bit15,lb:bit7)符号扩展或0扩展到所有高位(lbu即0扩展) li (load immediate)加载一个常数:li a0,0x1234  a0 = 0x1234 lui 上位加载一个立即数: lui a0,0x1234  a0 = 0x12340000; sd,sw,sh,sb:存储双字,字,半字,字节,存储指令不存在符号扩展的问题: sw v0,4(s0)  *(s0 +4) = v0; 杭州迪普科技有限公司

基本汇编指令 算术/逻辑运算 addu,daddu addiu,daddiu 32/64位加法(指令前缀d代表64位操作,一般只在64位系统上出现,i代表操作数有常数,后续不再列举) addu a2,a2,s5  a2 = a2+s5; subu 减法 : subu v0,a0,v0  v0 = a0-v0; and 逻辑与: and v0,a0,v0  v0 = a0&v0; or 逻辑或: or v0,a0,vo  v0 = a0|v0; xor 逻辑异或: xor v0,a0,vo  v0 = a0 ^vo; nor 逻辑取反: nor v0,a0,vo  v0 = ~(a0|v0); sll 逻辑左移(shift left logic): sll v1,v1,0x18  v1 = v1 << 0x18; srl 逻辑右移: srl v1,v1,0x18  v1 = v1 >> 0x18; sra 算术右移(shift right arithmetic) 适用于有符号数,最高位用原第 31位填充(没有算术左移) 杭州迪普科技有限公司

基本汇编指令 条件设置 slt,stlu,slti,sltiu, (set if less than) 条件满足将目标寄存器置为1 sltu v0,a0,a1  v0 = a0 < a1 ? 1:0 sle,sleu (set if less or equal) sle v0,t0,t1  v0 = to <= t1 ? 1:0 seq (set if equal) seq v0,s0,1  v0 = s0 == 1? 1:0 sgt,sgtu, sge,sgeu (set if great or equal) sgeu t0,s0,s1  t0 = s0 >=s1 ? 1:0 sne (set if not equal) sne s0,v0,v1  s0 = v0 != v1 ? 1:0 杭州迪普科技有限公司

基本汇编指令 跳转 j,jr(jump reg) 跳转,一般指函数内部,ra值不变 j label  goto label jr v0  goto vo jal,jalr 跳转到子函数,ra值自动保存为返回地址 jar lable  goto label jalr v0  goto vo beq,beqz (branch if equal zero) 比较分支跳转,用于函数内部 beq v0,v1,label  if (v0 == v1) goto label blt,bltz,ble,blez,blezl (branch if less than) bltz v0,label  if (vo < 0) goto label bne,bnez (branch if not equal) bgt,bgtz,bge,bgez (branch if great than zero) 杭州迪普科技有限公司

基本汇编指令 断点和自陷 break 断点 (直接重启)linux中宏BUG() 反汇编后即break tne 自陷 (trap if not equal)可理解为跟break一样 寄存器传送 move move a0,s0  a0 =s0 杭州迪普科技有限公司

Mips汇编中的一些隐式规则 存取全变变量或者调用子函数时总是使用两条指令 lui s4,0xdfcc /*加载地址的高位*/ addiu v0,s4,17412 /*加载低位的偏移量*/ 在kdb中输入0xdfcc0000+17142可以显示出对应的符号(全局变量或者函数名),用来快速找出汇编代码对应的c代码 分支和跳转的下一条指令先于分支和跳转指令本身执行 lui v0,0xdfc3 /*加载函数名地址高位*/ move a0,s0 /*对第一个参数赋值*/ addiu v0,v0,-17932 /*加载函数名地址低位*/ jalr v0 /*跳转到子函数*/ move a1,s1 /*对第二个参数赋值在跳转前执行*/ * bne a1,a0,0xdfc2cdac lw s0,0(s1) /*该指令先于bne执行*/ 杭州迪普科技有限公司

Mips汇编中的隐式规则 子函数的返回值约定存入v0, 赋值语句在子函数中 jalr v0 /*调用子函数*/ move a1,s1 /*参数赋值*/ beqz v0,0xdfc2ce04 /*这时v0的值已经自动改为子函数的返回值*/ 跳转进子函数时,a0-a4 是前四个参数的值,在调用函数中已经赋好,ra自动改为返回地址(隐式的),没有显式赋值语句 调用函数: 子函数: lui v0,0xcfb5 addiu sp,sp, -40 move a0,a1 sw ra,36(sp) /*ra = A,先保存*/ addiu v0,v0,24820 lui v0,0x802c jalr v0 addiu v0,v0,18544 move a1,a2 jalr v0 /*ra = B*/ A: move v0,s2 addiu a2,a2,-12 B: move a0,s0 lw ra,36(sp) jr ra /*返回A*/ 杭州迪普科技有限公司

Mips汇编中的隐式规则 计算结构体数组元素偏移时,数组元素的大小总是采用左移结合加减法完成的,因为乘除效率太低 下面是函数eth_mode_init()计算port_inf结构体大小的汇编代码:v0 = portid; sll s0,v0,0x3 /*s0 = v0 << 3 = 8v0*/ addu s0,s0,v0 /*s0 = s0+v0 = 9v0*/ sll s0,s0,0x3 /*s0 = 8s0 = 72v0*/ subu s0,s0,v0 /*s0 = s0 –v0 = 71v0*/ sll s0,s0,0x4 /*s0 = 16s0 = 1136v0*/ subu s0,s0,v0 /* s0 = s0 –v0 = 1135v0 */ sll s0,s0,0x3 /*s0 = 8s0 = 9080v0*/ 从上面可以看出,如果反汇编代码对一个变量有一连串的左移与加减运算就可猜测是在存取数组元素,有助于快速找到对应的C代码 杭州迪普科技有限公司

常用kdb命令 Kdb: (build_in kernel debugger)内核调试工具,可以查看内存内容,寄存器信息,跟踪调用栈 1> 启动设备到shell命令行输入:sysctl kernel.kdb=1 2> 键入Esc键 3> 键入大写KDB 进入kdb后输入help有帮助列表 下面是一些常用的: 命令 <参数> 功能 id <函数名/函数地址> 反汇编函数 rd <无参数> 显示32个通用寄存器当前值 rm <reg_id> <value> 修改寄存器值 md <全局变量名/地址> 内存读 杭州迪普科技有限公司

Kdb常用命令 mm <全局变量名/地址> <value> 内存写 bt <无参数> 打印当前cpu当前进程调用栈 btc <无参数> 打印所有cpu当前进程调用栈,在串口没有 响应时非常有用 cpu <cpu_id> 切换到指定cpu,每个cpu的进程,寄存 器都是 独立的,需要查看其它cpu信息的寄 存器,堆栈,或是调用栈信息时就需要该 命令切换 bp <函数名/地址> 设置断点(注意弱符号) bl <无参数> 列出当前设置的所有断点 bc <断点号> 清除指定断点,bc * :清除所有断点 bd <断点号> 无效指定断点 be <断点号> 使能指定断点 ss <无参数> 单步跟踪 杭州迪普科技有限公司

常用kdb命令 slabinfo <无参数>显示块内存使用信息,一般在内存泄露时 查看下是否因为skb没有释放造成的,正 常情况下size-2048 = 21788左右,如果达 到7,8万就说明有流程skb没有释放 go <无参数> 退出kdb 杭州迪普科技有限公司

使用kdb定位问题的具体方法 最常见的死机原因:访问空指针 oops <1>CPU 1 Unable to handle kernel paging request at virtual address 0000001c, epc == c94fed64 , ra == c94fed14 unaligned Oops[#1]: Cpu 1 $ 0 : 00000000 00000000 c94fe1ac 8f57cc38 $ 4 : c950af94 00000000 00000000 0000001e a1 $ 8 : 00000014 802c729c 8f4620c0 8f4620e0 $12 : ffffffff 4b8f2939 00000000 7fffffff $16 : 8f57cc20 80360c88 80440000 80440000 $20 : c94f362c 8162d648 00000023 80171c64 $24 : 00000000 80380000 $28 : 80490000 80491e10 00000000 c94fed14 Hi : 00000000 Lo : 00000000 epc : c94fed64 dpx_channel_cmd_init_outband+0xb4/0x18c [module_dpx_channel] Tainted: P ra : c94fed14 dpx_channel_cmd_init_outband+0x64/0x18c [module_dpx_channel] Status: 10005c03 KERNEL EXL IE Cause : 10808008 BadVA : 00000000 PrId : 000c4403 杭州迪普科技有限公司

Oops定位方法 Process insmod (pid: 134, threadinfo=80490000, task=83011000) Stack : 76657468 305f3331 00000023 80171c64 c9511c9c 80440000 c94fe188 c94fe178 c9511c9c 8162d400 80440000 80440000 80172910 8017427c c9511ca8 c950f5e4 00000000 80491f30 00000000 00000000 00000214 00000038 cfb7d80c 00000000 cfa9bf64 00000001 cffff980 c94f30b4 c94f2f6c 8162fda0 00000000 0000000f 0000000b 00000016 00000000 00000012 00000000 00000000 00000000 00000000 ... Call Trace: [<c94fed64>] dpx_channel_cmd_init_outband+0xb4/0x18c [module_dpx_channel] [<c94fe188>] init_module+0x5c/0x6c [module_dpx_channel] [<80172910>] sys_init_module+0x188/0x1d08 [<80123714>] stack_done_ra+0x0/0x1c 定位过程 1> 看下第一行,初步了解挂死的直接原因,用处不大,有个概念就行,常见的有 不能处理页请求(一般就是访问空地址),访问不对齐的地址 2> 找到正确的异常受害指令: cache error 就是error epc寄存器,其它情况都是epc,如果cause寄 存器最高位置位受害指令是epc+4,这时的epc是一条跳转指令) 反汇编异常受害指令附近代码,找到对应c代码 [0]kdb> id dpx_channel_cmd_init_outband 0xc94fecb0 dpx_channel_cmd_init_outband: addiu sp,sp,-32 0xc94fecb4 dpx_channel_cmd_init_outband+0x4: sw s1,20(sp) 0xc94fecb8 dpx_channel_cmd_init_outband+0x8: sw s0,16(sp) 杭州迪普科技有限公司

Oops定位方法 0xc94fecbc dpx_channel_cmd_init_outband+0xc: sw ra,24(sp) 0xc94fecc0 dpx_channel_cmd_init_outband+0x10: lui v0,0x8044 0xc94fecc4 dpx_channel_cmd_init_outband+0x14: lw a0,-21188(v0) 0xc94fecc8 dpx_channel_cmd_init_outband+0x18: lui v0,0x801b 0xc94feccc dpx_channel_cmd_init_outband+0x1c: addiu v0,v0,-7028 0xc94fecd0 dpx_channel_cmd_init_outband+0x20: jalr v0 0xc94fecd4 dpx_channel_cmd_init_outband+0x24: li a1,208 0xc94fecd8 dpx_channel_cmd_init_outband+0x28: move s0,v0 0xc94fecdc dpx_channel_cmd_init_outband+0x2c: move a0,v0 0xc94fece0 dpx_channel_cmd_init_outband+0x30: lui v0,0x8036 0xc94fece4 dpx_channel_cmd_init_outband+0x34: move a1,zero 0xc94fece8 dpx_channel_cmd_init_outband+0x38: li a2,84 0xc94fecec dpx_channel_cmd_init_outband+0x3c: beqz s0,0xc94fedfc dpx_channel_cmd_init_outband+0x14c [0]kdb> 0xc94fecf0 dpx_channel_cmd_init_outband+0x40: addiu s1,v0,3208 0xc94fecf4 dpx_channel_cmd_init_outband+0x44: lui v0,0x802c 0xc94fecf8 dpx_channel_cmd_init_outband+0x48: addiu v0,v0,29120 0xc94fecfc dpx_channel_cmd_init_outband+0x4c: jalr v0 0xc94fed00 dpx_channel_cmd_init_outband+0x50: nop 0xc94fed04 dpx_channel_cmd_init_outband+0x54: lui v0,0xcfc5 打印出来帮助定位 0xc94fed08 dpx_channel_cmd_init_outband+0x58: addiu v0,v0,-32696 杭州迪普科技有限公司

Oops定位方法 0xc94fed0c dpx_channel_cmd_init_outband+0x5c: jalr v0 调用dpx_channel_info_get_outband() 0xc94fed10 dpx_channel_cmd_init_outband+0x60: nop 0xc94fed14 dpx_channel_cmd_init_outband+0x64: lui v1,0xc951 0xc94fed18 dpx_channel_cmd_init_outband+0x68: sw v0,36(s0) 这时v0是函数返回值 0xc94fed1c dpx_channel_cmd_init_outband+0x6c: addiu v1,v1,-20600 0xc94fed20 dpx_channel_cmd_init_outband+0x70: move a1,s0 0xc94fed24 dpx_channel_cmd_init_outband+0x74: lbu at,0(v1) 0xc94fed28 dpx_channel_cmd_init_outband+0x78: addiu v1,v1,1 0xc94fed2c dpx_channel_cmd_init_outband+0x7c: sb at,0(a1) [0]kdb> 0xc94fed30 dpx_channel_cmd_init_outband+0x80: bnez at,0xc94fed24 dpx_channel_cmd_init_outband+0x74 0xc94fed34 dpx_channel_cmd_init_outband+0x84: addiu a1,a1,1 0xc94fed38 dpx_channel_cmd_init_outband+0x88: lui a0,0xc951 0xc94fed3c dpx_channel_cmd_init_outband+0x8c: addiu a0,a0,-20596 0xc94fed40 dpx_channel_cmd_init_outband+0x90: addiu v1,s0,16 0xc94fed44 dpx_channel_cmd_init_outband+0x94: lbu at,0(a0) 0xc94fed48 dpx_channel_cmd_init_outband+0x98: addiu a0,a0,1 0xc94fed4c dpx_channel_cmd_init_outband+0x9c: sb at,0(v1) 0xc94fed50 dpx_channel_cmd_init_outband+0xa0: bnez at,0xc94fed44 dpx_channel_cmd_init_outband+0x94 0xc94fed54 dpx_channel_cmd_init_outband+0xa4: addiu v1,v1,1 0xc94fed58 dpx_channel_cmd_init_outband+0xa8: lw a1,4(v0) 0xc94fed5c dpx_channel_cmd_init_outband+0xac: lui v0,0xc950 0xc94fed60 dpx_channel_cmd_init_outband+0xb0: addiu v0,v0,-7764 0xc94fed64 dpx_channel_cmd_init_outband+0xb4: lw v1,28(a1)  epc 0xc94fed68 dpx_channel_cmd_init_outband+0xb8: sw v0,68(s0) 0xc94fed6c dpx_channel_cmd_init_outband+0xbc: lui v0,0xc950 杭州迪普科技有限公司

Oops定位方法 3> EPC所在指令为lw v1,28(a1),查看a1的值,注意a1的值最好从挂死时打印信息来看,如果要从rd中读,先得从打印信息中获取挂死的cpu_id,然后使用kdb命令cpu <cpu_id>将当前kdb切换到死机所在cpu的kdb才能正确读取 4> 查看发现a1 = 0,挂死时打印信息中的第一行unable handle page address 0000001c就是a1+28 = 28,这时已经确认挂死是因为a1 =0,访问了空指针导致的 5> 向上追溯a1的来源,结合lui v0,0xc950,addiu v0,v0,-7764这种指令将对应符号打印出来,快速定位反汇编对应的c代码 [0]kdb> 0xc9500000-7764 0xc9500000 = 0xc94fe1ac ([module_dpx_channel]dpx_cmd_state_outband) [0]kdb> 0xcfc50000-32696 0xcfc50000 = 0xcfc48048 ([module_cpu_na]dpx_channel_info_get_outband) 根据dpx_cmd_state_outband定位c代码,可以猜测lw v1,28(a1)是pstcmd->dev_state = dpx_cmd_state_outband附近代码,查看c代码发现pstcmd->dev_state前面这 句,pstcmd->ifindex = channel_info->pstpost_info->ifindex, ifindex在port_info中的偏移 就是28,而追溯a1的来源时,找到这句lw a1,4(v0),port_info在channel_info中的 偏移又刚好是4,再向上追溯v0的来源时会发现v0就是dpx_channel_info_get_outband 的返回值,这时可以确定死机是因为从channel_info中取出的port_info指针为空 杭州迪普科技有限公司

Oops定位方法 6> 看c代码可知channel_info是全局变量g_drv_channel_info_outband指针,在kdb中读出 g_drv_channel_info_outband 的值发现port_inf确实为0 [0]kdb> md g_drv_channel_info_outband 0xcfdc0050 00000000 00000000 00000000 00000000 ................ 0xcfdc0060-0xcfdc00bf zero suppressed 0xcfdc00c0 00000000 00000000 00000000 00000000 ................ 7> 到此kdb的任务基本完成,回到c代码,追查port_info赋值的地方,很快就能找到错误的原因(后面的过程跟业务流程相关,在这里就不多说了) 快速定位反汇编对应c语句的一些技巧: 1> 在kdb中打印epc附近利用lui指令获取的符号(全局变量地址或函数名) 2> 结构体偏移,如这里的lw v1,28(a1)中的28, lw a1,4(v0)中的4,特别是比较大的偏移,如skb->data,偏移是380多,很少有结构体这么大,这样的偏移就非常有助于定位 3> mips汇编隐式规则中提到的计算数组大小的指令 杭州迪普科技有限公司

死锁问题定位方法 现象:串口不响应或者是数据面cpu不收包 分析步骤: 1> 进入kdb通过btc 查看各cpu当前在运行什么进程 btc: cpu status: Currently on cpu 0 Available cpus: 0-7 Stack traceback for pid 1121 0x8e3a8000 1121 1 1 0 R 0x8e3a81b0 *umc SP PC Function 0x8e3ff890 0x803806d4 _spin_trylock_bh+0xe0 Stack traceback for pid 0 0x84149800 0 1 1 1 R 0x841499b0 swapper 0x8416ffa0 0x80117da4 phoenix_wait+0x4 0x8416ffa0 0x8011a190 cpu_idle+0x50 Stack traceback for pid 154 0x842a9000 154 1 1 2 R 0x842a91b0 datatask_2 0x8e7a3f38 0xdfc1a448 [module_cpu_na]drv_skb_que_proc+0x9c Stack traceback for pid 155 0x8e647c00 155 1 1 3 R 0x8e647db0 datatask_3 0x8e7a5f38 0xdfc1a440 [module_cpu_na]drv_skb_que_proc+0x94 杭州迪普科技有限公司

死锁问题定位方法 2> 死锁问题的关键就是推导调用栈,只要找出是哪个函数调用的加锁函数, 问题基本就解决了 2> 死锁问题的关键就是推导调用栈,只要找出是哪个函数调用的加锁函数, 问题基本就解决了 3> rd 打印出当前进程各寄存器值,反汇编ra对应的函数 [0]kdb> rd zero = 0x00000000 at = 0x00000000 v0 = 0x00000001 v1 = 0x803801b0 a0 = 0xdfcb8aa8 a1 = 0xc0000028 a2 = 0xdfcb8a78 a3 = 0x665e5705 t0 = 0x8e3ff8a0 t1 = 0x8e3ff8a0 t2 = 0x00000000 t3 = 0x00000000 t4 = 0xdfa9df80 t5 = 0xdfa9dfa0 t6 = 0xdfa7fa68 t7 = 0x00080180 s0 = 0xdfcb8aa8 s1 = 0xc5b05118 s2 = 0xc5b05118 s3 = 0x5050c200 s4 = 0x5050c344 s5 = 0x8e3ff918 s6 = 0x00000000 s7 = 0x00000003 t8 = 0x00000000 t9 = 0xdf6b8680 k0 = 0x82e10000 k1 = 0x82e10000 gp = 0x8e3fe000 sp = 0x8e3ff890 s8 = 0xdfcc0000 ra = 0x803801c4 hi = 0x00000000 lo = 0x00000000 pc = 0x803806d4 sr = 0x10005c03 cause = 0x10808000 badva = 0x82e10000 杭州迪普科技有限公司

死锁问题定位方法 4 >将ra所在的函数反汇编找到调用_spin_trylock_bh代码,确认找到的ra是正确的 [0]kdb> id 0x803801c4 0x803801c4 _spin_lock_bh+0x14: ll v0,0(s0) 0x803801c8 _spin_lock_bh+0x18: bnez v0,0x803806d0 _spin_trylock_bh+0xdc 0x803801cc _spin_lock_bh+0x1c: li v0,1 0x803801d0 _spin_lock_bh+0x20: sc v0,0(s0) 0x803801d4 _spin_lock_bh+0x24: beqz v0,0x803806d0 _spin_trylock_bh+0xdc 0x803801d8 _spin_lock_bh+0x28: nop 0x803801dc _spin_lock_bh+0x2c: sync 0x803801e0 _spin_lock_bh+0x30: lw ra,20(sp) 0x803801e4 _spin_lock_bh+0x34: lw s0,16(sp) 0x803801e8 _spin_lock_bh+0x38: jr ra 0x803801ec _spin_lock_bh+0x3c: addiu sp,sp,24 这里要注意的是_spin_lock_bh调用__spin_trylock_bh时是直接跳转到_spin_trylock_bh+0xdc的,不是像一般的函数从__spin_trylock_bh函数第一行开始执行,也就是说__spin_trylock_bh没有执行压栈操作,当前sp值是函数_spin_lock_bh的栈 杭州迪普科技有限公司

死锁问题定位方法 5 > 反汇编_spin_lock_bh函数头部(ra赋值的地方总在函数头部),找到_spin_lock_bh函数的ra,也就是谁调用了_spin_lock_bh [0]kdb> id _spin_lock_bh 0x803801b0 _spin_lock_bh: addiu sp,sp,-24 0x803801b4 _spin_lock_bh+0x4: sw s0,16(sp) 0x803801b8 _spin_lock_bh+0x8: sw ra,20(sp) 0x803801bc _spin_lock_bh+0xc: jal 0x8014bb10 local_bh_disable 0x803801c0 _spin_lock_bh+0x10: move s0,a0 0x803801c4 _spin_lock_bh+0x14: ll v0,0(s0) 0x803801c8 _spin_lock_bh+0x18: bnez v0,0x803806d0 _spin_trylock_bh+0xdc 0x803801cc _spin_lock_bh+0x1c: li v0,1 0x803801d0 _spin_lock_bh+0x20: sc v0,0(s0) 0x803801d4 _spin_lock_bh+0x24: beqz v0,0x803806d0 _spin_trylock_bh+0xdc 0x803801d8 _spin_lock_bh+0x28: nop 0x803801dc _spin_lock_bh+0x2c: sync 0x803801e0 _spin_lock_bh+0x30: lw ra,20(sp) 0x803801e4 _spin_lock_bh+0x34: lw s0,16(sp) 0x803801e8 _spin_lock_bh+0x38: jr ra 0x803801ec _spin_lock_bh+0x3c: addiu sp,sp,24 杭州迪普科技有限公司

死锁问题定位方法 6 > 理清sw ra,20(sp)中的sp与rd读出的sp关系,:当前进程运行至_spin_lock_bh+0x18跳转到__spin_trylock_bh+0xdc后就挂死,从反汇编代码中可看出 addiu sp,sp,-24这条指令之后sp的值就没再改变,也就是说rd中的sp值就是sw ra,20(sp)中的sp值 【ps:由于这次死锁中sw ra,20(sp)与跳转到__spin_trylock_bh+0xdc指令离的很近,一眼就能看出sp的值没变,看下汇编也不费事,在实战时是没必要再看汇编的。因为sp的值只会在函数调用时改变,一般都在调用函数的第一条指令就把sp值压到该函数能用到的最低点(见 addiu sp,sp,-24 ),在函数内部sp的值不会变,__spin_trylock_bh这个函数比较特殊,调用它时都是直接跳转到+0xdc的位置,没有执行函数开头的压栈,所以rd出的sp就是rd出的ra函数的栈】 7> md sp+20 读出ra的值 [0]kdb> md 0x8e3ff890 0x8e3ff890 7f000001 7f000001 00000011 003595ed .............5.. 0x8e3ff8a0 dfcc0000 dfc1f728 82e10000 82e10000 .......(........ 0x8e3ff8b0 82e10000 82e10000 665e5705 82e10000 ........f^W..... 0x8e3ff8c0 00000003 00000001 8e3ff918 8e5b7600 .........?...[v. 0x8e3ff8d0 00000000 5050c34a 00000000 8e3ff918 ....PP.J.....?.. 0x8e3ff8e0 5050c302 dfc2009c 82e10000 82e10000 PP.............. 0x8e3ff8f0 82e10000 82e10000 5050c200 8e3ff9e0 ........PP...?.. 0x8e3ff900 5050c200 df6b4b04 82e10000 82e10000 PP...kK......... 杭州迪普科技有限公司

死锁问题定位方法 8> 反汇编dfc1f728,找到调用__spin_lock_bh的函数 [0]kdb> id 0xdfc1f728 0xdfc1f728 drv_ff_tab_add+0xe4: lui v0,0xdfcc 0xdfc1f72c drv_ff_tab_add+0xe8: addiu a3,v0,-30088 0xdfc1f730 drv_ff_tab_add+0xec: move a0,zero 0xdfc1f734 drv_ff_tab_add+0xf0: j 0xdfc1f744 drv_ff_tab_add+0x100 0xdfc1f738 drv_ff_tab_add+0xf4: lui a2,0x3 0xdfc1f73c drv_ff_tab_add+0xf8: beqz a1,0xdfc1f7c0 drv_ff_tab_add+0x17c 0xdfc1f740 drv_ff_tab_add+0xfc: addiu s1,s1,8 将0xdfc1f728前面的代码反汇编,找到调用__spin_lock_bh的指令,确认找到的ra是正确的 0xdfc1f714 drv_ff_tab_add+0xd0: lui v1,0x8038 0xdfc1f718 drv_ff_tab_add+0xd4: addu v0,v0,s3 0xdfc1f71c drv_ff_tab_add+0xd8: addiu v1,v1,432 0xdfc1f720 drv_ff_tab_add+0xdc: jalr v1 0xdfc1f724 drv_ff_tab_add+0xe0: addiu s4,v0,252 [0]kdb> 0x80380000+432 显示地址对应的符号 0x80380000 = 0x803801b0 (_spin_lock_bh) 杭州迪普科技有限公司

死锁问题定位方法 9> kdb的定位到此基本结束,回到si,将drv_ff_tab_add函数所有加锁,解锁,return高亮,很快就能发现那个流程没有解锁 死锁问题小结 1> 调用__spin_trylock_bh没有压栈操作,sp值是ra函数的栈 2> 推栈就是不断通过sp回溯ra的过程,具体步骤: a > 反汇编rd读出的ra值找到第一层调用函数 b > 确认rd中的sp是什么函数的栈(只要ra所在函数跳转到挂死时所在函数是正常的函数调用,不是像调用__spin_trylock_bh直接跳到函数中间,sp就是挂死所在函数的栈) c > 反汇编第一层调用函数头部(在这里就是_spin_lock_bh), 因为保存上层调用函数的ra值都在前几条指令 d > 根据ra赋值语句,从堆栈中读出(md sp+20),反汇编第二层ra找到第二层调用函数 e > 通过第一层调用函数第一条指令,即压栈操作(addiu sp,sp,-24),计算第二层调用函数的栈, _spin_lock_bh函数的sp是drv_ff_tab_add函数-24得到的,所以drv_ff_tab_add函数的栈就是sp+24,这个地方有点绕,但非常关键,好好理解下,要明白rd中的sp值永远是当前指令所在函数的栈(__spin_trylock_bh比较特殊) f > 反汇编第二层调用函数头部,找到第三层ra赋值语句 [0]kdb> id drv_ff_tab_add 0xdfc1f644 drv_ff_tab_add: addiu sp,sp,-64 0xdfc1f664 drv_ff_tab_add+0x20: sw s1,28(sp) 0xdfc1f668 drv_ff_tab_add+0x24: sw ra,60(sp) 杭州迪普科技有限公司

死锁问题定位方法 g> 根据ra赋值语句,从堆栈中找出第三层ra(md sp+24+60)值,反汇编 h> 重复步骤e,f,g可一直推到根函数 3> 新修改代码有return语句时,将整个函数浏览一遍,如前面有加锁操作,一定要解锁 4> 加锁时注意软中断(定时器,tasklet等),如果软中断也有可能调用,注意关中断(如在网卡驱动发包函数中) 杭州迪普科技有限公司

踩内存问题定位方法 踩内存是指由于其它流程引用指针时没有初始化,或是memcpy越界等导致一段正常的程序内存被写,设备挂死在这段正常的程序 怎么确认是踩内存 使用kdb定位到c语句后发现挂死时变量的值是一个完全不可能的值或挂死的函数是已经上线运行很长时间理论上不可能出问题的代码,这时可以出一个调试版本:在挂死变量前后各加一个用于观察的字段,初始化为一个特殊值,如0xabcd1234,代码中不再对这个字段做任何操作,问题复现时,如果观察字段的值被改,这时就可确认是被踩内存了 定位踩内存问题的一些方法: 1> 将挂死变量附近的内容全部打印出来,观察这一段内存的值有没有什么特殊性,可不可以联系上什么流程,因为写内存经常是将一串都写了。 2> 将挂死内存前面的内存地址对应的符号一个个的打印出来,如果能找到某个地址对应的是一个全局变量,很可能就是对这个全局变量的操作导致写内存的,回到c代码搜索该全局变量,重点关注memcpy语句 2> 比较版本差异,如果使用同样的环境上个版本是正常的,就说明是新版本引入的,直接比对代码,重点关注指针赋值,memcpy的地方 3> 寻找复现规律,找到之后,根据业务流程,逐个函数设置断点,每断住一个函数就从kdb中查看观察字段值是否还等于0xabcd1234,找到踩内存的函数,定位到函数这一层看c代码应该就能解决了 杭州迪普科技有限公司

异常信息分析方法 异常信息格式: --------------------------------------- 0 begin ------------------------------------- Exception: bus/cache error -死机原因:cache error Bridge: Phys Addr = 0x0010000000, Device_AERR = 0x00000001 Bridge: The devices reporting AERR are:         cpu 0 CPU: (XLR specific) Cache Error log = 0x0000000800000108, Phy Addr = 0x0010000000 CPU: epc = 0x802c561c, errorepc = 0x802c55f8, cacheerr = 0x00000000 异常受害指令Jiffies: 2920010 Occur time: Wed Jan 21 02:00:17 2009(1232474417s) 异常发生时间 Cpu 0 $ 0   : 00000000 00000000 89ad5022 89ad500e $ 4   : 89ad50b4 8ffffffa 00000526 ffe7ffff $ 8   : 00000000 00000000 00000000 00000000 $12   : 00000000 00000000 a0400000 bfc5f600 $16   : 802c54a0 000005ea 8f92fe40 89ad500e $20   : 000005c8 fc3a2b58 0000000e 8c3a4e40 $24   : 00000006 07eede40                   $28   : 8f830000 8f831d60 000005dc d2b5b6e0 Hi    : 00000000 Lo    : 00266800 epc   : 802c561c     Tainted: P       ra    : d2b5b6e0 Status: 1000dc05    KERNEL ERL IE  Cause : 80800000 PrId  : 000c0b04 杭州迪普科技有限公司

异常信息分析方法 Process <NULL> (pid: 0, threadinfo=813dc000, task=00000000) Stack : 00010050 00000000 80000000 8e3b8060 0000010c 00000000 8fffff68 000005c8         00000014 000005c8 03c5ceb8 00000000 00000022 d30ab564 8c3a4e40 00000003         fffffffa 8f831ed8 d30a1bc4 d30e28bc 8c3a317c 00000010 000000f4 d2b5b994         1000dc03 00000000 0026db38 00000003 8f831ed8 d2b548f8 0000010c 0000adc3         8cf73060 00000003 1000dc00 00000003 8014be58 8014be58 8f831ea0 0000008b         ... Code: ac890004  ac8a0008  ac8b000c <14d8fff1> 24840010  10c00018  30d80003  1306000a  00000000  (sizeof(unsigned long) * 128) bytes trace back from stack: 512字节堆栈信息 00010050 00000000 80000000 8e3b8060 0000010c 00000000 8fffff68 000005c8  00000014 000005c8 03c5ceb8 00000000 00000022 d30ab564 8c3a4e40 00000003  fffffffa 8f831ed8 d30a1bc4 d30e28bc 8c3a317c 00000010 000000f4 d2b5b994  1000dc03 00000000 0026db38 00000003 8f831ed8 d2b548f8 0000010c 0000adc3  8cf73060 00000003 1000dc00 00000003 8014be58 8014be58 8f831ea0 0000008b  d2b4eef4 00000003 bfc5f600 0dfb2882 bc400000 0dfb2860 00000000 80447678  81359a88 8135c018 00000000 5000dc00 00002668 8ca3366f 00000000 00000110  00000003 00000617 00000000 00000070 90461700 8ca33082 000005f6 00000000  8f831e1d 00000000 8f831ed8 d30e28bc fffffffa 0000000e 00000003 d2b54bbc  d2be8dac 00000003 81384b30 0d10d860 8f831ed8 d2b566b4 8f830000 8f831ec0  0000008b d2b4d9cc 8c3a4e40 00000003 fffffffa 0000000e 8c3a3060 d2b4b9a8  00000000 81384b30 00000000 00000000 1000dc01 8d2c1060 00000000 00000064  8f831e1d fffffffa 8c3a3060 8c3a308e 8c3a3060 00000073 8c3a308e 8c3a309c  d2be8dac 00000020 00004b30 0d09b860 0600011b d2e40000 d2b4eef4 d2defd3c  00000000 d2b848a4 00000072 00000003 d2be8dac 00000003 d2e40000 d2b4d9a0  ffffffff 00000010 d2b4eef4 d2defd3c 90c13200 0c3a3060 ffffffff 81384b30  --------------------------------------- 0 end --------------------------------------- 杭州迪普科技有限公司

异常信息分析方法 所谓异常信息是相对于kdb信息而言的,设备进kdb时,所有寄存器,堆栈,全局变量,内存值都是死机当时的值,我们称之为现场,但设备上线运行时都必须把kdb关掉,发生异常后设备会自动重启,不至于一发生异常就无法恢复,减小对现网的影响,这时用于定位的信息就只有发生异常时,cpu记录的异常信息,设备重启后通过exceptions disp total查看。异常信息的格式跟进入kdb时信息差不多,但只有打印出来的寄存器跟堆栈信息是发生异常时刻的值,内存,全局变量的值都是重启之后正常值,不能用于定位。 异常相关的命令: 查看异常信息:exceptions disp total (最前面的是最新的) 清除异常信息:excepiotns clear 异常问题定位方法: 1> 跟kdb差不多,最重要的还是通过EPC或是ERROR EPC,反汇编找到挂死的c语句 2> 因为异常信息中只有寄存器跟打印出的堆栈中的512字节信息可用,所以推栈跟找到s0—s7这些寄存器对应的c变量就显得更加重要 杭州迪普科技有限公司

进程栈演示 ADrv_ff_tab_add-Spin_lock--spin_trylock sp =sp- 24 rd_sp 杭州迪普科技有限公司

设备模块加载顺序 相关脚本\release\conplat\mips\root_fs\etc\rc.d rc.sysinit 内核态加载脚本 rc.conplat 用户态脚本 release\conplat\mips\root_fs\etc\startup_order 杭州迪普科技有限公司