好久没写notebook了,最近在做的事情是为google/syzkaller添加Linux RISC-V KVM Fuzz的相关实现,幸运地找到了一些bug,并且部分已经被社区接收了。
好,言归正传,今天在分析 BUG: unable to handle kernel paging request in kvm_riscv_vcpu_pmu_ctr_cfg_match 时遇到了 ffs, fls, __ffs, __fls这些helper函数,一开始搞不明白,后面在LLM的帮助下才知道是怎么回事。
这些函数都是位操作工具函数,定义在arch/riscv/include/asm/bitops.h里面:
// 没必要看源码,看注释就行
/**
* ffs - find first set bit in a word
* @x: the word to search
*
* This is defined the same way as the libc and compiler builtin ffs routines.
*
* ffs(value) returns 0 if value is 0 or the position of the first set bit if
* value is nonzero. The first (least significant) bit is at position 1.
*/
#define ffs(x) (__builtin_constant_p(x) ? __builtin_ffs(x) : variable_ffs(x))
/**
* fls - find last set bit in a word
* @x: the word to search
*
* This is defined in a similar way as ffs, but returns the position of the most
* significant set bit.
*
* fls(value) returns 0 if value is 0 or the position of the last set bit if
* value is nonzero. The last (most significant) bit is at position 32.
*/
#define fls(x) \
({ \
typeof(x) x_ = (x); \
__builtin_constant_p(x_) ? \
((x_ != 0) ? (32 - __builtin_clz(x_)) : 0) \
: \
variable_fls(x_); \
})
/**
* __ffs - find first set bit in a long word
* @word: The word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
#define __ffs(word) \
(__builtin_constant_p(word) ? \
(unsigned long)__builtin_ctzl(word) : \
variable__ffs(word))
/**
* __fls - find last set bit in a long word
* @word: the word to search
*
* Undefined if no set bit exists, so code should check against 0 first.
*/
#define __fls(word) \
(__builtin_constant_p(word) ? \
(unsigned long)(BITS_PER_LONG - 1 - __builtin_clzl(word)) : \
variable__fls(word))
好了,翻译一下:ffs指的是Find First Set bit, fls指的是Find Last Set bit; 加上__之后,代表着最低为是索引0,否则是1.
data = 0b00101000
ffs(data) = 4
fls(data) = 6
__ffs(data) = 3
__fls(data) = 5