From 8b84f643bd50c83230b723eb35b0edafe5670fca Mon Sep 17 00:00:00 2001 From: Tim Potter Date: Sun, 16 May 2004 11:20:06 +0000 Subject: 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) --- source4/build/pidl/eparser.pm | 574 ++++++++++++++++++++++++------------------ 1 file changed, 334 insertions(+), 240 deletions(-) (limited to 'source4') 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; } -- cgit