Transferred from: https://www.cnblogs.com/pengdonglin137/p/5808373.html
Author: Peng Donglin
Email: pengdonglin137@163.com
Date: 2016-08-26 18:04:14
PR is often used in Linux driver development_ Debug and dev_dbg prints the log of the driver. If config is selected during kernel configuration_ DYNAMIC_ Debug macro, then you can use the following command to open the log of the corresponding file:
echo -n "file xxx.c +p" > /sys/kernel/debug/dynamic_debug/control
But sometimes we need to see the log of this file in the kernel startup phase. What should we do to change it?
There are two ways:
Method 1: modify kernel parameters
Modify the bootargs passed by the bootloader to the kernel. If the device tree is used, you can modify the value of the bootargs attribute in the chosen node. The specific method is in the kernel document: Documentation / dynamic debug howto txt
The advantage of this scheme is that there is no need to modify the driver code.
For example, when we need to boot the kernel, open tfa98xx c,wcd-mbhc-v2.c and q6asm C log. First, we can take a look at the kbuild corresponding to these two files_ Modname, there are two ways to view this value:
- View the corresponding Makefile
Check the Makefile corresponding to the above three files in the driver, as follows:
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
Of which, tfa98xx C corresponding KBUILD_MODNAME is snd-soc-tfa98xx, wcd-mbhc-v2 C corresponding KBUILD_MODNAME is snd SOC WCD MBHC, q6asm C corresponding KBUILD_MODNAME is q6asm
- The second method is as follows. Open the logs of these three files with the following command. Then, when the logs of these three files are output, the corresponding kbuild will also be displayed_ Modname is also output
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 meanings of the symbols involved are as follows:
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)
Then perform relevant operations and let these files output log, which can be seen in the 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
As can be seen from the above log, the string in front of the first colon is the corresponding KBUILD_MODNAME.
After obtaining kbuild_ After modname, you can modify the device tree file. The following is the result after adding the original 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\""; };
In snd_soc_tfa98xx.dyndbg=\"file tfa98xx.c +p; file tfa_dsp.c +p \" as an example:
The naming rule in front of the equal sign is "KBUILD_MODNAME.dyndbg". The one behind the equal sign is easy to understand. It should be noted that double quotation marks need to be escaped.
When debugging this part, you can open kernel / params The log method of C is to define the DEBUG macro at the beginning of the file, so that the PR of the file will be_ DEBUG and dev_dbg open.
In this way, you can see the parsing process of the command line when the kernel is started:
<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'
Method 2: define the macro DEBUG at the beginning of the driver file that needs to open the log
In this way, PR in the driver file_ Debug and dev_dbg can be opened.
For example, the name of the driver file is tfa98xx c. Then add the definition of DEBUG macro in the first non comment line:
/* * 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> ......
Why can this be achieved? Now let's take pr_debug as an example for simple analysis.
Config is configured in the kernel_ DYNAMIC_ After debug, PR_ The definition of debug is as follows:
#define pr_debug(fmt, ...) \ dynamic_pr_debug(fmt, ##__VA_ARGS__)
dynamic_ pr_ The definition of debug is as follows:
#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)
The macro define is used here_ DYNAMIC_ DEBUG_ Metadata is defined as follows:
#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_ The definition of debug is as follows:
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); }
As you can see from the above code, each pr_ Each debug corresponds to a descriptor of type struct_ Ddebug variables are stored in the kernel__ verbose segment. Decide this pr_ The condition for whether debug can output log is descriptor flags & _ DPRINTK_FLAGS_PRINT is true.
When defining a descriptor, assign its flags member to_ DPRINTK_FLAGS_DEFAULT, let's take a look at the definitions of these two macros:
#if defined DEBUG #define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT #else #define _DPRINTK_FLAGS_DEFAULT 0 #endif
As you can see, if the macro DEBUG is defined, then_ DPRINTK_FLAGS_DEFAULT is actually_ DPRINTK_FLAGS_PRINT, so it can be printed by default. If there is no definition, then_ DPRINTK_FLAGS_DEFAULT is 0, and the above conditions will not hold, so it cannot be printed.
It will be traversed during dynamic debug initialization__ verbose section, processing each struct_ For ddebug type variables, if the DEBUG macro is defined, you can read the control node after startup, and you will find that there is already a "p" parameter.
root@colombo:/ # cat /d/dynamic_debug/control | grep tfa sound/soc/codecs/tfa98xx.c:2523 [snd_soc_tfa98xx]tfa98xx_mute =p "state: %d\012" sound/soc/codecs/tfa98xx.c:2573 [snd_soc_tfa98xx]tfa98xx_digital_mute =p "%s enter, mute: %d\012" sound/soc/codecs/tfa98xx.c:1077 [snd_soc_tfa98xx]tfa98xx_info_vstep =p "vsteps count: %d [prof=%d]\012" ... ...
Of course, you can also use the following command to close:
echo -n "file xxx.c -p" > /sys/kernel/debug/dynamic_debug/control
End.