动态调试

如何动态调试 (ddebug)

这篇文档主要介绍动态调试 (ddebug) 特性.  

动态调试的主要功能是允许你动态的打开或关闭内核代码的各种提示信息. 现在, 假如   
CONFIG_DYNAMIC_DEBUG 已经设置好了, 那么所有的 pr_debug()/dev_debug() 之类的函数可以动态的在代码里所使用.  

动态调试有很多有用的特性:  

 * 简洁的查询语言允许打开或关闭调试的状态通过匹配以下的任意组合:  

   - 资源文件名   
   - 函数名   
   - 行号 (包括一定范围的行号)  
   - 模块名   
   - 格式化字符串   

 * 提供一个debugfs 控制文件: <debugfs>/dynamic_debug/control 这个文件被读取用来显示已完成的调试信息列表, 来帮助指导你   
控制动态调试的行为   
===================================  

pr_debug()/dev_debug()的行为控制通过在'debugfs'文件系统上写一个控制文件 .因此,为了这个特性,你首先必须挂载这个debugfs文件系统. 然后, 我们再像这样使用控制文件: <debugfs>/dynamic_debug/control. 下面这个是个例子, 假如你要显示文件'svcsock.c'的1603行内容,你可以这样做:  

nullarbor:~ # echo 'file svcsock.c line 1603 +p' >  
                <debugfs>/dynamic_debug/control  

如果你的语法有错误,写成了下边这个样子,会有下面的写操作错误提示:  

nullarbor:~ # echo 'file svcsock.c wtf 1 +p' >  
                <debugfs>/dynamic_debug/control  
-bash: echo: write error: Invalid argument  
查看动态调试行为   
===========================  

你可以查看目前所有调试状态的行为配置通过以下命令:  

nullarbor:~ # cat <debugfs>/dynamic_debug/control  
# filename:lineno [module]function flags format  
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323  
[svcxprt_rdma]svc_rdma_cleanup - "SVCRDMA Module Removed, deregister RPC RDMA transport\012"  
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341  
[svcxprt_rdma]svc_rdma_init - "\011max_inline       : %d\012"  
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340  
[svcxprt_rdma]svc_rdma_init - "\011sq_depth         : %d\012"  
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338  
[svcxprt_rdma]svc_rdma_init - "\011max_requests     : %d\012"  
...  


你也可以应用标准的Unix文本过滤命令来过滤这些数据, 例如.  

nullarbor:~ # grep -i rdma <debugfs>/dynamic_debug/control  | wc -l  
62  

nullarbor:~ # grep -i tcp <debugfs>/dynamic_debug/control | wc -l  

42

在第三列(在Uninx下执行这个命令的结果是一列一列的)显示了调试状态位的激活标志(后边的是标志位的定义).  默认值, 无额外行为被激话, 是这个 "-".  因此你可以查看任何不是默认标志的状态位通过下面的命令:

nullarbor:~ # awk '$3 != "-"' <debugfs>/dynamic_debug/control  
# filename:lineno [module]function flags format  
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p  
"svc_process: st_sendto returned %d\012"  

命令语言参考  
==========================  

在词汇层面上,一个命令由一系列由空格分割的的单词组成。注意的是换行符会认为是单词的分割,同时*不会*结束一条命令或者允许多个命令一起完成。下面的这些都是等价的:  

nullarbor:~ # echo -c 'file svcsock.c line 1603 +p' >  
                <debugfs>/dynamic_debug/control  
nullarbor:~ # echo -c '  file   svcsock.c     line  1603 +p  ' >  
                <debugfs>/dynamic_debug/control  
nullarbor:~ # echo -c 'file svcsock.c\nline 1603 +p' >  
                <debugfs>/dynamic_debug/control  
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >  
                <debugfs>/dynamic_debug/control  

命令由wirte()的系统调用界定。如果你想执行多个命令,你需要为每个加入“echo”分割,像这样:  

nullarbor:~ # echo 'file svcsock.c line 1603 +p' > /proc/dprintk ;\  
> echo 'file svcsock.c line 1563 +p' > /proc/dprintk  

或者甚至是这样:   

nullarbor:~ # (  
> echo 'file svcsock.c line 1603 +p' ;\  
> echo 'file svcsock.c line 1563 +p' ;\  
> ) > /proc/dprintk  

在语法层面上,一个命令由一系列的规格匹配组成,随后由一个标记来改变这规格。  

command ::= match-spec* flags-spec  

match-spec常用来选择一个已知的dprintk()调用点的子集来套用flags-spec。把他们当做彼此之间的每对做隐式查询。注意一个空的match_specs列表是有可能的,但不是非常有用,因为它不会匹配任何调用点的调试子句。  

一个匹配规范由一个关键字组成,关键字控制被比较的调用点的属性和要比较的值。可能关键字是:  

match-spec ::= 'func' string |  
           'file' string |  
           'module' string |  
           'format' string |  
           'line' line-range  

line-range ::= lineno |  
           '-'lineno |  
           lineno'-' |  
           lineno'-'lineno  
// 注意:line-range不能包含空格,例如  
// “1-30”是有效的范围,但“1 - 30”就是无效的  

lineno ::= unsigned-int  

每个关键字的意思是:  

func  
     给定的字符穿会和每个调用点的函数名比较。例如:  

    func svc_tcp_accept  

file  
     给定的字符串会和每个调用点的源文件的全路径名或者相对名比较。例如:  

    file svcsock.c  
    file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c  

module  
    给定的字符串会和每个调用点的模块名进行比较。模块名是和在“lsmod”里看到的字符串一样,举例来说,没有路径或者是.ko后缀同时带有'-'的改变为'_'。  

    module sunrpc  
    module nfsd  

format  
     给定的字符串会在动态调试格式字符串里查找。注意这字符串不需要匹配这个格式,这是一部分。空格和其他特殊字符能够用C的八进制字符语法来转义,例如空字符是\040。作为选择,这个字符串可以附上双引号(")或者是单引号(‘)。  
     例如:  

    format svcrdma:        // 大多数NFS/RDMA 服务器的dprintks  
    format readahead        // 一些在预加载缓存里的dprintks  
    format nfsd:\040SETATTR // 一个使用空格来匹配格式的方式  
    format "nfsd: SETATTR"  // 一个整齐的方法来用空格匹配格式  
    format 'nfsd: SETATTR'  // 同样是一个用空格来匹配格式的方法和  

line  

     给定的行号或者是行号范围会和每个dprintk()调用点
      的行号进行比较。一个单一的行号与调用点 的行号 进行准
     确匹配。一个行号范围会和包含的第一行和最后一行 的任何调
      用点进行匹配。一个空的第一个数字表示该文件的第 一行
      ,一个空的行号表示文件的最后一行。例如:


    line 1603        // 准确定位到1603行   
    line 1600-1605  //1600行到1605行之间的6行  
    line -1605        // 从第一行到1605行之间的1605行  
    line 1600-        // 从1600行到结尾的全部行  

标记规范包含了一个由一个或多个标记字符跟随的变化操作。这变化操作是下面的字符之一:  

-  
     移除给定的标记  

+  
     加入给定的标记  

=  
    设置标记到给定的标记上   

这些标记是:  

f  
    包含已打印消息的函数名  
l  
     包含已在打印消息的行号  
m  
    包含已打印消息的模块名  
p  
    产生一个printk()消息到显示系统启动日志  
t  
    包含了不在中断上下文中产生的消息里的线程ID  

注意正则表达式^[-+=][flmpt]+$匹配一个标记规范。  
同样也要注意,没有便捷的语法来一次性移除所有的标记,你需要使用"-flmpt"。  

引导进程中的调试信息

即使在用户空间和debugfs存在之前,也可以使用引导参数:ddebug_query=“QUERY”来激活引导进程中的调试信息。

QUERY遵循上述语法,但一定不能超过1023个字符。调试信息的启动随着arch_initcall而完成。因此通过引导参数arch_initcall之后,你可以在所有的代码处理中启用调试信息。

例如,在一个x86的系统中,ACPI启用是一个subsys_initcall并且如果你的机器(通常是一台笔记本)有一个嵌入式的控制器,ddebug_query=“fileec.c+p”将会在ACPI装备期间显示早期的嵌入式控制器事务。PCI(或其他设备)的初始化也是使用这个引导参数来调试的热门候选。

实例  
========  

// 提供文件 svcsock.c   1603行信息  
nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' >  
                <debugfs>/dynamic_debug/control  

// 提供文件svcsock.c所有信息   
nullarbor:~ # echo -n 'file svcsock.c +p' >  
                <debugfs>/dynamic_debug/control  

// 提供NFS服务模块所有的信息  
nullarbor:~ # echo -n 'module nfsd +p' >  
                <debugfs>/dynamic_debug/control  

// 提供函数svc_process()的所有12条信息   
nullarbor:~ # echo -n 'func svc_process +p' >  
                <debugfs>/dynamic_debug/control  

// 不显示   函数svc_process()的所有12条信息  
nullarbor:~ # echo -n 'func svc_process -p' >  
                <debugfs>/dynamic_debug/control  

// 提供NFS调用的所有以READ开始的信息.  
nullarbor:~ # echo -n 'format "nfsd: READ" +p' >  
                <debugfs>/dynamic_debug/control

 

 

 

 

 
 

Linux内核动态调试信息的打开,如pr_debug

  (2012-08-23 13:38:54)
 

【1】配置Kconfig,添加要调试驱动模块的DDEBUG选项,如

kernel_imx\drivers\mxc\pmic\mc13892\Kconfig

config MXC_PMIC_DEBUG
 bool "Support MXC PMIC DEBUG"
 depends on MXC_PMIC
 

【2】配置Makefile,添加编译支持驱动模块 EXTRA_CFLAGS  += -DDEBUG ,如

kernel_imx\drivers\mxc\pmic\core\Makefile

ifeq ($(CONFIG_MXC_PMIC_DEBUG),y)
 EXTRA_CFLAGS  += -DDEBUG
endif

 

【3】配置内核,使支持动态调试

make menuconfig

  | |        Kernel hacking  --->

  | |    [*] Tracers  --->

  | |          [*]   Trace max stack

  | |    [*] Enable dynamic printk() support

 

  | |        Device Drivers  --->

  | |            MXC support drivers  --->

  | |                MXC PMIC support  ---> 
  | |                       [*] Support MXC PMIC DEBUG

 

【4】重烧内核启动后,改变控制台debug消息显示级别,可以打印printk(DEBUG ...)信息
echo > /proc/sys/kernel/printk "8"

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Xposed动态调试是一种在Android系统中使用Xposed框架的方法,通过该方法可以实现对第三方应用程序的动态调试和修改。Xposed框架是一个基于Android系统的插件框架,它允许开发人员在不修改应用程序源代码的情况下对应用程序进行修改和扩展。动态调试是指在应用程序运行过程中对其进行修改和调试的过程,可以用于改变应用程序的行为、增加新功能或者调试应用程序的问题。 在使用Xposed框架进行动态调试时,首先需要安装Xposed Installer应用程序。然后,需要下载并安装Xposed模块,可以通过Xposed官方网站或者其他来源获取适用的模块。安装完毕后,需要在Xposed Installer应用程序中激活所安装的模块,并重启设备以使其生效。 完成上述步骤后,就可以使用Xposed框架进行动态调试了。具体的操作方法包括创建Hook入口类、设置Xposed模块的配置信息和实现具体的Hook逻辑。通过Hook逻辑,可以拦截并修改应用程序的方法调用、改变应用程序的行为,甚至篡改应用程序的界面。这样就可以实现对第三方应用程序的动态调试和修改。 总之,Xposed动态调试是一种基于Xposed框架的方法,可用于实现对第三方应用程序的动态调试和修改。通过安装Xposed Installer应用程序和相应的Xposed模块,并设置和实现Hook逻辑,可以对应用程序进行拦截、修改和调试

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值