作者:彭東林

郵箱:pengdonglin137@163.com

日期:2016-08-26 18:04:14

在進行Linux驅動開發時經常見到使用pr_debug和dev_dbg打印驅動的log,如果在內核配置時選擇了CONFIG_DYNAMIC_DEBUG宏,那麼就可以利用類似下面的命令打開對應文件的log:

echo -n "file xxx.c +p" > /sys/kernel/debug/dynamic_debug/control

但是有時候我們需要看到這個文件在內核啓動階段的log,那麼改怎麼辦呢?

這裏有兩種方法:

方法一 修改內核傳參

修改bootloader傳遞給kernel的bootargs,如果使用了設備樹的話,可以修改在chosen節點中bootargs屬性的值,具體方法內核文檔:Documentation/dynamic-debug-howto.txt

這種方案的優點是不需要修改驅動代碼。

比如我們需要開機內核啓動的時候就打開tfa98xx.c、wcd-mbhc-v2.c和q6asm.c的log,首先我們可以看一下這兩個文件對應的KBUILD_MODNAME,這裏有兩種方法可以查看這個值:

  • 查看對應的Makefile

在驅動中查看上面的三個文件對應的Makefile,如下:

snd-soc-tfa98xx-objs := tfa98xx.o tfa_container.o tfa_dsp.o tfa9887B_init.o tfa9887_init.o tfa9888_init.o tfa9890_init.o tfa9891_init.o tfa9897_init.o
obj-$(CONFIG_SND_SOC_TFA98XX) += snd-soc-tfa98xx.o snd-soc-wcd-mbhc-objs := wcd-mbhc-v2.o
obj-$(CONFIG_SND_SOC_WCD_MBHC) += snd-soc-wcd-mbhc.o obj-y += audio_calibration.o audio_cal_utils.o q6adm.o q6afe.o q6asm.o \
q6audio-v2.o q6voice.o q6core.o rtac.o q6lsm.o audio_slimslave.o

其中,tfa98xx.c對應的KBUILD_MODNAME就是snd-soc-tfa98xx,wcd-mbhc-v2.c對應的KBUILD_MODNAME就是snd-soc-wcd-mbhc,q6asm.c對應的KBUILD_MODNAME是q6asm

  • 第二種方法如下,用如下命令打開這三個文件的log,那麼在這三個文件輸出log的同時也會將對應的KBUILD_MODNAME也輸出出來
adb shell 'echo -n "file tfa98xx.c +pmflt" > /sys/kernel/debug/dynamic_debug/control'
adb shell 'echo -n "file wcd-mbhc-v2.c +pmflt" > /sys/kernel/debug/dynamic_debug/control'
adb shell 'echo -n "file q6asm.c +pmflt" > /sys/kernel/debug/dynamic_debug/control'

其中涉及到的符號的含義如下:

The flags specification comprises a change operation followed
by one or more flag characters. The change operation is one
of the characters: - remove the given flags
+ add the given flags
= set the flags to the given flags The flags are: p enables the pr_debug() callsite.
f Include the function name in the printed message
l Include line number in the printed message
m Include module name in the printed message
t Include thread ID in messages not generated from interrupt context
_ No flags are set. (Or'd with others on input)

然後執行相關的操作,讓這幾個文件輸出log,在log中可以看到:

[ 1171.400553] [] snd_soc_tfa98xx:tfa98xx_mute:: tfa98xx -: state:
[ 1171.401523] <intr> q6asm:q6asm_callback:: q6asm_callback: nowait_cmd_cnt [ 1184.540904] [] snd_soc_wcd_mbhc:wcd_correct_swch_plug:: wcd_correct_swch_plug: hs_comp_res:

從上面的log中可以看到,第一個冒號前面的字符串就是對應的KBUILD_MODNAME。

在獲得了KBUILD_MODNAME後,就可以修改設備樹文件了,下面是在原有bootargs後追加後的結果。

    chosen {
bootargs = "sched_enable_hmp=1 sched_enable_power_aware=1 snd_soc_wcd_mbhc.dyndbg=\"file wcd-mbhc-v2.c +p\" snd_soc_tfa98xx.dyndbg=\"file tfa98xx.c +p; file tfa_dsp.c +p\"";
};

以 snd_soc_tfa98xx.dyndbg=\"file tfa98xx.c +p; file tfa_dsp.c +p\" 爲例說明一下:

等號前面的命名規則是 "KBUILD_MODNAME.dyndbg",等號後面的比較好理解,需要注意的是需要對雙引號進行轉義。

在調試這部分時可以打開kernel/params.c的log,方法是文件的開頭定義DEBUG宏,這樣就會將這個文件的pr_debug和dev_dbg打開。

這樣在kernel啓動的時候就可以看到對命令行的解析過程:

<>[    0.015794] doing dyndbg params, parsing ARGS: 'sched_enable_hmp=1 sched_enable_power_aware=1 snd_soc_wcd_mbhc.dyndbg="file wcd-mbhc-v2.c +p" snd_soc_tfa98xx.dyndbg="file tfa98xx.c +p; file tfa_dsp.c +p" console=ttyHSL0,115200,n8 androidboot.console=ttyHSL0 androidboot.hardware=qcom user_debug=31 msm_rtb.filter=0x237 ehci-hcd.park=3 lpm_levels.sleep_disabled=1 zswap.enabled=1 cma=32M@0-0xffffffff loglevel=0 androidboot.bootdevice=624000.ufshc androidboot.verifiedbootstate=orange androidboot.veritymode=logging androidboot.serialno=d94b873f androidboot.fingerprint.id=fpc androidboot.hardware.id=0x1c uart_enable=0 ro.housing.color=black  pmode=0 androidboot.baseband=msm mdss_mdp.panel=1:dsi:0:qcom,mdss_dsi_nt35597_dsc_wqxga_cmd:config2:1:none:cfg:single_dsi fpsimd.fpsimd_settings=0'
<>[ 0.015810] doing dyndbg params: sched_enable_hmp=''
<>[ 0.015818] doing dyndbg params: sched_enable_power_aware=''
<>[ 0.015824] doing dyndbg params: snd_soc_wcd_mbhc.dyndbg='file wcd-mbhc-v2.c +p'
<>[ 0.015901] doing dyndbg params: snd_soc_tfa98xx.dyndbg='file tfa98xx.c +p; file tfa_dsp.c +p'
<>[ 0.015975] doing dyndbg params: console='ttyHSL0,115200,n8'
<>[ 0.015980] doing dyndbg params: androidboot.console='ttyHSL0'
<>[ 0.015986] doing dyndbg params: androidboot.hardware='qcom'
<>[ 0.015991] doing dyndbg params: user_debug=''
<>[ 0.015996] doing dyndbg params: msm_rtb.filter='0x237'
<>[ 0.016001] doing dyndbg params: ehci-hcd.park=''
<>[ 0.016006] doing dyndbg params: lpm_levels.sleep_disabled=''
<>[ 0.016011] doing dyndbg params: zswap.enabled=''
<>[ 0.016016] doing dyndbg params: cma='32M@0-0xffffffff'
<>[ 0.016020] doing dyndbg params: loglevel=''
<>[ 0.016026] doing dyndbg params: androidboot.bootdevice='624000.ufshc'
<>[ 0.016031] doing dyndbg params: androidboot.verifiedbootstate='orange'
<>[ 0.016036] doing dyndbg params: androidboot.veritymode='logging'
<>[ 0.016041] doing dyndbg params: androidboot.serialno='d94b873f'
<>[ 0.016046] doing dyndbg params: androidboot.fingerprint.id='fpc'
<>[ 0.016051] doing dyndbg params: androidboot.hardware.id='0x1c'
<>[ 0.016056] doing dyndbg params: uart_enable=''
<>[ 0.016061] doing dyndbg params: ro.housing.color='black'
<>[ 0.016065] doing dyndbg params: pmode=''
<>[ 0.016070] doing dyndbg params: androidboot.baseband='msm'
<>[ 0.016075] doing dyndbg params: mdss_mdp.panel='1:dsi:0:qcom,mdss_dsi_nt35597_dsc_wqxga_cmd:config2:1:none:cfg:single_dsi'
<>[ 0.016081] doing dyndbg params: fpsimd.fpsimd_settings=''

方法二 在需要開啓log的驅動文件的開頭定義宏DEBUG

這樣該驅動文件中的pr_debug和dev_dbg就可以打開了。

比如驅動文件的名字是tfa98xx.c,那麼就在其第一個非註釋行添加DEBUG宏的定義:

/*
* tfa98xx.c tfa98xx codec module
*
* Copyright (c) 2015 NXP Semiconductors
*
* Author: Sebastien Jan <sjan@baylibre.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/ #define DEBUG
#define pr_fmt(fmt) "%s(): " fmt, __func__ #include <linux/module.h>
#include <linux/i2c.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <linux/of_gpio.h>
......

爲什麼這樣做可以實現呢?下面我們以pr_debug爲例簡單分析。

在內核配置了CONFIG_DYNAMIC_DEBUG後,pr_debug的定義如下:

#define pr_debug(fmt, ...) \
dynamic_pr_debug(fmt, ##__VA_ARGS__)

dynamic_pr_debug的定義如下:

#define dynamic_pr_debug(fmt, ...)                \
do { \
DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \
__dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
##__VA_ARGS__); \
} while ()

這裏用到了宏DEFINE_DYNAMIC_DEBUG_METADATA,定義如下:

#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)        \
static struct _ddebug __aligned() \
__attribute__((section("__verbose"))) name = { \
.modname = KBUILD_MODNAME, \
.function = __func__, \
.filename = __FILE__, \
.format = (fmt), \
.lineno = __LINE__, \
.flags = _DPRINTK_FLAGS_DEFAULT, \
}

__dynamic_pr_debug的定義如下:

void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
{
va_list args;
struct va_format vaf;
char buf[PREFIX_SIZE]; BUG_ON(!descriptor);
BUG_ON(!fmt); va_start(args, fmt); vaf.fmt = fmt;
vaf.va = &args; printk(KERN_DEBUG "%s%pV", dynamic_emit_prefix(descriptor, buf), &vaf); va_end(args);
}

從上面的代碼可以看到,每一個pr_debug都對應一個名爲descriptor,類型爲struct _ddebug的變量,存放在kernel的__verbose段。決定這個pr_debug能否輸出log的條件就是descriptor.flags & _DPRINTK_FLAGS_PRINT爲true。

在定義descriptor時,將其flags成員賦值爲了_DPRINTK_FLAGS_DEFAULT,下面看一下這兩個宏的定義:

#if defined DEBUG
#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT
#else
#define _DPRINTK_FLAGS_DEFAULT 0
#endif

可以看到,如果定義了宏DEBUG,那麼_DPRINTK_FLAGS_DEFAULT其實就是_DPRINTK_FLAGS_PRINT,所以默認就是可以打印的。如果沒有定義,那麼_DPRINTK_FLAGS_DEFAULT就是0,上面的條件不會成立,也就打印不出來。

在dynamic debug初始化的時候會遍歷__verbose段,處理每一個struct _ddebug類型的變量,如果定義了DEBUG宏,在開機後,可以讀取control節點,會發現已經有"p"參數了。

root@colombo:/ # cat /d/dynamic_debug/control | grep tfa
sound/soc/codecs/tfa98xx.c: [snd_soc_tfa98xx]tfa98xx_mute =p "state: %d\012"
sound/soc/codecs/tfa98xx.c: [snd_soc_tfa98xx]tfa98xx_digital_mute =p "%s enter, mute: %d\012"
sound/soc/codecs/tfa98xx.c: [snd_soc_tfa98xx]tfa98xx_info_vstep =p "vsteps count: %d [prof=%d]\012"
... ...

當然,也可以使用下面的命令關閉:

echo -n "file xxx.c -p" > /sys/kernel/debug/dynamic_debug/control

完。

默認打開pr_debug和dev_dbg的更多相关文章

  1. Win8下修改任務欄的資源管理器默認打開位置

    不能像win7一樣右鍵屬性改了,但還是有辦法的. 新建一個文件夾,建立快捷方式,右鍵快捷方式,將目標改為%windir%\explorer.exe /n,/e,D:\Desktop 然後將該快捷方式拖 ...

  2. pr_debug、dev_dbg等动态调试一

    内核版本:Linux-3.14 作者:彭东林 邮箱:pengdonglin137@163.com pr_debug: #if defined(CONFIG_DYNAMIC_DEBUG) /* dyna ...

  3. office word 設置默認的縮放為100%, office word set default Zoom to 100% permanently

    如題,今天剛好遇到一個老師不知道什麽原因造成Microsoft office word 每次打開都會縮放到70% ,所以google 了一下,還真有解決方法. 只要將默認的 使用者範本檔 Normal ...

  4. 02.C#可空類型、默認參數、LINQ(一章1.3-1.4)

    利用上班時間發個隨筆,不知領導會不會看到,可能會有同事看到也說不定啊:) 關于可空類型,在C#1中沒有這個概念,在C#3中引入的.那比如我們要實現一個表示人的類,人有名字和年齡兩個屬性,如何表示一個沒 ...

  5. Mysql工作記錄之修改默認存儲引擎及重設root用戶密碼

    1>修改默認存儲引擎方法 修改配置文件,然後重啟mysql服務: [root@CHW mysql]# cat /etc/my.cnf                            [my ...

  6. pr_debug、dev_dbg等动态调试二

    内核版本:Linux-3.14 作者:彭东林 邮箱:pengdonglin137@163.com 下面我们简要分析 1: echo -n "file demo.c +p" > ...

  7. pr_debug、dev_dbg等动态调试三

    内核版本:Linux-3.14 作者:彭东林 邮箱:pengdonglin137@163.com 如果没有使用CONFIG_DYNAMIC_DEBUG,那么就需要定义DEBUG,那么此时pr_debu ...

  8. SessionState,默認mode應該是"InProc"

    在ASP.NET的sessionState的三種屬性 http://www.dotblogs.com.tw/boei/archive/2010/07/06/16414.aspx需要在另外的config ...

  9. 開玩樹莓派(二):配置IP,實現無顯示器局域網內Putty連接和RDP遠程

    目錄: 開玩樹莓派(一):安裝Raspbian系統 開玩樹莓派(二):配置IP,實現無顯示器局域網內Putty連接和RDP遠程 開玩樹莓派(三):Python編程 開玩樹莓派(四):GPIO控制和遠程 ...

随机推荐

  1. Android--多媒体操作

    ---恢复内容开始--- 1.拍照,这里直接上代码,看注释就好 public void onCreate(Bundle savedInstanceState) { super.onCreate(sav ...

  2. linux-14基础命令之-复制(cp)移动(mv),删除(rm),拷贝文件(dd)

    1.cp 命令用于复制文件或者目录 格式为:cp[选项]源文件  目标文件 复制名录有三种情况: @1.目标文件是一个目录,将源复制到该目录下:  @2.目标文件是一个文件,将源文件覆盖该文件: @3 ...

  3. cocoapods安装以及使用,安装过程中ruby版本过低

    cocoapods安装以及使用,安装过程中ruby版本过低 字数473 阅读103 评论1 喜欢2 1.打开终端 2.移除现有 Ruby 默认源 $ gem sources --remove http ...

  4. springrain 1.1 发布,spring 的极简封装

    经过2个月的测试修改,springrain1.1已经稳定,今日发布. 主要改动如下: 1.添加批量更新和保存的方法 2.添加maven分支 3.添加博客管理的demo 4.增加redis做为缓存实现 ...

  5. Apache Lucene 4.5 发布,Java 搜索引擎

    Apache Lucene 4.5 发布了,该版本提供基于磁盘的文档值以及改进了过滤器的缓存.Lucene 4.5 的文档请看这里. Lucene 是apache软件基金会一个开放源代码的全文检索引擎 ...

  6. Xamarin开发Android笔记:拍照或相册选取图片角度问题

    在开发Android应用的时候,可能会遇到类似微信朋友圈中拍照或相册选取图片的场景,拍照或选取图片之后在显示的时候却发现图片的角度不对,明明是竖版拍照,显示出来缺失躺着的. 这是因为在某些特定手机上例 ...

  7. javascript 设计模式-----工厂模式

    所谓的工厂模式,顾名思义就是成批量地生产模式.它的核心作用也是和现实中的工厂一样利用重复的代码最大化地产生效益.在javascript中,它常常用来生产许许多多相同的实例对象,在代码上做到最大的利用. ...

  8. note of introduction of Algorithms(Lecture 3 - Part1)

    Lecture 3(part 1) Divide and conquer 1. the general paradim of algrithm as bellow: 1. divide the pro ...

  9. angularjs移除不必要的$watch

    在我们的web page,特别是移动设备上,太多的angular $watch将可能导致性能问题.这篇文章将解释如何去移除额外的$watch提高你的应用程序性能. $watch如果不再使用,我们最好将 ...

  10. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...