fuzidage
专注嵌入式、linux驱动 、arm裸机研究

导航

 

1 dynamic_debug介绍

image

这里强烈推荐驱动开发者用这种方式输出log。linux kernel space中有pr_debugdev_dbg来使用dynamic debug。可以看到当用户define DEBUG后,pr_debugdev_dbg就等于printk的KERN_DEBUG级别输出了;否则什么也不打印。

image

1.1 开启dynamic debug

要使用dynamic_debug需要在kernel的defconfig中开启。

CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y

用menuconfig去配置的话如下图:

image

1.2 dynamic debug使用

编译好image后,需要挂载debugfs(不挂载的话将不会创建debugfs,那么/sys/kernel/debug/下是空的)。

修改etc/fstab文件,追加下面这段字符:

nodev      /sys/kernel/debug debugfs   defaults    0   0

image

可以用cat /sys/kernel/debug/dynamic_debug/control | grep xxx.c来查看自己想要查看的log所在文件有没有包含进去。

image

这里可以看到该文件所有用dev_dbg()打印出的讯息。

那如果不开启CONFIG_DYNAMIC_DEBUG,将不会产生/sys/kernel/debug/dynamic_debug目录, 是不能进行动态打印的。

1.2.1 开启dynamic debug

echo "module xxx_mipi_rx +p" > /sys/kernel/debug/dynamic_debug/control
echo "file xxx_vip_cif.c +p" >/sys/kernel/debug/dynamic_debug/control

这两种方式都是开dynamic debug,第一种是对模块开启,第二种只对文件开启。

下面举一个栗子:

image

开启之后,可以看到dev_dbg()打印的log都会输出。
image

反之,关闭dynamic debug

echo "module xxx_mipi_rx -p" > /sys/kernel/debug/dynamic_debug/control
echo "file xxx_vip_cif.c -p" >/sys/kernel/debug/dynamic_debug/control

除了上面的两种方式还有一种可以只开启某个function:

echo "func _init_resource +p" > /sys/kernel/debug/dynamic_debug/control

image

2 dev_err/dev_info/dev_warn

在Linux驱动代码中,有大量的调试信息,那么推荐使用dev_err/dev_info/dev_warn这一系列函数族。这一系列函数族定义在include/linux/device.h

image

其实这些函数族本质上和下面printk.h中的定义也是完全一致的。

#define pr_emerg(fmt, ...) \
        printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
#define pr_alert(fmt, ...) \
        printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_crit(fmt, ...) \
        printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
#define pr_err(fmt, ...) \
        printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
        printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warn pr_warning
#define pr_notice(fmt, ...) \
        printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
        printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)

下图是示例,可以看到err级别以下的log没有打印,那么设置printk的控制台级别可以把对应的log输出到console。

image

如何设置printk console level可以看上一篇Linux日志管理-printk和dmesg

3 可变参数宏

##__VA_ARGS__表示可变参数宏,可以用来传递多个参数,如:

#define my_dbg(fmt, ...) \
do {                        \
        printf("[%s] [%d] " fmt, __func__, __LINE__, ##__VA_ARGS__);\
} while(0)
#define my_dbg(fmt...) \
do { \
  printf("[%s] [%d] ", __func__, __LINE__); \
  printf(fmt); \
} while(0)

char *name = "robin"; int age = 18; my_dbg("this is a test. name:%s, age:%d\n", name, age);

结果如下:

image

那和下面这种写法呢本质上是完全一样的。

image

4 模块打印等级控制

4.1 按照打印等级控制

#ifndef _VPSS_DEBUG_H_
#define _VPSS_DEBUG_H_

#include <linux/debugfs.h>

extern u32 xxx_log_lv;

#define DBG_ERR        1   /* error conditions                     */
#define DBG_WARN       2   /* warning conditions                   */
#define DBG_NOTICE     3   /* normal but significant condition     */
#define DBG_INFO       4   /* informational                        */
#define DBG_DEBUG      5   /* debug-level messages                 */

#if defined(CONFIG_LOG)
#define TRACE_XXX(level, fmt, ...) \
    do { \
        if (level <= xxx_log_lv) { \
            if (level == DBG_ERR) \
                pr_err("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == DBG_WARN) \
                pr_warn("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == DBG_NOTICE) \
                pr_notice("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == DBG_INFO) \
                pr_info("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == DBG_DEBUG) \
                printk(KERN_DEBUG "%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
        } \
    } while (0)
#else
#define TRACE_XXX(level, fmt, ...)
#endif

#endif /* _xxx_DEBUG_H_ */

当级别高于DBG,即可输出高于DBG的所有级别打印。

4.2 精确控制打印等级

extern u32 vi_log_lv;
enum vi_msg_pri {
    VI_ERR        = 0x1,
    VI_WARN        = 0x2,
    VI_NOTICE    = 0x4,
    VI_INFO        = 0x8,
    VI_DBG        = 0x10,
};
#define vi_pr(level, fmt, arg...) \
    do { \
        if (vi_log_lv & level) { \
            if (level == VI_ERR) \
                pr_err("%s:%d(): " fmt, __func__, __LINE__, ## arg); \
            else if (level == VI_WARN) \
                pr_warn("%s:%d(): " fmt, __func__, __LINE__, ## arg); \
            else if (level == VI_NOTICE) \
                pr_notice("%s:%d(): " fmt, __func__, __LINE__, ## arg); \
            else if (level == VI_INFO) \
                pr_info("%s:%d(): " fmt, __func__, __LINE__, ## arg); \
            else if (level == VI_DBG) \
                pr_debug("%s:%d(): " fmt, __func__, __LINE__, ## arg); \
        } \
    } while (0)

可以随意开启任意级别打印,比如只开启DBG,只开启WARN。

5 用户态模块打印等级控制

XXX_S32 *log_levels;
XXX_CHAR const *log_name[8] = {
    (XXX_CHAR *)"EMG", (XXX_CHAR *)"ALT", (XXX_CHAR *)"CRI", (XXX_CHAR *)"ERR",
    (XXX_CHAR *)"WRN", (XXX_CHAR *)"NOT", (XXX_CHAR *)"INF", (XXX_CHAR *)"DBG"
};

XXX_S32 XXX_LOG_SetLevelConf(LOG_LEVEL_CONF_S *pstConf)
{
    log_levels[pstConf->enModId] = pstConf->s32Level;
    return XXX_SUCCESS;
}

XXX_S32 XXX_LOG_GetLevelConf(LOG_LEVEL_CONF_S *pstConf)
{
    pstConf->s32Level = log_levels[pstConf->enModId];
    return XXX_SUCCESS;
}

#ifndef __XXX_DEBUG_H__
#define __XXX_DEBUG_H__

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <XXX_common.h>

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* End of #ifdef __cplusplus */

/*
 * Debug Config
 */
#define CONFIG_XXX_GDB_NO 1
#define CONFIG_XXX_GDB "n"
#define CONFIG_XXX_LOG_TRACE_SUPPORT 1
#define CONFIG_XXX_LOG_TRACE_ALL 1
#define CONFIG_XXX_LOG_TRACE_LEVEL 4


#define XXX_DBG_EMERG      0   /* system is unusable                   */
#define XXX_DBG_ALERT      1   /* action must be taken immediately     */
#define XXX_DBG_CRIT       2   /* critical conditions                  */
#define XXX_DBG_ERR        3   /* error conditions                     */
#define XXX_DBG_WARN       4   /* warning conditions                   */
#define XXX_DBG_NOTICE     5   /* normal but significant condition     */
#define XXX_DBG_INFO       6   /* informational                        */
#define XXX_DBG_DEBUG      7   /* debug-level messages                 */

typedef struct _LOG_LEVEL_CONF_S {
    MOD_ID_E  enModId;
    XXX_S32   s32Level;
    char   cModName[16];
} LOG_LEVEL_CONF_S;

#define XXX_PRINT printf

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-variable"

extern XXX_S32 * log_levels;
extern XXX_CHAR const *log_name[8];

#pragma GCC diagnostic pop

#define _GENERATE_STRING(STRING) (#STRING),
static const char *const MOD_STRING[] = FOREACH_MOD(_GENERATE_STRING);
#define XXX_GET_MOD_NAME(id) (id < XXX_ID_BUTT)? MOD_STRING[id] : "UNDEF"

/* #ifdef XXX_DEBUG */
#ifdef CONFIG_XXX_LOG_TRACE_SUPPORT

    #define XXX_ASSERT(expr)                               \
    do {                                                   \
        if (!(expr)) {                                 \
            printf("\nASSERT at:\n"                \
                   "  >Function : %s\n"            \
                   "  >Line No. : %d\n"            \
                   "  >Condition: %s\n",           \
                   __func__, __LINE__, #expr);     \
            _exit(-1);                             \
        } \
    } while (0)

#ifndef FPGA_PORTING

    #define XXX_TRACE(level, enModId, fmt, ...)            \
    do {                                                   \
        XXX_S32 LogLevel = (log_levels == NULL) ? CONFIG_XXX_LOG_TRACE_LEVEL : log_levels[enModId];      \
        if (level <= LogLevel)           \
            syslog(LOG_LOCAL5|level, "[%s-%s] " fmt, XXX_GET_MOD_NAME(enModId), log_name[level],    \
                ##__VA_ARGS__);           \
    } while (0)
#else
    #define XXX_TRACE(level, enModId, fmt, ...) \
        printf(fmt, ##__VA_ARGS__)
#endif
#else
    #define XXX_ASSERT(expr)
    #define XXX_TRACE(level, enModId, fmt...)
#endif

#define XXX_TRACE_ID(level, id, fmt, ...)                                           \
        XXX_TRACE(level, id, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define XXX_TRACE_LOG(level, fmt, ...)  \
        XXX_TRACE(level, XXX_ID_LOG, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define XXX_TRACE_SYS(level, fmt, ...)                                           \
        XXX_TRACE(level, XXX_ID_SYS, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

#endif  /* __XXX_COMM_SYS_H__ */
posted on 2021-05-19 16:39  fuzidage  阅读(2327)  评论(0编辑  收藏  举报