默認打開pr_debug和dev_dbg

摘要:
14.PR通常用于Linux驱动程序开发_调试和开发_ dbg打印驱动器的日志,以便在三个文件输出日志时显示相应的KBUILD _ MODNAME也输出adbshell'echo-n“filetfa98xx.c+pmflt”>

作者:彭東林

郵箱: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] [1778] snd_soc_tfa98xx:tfa98xx_mute:2525: tfa98xx 9-0034: state: 0
[ 1171.401523] <intr> q6asm:q6asm_callback:1611: q6asm_callback: nowait_cmd_cnt 1

[ 1184.540904] [71] snd_soc_wcd_mbhc:wcd_correct_swch_plug:1228: wcd_correct_swch_plug: hs_comp_res: 0

從上面的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啓動的時候就可以看到對命令行的解析過程:

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

方法二 在需要開啓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 (0)

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

#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)        
    static struct _ddebug  __aligned(8)            
    __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:2523 [snd_soc_tfa98xx]tfa98xx_mute =p "state: %d

免责声明:内容来源于网络,仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ArcGIS生成根据点图层生成等值面并减小栅格锯齿的操作步骤(转)sysbench简易使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

内网esxi磁盘空间不足导致虚拟机宕机

内网esxi磁盘空间不足导致虚拟机宕机 一、问题引入   周一上班的时候,发现公司内网的戴尔服务器上(前人装的ESXi系统,里面有很多个虚拟机),好几个虚拟机异常关机了。点击重新开机,有以下报错提示: 选Retry是没用的,选Cancel,才有可能开机,为啥叫可能,因为有一些空间占用多的虚拟机不一定能开机,会一直重复这种报错。 二、问题研究及解决   检...

Java日志-Log4j2

Log4j2参考资料 Log4j2 官方配置文档 1. Log4j2基本概念: Logger 在代码中产生日志信息的。比如logger.info("some log message")。 有name属性,并与LoggerConfig(Logger的配置信息)相关联。使用LogManager.getLogger方法获得。一般来说在每个需要记录日志的类中都需要...

log4j简介及应用

一、介绍  Log4j是Apache的一个开放源代码项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件、甚至是套接口服务 器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。 Log4j由三个重要的组件构成:日志信息...

KendoUI 用下来的小总结

Kendoui 官网地址:http://demos.telerik.com/kendo-ui/ Aspnetmvc * 引用jquery.1.10以上 * 1.项目引用 Kendo.Mvc.dll 2.页面引用 @using Kendo.Mvc.UI; 3.Name和 HtmlAttribute(new {id=’’}) 没有id就用name作为默认id...

layui开关遇见的坑以及用法总结

1.先看官方文档: 官方效果: 注意:如果你直接把文档中这块代码粘贴过去是不会有效果的,如果问为什么,下面是原因: 说的很清楚了,必须有form进行渲染,也就是要放到form中,当然别忘了引入一套layui,下面代码才可以正常显示 <form class="layui-form"> <div class="layui-form-i...

wpf简单进度条

UserControl x:Class="WpfApplication1.UserControl2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:...