summaryrefslogtreecommitdiff
path: root/source4/build/pidl
diff options
context:
space:
mode:
authorTim Potter <tpot@samba.org>2004-05-16 11:20:06 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 12:53:48 -0500
commit8b84f643bd50c83230b723eb35b0edafe5670fca (patch)
tree68ea2bf92c07a750a1b43ac9bc9e4e7d95572889 /source4/build/pidl
parent6703be3ef027a12232cb8de2b64b51af5dd9bbde (diff)
downloadsamba-8b84f643bd50c83230b723eb35b0edafe5670fca.tar.gz
samba-8b84f643bd50c83230b723eb35b0edafe5670fca.tar.bz2
samba-8b84f643bd50c83230b723eb35b0edafe5670fca.zip
r753: Big reorganisation of everything - also fixes handling of dissectors
for structures. Instead of trying to parse everything to produce output in the right order, generate parser in two steps: 1) gather information and register names, fields, types etc. 2) generate output using data from step 1. (This used to be commit 03863a2ca88c374e168d579e7e4f78877160215c)
Diffstat (limited to 'source4/build/pidl')
-rw-r--r--source4/build/pidl/eparser.pm574
1 files changed, 334 insertions, 240 deletions
diff --git a/source4/build/pidl/eparser.pm b/source4/build/pidl/eparser.pm
index bb29389538..6c6596bf07 100644
--- a/source4/build/pidl/eparser.pm
+++ b/source4/build/pidl/eparser.pm
@@ -1,18 +1,129 @@
###################################################
# parser generator for IDL structures
-# Copyright tpot@samba.org 2001
-# Copyright tridge@samba.org 2000
+# Copyright tpot@samba.org 2004
# released under the GNU GPL
package IdlEParser;
use strict;
use dump;
+#use Data::Dumper;
-my($module);
+#####################################################################
+# Code for managing hf's
+
+my %hf_info = ();
+
+# Convert an idl type to an ethereal FT_* type
+
+sub type2ft($)
+{
+ my($t) = shift;
+
+ return "FT_UINT32", if ($t eq "uint32");
+ return "FT_UINT16", if ($t eq "uint16");
+ return "FT_BYTES";
+}
+
+# Select an ethereal BASE_* type for an idl type
+
+sub type2base($)
+{
+ my($t) = shift;
+
+ return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
+ return "BASE_NONE";
+}
+
+# Create a new field. The name of the field is hf_${name}_${type} where
+# name and type are taken from the IDL definition for the element.
+
+sub AddField($$)
+{
+ my($name) = shift;
+ my($type) = shift;
+
+ my $hf_name = "${name}_${type}";
+ return, if defined $hf_info{$hf_name};
+
+ $hf_info{$hf_name} = {
+ 'name' => $name, # Field name
+ 'type' => $type, # Field type
+ 'ft' => type2ft($type), # Ethereal type
+ 'base' => type2base($type), # Base of type
+ };
+}
+
+# Generate field definitions from %hf_info
+
+sub EtherealFieldDefinitions()
+{
+ my($res) = "";
+
+ $res .= << "EOF";
+static int hf_opnum = -1;
+static int hf_rc = -1;
+static int hf_policy_handle = -1;
+EOF
+
+ foreach my $hf (keys(%hf_info)) {
+ my($hf_name) = "$hf_info{$hf}{name}_$hf_info{$hf}{type}";
+ $res .= "static int hf_$hf_name = -1;\n";
+ }
+
+ return $res;
+}
+
+# Generate field initialisers
+
+sub EtherealFieldInitialisation($)
+{
+ my($module) = shift;
+ my($res) = "";
+
+ # Fields present in all parsers
+
+ $res .= << "EOF";
+\t{ &hf_opnum,
+\t { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},
+\t{ &hf_policy_handle,
+\t { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},
+\t{ &hf_rc,
+\t { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},
+EOF
+
+ foreach my $hf (keys(%hf_info)) {
+ $res .= "\t{ &hf_$hf,\n";
+ $res .= "\t { \"$hf_info{$hf}{name}\", \"$hf\", $hf_info{$hf}{ft}, $hf_info{$hf}{base},\n";
+ $res .= "\t NULL, 0, \"$hf\", HFILL }},\n";
+ }
+
+ return $res;
+}
#####################################################################
-# handlers for parsing ndr argument types
+# Code for managing subtrees
+
+sub EtherealSubtreeDefinitions($)
+{
+ my($module) = shift;
+ my($res) = "";
+
+ $res .= << "EOF";
+static gint ett_dcerpc_$module = -1;
+EOF
+
+ return $res;
+}
+
+sub EtherealSubtreeInitialisation()
+{
+ my($res) = "";
+ return $res;
+}
+
+#####################################################################
+# Generate dissection functions for NDR types
sub ParamSimpleNdrType($)
{
@@ -49,45 +160,52 @@ sub ParamStruct($)
my($p) = shift;
my($res);
- $res .= "\toffset = dissect_${module}_$p->{TYPE}(tvb, offset, pinfo, tree, drep);\n";
+ $res .= "\toffset = dissect_$p->{TYPE}(tvb, offset, pinfo, tree, drep);\n";
return $res;
}
+# Index of NDR types and functions to generate code to dissect that type
+
my %param_handlers = (
- 'uint8' => \&ParamSimpleNdrType,
- 'uint16' => \&ParamSimpleNdrType,
- 'uint32' => \&ParamSimpleNdrType,
+ 'uint8' => \&ParamSimpleNdrType,
+ 'uint16' => \&ParamSimpleNdrType,
+ 'uint32' => \&ParamSimpleNdrType,
'policy_handle' => \&ParamPolicyHandle,
- 'string' => \&ParamString,
+ 'string' => \&ParamString,
);
-my %hf_info = (); # Field info - remember for trailing stuff
+# Generate a parser for a NDR parameter
-#####################################################################
-# parse a function
sub ParseParameter($)
{
my($p) = shift;
my($res);
+ # Call function registered for this type
+
if (defined($param_handlers{$p->{TYPE}})) {
$res .= &{$param_handlers{$p->{TYPE}}}($p);
return $res;
}
+ # Unknown type - make a note in the protocol tree
+
$res .= "\tproto_tree_add_text(tree, tvb, offset, -1, \"Unhandled IDL type '$p->{TYPE}'\");\n";
return $res;
}
#####################################################################
-# parse a function
-sub ParseFunction($)
+# Generate code fragment for an IDL function
+
+sub EtherealFunction($)
{
my($f) = shift;
my($res);
+ # Comment displaying IDL for this function
+
$res .= "/*\n\n";
$res .= IdlDump::DumpFunction($f);
$res .= "*/\n\n";
@@ -125,52 +243,38 @@ sub ParseFunction($)
}
#####################################################################
-# parse a function
-sub ParseEnum($$)
-{
- my($name) = shift;
- my($enum) = shift;
+# Generate code fragment for an IDL struct
- return "/* Enum $name */\n\n";
-}
-
-#####################################################################
-# parse a function
-sub ParseStruct($$)
-{
- my($name) = shift;
+sub EtherealStruct($$)
+{
+ my($module) = shift;
my($struct) = shift;
- my($res);
-
- # Add struct name to param handler list
-
- $param_handlers{$name} = \&ParamStruct;
-
- # Create parse function
+ my($res) = "";
$res .= "/*\n\n";
- $res .= IdlDump::DumpStruct($struct);
+ $res .= IdlDump::DumpStruct($struct->{DATA});
$res .= "\n\n*/\n\n";
$res .= << "EOF";
-int dissect_${module}_$name(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
+int dissect_$struct->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
{
proto_item *item = NULL;
proto_tree *tree = NULL;
int old_offset = offset;
if (parent_tree) {
- item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$name");
+ item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$struct->{NAME}");
tree = proto_item_add_subtree(item, ett_dcerpc_$module);
}
EOF
- foreach my $d (@{$struct->{ELEMENTS}}) {
+ # Parse elements
+
+ foreach my $d (@{$struct->{DATA}->{ELEMENTS}}) {
$res .= ParseParameter($d);
}
-
$res .= << "EOF";
proto_item_set_len(item, offset - old_offset);
@@ -184,212 +288,184 @@ EOF
}
#####################################################################
-# parse a function
-sub ParseUnion($$)
-{
- my($name) = shift;
- my($union) = shift;
+# Generate code fragment for an IDL union
- return "/* Union $name */\n\n";
-}
-
-#####################################################################
-# parse a function
-sub ParseTypedef($)
+sub EtherealUnion($$)
{
- my($typedef) = shift;
- my($data) = $typedef->{DATA};
+ my($module) = shift;
+ my($union) = shift;
my($res) = "";
- $res .= ParseEnum($typedef->{NAME}, $data), if $data->{TYPE} eq "ENUM";
- $res .= ParseStruct($typedef->{NAME}, $data), if $data->{TYPE} eq "STRUCT";
- $res .= ParseUnion($typedef->{NAME}, $data), if $data->{TYPE} eq "UNION";
-
- return $res;
-}
+ $res .= "/*\n\n";
+ $res .= IdlDump::DumpUnion($union->{DATA});
+ $res .= "\n\n*/\n\n";
-#####################################################################
-# parse the interface definitions
-sub Pass2Interface($)
+ $res .= << "EOF";
+int dissect_$union->{NAME}(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *parent_tree, guint8 *drep)
{
- my($interface) = shift;
- my($data) = $interface->{DATA};
- my($res) = "";
+ proto_item *item = NULL;
+ proto_tree *tree = NULL;
+ int old_offset = offset;
- foreach my $d (@{$data}) {
- $res .= ParseFunction($d), if $d->{TYPE} eq "FUNCTION";
- $res .= ParseTypedef($d), if $d->{TYPE} eq "TYPEDEF";
+ if (parent_tree) {
+ item = proto_tree_add_text(parent_tree, tvb, offset, -1, "$union->{NAME}");
+ tree = proto_item_add_subtree(item, ett_dcerpc_$module);
}
- return $res;
-}
-
-#####################################################################
-# Pass 1: Stuff required before structs and functions
+EOF
-sub Pass1ModuleHeader($)
-{
- my($d) = shift;
- my($res) = "";
+ # TODO: Parse elements
- $res .= << "EOF";
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+$res .= << "EOF";
-#include "packet-dcerpc.h"
-#include "packet-dcerpc-nt.h"
+ proto_item_set_len(item, offset - old_offset);
-extern const value_string NT_errors[];
+ return offset;
+}
EOF
- # UUID
-
- if ($d->{TYPE} eq "MODULEHEADER" and defined($d->{PROPERTIES}->{uuid})) {
- my $uuid = $d->{PROPERTIES}->{uuid};
- $res .= "static e_uuid_t uuid_dcerpc_$module = {\n";
- $res .= "\t0x" . substr($uuid, 0, 8);
- $res .= ", 0x" . substr($uuid, 9, 4);
- $res .= ", 0x" . substr($uuid, 14, 4) . ",\n";
- $res .= "\t{ 0x" . substr($uuid, 19, 2);
- $res .= ", 0x" . substr($uuid, 21, 2);
- $res .= ", 0x" . substr($uuid, 24, 2);
- $res .= ", 0x" . substr($uuid, 26, 2);
- $res .= ", 0x" . substr($uuid, 28, 2);
- $res .= ", 0x" . substr($uuid, 30, 2);
- $res .= ", 0x" . substr($uuid, 32, 2);
- $res .= ", 0x" . substr($uuid, 34, 2) . " }\n";
- $res .= "};\n\n";
-
- $res .= "static guint16 ver_dcerpc_samr = " .
- $d->{PROPERTIES}->{version} . ";\n\n";
- }
-
return $res;
}
-# Convert an idl type to an ethereal FT_* type
+#####################################################################
+# Generate code fragment for an IDL typedef
-sub type2ft($)
-{
- my($t) = shift;
+sub EtherealTypedef($$)
+{
+ my($module) = shift;
+ my($typedef) = shift;
- return "FT_UINT32", if ($t eq "uint32");
- return "FT_UINT16", if ($t eq "uint16");
-
- return "FT_BYTES";
+ return EtherealStruct($module, $typedef),
+ if $typedef->{DATA}{TYPE} eq "STRUCT";
+
+ return EtherealUnion($module, $typedef),
+ if $typedef->{DATA}{TYPE} eq "UNION";
+
+ return "/* Unsupported typedef $typedef->{DATA}{TYPE} " .
+ "$typedef->{NAME}*/\n\n";
}
-# Select an ethereal BASE_* type for an idl type
+#####################################################################
+# Generate code fragment for the start of the dissector
-sub type2base($)
+sub EtherealHeader($)
{
- my($t) = shift;
+ my($module) = shift;
+ my($res) = "";
- return "BASE_DEC", if ($t eq "uint32") or ($t eq "uint16");
+ $res .= << "EOF";
+/* parser auto-generated by pidl */
- return "BASE_NONE";
-}
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
-sub AddField($$)
-{
- my($name) = shift;
- my($type) = shift;
- my($res) = "";
+#include "packet-dcerpc.h"
+#include "packet-dcerpc-nt.h"
- my $hf_name = "${name}_${type}";
- return $res, if defined $hf_info{$hf_name};
-
- # Make a note about new field
-
- $res .= "static int hf_$hf_name = -1;\n";
- $hf_info{$hf_name} = {
- 'ft' => type2ft($type),
- 'base' => type2base($name),
- 'name' => $name
- };
+extern const value_string NT_errors[];
- return $res;
-}
+static int proto_dcerpc_$module = -1;
-sub ScanFunction($)
-{
- my($fn) = shift;
- my($res) = "";
+EOF
- foreach my $args ($fn) {
- foreach my $params (@{$args}) {
- $res .= AddField($params->{NAME}, $params->{TYPE});
- }
- }
return $res;
}
-
-sub ScanTypedef($)
+
+sub EtherealUuidRegistration($$$)
{
- my($td) = shift;
+ my($module) = shift;
+ my($uuid) = shift;
+ my($uuid_version) = shift;
my($res) = "";
- if ($td->{TYPE} eq "STRUCT") {
- foreach my $e (@{$td->{ELEMENTS}}) {
- $res .= AddField($e->{NAME}, $e->{TYPE});
- }
- }
+ # Various objects for dissector initialisation
+
+ $res .= "static e_uuid_t uuid_dcerpc_$module = {\n";
+ $res .= "\t0x" . substr($uuid, 0, 8);
+ $res .= ", 0x" . substr($uuid, 9, 4);
+ $res .= ", 0x" . substr($uuid, 14, 4) . ",\n";
+ $res .= "\t{ 0x" . substr($uuid, 19, 2);
+ $res .= ", 0x" . substr($uuid, 21, 2);
+ $res .= ", 0x" . substr($uuid, 24, 2);
+ $res .= ", 0x" . substr($uuid, 26, 2);
+ $res .= ", 0x" . substr($uuid, 28, 2);
+ $res .= ", 0x" . substr($uuid, 30, 2);
+ $res .= ", 0x" . substr($uuid, 32, 2);
+ $res .= ", 0x" . substr($uuid, 34, 2) . " }\n";
+ $res .= "};\n\n";
+
+ $res .= "static guint16 ver_dcerpc_$module = " . $uuid_version . ";\n\n";
return $res;
}
-sub Pass1Interface($)
+#####################################################################
+# Generate code fragment for the tail of the dissector
+
+sub EtherealModuleRegistration($$$)
{
- my($interface) = shift;
+ my($module) = shift;
+ my($hf_register_info) = shift;
+ my($ett_info) = shift;
my($res) = "";
$res .= << "EOF";
-static int proto_dcerpc_$module = -1;
+void
+proto_register_dcerpc_${module}(void)
+{
+ static hf_register_info hf[] = {
+$hf_register_info
+ };
-static int hf_opnum = -1;
-static int hf_rc = -1;
-static int hf_policy_handle = -1;
+ static gint *ett[] = {
+ &ett_dcerpc_$module,
+$ett_info
+ };
-static gint ett_dcerpc_$module = -1;
+ proto_dcerpc_$module = proto_register_protocol("$module", "$module", "$module");
-EOF
+ proto_register_field_array(proto_dcerpc_$module, hf, array_length (hf));
+ proto_register_subtree_array(ett, array_length(ett));
- foreach my $fn (@{$interface->{DATA}}) {
- $res .= ScanFunction($fn->{DATA}), if $fn->{TYPE} eq "FUNCTION";
- $res .= ScanTypedef($fn->{DATA}), if $fn->{TYPE} eq "TYPEDEF";
- }
+}
- $res .= "\n";
+void
+proto_reg_handoff_dcerpc_$module(void)
+{
+ dcerpc_init_uuid(proto_dcerpc_$module, ett_dcerpc_$module,
+ &uuid_dcerpc_$module, ver_dcerpc_$module,
+ dcerpc_${module}_dissectors, hf_opnum);
+}
+EOF
return $res;
}
#####################################################################
-# Pass 3: trailing stuff
+# Generate code fragment for DCERPC subdissector registration
-sub Pass3Interface($)
+sub EtherealSubdissectorRegistration($$)
{
- my($interface) = shift;
+ my($module) = shift;
+ my($functions) = shift;
my($res) = "";
$res .= "static dcerpc_sub_dissector dcerpc_${module}_dissectors[] = {\n";
my $num = 0;
- foreach my $d (@{$interface->{DATA}}) {
- if ($d->{TYPE} eq "FUNCTION") {
- # Strip module name from function name, if present
- my $n = $d->{NAME};
- $n = substr($d->{NAME}, length($module) + 1),
- if $module eq substr($d->{NAME}, 0, length($module));
-
- $res .= "\t{ $num, \"$n\",\n";
- $res .= "\t\t$d->{NAME}_rqst,\n";
- $res .= "\t\t$d->{NAME}_resp },\n";
- $num++;
- }
+ foreach my $name (@$functions) {
+ # Strip module name from function name, if present
+ my($n) = $name;
+ $n = substr($name, length($module) + 1),
+ if $module eq substr($name, 0, length($module));
+
+ $res .= "\t{ $num, \"$n\",\n";
+ $res .= "\t\t${name}_rqst,\n";
+ $res .= "\t\t${name}_resp },\n";
+ $num++;
}
$res .= "};\n\n";
@@ -398,83 +474,101 @@ sub Pass3Interface($)
}
#####################################################################
-# parse a parsed IDL structure back into an IDL file
+# Generate an ethereal dissector from an IDL syntax tree.
+
sub Parse($)
{
my($idl) = shift;
- my($res) = "/* parser auto-generated by pidl */\n\n";
- my($d);
+ my($res) = "";
- # Pass 0: set module name
+ #
+ # Phase 1 : Gather information from IDL tree
+ #
- foreach $d (@{$idl}) {
- $module = $d->{NAME}, if ($d->{TYPE} eq "INTERFACE");
- }
+ my($module) = "";
+ my($uuid) = "";
+ my($uuid_version) = "";
+ my(@fns) = ();
- # Pass 1: header stuff
+ foreach my $d (@$idl) {
- foreach $d (@{$idl}) {
- $res .= Pass1ModuleHeader($d), if $d->{TYPE} eq "MODULEHEADER";
- $res .= Pass1Interface($d), if $d->{TYPE} eq "INTERFACE";
- }
+ # Get data from interface definition
- # Pass 2: typedefs and functions
+ $module = $d->{NAME}, if $d->{TYPE} eq "INTERFACE";
- foreach $d (@{$idl}) {
- $res .= Pass2Interface($d), if $d->{TYPE} eq "INTERFACE";
- }
+ if ($d->{TYPE} eq "MODULEHEADER") {
+ $uuid = $d->{PROPERTIES}->{uuid};
+ $uuid_version = $d->{PROPERTIES}->{version};
+ }
- # Pass 3: trailing stuff
+ # Iterate over function definitions and register field info
- foreach $d (@{$idl}) {
- $res .= Pass3Interface($d), if $d->{TYPE} eq "INTERFACE";
- }
+ if ($d->{TYPE} eq "INTERFACE") {
- my $hf_register_info = << "EOF";
-\t{ &hf_opnum,
-\t { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},
-\t{ &hf_policy_handle,
-\t { \"Policy handle\", \"$module.policy\", FT_BYTES, BASE_NONE, NULL, 0x0, \"Policy handle\", HFILL }},
-\t{ &hf_rc,
-\t { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},
-EOF
+ foreach my $d (@{$d->{DATA}}) {
- foreach my $hf (keys(%hf_info)) {
- $hf_register_info .= "\t{ &hf_$hf,\n";
- $hf_register_info .= "\t { \"$hf_info{$hf}{name}\", \"$hf\", $hf_info{$hf}{ft}, $hf_info{$hf}{base},\n";
- $hf_register_info .= "\t NULL, 0, \"$hf\", HFILL }},\n";
+ if ($d->{TYPE} eq "FUNCTION") {
+
+ # Register function name
+
+ $fns[$#fns + 1] = $d->{NAME};
+
+ # Register function fields (parameter names)
+
+ foreach my $e (@{$d->{DATA}}) {
+ AddField($e->{NAME}, $e->{TYPE});
+ }
+ }
+
+ if ($d->{TYPE} eq "TYPEDEF") {
+
+ # Register structure names
+
+ $param_handlers{$d->{NAME}} = \&ParamStruct;
+
+ # Register typedef fields (element names)
+
+ if ($d->{DATA}->{TYPE} eq "STRUCT") {
+ foreach my $e (@{$d->{DATA}->{ELEMENTS}}) {
+ AddField($e->{NAME}, $e->{TYPE});
+ }
+ }
+ }
+ }
+ }
}
-
- my $ett_info = "/* spotty */";
-
- $res .= << "EOF";
-void
-proto_register_dcerpc_${module}(void)
-{
- static hf_register_info hf[] = {
-$hf_register_info
- };
- static gint *ett[] = {
- &ett_dcerpc_$module,
-$ett_info
- };
+ #
+ # Phase 2 : Spit out parser from fragments generated above
+ #
- proto_dcerpc_$module = proto_register_protocol("$module", "$module", "$module");
+ $res .= EtherealHeader($module);
+ $res .= EtherealFieldDefinitions();
+ $res .= EtherealSubtreeDefinitions($module);
- proto_register_field_array (proto_dcerpc_$module, hf, array_length (hf));
- proto_register_subtree_array(ett, array_length(ett));
+ foreach my $d (@$idl) {
-}
+ if ($d->{TYPE} eq "INTERFACE") {
+ foreach my $d (@{$d->{DATA}}) {
-void
-proto_reg_handoff_dcerpc_$module(void)
-{
- dcerpc_init_uuid(proto_dcerpc_$module, ett_dcerpc_$module,
- &uuid_dcerpc_$module, ver_dcerpc_$module,
- dcerpc_${module}_dissectors, hf_opnum);
-}
-EOF
+ # Generate function code fragments
+
+ $res .= EtherealFunction($d), if $d->{TYPE} eq "FUNCTION";
+
+ # Generate structure code fragments
+
+ $res .= EtherealTypedef($module, $d),
+ if $d->{TYPE} eq "TYPEDEF";
+ }
+ }
+ }
+
+ $res .= EtherealSubdissectorRegistration($module, \@fns);
+
+ $res .= EtherealUuidRegistration($module, $uuid, $uuid_version);
+ $res .= EtherealModuleRegistration($module,
+ EtherealFieldInitialisation($module),
+ EtherealSubtreeInitialisation());
return $res;
}