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

导航

 

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

一. 开启dynamic debug功能

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

CONFIG_DEBUG_FS=y
CONFIG_DYNAMIC_DEBUG=y

用menuconfig去配置的话如下图:

二 dynamic debug功能使用

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

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

nodev      /sys/kernel/debug debugfs   defaults    0   0

 

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

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

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

开启dynamic debug:

echo "module cvi_mipi_rx +p" > /sys/kernel/debug/dynamic_debug/control
②echo "file cvi_vip_cif.c +p" >/sys/kernel/debug/dynamic_debug/control

这两种方式都是开dynamic debug,第一种是对模块开启,第二种只对文件开启。下面举一个栗子:

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

 

反之,关闭dynamic debug:

echo "module cvi_mipi_rx -p" > /sys/kernel/debug/dynamic_debug/control
②echo "file cvi_vip_cif.c -p" >/sys/kernel/debug/dynamic_debug/control

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

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

不过一般不太推荐使用这种做法,因为很多functions都是相同名字但属于不同modules的。

三 dev_err/dev_info/dev_warn系列函数

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

其实这些函数族本质上和下面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(如何设置printk console level可以看上一篇1. printk & dmesg)。

 

四 可变参数宏(##__VA_ARGS__)

##__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);

 结果如下:

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

 

 

#ifndef _VPSS_DEBUG_H_
#define _VPSS_DEBUG_H_

#include <linux/debugfs.h>

extern u32 vpss_log_lv;

#define CVI_DBG_ERR        1   /* error conditions                     */
#define CVI_DBG_WARN       2   /* warning conditions                   */
#define CVI_DBG_NOTICE     3   /* normal but significant condition     */
#define CVI_DBG_INFO       4   /* informational                        */
#define CVI_DBG_DEBUG      5   /* debug-level messages                 */

#if defined(CONFIG_CVI_LOG)
#define CVI_TRACE_VPSS(level, fmt, ...) \
    do { \
        if (level <= vpss_log_lv) { \
            if (level == CVI_DBG_ERR) \
                pr_err("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == CVI_DBG_WARN) \
                pr_warn("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == CVI_DBG_NOTICE) \
                pr_notice("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == CVI_DBG_INFO) \
                pr_info("%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
            else if (level == CVI_DBG_DEBUG) \
                printk(KERN_DEBUG "%s:%d(): " fmt, __func__, __LINE__, ##__VA_ARGS__); \
        } \
    } while (0)
#else
#define CVI_TRACE_VPSS(level, fmt, ...)
#endif

#endif /* _VPSS_DEBUG_H_ */
View Code

 

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)

 可以看到这两种log控制级别的差异,第一种简单,当级别高于DBG,即可输出高于DBG的所有级别打印。第二种优点是可以随意开启任意级别打印,比如只开启DBG,只开启WARN。

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

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

CVI_S32 CVI_LOG_SetLevelConf(LOG_LEVEL_CONF_S *pstConf)
{
    log_levels[pstConf->enModId] = pstConf->s32Level;
    return CVI_SUCCESS;
}

CVI_S32 CVI_LOG_GetLevelConf(LOG_LEVEL_CONF_S *pstConf)
{
    pstConf->s32Level = log_levels[pstConf->enModId];
    return CVI_SUCCESS;
}


/*
 * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
 *
 * File Name: include/cvi_debug.h
 * Description:
 */

#ifndef __CVI_DEBUG_H__
#define __CVI_DEBUG_H__

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

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

/*
 * Debug Config
 */
#define CONFIG_CVI_GDB_NO 1
#define CONFIG_CVI_GDB "n"
#define CONFIG_CVI_LOG_TRACE_SUPPORT 1
#define CONFIG_CVI_LOG_TRACE_ALL 1
#define CONFIG_CVI_LOG_TRACE_LEVEL 4


#define CVI_DBG_EMERG      0   /* system is unusable                   */
#define CVI_DBG_ALERT      1   /* action must be taken immediately     */
#define CVI_DBG_CRIT       2   /* critical conditions                  */
#define CVI_DBG_ERR        3   /* error conditions                     */
#define CVI_DBG_WARN       4   /* warning conditions                   */
#define CVI_DBG_NOTICE     5   /* normal but significant condition     */
#define CVI_DBG_INFO       6   /* informational                        */
#define CVI_DBG_DEBUG      7   /* debug-level messages                 */

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

#define CVI_PRINT printf

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

extern CVI_S32 * log_levels;
extern CVI_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 CVI_GET_MOD_NAME(id) (id < CVI_ID_BUTT)? MOD_STRING[id] : "UNDEF"

/* #ifdef CVI_DEBUG */
#ifdef CONFIG_CVI_LOG_TRACE_SUPPORT

    #define CVI_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 CVI_TRACE(level, enModId, fmt, ...)            \
    do {                                                   \
        CVI_S32 LogLevel = (log_levels == NULL) ? CONFIG_CVI_LOG_TRACE_LEVEL : log_levels[enModId];      \
        if (level <= LogLevel)           \
            syslog(LOG_LOCAL5|level, "[%s-%s] " fmt, CVI_GET_MOD_NAME(enModId), log_name[level],    \
                ##__VA_ARGS__);           \
    } while (0)
#else
    #define CVI_TRACE(level, enModId, fmt, ...) \
        printf(fmt, ##__VA_ARGS__)
#endif
#else
    #define CVI_ASSERT(expr)
    #define CVI_TRACE(level, enModId, fmt...)
#endif

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

#define CVI_TRACE_LOG(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_LOG, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_SYS(level, fmt, ...)                                           \
        CVI_TRACE(level, CVI_ID_SYS, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_VB(level, fmt, ...)                                           \
        CVI_TRACE(level, CVI_ID_VB, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_SNS(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_VI, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_VI(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_VI, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_VPSS(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_VPSS, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_VO(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_VO, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_GDC(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_GDC, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_RGN(level, fmt, ...)                                           \
        CVI_TRACE(level, CVI_ID_RGN, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_MISC(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_SYS, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_DWA(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_DWA, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_DPU(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_DPU, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_STITCH(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_STITCH, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)

#define CVI_TRACE_HDMI(level, fmt, ...)  \
        CVI_TRACE(level, CVI_ID_HDMI, "%s:%d:%s(): " fmt, __FILENAME__, __LINE__, __func__, ##__VA_ARGS__)
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

#endif  /* __CVI_COMM_SYS_H__ */

 

posted on 2021-05-19 16:39  fuzidage  阅读(2082)  评论(0编辑  收藏  举报