我是Frama-c的新手,当我尝试打开C源文件时,我遇到了一个问题。
The error shows as
"fatal error: event.h: No such file or directory. Compilation terminated".
[kernel] Parsing FRAMAC_SHARE/libc/__fc_builtin_for_normalization.i (no preprocessing)
[kernel] Parsing WorkSpace/bipbuffer.c (with preprocessing)
[kernel] user error: failed to run: gcc -E -C -I. -dD -D__FRAMAC__ -nostdinc -D__FC_MACHDEP_X86_32 -I/usr/share/frama-c/libc -o '/tmp/bipbuffer.ce6d077.i' '/home/xxx/WorkSpace/bipbuffer.c' you may set the CPP environment variable to select the proper preprocessor command or use the option "-cpp-command".
[kernel] user error: stopping on file "/home/xxx/WorkSpace/bipbuffer.c" that has errors. Add'-kernel-msg-key pp' for preprocessing command.
所以基本上我试图打开一个C源文件,但它返回一个这样的错误。我也尝试过其他非常简单的C文件,比如hello world和其他切片函数,效果很好。
我认为这是因为我没有'event.h'的依赖项,但在安装libevent依赖项后它仍然会返回这些错误。我不确定是否需要手动为frama-c
设置依赖关系的路径以下是我要打开的C文件(源链接:https://memcached.org/)的一部分:
#include "stdio.h"
#include <stdlib.h>
/* for memcpy */
#include <string.h>
#include "bipbuffer.h"
static size_t bipbuf_sizeof(const unsigned int size)
{
return sizeof(bipbuf_t) + size;
}
int bipbuf_unused(const bipbuf_t* me)
{
if (1 == me->b_inuse)
/* distance between region B and region A */
return me->a_start - me->b_end;
else
return me->size - me->a_end;
}
......
谢谢,
答案 0 :(得分:2)
使用C源代码的编译器和其他工具需要知道在哪里找到头文件。它们有一些自动显示的标准位置,但Frama-C比普通编译器中的(和不同的)更少。
您需要找出安装event.h
的位置,然后将-cpp-extra-args "-I /path/to/directory/"
之类的内容传递给Frama-C。仅传递目录名称,不包括名称event.h
本身。
答案 1 :(得分:2)
除了Isabelle Newbie的回答之外,我还要指出,其版本为recently announced的Floma-C的Chlorine版本提供了一个新选项-json-compilation-database
,试图阅读要从a compilation database传递给预处理器的参数。
这样的数据库可以由cmake
直接生成,但是有基于make
的项目的解决方案,例如你引用的项目,特别是bear,它拦截了发起的命令通过make
来构建数据库。
答案 2 :(得分:1)
此处详细介绍了如何继续使用Frama-C 17 Chlorine的新-json-compilation-database
选项,以及额外的脚本list_files.py
(不在测试版中,但是将在最终的17版本中提供,可以下载here):
使用Frama-C获取要分析的源文件,运行./configure
,如果可能,尝试禁用外部库中的可选依赖项;例如,一些代码库包括基于库/系统功能的可用性的可选依赖项,但具有后备选项(使用标准C库或POSIX函数)。你给Frama-C的次数越多,分析它的机会就越大,所以如果这些外部库不是必需的,排除它们可能有助于获得更多的东西。代码,应该有所帮助。这通常在config.h
文件中以通常名为HAVE_*
的宏中可见。
编译并安装Build EAR或一些等效工具以获取compile_commands.json
文件。
运行bear make
(或带有标记CMAKE_EXPORT_COMPILE_COMMANDS
的cmake)以获取compile_commands.json
文件。
在包含list_files.py
的目录中运行上述compile_commands.json
,以获取编译期间使用的C源列表。
运行Frama-C(17 Chlorine或更新版本),为其提供上一步中找到的源列表,以及选项-json-compilation-database .
来解析compile_commands.json
,并希望获得适当的预处理标志。
理想情况下,这应该足够了,但在实践中,这已经不够了。特别是由于存在外部库和非C99,非POSIX功能,总是需要以下步骤。
在此步骤中,Frama-C会抱怨缺少event.h
。您必须自己包含此库的标题。 注意:由于多个特定于体系结构的定义,尤其是/usr/include
等文件,直接从bits/*.h
复制标题 可能无法正常工作。 。
相反,请考虑下载外部库并准备它们(例如至少运行./configure
)。然后通过-cpp-extra-args="-I <path/to/your/sources/for/libevent.h>/include"
手动添加额外的include目录。
可能缺少一些其他标头,特别是GNU或BSD特定的来源(例如sysexits.h
)。获取这些标头并在必要时添加它们。这种情况下的错误消息来自预处理器(gcc),与此类似:
memcached.c:51:10: fatal error: sysexits.h: No such file or directory
#include <sysexits.h>
^~~~~~~~~~~~
compilation terminated.
此时,所有必需的标头都应该可用,但使用Frama-C进行解析可能仍会失败。这是由于使用了非POSIX类型定义(例如caddr_t
,struct ling
),非POSIX常量(例如MAXPATHLEN
,SOCK_NONBLOCK
,NI_MAXSERV
) 。错误消息通常类似于以下内容:
[kernel] memcached.c:3261: Failure: Cannot resolve variable MAXPATHLEN
通过点击/usr/include
中可用的内容,常常很容易手动提供常量。
类型定义可能需要在正确的位置进行一些复制粘贴,特别是如果它们依赖于其他也缺少的类型。这一步很难实现自动化,但一旦习惯了某些特定的错误信息,就会相对简单。
例如,以下错误消息与缺少的类型定义(caddr_t
)相关:
[kernel] Parsing memcached.c (with preprocessing)
[kernel] memcached.c:1074:
syntax error:
Location: line 1074, between columns 38 and 47, before or at token: c
1072 *hdr++ = 0;
1073 *hdr++ = 0;
1074 assert((void *) hdr == (caddr_t)c->msglist[i].msg_iov[0].iov_base + UDP_HEADER_SIZE);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1075 }
1076
请注意,c
之前的令牌为(caddr_t)
,从未定义过(通常定义为void *
或char *
)。
以下错误消息与不完整的类型有关,即某个地方使用但未定义的struct
:
[kernel] memcached.c:5811: User Error:
variable `ling' has initializer but incomplete type
这意味着从未定义变量ling
的类型,即struct linger
(非POSIX)。在这种情况下,我们可以从/usr/include/bits/socket.h
:
struct linger
{
int l_onoff; /* Nonzero to linger on close. */
int l_linger; /* Time to linger. */
};
注意:如果Frama-C的libc中缺少POSIX常量/定义,请考虑通知其开发人员,或在Frama-C的Github中提出pull请求。 < / p>
解析可能在上一步之后成功,但由于功能原型不兼容,它可能仍然失败。例如,您可能会得到:
[kernel] User Error: Incompatible declaration for usleep:
different integer types int and unsigned int
First declaration was at assoc.c:238
Current declaration is at items.c:1573
这是先前发出警告的结果:
[kernel:typing:implicit-function-declaration] slabs.c:1150: Warning:
Calling undeclared function usleep. Old style K&R code?
这意味着函数usleep
被调用,但它没有原型,因此Frama-C使用了&#34;隐式int&#34;的前C99约定:它生成了这样的原型,但后来在代码中,找到了usleep
的实际声明,其类型为 not int
。因此错误。
为防止出现这种情况,您需要确保正确包含usleep
原型。由于不 POSIX.1-2008,您需要定义/取消定义相应的宏(请参阅unistd.h
),或添加自己的原型。
最后,这应该允许Frama-C解析文件并构建AST。
然而,还有几个缺少的原型;我们很幸运,没有与实际声明相冲突。理想情况下,当没有更多消息(例如implicit-function-declaration
和类似警告)时,您将考虑解析阶段。
memcached中缺少的一些原型(例如getsubopt
)是POSIX,应该集成到Frama-C的标准库中。其他人可能会成为非标准存根的小型库的一部分,可以重复用于其他软件。
成功完成此类开源库的解析阶段足以考虑将它们集成到this repository of open source case studies中,以便将来的用户可以开始他们的分析而无需重做所有这些步骤。 (存储库面向Eva,但不仅限于:解析对所有Frama-C插件都很有用。)