1.linux内核调试工具crash并不能直接显示函数参数,而这个对调试又非常重要
下面是工作中一个实际的问题,我们的进程hang在如下一个内核栈中了,通过栈回溯可知是打开了一个nfs3的网盘文件或者目录,已知客户机器的NAS盘不可访问了,只要访问就会hang住,但我们的进程理论上是不会访问该NAS盘的,那么如何知道open打开的是什么文件呢,这时候就迫切的需要知道do_sys_open的filename参数了(此时多么希望VS, gdb能够出手相救)。
但在x64位linux系统中,前6个参数使用的是rdi, rsi, rdx, rcx, r8, r9寄存器来传递,超出的才会用栈来传递,filename是第2个参数,会用rsi来传递,这下就GG了,函数经过这么多层调用,到当前栈帧的时候rsi早就是n手货了,而且rsi又不是保留寄存器,下层函数不会给他提供VIP待遇做保存,绝望,绝望,就是这么的绝望。

 

 
 
2.希望之光:通过函数参数被局部变量缓存获取

1> 上帝关上了一扇门,必然会为你打开另一扇窗

虽然寄存器不会被缓存,但局部变量会啊,局部变量是用栈保存的,函数调用栈未返回之前,栈都会一直给你当宝一样存着,so换个思路,假设,我们假设这个函数参数filename传递给了某个路人局部变量,那么我们找到这个路人,不就相当于找到了filename么。
 

2> 思路打开,上帝就立马给你送来了这个路人。

我们看do_sys_open,开头就把filename丢给了tmp这个路人,因此我们只要去栈上把tmp逮捕归案就能收工下班。

 

3> 逮捕方案1:"-FF"

crash的bt命令提供了"-FF"参数,宣称可以打印局部变量。但是吗,往往宣称是一回事,实际又是另一回事。"bt -FF"一敲,甭说放大镜,用电子显微镜也找不到tmp在哪。

4> 逮捕方案2:速请汇编大仙

既然tmp是个局部变量,又会作为第二个参数传递给do_filp_open,那么我们找到汇编大仙call do_filp_open的地方,就能找到tmp了。
来吧,dis照妖镜,do_sys_open原形毕露如下,tmp是调用getname返回的,返回值rax立马给了r14(汇编里返回值都是用rax传递),不妙不妙,还是不给留栈上啊,难怪"bt -FF"瞎眼了。虽然但是呢,上帝又给留了一扇窗(PS: 这上帝给的有点多),r14是保留寄存器,享受终生大保健VIP待遇,下层函数调用一定会给留个位的,走,去do_filp_open栈上逛逛。
 
dis给do_filp_open一照,嘿,上帝对咱是true love了,第2个push就把r14留do_filp_open栈上了,下班收工指日可待了这不。
调转枪头再来看一眼前面让我们绝望的"bt -FF"的栈,根据汇编基础知识,linux x64调用函数先将返回地址压栈,调用do_filp_open后再将rbp压栈,最后就是我们朝思暮想的r14了,所以从do_filp_open栈底数第3个就是tmp了,抓!!!
原来是用的第三方库openssl里面会打开一个编译机上的openssl.cnf文件,刚好在编译机的/mnt目录下,而/mnt目录是NAS等网盘默认挂载路径,当NAS出现异常时(如在有文件被占用情况下卸载NAS),此时访问NAS文件目录都会hang住,导致进程hang。

 
3.后记
上面的例子上帝开的窗有点多,通过保存了函数参数的局部变量,咱们很快就真相大白了,但是如果万一万一非常点背,我们要找的函数参数就是没有在局部变量中保存,那怎么办呢。这种情况一般是不会有的,因为重要的参数只要有需要,就会传递到某一层函数局部变量中,耐心点找找就会有的,如果确实没有,可能就需要更耐心的分析整个调用栈,看看哪里会有些勾勾搭搭的局部变量,寄存器没有被破坏,也终究是可以抓出来的。

linux内核调试痛点之函数参数抓捕记的更多相关文章

  1. linux 内核调试之关键函数名记要

    gdbserver + gdb 调试内核 记到函数名,其它就能用gdb看了 start_kernel 内核启动 run_init_process    init进程启动 主要是根据shell脚本初始化 ...

  2. Linux内核调试方法总结【转】

    转自:http://my.oschina.net/fgq611/blog/113249 内核开发比用户空间开发更难的一个因素就是内核调试艰难.内核错误往往会导致系统宕机,很难保留出错时的现场.调试内核 ...

  3. linux内核调试指南

    linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...

  4. 【转】Linux内核调试方法总结

    目录[-] 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2  dump_sta ...

  5. Linux内核调试方法总结

    Linux内核调试方法总结 一  调试前的准备 二  内核中的bug 三  内核调试配置选项 1  内核配置 2  调试原子操作 四  引发bug并打印信息 1  BUG()和BUG_ON() 2   ...

  6. Linux内核调试方法【转】

    转自:http://www.cnblogs.com/shineshqw/articles/2359114.html kdb:只能在汇编代码级进行调试: 优点是不需要两台机器进行调试. gdb:在调试模 ...

  7. Linux Kernel - Debug Guide (Linux内核调试指南 )

    http://blog.csdn.net/blizmax6/article/details/6747601 linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级 ...

  8. Linux内核调试的方式以及工具集锦【转】

    转自:https://blog.csdn.net/gatieme/article/details/68948080 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原 ...

  9. Linux内核调试的方式以及工具集锦

    原文:https://blog.csdn.net/gatieme/article/details/68948080 CSDN GitHubLinux内核调试的方式以及工具集锦 LDD-LinuxDev ...

  10. Linux内核调试方法总结之栈帧

    栈帧 栈帧和指针可以说是C语言的精髓.栈帧是一种特殊的数据结构,在C语言函数调用时,栈帧用来保存当前函数的父一级函数的栈底指针,当前函数的局部变量以及被调用函数返回后下一条汇编指令的地址.如下图所示: ...

随机推荐

  1. [春秋云镜] Initial

    [春秋云镜] Initial **整套网络环境拓扑:** ​​ 一.打进内网 开局一个ip:39.101.184.25,fscan扫一下 ​​ 存在thinkphp5.0.23的漏洞,可以rce,我们 ...

  2. 我出一道面试题,看看你能拿 3k 还是 30k!

    大家好,我是程序员鱼皮.欢迎屏幕前的各位来到今天的模拟面试现场,接下来我会出一道经典的后端面试题,你只需要进行 4 个简单的选择,就能判断出来你的水平是新手(3k).初级(10k).中级(15k)还是 ...

  3. Jmeter函数助手16-StringFromFile

    StringFromFile函数用于获取文本文件的值,一次读取一行,可读取多个文件. 输入文件的全路径:填入文件路径 存储结果的变量名(可选) Start file sequence number ( ...

  4. javaDoc生成方式

    命令行生成 在cmd控制台窗口上找到需要生成文件的路径,然后执行命令. # javadoc -encoding UTF-8 -charset UTF-8 文件名 javadoc -encoding U ...

  5. 【Docker】03 基础操作

    [Docker 本体操作相关] 检查Docker版本: docker -v 检查Docker当前状态: systemctl status docker 停止Docker与开启Docker system ...

  6. window系统使用经验:新买的window11初始化时最好要选择用Microsoft账户激活,而不要用local账户激活

    Windows系统初始化时有两种类型的账户可以选择,一种时Microsoft账户,一种时local账户,Microsoft账户需要联网初始化,而local账户则和传统的初始化方式一致,即账号信息保存在 ...

  7. NVIDIA的OpenUSD是什么? —— Universal Scene Description (USD)

    正如NVIDIA的老黄在2024年的技术大会上的展示一样,NVIDIA公司或许最准确的定义应该是计算机图形学公司,因为不论是NVIDIA搞GPU还是搞通用计算还是搞软件生态以至于现在搞AI搞机器人搞自 ...

  8. java获取包下所有的类

    1.背景 给一个Java的包名,获取包名下的所有类.. 根据类上的注解,可以展开很多统一操作的业务 2.直接看代码-spring环境下 package com.qxnw.digit.scm.commo ...

  9. vue之循环遍历v-for

    1.背景 2.遍历数组 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&qu ...

  10. 再探GraphRAG:如何提升LLM总结能力?

    作者:王振亚 编者语: 自微软发布GraphRAG之后,相关解读文层出不穷,其中不乏优秀的内容.比如前段时间转载薛明同学的<微软GraphRAG框架源码解读>让大家快速对GraphRAG的 ...