Move bifcl to a separate repo

This commit is contained in:
Jon Siwek 2018-07-12 17:51:23 -05:00
parent 15d74ac081
commit e1b7820b01
10 changed files with 9 additions and 1391 deletions

3
.gitmodules vendored
View file

@ -25,3 +25,6 @@
[submodule "aux/netcontrol-connectors"]
path = aux/netcontrol-connectors
url = git://git.bro.org/bro-netcontrol
[submodule "aux/bifcl"]
path = aux/bifcl
url = git://git.bro.org/bifcl

View file

@ -108,6 +108,10 @@ if (NOT BinPAC_ROOT_DIR AND
endif ()
FindRequiredPackage(BinPAC)
if ( NOT BIFCL_EXE_PATH )
add_subdirectory(aux/bifcl)
endif ()
if (ENABLE_JEMALLOC)
find_package(JeMalloc)
endif ()

1
aux/bifcl Submodule

@ -0,0 +1 @@
Subproject commit a25704cc769438b6ecaf92331511456826e90409

2
cmake

@ -1 +1 @@
Subproject commit 1600554d1d907f4f252f19cf1f55e13d368a936f
Subproject commit a416553abcb7aa650e934cd3800bcab0cbcf3e63

View file

@ -44,15 +44,6 @@ endmacro(REPLACE_YY_PREFIX_TARGET)
set(BISON_FLAGS "--debug")
# BIF parser/scanner
bison_target(BIFParser builtin-func.y
${CMAKE_CURRENT_BINARY_DIR}/bif_parse.cc
HEADER ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.h
#VERBOSE ${CMAKE_CURRENT_BINARY_DIR}/bif_parse.output
COMPILE_FLAGS "${BISON_FLAGS}")
flex_target(BIFScanner builtin-func.l ${CMAKE_CURRENT_BINARY_DIR}/bif_lex.cc)
add_flex_bison_dependency(BIFScanner BIFParser)
# Rule parser/scanner
bison_target(RuleParser rule-parse.y
${CMAKE_CURRENT_BINARY_DIR}/rup.cc
@ -93,24 +84,6 @@ replace_yy_prefix_target(${CMAKE_CURRENT_BINARY_DIR}/p.cc
flex_target(Scanner scan.l ${CMAKE_CURRENT_BINARY_DIR}/scan.cc
COMPILE_FLAGS "-Pbro")
########################################################################
## bifcl (BIF compiler) target
set(bifcl_SRCS
${BISON_BIFParser_INPUT}
${FLEX_BIFScanner_INPUT}
${BISON_BIFParser_OUTPUTS}
${FLEX_BIFScanner_OUTPUTS}
bif_arg.cc
module_util.cc
bif_arg.h
module_util.h
)
add_executable(bifcl ${bifcl_SRCS})
target_link_libraries(bifcl)
########################################################################
## bifcl-dependent targets

View file

@ -1,83 +0,0 @@
#include "bro-config.h"
#include <set>
#include <string>
using namespace std;
#include <string.h>
#include "bif_arg.h"
static struct {
const char* bif_type;
const char* bro_type;
const char* c_type;
const char* accessor;
const char* constructor;
} builtin_func_arg_type[] = {
#define DEFINE_BIF_TYPE(id, bif_type, bro_type, c_type, accessor, constructor) \
{bif_type, bro_type, c_type, accessor, constructor},
#include "bif_type.def"
#undef DEFINE_BIF_TYPE
};
extern const char* arg_list_name;
BuiltinFuncArg::BuiltinFuncArg(const char* arg_name, int arg_type)
{
name = arg_name;
type = arg_type;
type_str = "";
attr_str = "";
}
BuiltinFuncArg::BuiltinFuncArg(const char* arg_name, const char* arg_type_str,
const char* arg_attr_str)
{
name = arg_name;
type = TYPE_OTHER;
type_str = arg_type_str;
attr_str = arg_attr_str;
for ( int i = 0; builtin_func_arg_type[i].bif_type[0] != '\0'; ++i )
if ( ! strcmp(builtin_func_arg_type[i].bif_type, arg_type_str) )
{
type = i;
type_str = "";
}
}
void BuiltinFuncArg::PrintBro(FILE* fp)
{
fprintf(fp, "%s: %s%s %s", name, builtin_func_arg_type[type].bro_type,
type_str, attr_str);
}
void BuiltinFuncArg::PrintCDef(FILE* fp, int n)
{
fprintf(fp,
"\t%s %s = (%s) (",
builtin_func_arg_type[type].c_type,
name,
builtin_func_arg_type[type].c_type);
char buf[1024];
snprintf(buf, sizeof(buf), "(*%s)[%d]", arg_list_name, n);
// Print the accessor expression.
fprintf(fp, builtin_func_arg_type[type].accessor, buf);
fprintf(fp, ");\n");
}
void BuiltinFuncArg::PrintCArg(FILE* fp, int n)
{
const char* ctype = builtin_func_arg_type[type].c_type;
char buf[1024];
fprintf(fp, "%s %s", ctype, name);
}
void BuiltinFuncArg::PrintBroValConstructor(FILE* fp)
{
fprintf(fp, builtin_func_arg_type[type].constructor, name);
}

View file

@ -1,51 +0,0 @@
#ifndef bif_arg_h
#define bif_arg_h
#include <stdio.h>
enum builtin_func_arg_type {
#define DEFINE_BIF_TYPE(id, bif_type, bro_type, c_type, accessor, constructor) \
id,
#include "bif_type.def"
#undef DEFINE_BIF_TYPE
/*
TYPE_ANY,
TYPE_BOOL,
TYPE_COUNT,
TYPE_INT,
TYPE_STRING,
TYPE_PATTERN,
TYPE_PORT,
TYPE_OTHER,
*/
};
extern const char* builtin_func_arg_type_bro_name[];
class BuiltinFuncArg {
public:
BuiltinFuncArg(const char* arg_name, int arg_type);
BuiltinFuncArg(const char* arg_name, const char* arg_type_str,
const char* arg_attr_str = "");
void SetAttrStr(const char* arg_attr_str)
{
attr_str = arg_attr_str;
};
const char* Name() const { return name; }
int Type() const { return type; }
void PrintBro(FILE* fp);
void PrintCDef(FILE* fp, int n);
void PrintCArg(FILE* fp, int n);
void PrintBroValConstructor(FILE* fp);
protected:
const char* name;
int type;
const char* type_str;
const char* attr_str;
};
#endif

View file

@ -1,22 +0,0 @@
// DEFINE_BIF_TYPE(id, bif_type, bro_type, c_type, accessor, constructor)
DEFINE_BIF_TYPE(TYPE_ADDR, "addr", "addr", "AddrVal*", "%s->AsAddrVal()", "%s")
DEFINE_BIF_TYPE(TYPE_ANY, "any", "any", "Val*", "%s", "%s")
DEFINE_BIF_TYPE(TYPE_BOOL, "bool", "bool", "int", "%s->AsBool()", "new Val(%s, TYPE_BOOL)")
DEFINE_BIF_TYPE(TYPE_CONN_ID, "conn_id", "conn_id", "Val*", "%s", "%s")
DEFINE_BIF_TYPE(TYPE_CONNECTION, "connection", "connection", "Connection*", "%s->AsRecordVal()->GetOrigin()", "%s->BuildConnVal()")
DEFINE_BIF_TYPE(TYPE_COUNT, "count", "count", "bro_uint_t", "%s->AsCount()", "new Val(%s, TYPE_COUNT)")
DEFINE_BIF_TYPE(TYPE_DOUBLE, "double", "double", "double", "%s->AsDouble()", "new Val(%s, TYPE_DOUBLE)")
DEFINE_BIF_TYPE(TYPE_FILE, "file", "file", "BroFile*", "%s->AsFile()", "new Val(%s)")
DEFINE_BIF_TYPE(TYPE_INT, "int", "int", "bro_int_t", "%s->AsInt()", "new Val(%s, TYPE_INT)")
DEFINE_BIF_TYPE(TYPE_INTERVAL, "interval", "interval", "double", "%s->AsInterval()", "new IntervalVal(%s, Seconds)")
DEFINE_BIF_TYPE(TYPE_PACKET, "packet", "packet", "TCP_TracePacket*", "%s->AsRecordVal()->GetOrigin()", "%s->PacketVal()")
DEFINE_BIF_TYPE(TYPE_PATTERN, "pattern", "pattern", "RE_Matcher*", "%s->AsPattern()", "new PatternVal(%s)")
// DEFINE_BIF_TYPE(TYPE_PORT, "port", "port", "uint32", "%s->AsPortVal()->Port()", "incomplete data")
DEFINE_BIF_TYPE(TYPE_PORT, "port", "port", "PortVal*", "%s->AsPortVal()", "%s")
DEFINE_BIF_TYPE(TYPE_PORTVAL, "portval", "port", "PortVal*", "%s->AsPortVal()", "%s")
DEFINE_BIF_TYPE(TYPE_STRING, "string", "string", "StringVal*", "%s->AsStringVal()", "%s")
// DEFINE_BIF_TYPE(TYPE_STRING, "string", "string", "BroString*", "%s->AsString()", "new StringVal(%s)")
DEFINE_BIF_TYPE(TYPE_SUBNET, "subnet", "subnet", "SubNetVal*", "%s->AsSubNetVal()", "%s")
DEFINE_BIF_TYPE(TYPE_TIME, "time", "time", "double", "%s->AsTime()", "new Val(%s, TYPE_TIME)")
DEFINE_BIF_TYPE(TYPE_OTHER, "", "", "Val*", "%s", "%s")

View file

@ -1,422 +0,0 @@
%{
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include "bif_arg.h"
#include "bif_parse.h"
char* copy_string(const char* s)
{
char* c = new char[strlen(s)+1];
strcpy(c, s);
return c;
}
int line_number = 1;
extern int in_c_code;
int check_c_mode(int t)
{
if ( ! in_c_code )
return t;
yylval.str = copy_string(yytext);
return TOK_C_TOKEN;
}
%}
WS [ \t]+
OWS [ \t]*
/* Note, bifcl only accepts a single "::" in IDs while the policy
layer acceptes multiple. (But the policy layer doesn't have
a hierachy. */
IDCOMPONENT [A-Za-z_][A-Za-z_0-9]*
ID {IDCOMPONENT}(::{IDCOMPONENT})?
ESCSEQ (\\([^\n]|[0-7]+|x[[:xdigit:]]+))
DEC [[:digit:]]+
HEX [0-9a-fA-F]+
%option nodefault
%%
#.* {
yylval.str = copy_string(yytext);
return TOK_COMMENT;
}
\n {
++line_number;
return TOK_LF;
}
{WS} {
yylval.str = copy_string(yytext);
return TOK_WS;
}
[=,:;] return check_c_mode(yytext[0]);
"%{" return TOK_LPB;
"%}" return TOK_RPB;
"%%{" return TOK_LPPB;
"%%}" return TOK_RPPB;
"%(" return check_c_mode(TOK_LPP);
"%)" return check_c_mode(TOK_RPP);
"..." return check_c_mode(TOK_VAR_ARG);
"function" return check_c_mode(TOK_FUNCTION);
"event" return check_c_mode(TOK_EVENT);
"const" return check_c_mode(TOK_CONST);
"enum" return check_c_mode(TOK_ENUM);
"type" return check_c_mode(TOK_TYPE);
"record" return check_c_mode(TOK_RECORD);
"set" return check_c_mode(TOK_SET);
"table" return check_c_mode(TOK_TABLE);
"vector" return check_c_mode(TOK_VECTOR);
"of" return check_c_mode(TOK_OF);
"opaque" return check_c_mode(TOK_OPAQUE);
"module" return check_c_mode(TOK_MODULE);
"@ARG@" return TOK_ARG;
"@ARGS@" return TOK_ARGS;
"@ARGC@" return TOK_ARGC;
"T" yylval.val = 1; return TOK_BOOL;
"F" yylval.val = 0; return TOK_BOOL;
{DEC} {
yylval.str = copy_string(yytext);
return TOK_INT;
}
"0x"{HEX} {
yylval.str = copy_string(yytext);
return TOK_INT;
}
{ID} {
yylval.str = copy_string(yytext);
return TOK_ID;
}
/*
Hacky way to pass along arbitrary attribute expressions since the BIF parser
has little understanding of valid Bro expressions. With this pattern, the
attribute expression should stop when it reaches another attribute, another
function argument, or the end of the function declaration.
*/
&{ID}({OWS}={OWS}[^&%;,]+)? {
int t = check_c_mode(TOK_ATTR);
if ( t == TOK_ATTR )
{
yylval.str = copy_string(yytext);
return TOK_ATTR;
}
else
return t;
}
\"([^\\\n\"]|{ESCSEQ})*\" {
yylval.str = copy_string(yytext);
return TOK_CSTR;
}
\'([^\\\n\']|{ESCSEQ})*\' {
yylval.str = copy_string(yytext);
return TOK_CSTR;
}
. {
yylval.val = yytext[0];
return TOK_ATOM;
}
%%
int yywrap()
{
yy_delete_buffer(YY_CURRENT_BUFFER);
return 1;
}
extern int yyparse();
char* input_filename = 0;
char* input_filename_with_path = 0;
char* plugin = 0;
int alternative_mode = 0;
FILE* fp_bro_init = 0;
FILE* fp_func_def = 0;
FILE* fp_func_h = 0;
FILE* fp_func_init = 0;
FILE* fp_func_register = 0;
FILE* fp_netvar_h = 0;
FILE* fp_netvar_def = 0;
FILE* fp_netvar_init = 0;
void remove_file(const char *surfix);
void err_exit(void);
FILE* open_output_file(const char* surfix);
void close_if_open(FILE **fpp);
void close_all_output_files(void);
FILE* open_output_file(const char* surfix)
{
char fn[1024];
FILE* fp;
snprintf(fn, sizeof(fn), "%s.%s", input_filename, surfix);
if ( (fp = fopen(fn, "w")) == NULL )
{
fprintf(stderr, "Error: cannot open file: %s\n", fn);
err_exit();
}
return fp;
}
void usage()
{
fprintf(stderr, "usage: bifcl [-p <plugin> | -s] *.bif\n");
exit(1);
}
void init_alternative_mode()
{
fp_bro_init = open_output_file("bro");
fp_func_h = open_output_file("h");
fp_func_def = open_output_file("cc");
fp_func_init = open_output_file("init.cc");
fp_func_register = plugin ? open_output_file("register.cc") : NULL;
fp_netvar_h = fp_func_h;
fp_netvar_def = fp_func_def;
fp_netvar_init = fp_func_init;
int n = 1024 + strlen(input_filename);
char auto_gen_comment[n];
snprintf(auto_gen_comment, n,
"This file was automatically generated by bifcl from %s (%s mode).",
input_filename_with_path, plugin ? "plugin" : "alternative");
fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment);
fprintf(fp_func_def, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_h, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_init, "// %s\n\n", auto_gen_comment);
if ( fp_func_register )
fprintf(fp_func_register, "// %s\n\n", auto_gen_comment);
static char guard[1024];
if ( getcwd(guard, sizeof(guard)) == NULL )
{
fprintf(stderr, "Error: cannot get current working directory\n");
err_exit();
}
strncat(guard, "/", sizeof(guard) - strlen(guard) - 1);
strncat(guard, input_filename, sizeof(guard) - strlen(guard) - 1);
for ( char* p = guard; *p; p++ )
{
if ( ! isalnum(*p) )
*p = '_';
}
fprintf(fp_func_h, "#if defined(BRO_IN_NETVAR) || ! defined(%s)\n", guard);
fprintf(fp_func_h, "#ifndef BRO_IN_NETVAR\n");
fprintf(fp_func_h, "#ifndef %s\n", guard);
fprintf(fp_func_h, "#define %s\n", guard);
fprintf(fp_func_h, "#include \"bro-bif.h\"\n");
fprintf(fp_func_h, "#endif\n");
fprintf(fp_func_h, "#endif\n");
fprintf(fp_func_h, "\n");
fprintf(fp_func_def, "\n");
fprintf(fp_func_def, "#include \"%s.h\"\n", input_filename);
fprintf(fp_func_def, "\n");
static char name[1024];
strncpy(name, input_filename, sizeof(name));
char* dot = strchr(name, '.');
if ( dot )
*dot = '\0';
if ( plugin )
{
static char plugin_canon[1024];
strncpy(plugin_canon, plugin, sizeof(plugin_canon));
char* colon = strstr(plugin_canon, "::");
if ( colon ) {
*colon = '_';
memmove(colon + 1, colon + 2, plugin_canon + strlen(plugin_canon) - colon);
}
fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "#include <list>\n");
fprintf(fp_func_init, "#include <string>\n");
fprintf(fp_func_init, "#include \"plugin/Plugin.h\"\n");
fprintf(fp_func_init, "#include \"%s.h\"\n", input_filename);
fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "namespace plugin { namespace %s {\n", plugin_canon);
fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "void __bif_%s_init(plugin::Plugin* plugin)\n", name);
fprintf(fp_func_init, "\t{\n");
fprintf(fp_func_register, "#include \"plugin/Manager.h\"\n");
fprintf(fp_func_register, "\n");
fprintf(fp_func_register, "namespace plugin { namespace %s {\n", plugin_canon);
fprintf(fp_func_register, "void __bif_%s_init(plugin::Plugin* plugin);\n", name);
fprintf(fp_func_register, "::plugin::__RegisterBif __register_bifs_%s_%s(\"%s\", __bif_%s_init);\n", plugin_canon, name, plugin, name);
fprintf(fp_func_register, "} }\n");
}
}
void finish_alternative_mode()
{
fprintf(fp_func_h, "\n");
fprintf(fp_func_h, "#endif\n");
if ( plugin )
{
fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "\t}\n");
fprintf(fp_func_init, "} }\n");
fprintf(fp_func_init, "\n");
fprintf(fp_func_init, "\n");
}
}
int main(int argc, char* argv[])
{
int opt;
while ( (opt = getopt(argc, argv, "p:s")) != -1 )
{
switch ( opt ) {
case 'p':
alternative_mode = 1;
plugin = optarg;
break;
case 's':
alternative_mode = 1;
break;
default:
usage();
}
}
for ( int i = optind; i < argc; i++ )
{
FILE* fp_input;
char* slash;
input_filename = input_filename_with_path = argv[i];
slash = strrchr(input_filename, '/');
if ( (fp_input = fopen(input_filename, "r")) == NULL )
{
fprintf(stderr, "Error: cannot open file: %s\n", input_filename);
/* no output files open. can simply exit */
exit(1);
}
if ( slash )
input_filename = slash + 1;
if ( ! alternative_mode )
{
fp_bro_init = open_output_file("bro");
fp_func_h = open_output_file("func_h");
fp_func_def = open_output_file("func_def");
fp_func_init = open_output_file("func_init");
fp_netvar_h = open_output_file("netvar_h");
fp_netvar_def = open_output_file("netvar_def");
fp_netvar_init = open_output_file("netvar_init");
int n = 1024 + strlen(input_filename);
char auto_gen_comment[n];
snprintf(auto_gen_comment, n,
"This file was automatically generated by bifcl from %s.",
input_filename);
fprintf(fp_bro_init, "# %s\n\n", auto_gen_comment);
fprintf(fp_func_def, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_h, "// %s\n\n", auto_gen_comment);
fprintf(fp_func_init, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_def, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_h, "// %s\n\n", auto_gen_comment);
fprintf(fp_netvar_init, "// %s\n\n", auto_gen_comment);
}
else
init_alternative_mode();
yy_switch_to_buffer(yy_create_buffer(fp_input, YY_BUF_SIZE));
yyparse();
if ( alternative_mode )
finish_alternative_mode();
fclose(fp_input);
close_all_output_files();
}
}
void close_if_open(FILE **fpp)
{
if (*fpp)
fclose(*fpp);
*fpp = NULL;
}
void close_all_output_files(void)
{
close_if_open(&fp_bro_init);
close_if_open(&fp_func_h);
close_if_open(&fp_func_def);
close_if_open(&fp_func_init);
close_if_open(&fp_func_register);
if ( ! alternative_mode )
{
close_if_open(&fp_netvar_h);
close_if_open(&fp_netvar_def);
close_if_open(&fp_netvar_init);
}
}
void remove_file(const char *surfix)
{
char fn[1024];
snprintf(fn, sizeof(fn), "%s.%s", input_filename, surfix);
unlink(fn);
}
void err_exit(void)
{
close_all_output_files();
/* clean up. remove all output files we've generated so far */
remove_file("bro");
remove_file("func_h");
remove_file("func_def");
remove_file("func_init");
remove_file("func_register");
remove_file("netvar_h");
remove_file("netvar_def");
remove_file("netvar_init");
exit(1);
}

View file

@ -1,785 +0,0 @@
%{
#include <vector>
#include <set>
#include <string>
#include <cstring>
using namespace std;
#include <stdio.h>
#include <stdlib.h>
#include "module_util.h"
using namespace std;
extern int line_number;
extern char* input_filename;
extern char* plugin;
#define print_line_directive(fp) fprintf(fp, "\n#line %d \"%s\"\n", line_number, input_filename)
extern FILE* fp_bro_init;
extern FILE* fp_func_def;
extern FILE* fp_func_h;
extern FILE* fp_func_init;
extern FILE* fp_netvar_h;
extern FILE* fp_netvar_def;
extern FILE* fp_netvar_init;
int in_c_code = 0;
string current_module = GLOBAL_MODULE_NAME;
int definition_type;
string type_name;
enum {
C_SEGMENT_DEF,
FUNC_DEF,
EVENT_DEF,
TYPE_DEF,
CONST_DEF,
};
// Holds the name of a declared object (function, enum, record type, event,
// etc. and information about namespaces, etc.
struct decl_struct {
string module_name;
string bare_name; // name without module or namespace
string c_namespace_start; // "opening" namespace for use in netvar_*
string c_namespace_end; // closing "}" for all the above namespaces
string c_fullname; // fully qualified name (namespace::....) for use in netvar_init
string bro_fullname; // fully qualified bro name, for netvar (and lookup_ID())
string bro_name; // the name as we read it from input. What we write into the .bro file
// special cases for events. Events have an EventHandlerPtr
// and a generate_* function. This name is for the generate_* function
string generate_bare_name;
string generate_c_fullname;
string generate_c_namespace_start;
string generate_c_namespace_end;
} decl;
void set_definition_type(int type, const char *arg_type_name)
{
definition_type = type;
if ( type == TYPE_DEF && arg_type_name )
type_name = string(arg_type_name);
else
type_name = "";
}
void set_decl_name(const char *name)
{
decl.bare_name = extract_var_name(name);
// make_full_var_name prepends the correct module, if any
// then we can extract the module name again.
string varname = make_full_var_name(current_module.c_str(), name);
decl.module_name = extract_module_name(varname.c_str());
decl.c_namespace_start = "";
decl.c_namespace_end = "";
decl.c_fullname = "";
decl.bro_fullname = "";
decl.bro_name = "";
decl.generate_c_fullname = "";
decl.generate_bare_name = string("generate_") + decl.bare_name;
decl.generate_c_namespace_start = "";
decl.generate_c_namespace_end = "";
switch ( definition_type ) {
case TYPE_DEF:
decl.c_namespace_start = "namespace BifType { namespace " + type_name + "{ ";
decl.c_namespace_end = " } }";
decl.c_fullname = "BifType::" + type_name + "::";
break;
case CONST_DEF:
decl.c_namespace_start = "namespace BifConst { ";
decl.c_namespace_end = " } ";
decl.c_fullname = "BifConst::";
break;
case FUNC_DEF:
decl.c_namespace_start = "namespace BifFunc { ";
decl.c_namespace_end = " } ";
decl.c_fullname = "BifFunc::";
break;
case EVENT_DEF:
decl.c_namespace_start = "";
decl.c_namespace_end = "";
decl.c_fullname = "::"; // need this for namespace qualified events due do event_c_body
decl.generate_c_namespace_start = "namespace BifEvent { ";
decl.generate_c_namespace_end = " } ";
decl.generate_c_fullname = "BifEvent::";
break;
default:
break;
}
if ( decl.module_name != GLOBAL_MODULE_NAME )
{
decl.c_namespace_start += "namespace " + decl.module_name + " { ";
decl.c_namespace_end += string(" }");
decl.c_fullname += decl.module_name + "::";
decl.bro_fullname += decl.module_name + "::";
decl.generate_c_namespace_start += "namespace " + decl.module_name + " { ";
decl.generate_c_namespace_end += " } ";
decl.generate_c_fullname += decl.module_name + "::";
}
decl.bro_fullname += decl.bare_name;
if ( definition_type == FUNC_DEF )
decl.bare_name = string("bro_") + decl.bare_name;
decl.c_fullname += decl.bare_name;
decl.bro_name += name;
decl.generate_c_fullname += decl.generate_bare_name;
}
const char* arg_list_name = "BiF_ARGS";
#include "bif_arg.h"
/* Map bif/bro type names to C types for use in const declaration */
static struct {
const char* bif_type;
const char* bro_type;
const char* c_type;
const char* accessor;
const char* constructor;
} builtin_types[] = {
#define DEFINE_BIF_TYPE(id, bif_type, bro_type, c_type, accessor, constructor) \
{bif_type, bro_type, c_type, accessor, constructor},
#include "bif_type.def"
#undef DEFINE_BIF_TYPE
};
int get_type_index(const char *type_name)
{
for ( int i = 0; builtin_types[i].bif_type[0] != '\0'; ++i )
{
if ( strcmp(builtin_types[i].bif_type, type_name) == 0 )
return i;
}
return TYPE_OTHER;
}
int var_arg; // whether the number of arguments is variable
std::vector<BuiltinFuncArg*> args;
extern int yyerror(const char[]);
extern int yywarn(const char msg[]);
extern int yylex();
char* concat(const char* str1, const char* str2)
{
int len1 = strlen(str1);
int len2 = strlen(str2);
char* s = new char[len1 + len2 +1];
memcpy(s, str1, len1);
memcpy(s + len1, str2, len2);
s[len1+len2] = '\0';
return s;
}
// Print the bro_event_* function prototype in C++, without the ending ';'
void print_event_c_prototype(FILE *fp, bool is_header)
{
if ( is_header )
fprintf(fp, "%s void %s(analyzer::Analyzer* analyzer%s",
decl.generate_c_namespace_start.c_str(), decl.generate_bare_name.c_str(),
args.size() ? ", " : "" );
else
fprintf(fp, "void %s(analyzer::Analyzer* analyzer%s",
decl.generate_c_fullname.c_str(),
args.size() ? ", " : "" );
for ( int i = 0; i < (int) args.size(); ++i )
{
if ( i > 0 )
fprintf(fp, ", ");
args[i]->PrintCArg(fp, i);
}
fprintf(fp, ")");
if ( is_header )
fprintf(fp, "; %s\n", decl.generate_c_namespace_end.c_str());
else
fprintf(fp, "\n");
}
// Print the bro_event_* function body in C++.
void print_event_c_body(FILE *fp)
{
fprintf(fp, "\t{\n");
fprintf(fp, "\t// Note that it is intentional that here we do not\n");
fprintf(fp, "\t// check if %s is NULL, which should happen *before*\n",
decl.c_fullname.c_str());
fprintf(fp, "\t// %s is called to avoid unnecessary Val\n",
decl.generate_c_fullname.c_str());
fprintf(fp, "\t// allocation.\n");
fprintf(fp, "\n");
fprintf(fp, "\tval_list* vl = new val_list;\n\n");
BuiltinFuncArg *connection_arg = 0;
for ( int i = 0; i < (int) args.size(); ++i )
{
fprintf(fp, "\t");
fprintf(fp, "vl->append(");
args[i]->PrintBroValConstructor(fp);
fprintf(fp, ");\n");
if ( args[i]->Type() == TYPE_CONNECTION )
{
if ( connection_arg == 0 )
connection_arg = args[i];
else
{
// We are seeing two connection type arguments.
yywarn("Warning: with more than connection-type "
"event arguments, bifcl only passes "
"the first one to EventMgr as cookie.");
}
}
}
fprintf(fp, "\n");
fprintf(fp, "\tmgr.QueueEvent(%s, vl, SOURCE_LOCAL, analyzer->GetID(), timer_mgr",
decl.c_fullname.c_str());
if ( connection_arg )
// Pass the connection to the EventMgr as the "cookie"
fprintf(fp, ", %s", connection_arg->Name());
fprintf(fp, ");\n");
fprintf(fp, "\t} // event generation\n");
//fprintf(fp, "%s // end namespace\n", decl.generate_c_namespace_end.c_str());
}
void record_bif_item(const char* id, const char* type)
{
if ( ! plugin )
return;
fprintf(fp_func_init, "\tplugin->AddBifItem(\"%s\", plugin::BifItem::%s);\n", id, type);
}
%}
%token TOK_LPP TOK_RPP TOK_LPB TOK_RPB TOK_LPPB TOK_RPPB TOK_VAR_ARG
%token TOK_BOOL
%token TOK_FUNCTION TOK_EVENT TOK_CONST TOK_ENUM TOK_OF
%token TOK_TYPE TOK_RECORD TOK_SET TOK_VECTOR TOK_OPAQUE TOK_TABLE TOK_MODULE
%token TOK_ARGS TOK_ARG TOK_ARGC
%token TOK_ID TOK_ATTR TOK_CSTR TOK_LF TOK_WS TOK_COMMENT
%token TOK_ATOM TOK_INT TOK_C_TOKEN
%left ',' ':'
%type <str> TOK_C_TOKEN TOK_ID TOK_CSTR TOK_WS TOK_COMMENT TOK_ATTR TOK_INT opt_ws type attr_list opt_attr_list opt_func_attrs
%type <val> TOK_ATOM TOK_BOOL
%union {
const char* str;
int val;
}
%%
builtin_lang: definitions
{
fprintf(fp_bro_init, "} # end of export section\n");
fprintf(fp_bro_init, "module %s;\n", GLOBAL_MODULE_NAME);
}
definitions: definitions definition opt_ws
{
if ( in_c_code )
fprintf(fp_func_def, "%s", $3);
else
fprintf(fp_bro_init, "%s", $3);
}
| opt_ws
{
fprintf(fp_bro_init, "%s", $1);
fprintf(fp_bro_init, "export {\n");
}
;
definition: event_def
| func_def
| c_code_segment
| enum_def
| const_def
| type_def
| module_def
;
module_def: TOK_MODULE opt_ws TOK_ID opt_ws ';'
{
current_module = string($3);
fprintf(fp_bro_init, "module %s;\n", $3);
}
// XXX: Add the netvar glue so that the event engine knows about
// the type. One still has to define the type in bro.init.
// Would be nice, if we could just define the record type here
// and then copy to the .bif.bro file, but type declarations in
// Bro can be quite powerful. Don't know whether it's worth it
// extend the bif-language to be able to handle that all....
// Or we just support a simple form of record type definitions
// TODO: add other types (tables, sets)
type_def: TOK_TYPE opt_ws TOK_ID opt_ws ':' opt_ws type_def_types opt_ws ';'
{
set_decl_name($3);
fprintf(fp_netvar_h, "%s extern %sType * %s; %s\n",
decl.c_namespace_start.c_str(), type_name.c_str(),
decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_def, "%s %sType * %s; %s\n",
decl.c_namespace_start.c_str(), type_name.c_str(),
decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_init,
"\t%s = internal_type(\"%s\")->As%sType();\n",
decl.c_fullname.c_str(), decl.bro_fullname.c_str(),
type_name.c_str());
record_bif_item(decl.bro_fullname.c_str(), "TYPE");
}
;
type_def_types: TOK_RECORD
{ set_definition_type(TYPE_DEF, "Record"); }
| TOK_SET
{ set_definition_type(TYPE_DEF, "Set"); }
| TOK_VECTOR
{ set_definition_type(TYPE_DEF, "Vector"); }
| TOK_TABLE
{ set_definition_type(TYPE_DEF, "Table"); }
;
opt_func_attrs: attr_list opt_ws
{ $$ = $1; }
| /* nothing */
{ $$ = ""; }
;
event_def: event_prefix opt_ws plain_head opt_func_attrs
{ fprintf(fp_bro_init, "%s", $4); } end_of_head ';'
{
print_event_c_prototype(fp_func_h, true);
print_event_c_prototype(fp_func_def, false);
print_event_c_body(fp_func_def);
}
func_def: func_prefix opt_ws typed_head opt_func_attrs
{ fprintf(fp_bro_init, "%s", $4); } end_of_head body
;
enum_def: enum_def_1 enum_list TOK_RPB opt_attr_list
{
// First, put an end to the enum type decl.
fprintf(fp_bro_init, "} ");
fprintf(fp_bro_init, "%s", $4);
fprintf(fp_bro_init, ";\n");
if ( decl.module_name != GLOBAL_MODULE_NAME )
fprintf(fp_netvar_h, "}; } }\n");
else
fprintf(fp_netvar_h, "}; }\n");
// Now generate the netvar's.
fprintf(fp_netvar_h, "%s extern EnumType * %s; %s\n",
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_def, "%s EnumType * %s; %s\n",
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_init,
"\t%s = internal_type(\"%s\")->AsEnumType();\n",
decl.c_fullname.c_str(), decl.bro_fullname.c_str());
record_bif_item(decl.bro_fullname.c_str(), "TYPE");
}
;
enum_def_1: TOK_ENUM opt_ws TOK_ID opt_ws TOK_LPB opt_ws
{
set_definition_type(TYPE_DEF, "Enum");
set_decl_name($3);
fprintf(fp_bro_init, "type %s: enum %s{%s", decl.bro_name.c_str(), $4, $6);
// this is the namespace were the enumerators are defined, not where
// the type is defined.
// We don't support fully qualified names as enumerators. Use a module name
fprintf(fp_netvar_h, "namespace BifEnum { ");
if ( decl.module_name != GLOBAL_MODULE_NAME )
fprintf(fp_netvar_h, "namespace %s { ", decl.module_name.c_str());
fprintf(fp_netvar_h, "enum %s {\n", $3);
}
;
enum_list: enum_list TOK_ID opt_ws ',' opt_ws
{
fprintf(fp_bro_init, "%s%s,%s", $2, $3, $5);
fprintf(fp_netvar_h, "\t%s,\n", $2);
}
| enum_list TOK_ID opt_ws '=' opt_ws TOK_INT opt_ws ',' opt_ws
{
fprintf(fp_bro_init, "%s = %s%s,%s", $2, $6, $7, $9);
fprintf(fp_netvar_h, "\t%s = %s,\n", $2, $6);
}
| /* nothing */
;
const_def: TOK_CONST opt_ws TOK_ID opt_ws ':' opt_ws TOK_ID opt_ws ';'
{
set_definition_type(CONST_DEF, 0);
set_decl_name($3);
int typeidx = get_type_index($7);
char accessor[1024];
snprintf(accessor, sizeof(accessor), builtin_types[typeidx].accessor, "");
fprintf(fp_netvar_h, "%s extern %s %s; %s\n",
decl.c_namespace_start.c_str(),
builtin_types[typeidx].c_type, decl.bare_name.c_str(),
decl.c_namespace_end.c_str());
fprintf(fp_netvar_def, "%s %s %s; %s\n",
decl.c_namespace_start.c_str(),
builtin_types[typeidx].c_type, decl.bare_name.c_str(),
decl.c_namespace_end.c_str());
fprintf(fp_netvar_init, "\t%s = internal_const_val(\"%s\")%s;\n",
decl.c_fullname.c_str(), decl.bro_fullname.c_str(),
accessor);
record_bif_item(decl.bro_fullname.c_str(), "CONSTANT");
}
attr_list:
attr_list TOK_ATTR
{ $$ = concat($1, $2); }
|
TOK_ATTR
;
opt_attr_list:
attr_list
| /* nothing */
{ $$ = ""; }
;
func_prefix: TOK_FUNCTION
{ set_definition_type(FUNC_DEF, 0); }
;
event_prefix: TOK_EVENT
{ set_definition_type(EVENT_DEF, 0); }
;
end_of_head: /* nothing */
{
fprintf(fp_bro_init, ";\n");
}
;
typed_head: plain_head return_type
{
}
;
plain_head: head_1 args arg_end opt_ws
{
if ( var_arg )
fprintf(fp_bro_init, "va_args: any");
else
{
for ( int i = 0; i < (int) args.size(); ++i )
{
if ( i > 0 )
fprintf(fp_bro_init, ", ");
args[i]->PrintBro(fp_bro_init);
}
}
fprintf(fp_bro_init, ")");
fprintf(fp_bro_init, "%s", $4);
fprintf(fp_func_def, "%s", $4);
}
;
head_1: TOK_ID opt_ws arg_begin
{
const char* method_type = 0;
set_decl_name($1);
if ( definition_type == FUNC_DEF )
{
method_type = "function";
print_line_directive(fp_func_def);
}
else if ( definition_type == EVENT_DEF )
method_type = "event";
if ( method_type )
fprintf(fp_bro_init,
"global %s: %s%s(",
decl.bro_name.c_str(), method_type, $2);
if ( definition_type == FUNC_DEF )
{
fprintf(fp_func_init,
"\t(void) new BuiltinFunc(%s, \"%s\", 0);\n",
decl.c_fullname.c_str(), decl.bro_fullname.c_str());
fprintf(fp_func_h,
"%sextern Val* %s(Frame* frame, val_list*);%s\n",
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_func_def,
"Val* %s(Frame* frame, val_list* %s)",
decl.c_fullname.c_str(), arg_list_name);
record_bif_item(decl.bro_fullname.c_str(), "FUNCTION");
}
else if ( definition_type == EVENT_DEF )
{
// TODO: add namespace for events here
fprintf(fp_netvar_h,
"%sextern EventHandlerPtr %s; %s\n",
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_def,
"%sEventHandlerPtr %s; %s\n",
decl.c_namespace_start.c_str(), decl.bare_name.c_str(), decl.c_namespace_end.c_str());
fprintf(fp_netvar_init,
"\t%s = internal_handler(\"%s\");\n",
decl.c_fullname.c_str(), decl.bro_fullname.c_str());
record_bif_item(decl.bro_fullname.c_str(), "EVENT");
// C++ prototypes of bro_event_* functions will
// be generated later.
}
}
;
arg_begin: TOK_LPP
{ args.clear(); var_arg = 0; }
;
arg_end: TOK_RPP
;
args: args_1
| opt_ws
{ /* empty, to avoid yacc complaint about type clash */ }
;
args_1: args_1 ',' opt_ws arg opt_ws opt_attr_list
{ if ( ! args.empty() ) args[args.size()-1]->SetAttrStr($6); }
| opt_ws arg opt_ws opt_attr_list
{ if ( ! args.empty() ) args[args.size()-1]->SetAttrStr($4); }
;
// TODO: Migrate all other compound types to this rule. Once the BiF language
// can parse all regular Bro types, we can throw out the unnecessary
// boilerplate typedefs for addr_set, string_set, etc.
type:
TOK_OPAQUE opt_ws TOK_OF opt_ws TOK_ID
{ $$ = concat("opaque of ", $5); }
| TOK_ID
{ $$ = $1; }
;
arg: TOK_ID opt_ws ':' opt_ws type
{ args.push_back(new BuiltinFuncArg($1, $5)); }
| TOK_VAR_ARG
{
if ( definition_type == EVENT_DEF )
yyerror("events cannot have variable arguments");
var_arg = 1;
}
;
return_type: ':' opt_ws type opt_ws
{
BuiltinFuncArg* ret = new BuiltinFuncArg("", $3);
ret->PrintBro(fp_bro_init);
delete ret;
fprintf(fp_func_def, "%s", $4);
}
;
body: body_start c_body body_end
{
fprintf(fp_func_def, " // end of %s\n", decl.c_fullname.c_str());
print_line_directive(fp_func_def);
}
;
c_code_begin: /* empty */
{
in_c_code = 1;
print_line_directive(fp_func_def);
}
;
c_code_end: /* empty */
{ in_c_code = 0; }
;
body_start: TOK_LPB c_code_begin
{
int implicit_arg = 0;
int argc = args.size();
fprintf(fp_func_def, "{");
if ( argc > 0 || ! var_arg )
fprintf(fp_func_def, "\n");
if ( ! var_arg )
{
fprintf(fp_func_def, "\tif ( %s->length() != %d )\n", arg_list_name, argc);
fprintf(fp_func_def, "\t\t{\n");
fprintf(fp_func_def,
"\t\treporter->Error(\"%s() takes exactly %d argument(s)\");\n",
decl.bro_fullname.c_str(), argc);
fprintf(fp_func_def, "\t\treturn 0;\n");
fprintf(fp_func_def, "\t\t}\n");
}
else if ( argc > 0 )
{
fprintf(fp_func_def, "\tif ( %s->length() < %d )\n", arg_list_name, argc);
fprintf(fp_func_def, "\t\t{\n");
fprintf(fp_func_def,
"\t\treporter->Error(\"%s() takes at least %d argument(s)\");\n",
decl.bro_fullname.c_str(), argc);
fprintf(fp_func_def, "\t\treturn 0;\n");
fprintf(fp_func_def, "\t\t}\n");
}
for ( int i = 0; i < (int) args.size(); ++i )
args[i]->PrintCDef(fp_func_def, i + implicit_arg);
print_line_directive(fp_func_def);
}
;
body_end: TOK_RPB c_code_end
{
fprintf(fp_func_def, "}");
}
;
c_code_segment: TOK_LPPB c_code_begin c_body c_code_end TOK_RPPB
;
c_body: opt_ws
{ fprintf(fp_func_def, "%s", $1); }
| c_body c_atom opt_ws
{ fprintf(fp_func_def, "%s", $3); }
;
c_atom: TOK_ID
{ fprintf(fp_func_def, "%s", $1); }
| TOK_C_TOKEN
{ fprintf(fp_func_def, "%s", $1); }
| TOK_ARG
{ fprintf(fp_func_def, "(*%s)", arg_list_name); }
| TOK_ARGS
{ fprintf(fp_func_def, "%s", arg_list_name); }
| TOK_ARGC
{ fprintf(fp_func_def, "%s->length()", arg_list_name); }
| TOK_CSTR
{ fprintf(fp_func_def, "%s", $1); }
| TOK_ATOM
{ fprintf(fp_func_def, "%c", $1); }
| TOK_INT
{ fprintf(fp_func_def, "%s", $1); }
;
opt_ws: opt_ws TOK_WS
{ $$ = concat($1, $2); }
| opt_ws TOK_LF
{ $$ = concat($1, "\n"); }
| opt_ws TOK_COMMENT
{
if ( in_c_code )
$$ = concat($1, $2);
else
if ( $2[1] == '#' )
// This is a special type of comment that is used to
// generate bro script documentation, so pass it through.
$$ = concat($1, $2);
else
$$ = $1;
}
| /* empty */
{ $$ = ""; }
;
%%
extern char* yytext;
extern char* input_filename;
extern int line_number;
void err_exit(void);
void print_msg(const char msg[])
{
int msg_len = strlen(msg) + strlen(yytext) + 64;
char* msgbuf = new char[msg_len];
if ( yytext[0] == '\n' )
snprintf(msgbuf, msg_len, "%s, on previous line", msg);
else if ( yytext[0] == '\0' )
snprintf(msgbuf, msg_len, "%s, at end of file", msg);
else
snprintf(msgbuf, msg_len, "%s, at or near \"%s\"", msg, yytext);
/*
extern int column;
sprintf(msgbuf, "%*s\n%*s\n", column, "^", column, msg);
*/
if ( input_filename )
fprintf(stderr, "%s:%d: ", input_filename, line_number);
else
fprintf(stderr, "line %d: ", line_number);
fprintf(stderr, "%s\n", msgbuf);
delete [] msgbuf;
}
int yywarn(const char msg[])
{
print_msg(msg);
return 0;
}
int yyerror(const char msg[])
{
print_msg(msg);
err_exit();
return 0;
}