kernel自带的静态代码检查工具Sparse介绍

1.Sparse介绍

Linus在2004年开发了kernel代码静态检查工具,可以检查出kernel中潜在的风险代码,Sparse通过 gcc 的扩展属性__attribute__ 以及自己定义的 __context__来对代码进行静态检查,重点检查kernel代码中的变量类型和各类锁。

具体可以参考kernel文档
Documentation/dev-tools/sparse.rst

那么如何指定代码可以被Sparse检查的到呢?以__iomem为例,可以对需要检查的变量类型放到特定文件中,以__CHECKER__进行限定即可。

#ifdef __CHECKER__
# define __user		__attribute__((noderef, address_space(1)))
# define __kernel	__attribute__((address_space(0)))
# define __safe		__attribute__((safe))
# define __force	__attribute__((force))
# define __nocast	__attribute__((nocast))
# define __iomem	__attribute__((noderef, address_space(2)))
# define __must_hold(x)	__attribute__((context(x,1,1)))
# define __acquires(x)	__attribute__((context(x,0,1)))
# define __releases(x)	__attribute__((context(x,1,0)))
# define __acquire(x)	__context__(x,1)
# define __release(x)	__context__(x,-1)
# define __cond_lock(x,c)	((c) ? ({ __acquire(x); 1; }) : 0)
# define __percpu	__attribute__((noderef, address_space(3)))
# define __rcu		__attribute__((noderef, address_space(4)))
# define __private	__attribute__((noderef))
extern void __chk_user_ptr(const volatile void __user *);
extern void __chk_io_ptr(const volatile void __iomem *);
# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member))
#else /* __CHECKER__ */
# ifdef STRUCTLEAK_PLUGIN
#  define __user __attribute__((user))
# else
#  define __user
# endif
# define __kernel
# define __safe
# define __force
# define __nocast
# define __iomem
# define __chk_user_ptr(x) (void)0
# define __chk_io_ptr(x) (void)0
# define __builtin_warning(x, y...) (1)
# define __must_hold(x)
# define __acquires(x)
# define __releases(x)
# define __acquire(x) (void)0
# define __release(x) (void)0
# define __cond_lock(x,c) (c)
# define __percpu
# define __rcu
# define __private
# define ACCESS_PRIVATE(p, member) ((p)->member)
#endif /* __CHECKER__ */

2. 安装Sparse工具

通常来说,开发环境中没有Sparse工具,需要手动安装,否则报如下错误:

ubuntu16@ubuntu16:linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 C=2
  CHECK   scripts/mod/empty.c
/bin/sh: 1: sparse: not found
scripts/Makefile.build:261: recipe for target 'scripts/mod/empty.o' failed
  1. 获取Sparse代码
ubuntu16@ubuntu16:~$ git clone git://git.kernel.org/pub/scm/devel/sparse/sparse.git
Cloning into 'sparse'...
remote: Enumerating objects: 17, done.
remote: Counting objects: 100% (17/17), done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 20026 (delta 6), reused 0 (delta 0), pack-reused 20009
Receiving objects: 100% (20026/20026), 4.29 MiB | 924.00 KiB/s, done.
Resolving deltas: 100% (14035/14035), done.
Checking connectivity... done.
  1. 编译Sparse
ubuntu16@ubuntu16:~$ cd sparse/
ubuntu16@ubuntu16:sparse$ make
Makefile:152: Your system does not have libxml, disabling c2xml
Makefile:170: Your system does not have sqlite3, disabling semind
Makefile:192: Your system does not have gtk3/gtk2, disabling test-inspect
Makefile:226: Your system does not have llvm, disabling sparse-llvm
  1. 安装Sparse
ubuntu16@ubuntu16:sparse$ make install
Makefile:152: Your system does not have libxml, disabling c2xml
Makefile:170: Your system does not have sqlite3, disabling semind
Makefile:192: Your system does not have gtk3/gtk2, disabling test-inspect
Makefile:226: Your system does not have llvm, disabling sparse-llvm
INSTALL /home/ubuntu16/bin/sparse
INSTALL /home/ubuntu16/bin/cgcc
INSTALL /home/ubuntu16/share/man/man1/sparse.1
INSTALL /home/ubuntu16/share/man/man1/cgcc.1
ubuntu16@ubuntu16:sparse$ 

3.执行Sparse静态检查

从kernel顶层Makefile中可以看出,当编译kernel时通过指定C=1C=2,可以调用到Sparse进行代码静态检查。

192 # Call a source code checker (by default, "sparse") as part of the
193 # C compilation.
194 #
195 # Use 'make C=1' to enable checking of only re-compiled files.
196 # Use 'make C=2' to enable checking of *all* source files, regardless
197 # of whether they are re-compiled or not.
198 #
199 # See the file "Documentation/dev-tools/sparse.rst" for more details,
200 # including where to get the "sparse" utility.

执行结果:

ubuntu16@ubuntu16:linux$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4 C=2
  CHECK   scripts/mod/empty.c
  CALL    scripts/atomic/check-atomics.sh
  CALL    scripts/checksyscalls.sh
  CHECK   arch/arm/vfp/vfpmodule.c
  CHECK   init/main.c
arch/arm/vfp/vfpmodule.c:38:17: warning: symbol 'vfp_vector' was not declared. Should it be static?
arch/arm/vfp/vfpmodule.c:56:17: warning: symbol 'vfp_current_hw_state' was not declared. Should it be static?
arch/arm/vfp/vfpmodule.c:323:6: warning: symbol 'VFP_bounce' was not declared. Should it be static?
arch/arm/vfp/vfpmodule.c:714:6: warning: symbol 'kernel_neon_begin' was not declared. Should it be static?
arch/arm/vfp/vfpmodule.c:745:6: warning: symbol 'kernel_neon_end' was not declared. Should it be static?
...
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Linux与SoC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值