如何使用 Wine 日志调试问题

输出调试日志是调试程序的一种常见方法,尤其是处理那些难以捉摸的多线程错误、随机崩溃等问题时 。通过在合适的位置输出调试日志,可以帮助我们更快地定位问题所在。

对于不熟悉的代码,经常打日志也有助于快速理解代码的执行流程和功能。在大型项目中,通常会先实现一套自己的调试日志框架,主要有两个目的:

  • 统一日志风格和存储:确保日志格式一致,并且有统一的存储方式,这有助于用户更容易地报告问题。
  • 方便开发人员:开发人员能够轻松地记录日志,从而快速调试问题。

Wine 项目也不例外,它也实现了一套自己的日志系统。这套系统非常简洁,下面我们就来详细介绍。

Wine 的调试日志实现

调试通道(debug channel)

Wine 定义了调试通道的概念来分类日志,将日志的记录和实际的输出分离,无需重新编译 Wine,就能动态地灵活控制 Wine 运行时的日志输出。

  • 每个调试通道有一个唯一的名字, 长度不超过14个可见的 ASCII 字符, 一般一个模块至少定义了一个调试通道,比如 gdi32.dll 模块,有一个名称叫 gdi 的调试通道。
  • 复杂的模块,为了细分日志定义了多个调试通道,比如 gdi32.dll 模块,还定义了clipping、region、font、bitmap、print、bitblt 等调试通道。
  • 调试通道在代码里面来看实际是一个__wine_debug_channel 的结构体,刚好16个字节,非常符合 UNIX 简单原则的哲学理念:

struct __wine_debug_channel
{
unsigned char flags;
char name[15];
};

  • 日志一次只发送给一个调试通道。

  • 代码里增加一个新的调试通道,非常简单:

1. 包含 include/wine/debug.h

2. 然后用WINE_DEFAULT_DEBUG_CHANNELWINE_DEFAULT_DEBUG_CHANNEL宏来声明。

  • 要知道一个模块定义了哪些调试通道,只需这样搜索该模块的所有源码:git grep _DEBUG_CHANNEL

向调试通道发送日志

Wine 把日志分成了4个级别,从高到低依次是:fixme/ err(or)/ warn/ trace,对应的提供了4个宏来输出不同级别的日志到调试通道:FIXME/ ERR/ WARN/ TRACE,非常简单、清晰。

#define __WINE_DPRINTF(dbcl,dbch) \
do { if(__WINE_GET_DEBUGGING(dbcl,(dbch))) { \
struct __wine_debug_channel * const __dbch = (dbch); \
const enum __wine_debug_class __dbcl = __WINE_DBCL##dbcl; \
__WINE_DBG_LOG

#define __WINE_DBG_LOG(args...) \
wine_dbg_log( __dbcl, __dbch, __FUNCTION__, args); } } while(0)

#define TRACE                 __WINE_DPRINTF(_TRACE,__wine_dbch___default)
#define TRACE_(ch)            __WINE_DPRINTF(_TRACE,&__wine_dbch_##ch)
#define TRACE_ON(ch)          __WINE_IS_DEBUG_ON(_TRACE,&__wine_dbch_##ch)

#define WARN                  __WINE_DPRINTF(_WARN,__wine_dbch___default)
#define WARN_(ch)             __WINE_DPRINTF(_WARN,&__wine_dbch_##ch)
#define WARN_ON(ch)           __WINE_IS_DEBUG_ON(_WARN,&__wine_dbch_##ch)

#define FIXME                 __WINE_DPRINTF(_FIXME,__wine_dbch___default)
#define FIXME_(ch)            __WINE_DPRINTF(_FIXME,&__wine_dbch_##ch)
#define FIXME_ON(ch)          __WINE_IS_DEBUG_ON(_FIXME,&__wine_dbch_##ch)

#define ERR                   __WINE_DPRINTF(_ERR,__wine_dbch___default)
#define ERR_(ch)              __WINE_DPRINTF(_ERR,&__wine_dbch_##ch)
#define ERR_ON(ch)            __WINE_IS_DEBUG_ON(_ERR,&__wine_dbch_##ch)

最终都是调用函数 wine_dbg_log 来打日志:

int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *channel,
const char *func, const char *format, ... )
{
int ret;
va_list valist;

if (!(__wine_dbg_get_channel_flags( channel ) & (1&n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值