diff --git a/src/Type.cc b/src/Type.cc index ba21120bba..48f40296f3 100644 --- a/src/Type.cc +++ b/src/Type.cc @@ -824,6 +824,43 @@ void RecordType::DescribeReST(ODesc* d, bool roles_only) const d->PopType(this); } +TableVal* RecordType::GetRecordFieldsVal(const RecordVal* rv) const + { + auto rval = new TableVal(internal_type("record_field_table")->AsTableType()); + + for ( int i = 0; i < NumFields(); ++i ) + { + const BroType* ft = FieldType(i); + const TypeDecl* fd = FieldDecl(i); + Val* fv = nullptr; + + if ( rv ) + fv = rv->Lookup(i); + + if ( fv ) + ::Ref(fv); + + bool logged = (fd->attrs && fd->FindAttr(ATTR_LOG) != 0); + + RecordVal* nr = new RecordVal(internal_type("record_field")->AsRecordType()); + + if ( ft->Tag() == TYPE_RECORD ) + nr->Assign(0, new StringVal("record " + ft->GetName())); + else + nr->Assign(0, new StringVal(type_name(ft->Tag()))); + + nr->Assign(1, val_mgr->GetBool(logged)); + nr->Assign(2, fv); + nr->Assign(3, FieldDefault(i)); + + Val* field_name = new StringVal(FieldName(i)); + rval->Assign(field_name, nr); + Unref(field_name); + } + + return rval; + } + const char* RecordType::AddFields(type_decl_list* others, attr_list* attr) { assert(types); diff --git a/src/Type.h b/src/Type.h index a4261e453a..7be4e01946 100644 --- a/src/Type.h +++ b/src/Type.h @@ -75,6 +75,7 @@ class VectorType; class TypeType; class OpaqueType; class EnumVal; +class TableVal; const int DOES_NOT_MATCH_INDEX = 0; const int MATCHES_INDEX_SCALAR = 1; @@ -483,6 +484,13 @@ public: int NumFields() const { return num_fields; } + /** + * Returns a "record_field_table" value for introspection purposes. + * @param rv an optional record value, if given the values of + * all fields will be provided in the returned table. + */ + TableVal* GetRecordFieldsVal(const RecordVal* rv = nullptr) const; + // Returns 0 if all is ok, otherwise a pointer to an error message. // Takes ownership of list. const char* AddFields(type_decl_list* types, attr_list* attr); diff --git a/src/Val.cc b/src/Val.cc index 075e5805bd..0642d6ddb2 100644 --- a/src/Val.cc +++ b/src/Val.cc @@ -396,14 +396,12 @@ bool Val::WouldOverflow(const BroType* from_type, const BroType* to_type, const TableVal* Val::GetRecordFields() { - TableVal* fields = new TableVal(internal_type("record_field_table")->AsTableType()); - auto t = Type(); if ( t->Tag() != TYPE_RECORD && t->Tag() != TYPE_TYPE ) { reporter->Error("non-record value/type passed to record_fields"); - return fields; + return new TableVal(internal_type("record_field_table")->AsTableType()); } RecordType* rt = nullptr; @@ -421,43 +419,13 @@ TableVal* Val::GetRecordFields() if ( t->Tag() != TYPE_RECORD ) { reporter->Error("non-record value/type passed to record_fields"); - return fields; + return new TableVal(internal_type("record_field_table")->AsTableType()); } rt = t->AsRecordType(); } - for ( int i = 0; i < rt->NumFields(); ++i ) - { - BroType* ft = rt->FieldType(i); - TypeDecl* fd = rt->FieldDecl(i); - Val* fv = nullptr; - - if ( rv ) - fv = rv->Lookup(i); - - if ( fv ) - ::Ref(fv); - - bool logged = (fd->attrs && fd->FindAttr(ATTR_LOG) != 0); - - RecordVal* nr = new RecordVal(internal_type("record_field")->AsRecordType()); - - if ( ft->Tag() == TYPE_RECORD ) - nr->Assign(0, new StringVal("record " + ft->GetName())); - else - nr->Assign(0, new StringVal(type_name(ft->Tag()))); - - nr->Assign(1, val_mgr->GetBool(logged)); - 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; + return rt->GetRecordFieldsVal(rv); } // This is a static method in this file to avoid including json.hpp in Val.h since it's huge. @@ -2665,6 +2633,11 @@ RecordVal* RecordVal::CoerceTo(RecordType* t, bool allow_orphaning) return CoerceTo(t, 0, allow_orphaning); } +TableVal* RecordVal::GetRecordFieldsVal() const + { + return Type()->AsRecordType()->GetRecordFieldsVal(this); + } + void RecordVal::Describe(ODesc* d) const { const val_list* vl = AsRecord(); diff --git a/src/Val.h b/src/Val.h index bcdaa52393..09e8858e61 100644 --- a/src/Val.h +++ b/src/Val.h @@ -960,6 +960,11 @@ public: void Describe(ODesc* d) const override; + /** + * Returns a "record_field_table" value for introspection purposes. + */ + TableVal* GetRecordFieldsVal() const; + // This is an experiment to associate a BroObj within the // event engine to a record value in bro script. void SetOrigin(BroObj* o) { origin = o; } diff --git a/src/zeek.bif b/src/zeek.bif index 970ad7c1d0..4b1aec875d 100644 --- a/src/zeek.bif +++ b/src/zeek.bif @@ -1994,6 +1994,19 @@ function lookup_ID%(id: string%) : any ## Returns: A table that describes the fields of a record. function record_fields%(rec: any%): record_field_table %{ + if ( rec->Type()->Tag() == TYPE_STRING ) + { + auto id = global_scope()->Lookup(rec->AsStringVal()->ToStdString()); + + if ( ! id || ! id->AsType() || id->AsType()->Tag() != TYPE_RECORD ) + { + reporter->Error("record_fields string argument does not name a record type"); + return new TableVal(internal_type("record_field_table")->AsTableType()); + } + + return id->AsType()->AsRecordType()->GetRecordFieldsVal(); + } + return rec->GetRecordFields(); %} diff --git a/testing/btest/Baseline/bifs.records_fields/out b/testing/btest/Baseline/bifs.records_fields/out index 01bffa1510..0bcc001b8e 100644 --- a/testing/btest/Baseline/bifs.records_fields/out +++ b/testing/btest/Baseline/bifs.records_fields/out @@ -31,3 +31,20 @@ F { } +{ +[myfield] = [type_name=bool, log=F, value=, default_val=] +} +{ +[b] = [type_name=string, log=F, value=, default_val=Bar], +[c] = [type_name=double, log=F, value=, default_val=], +[a] = [type_name=bool, log=F, value=, default_val=], +[d] = [type_name=string, log=T, value=, default_val=], +[m] = [type_name=record myrec, log=F, value=, default_val=] +} +{ +[b] = [type_name=string, log=F, value=, default_val=Foo], +[c] = [type_name=double, log=F, value=, default_val=], +[e] = [type_name=any, log=F, value=, default_val=], +[a] = [type_name=count, log=F, value=, default_val=], +[d] = [type_name=string, log=T, value=, default_val=] +} diff --git a/testing/btest/bifs/records_fields.zeek b/testing/btest/bifs/records_fields.zeek index 632bcb2fcf..a6d09d737d 100644 --- a/testing/btest/bifs/records_fields.zeek +++ b/testing/btest/bifs/records_fields.zeek @@ -43,4 +43,8 @@ event zeek_init() print t; t = record_fields(x$e); print t; + + print record_fields("myrec"); + print record_fields("tt"); + print record_fields("r"); }