New BiF record_field_vals() that returns the fields of a record in a

table with meta-information.

Example:

type r: record {
	a: count;
	b: string &default="Foo";
	c: double &optional;
	d: string &log;
};

event bro_init()
{
    local x: r = [$a=42, $d="Bar"];
    print record_fields(x);
}

This prints:

  {
  [a] = [type_name=record, log=F, value=42, default_val=<uninitialized>]
  [b] = [type_name=record, log=F, value=<uninitialized>, default_val=Foo],
  [c] = [type_name=record, log=F, value=<uninitialized>, default_val=<uninitialized>],
  [d] = [type_name=record, log=T, value=Bar, default_val=<uninitialized>],
  }

This is one more step in Seth's quest for full inspection support. :-)
This commit is contained in:
Robin Sommer 2011-07-07 18:41:50 -07:00
parent cdd8827cc4
commit 8bacb6eb3d
9 changed files with 99 additions and 9 deletions

View file

@ -183,6 +183,17 @@ type script_id: record {
value: any &optional;
};
type id_table: table[string] of script_id;
type record_field: record {
type_name: string;
log: bool;
value: any &optional;
default_val: any &optional;
};
type record_field_table: table[string] of record_field;
# The following two variables are defined here until the core is not
# dependent on the names remaining as they are now.
## This is the list of capture filters indexed by some user-definable ID.
@ -190,8 +201,6 @@ global capture_filters: table[string] of string &redef;
## This is the list of restriction filters indexed by some user-definable ID.
global restrict_filters: table[string] of string &redef;
type id_table: table[string] of script_id;
# {precompile,install}_pcap_filter identify the filter by IDs
type PcapFilterID: enum { None };

View file

@ -248,6 +248,8 @@ int record_all_packets;
RecordType* script_id;
TableType* id_table;
RecordType* record_field;
TableType* record_field_table;
StringVal* cmd_line_bpf_filter;
@ -550,4 +552,6 @@ void init_net_var()
script_id = internal_type("script_id")->AsRecordType();
id_table = internal_type("id_table")->AsTableType();
record_field = internal_type("record_field")->AsRecordType();
record_field_table = internal_type("record_field_table")->AsTableType();
}

View file

@ -251,6 +251,8 @@ extern int record_all_packets;
extern RecordType* script_id;
extern TableType* id_table;
extern RecordType* record_field;
extern TableType* record_field_table;
extern StringVal* cmd_line_bpf_filter;

View file

@ -987,6 +987,18 @@ BroType* RecordType::FieldType(int field) const
}
}
Val* RecordType::FieldDefault(int field) const
{
const TypeDecl* td = FieldDecl(field);
if ( ! td->attrs )
return false;
const Attr* def_attr = td->attrs->FindAttr(ATTR_DEFAULT);
return def_attr ? def_attr->AttrExpr()->Eval(0) : 0;
}
int RecordType::FieldOffset(const char* field) const
{
if ( types )

View file

@ -448,6 +448,7 @@ public:
int HasField(const char* field) const;
BroType* FieldType(const char* field) const;
BroType* FieldType(int field) const;
Val* FieldDefault(int field) const; // Ref's the returned value; 0 if none.
// A field's offset is its position in the type_decl_list,
// starting at 0. Returns negative if the field doesn't exist.

View file

@ -2935,11 +2935,7 @@ Val* RecordVal::LookupWithDefault(int field) const
if ( val )
return val->Ref();
// Check for &default.
const Attr* def_attr =
record_type->FieldDecl(field)->attrs->FindAttr(ATTR_DEFAULT);
return def_attr ? def_attr->AttrExpr()->Eval(0) : 0;
return record_type->FieldDefault(field);
}
RecordVal* RecordVal::CoerceTo(const RecordType* t, Val* aggr) const

View file

@ -1657,6 +1657,44 @@ function global_ids%(%): id_table
return ids;
%}
function record_fields%(rec: any%): record_field_table
%{
TableVal* fields = new TableVal(record_field_table);
RecordVal* rv = rec->AsRecordVal();
RecordType* rt = rv->Type()->AsRecordType();
if ( rt->Tag() != TYPE_RECORD )
{
reporter->Error("non-record passed to record_fields");
return fields;
}
for ( int i = 0; i < rt->NumFields(); ++i )
{
BroType* ft = rt->FieldType(i);
TypeDecl* fd = rt->FieldDecl(i);
Val* fv = rv->Lookup(i);
if ( fv )
Ref(fv);
bool logged = (fd->attrs && fd->FindAttr(ATTR_LOG) != 0);
RecordVal* nr = new RecordVal(record_field);
nr->Assign(0, new StringVal(type_name(rt->Tag())));
nr->Assign(1, new Val(logged, TYPE_BOOL));
nr->Assign(2, fv);
nr->Assign(3, rt->FieldDefault(i));
Val* field_name = new StringVal(rt->FieldName(i));
fields->Assign(field_name, nr);
Unref(field_name);
}
return fields;
%}
%%{
#include "Anon.h"
%%}

View file

@ -0,0 +1,8 @@
[a=42, b=<uninitialized>, c=<uninitialized>, d=Bar]
{
[b] = [type_name=record, log=F, value=<uninitialized>, default_val=Foo],
[d] = [type_name=record, log=T, value=Bar, default_val=<uninitialized>],
[c] = [type_name=record, log=F, value=<uninitialized>, default_val=<uninitialized>],
[a] = [type_name=record, log=F, value=42, default_val=<uninitialized>]
}
F

View file

@ -0,0 +1,20 @@
#
# @TEST-EXEC: bro %INPUT >out
# @TEST-EXEC: btest-diff out
type r: record {
a: count;
b: string &default="Foo";
c: double &optional;
d: string &log;
};
event bro_init()
{
local x: r = [$a=42, $d="Bar"];
print x;
local t: record_field_table;
t = record_fields(x);
print t;
print t["c"]?$value;
}