diff options
author | Tim Potter <tpot@samba.org> | 2005-01-02 00:00:43 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:07:54 -0500 |
commit | 971112285c3320a3972ff619f2c38fdf6783231c (patch) | |
tree | f593b89d9fdde4ab4f8c6da9f4c778c39f1f8cf3 | |
parent | 9681464dc861a0be240ecd7080b340bf460929f7 (diff) | |
download | samba-971112285c3320a3972ff619f2c38fdf6783231c.tar.gz samba-971112285c3320a3972ff619f2c38fdf6783231c.tar.bz2 samba-971112285c3320a3972ff619f2c38fdf6783231c.zip |
r4469: Version n + 1 of the pidl ethereal parser generator. This version is
based on the idea of manipulating the .c and .h files generated by
parser.pm with perl regexps and glueing it all together to make an
ethereal plugin.
I thought this was a pretty crazy idea to start off with but it has
turned out to be not as complicated as I thought and has the huge advantage
of not duplicating any of the difficult code in parser.pm.
(This used to be commit 7007522f83740f41f9a47f5ad5942ea46320d405)
-rw-r--r-- | source4/build/pidl/eparser.pm | 376 | ||||
-rwxr-xr-x | source4/build/pidl/pidl.pl | 26 |
2 files changed, 335 insertions, 67 deletions
diff --git a/source4/build/pidl/eparser.pm b/source4/build/pidl/eparser.pm index a6f44b5b14..09e2855e23 100644 --- a/source4/build/pidl/eparser.pm +++ b/source4/build/pidl/eparser.pm @@ -689,47 +689,17 @@ sub ParseFunctionPull($) my($fn) = shift; my $static = fn_prefix($fn); - pidl "/*\n\n"; - pidl IdlDump::DumpFunction($fn); - pidl "*/\n\n"; - # request function pidl "int $fn->{NAME}_rqst(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n"; - pidl "\tstruct ndr_pull *ndr = ndr_pull_init(tvb, offset, pinfo, drep);\n"; - pidl "\tstruct $fn->{NAME} *r = (struct $fn->{NAME} *)g_malloc(sizeof(struct $fn->{NAME}));\n\n"; - - # declare any internal pointers we need - foreach my $e (@{$fn->{DATA}}) { - if (util::need_wire_pointer($e) && - util::has_property($e, "in")) { - pidl "\tuint32_t _ptr_$e->{NAME};\n"; - } - } - - pidl "\n\tZERO_STRUCTP(r);\n\n"; + pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n"; + pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n"; + pidl "\tpidl_tree ptree;\n\n"; - # auto-init the out section of a structure. I originally argued that - # this was a bad idea as it hides bugs, but coping correctly - # with initialisation and not wiping ref vars is turning - # out to be too tricky (tridge) - foreach my $e (@{$fn->{DATA}}) { - if (util::has_property($e, "out")) { - pidl "\tZERO_STRUCT(r->out);\n\n"; - last; - } - } + pidl "\tptree.proto_tree = tree;\n"; + pidl "\tptree.subtree_list = NULL;\n\n"; - foreach my $e (@{$fn->{DATA}}) { - if (util::has_property($e, "in")) { - ParseFunctionElementPull($e, "in"); - } - # we need to allocate any reference output variables, so that - # a dcerpc backend can be sure they are non-null - if (util::has_property($e, "out") && util::has_property($e, "ref")) { - AllocateRefVars($e); - } - } + pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_IN, &ptree, r);\n"; pidl "\n\treturn ndr->offset;\n"; pidl "}\n\n"; @@ -737,28 +707,14 @@ sub ParseFunctionPull($) # response function pidl "int $fn->{NAME}_resp(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, guint8 *drep)\n{\n"; - pidl "\tstruct ndr_pull *ndr = ndr_pull_init(tvb, offset, pinfo, drep);\n"; - pidl "\tstruct $fn->{NAME} *r = (struct $fn->{NAME} *)g_malloc(sizeof(struct $fn->{NAME}));\n\n"; - - # declare any internal pointers we need - foreach my $e (@{$fn->{DATA}}) { - if (util::need_wire_pointer($e) && - util::has_property($e, "out")) { - pidl "\tuint32_t _ptr_$e->{NAME};\n"; - } - } - - pidl "\tZERO_STRUCTP(r);\n\n"; + pidl "\tstruct pidl_pull *ndr = pidl_pull_init(tvb, offset, pinfo, drep);\n"; + pidl "\tstruct $fn->{NAME} *r = talloc_p(NULL, struct $fn->{NAME});\n"; + pidl "\tpidl_tree ptree;\n\n"; - foreach my $e (@{$fn->{DATA}}) { - if (util::has_property($e, "out")) { - ParseFunctionElementPull($e, "out"); - } - } + pidl "\tptree.proto_tree = tree;\n"; + pidl "\tptree.subtree_list = NULL;\n\n"; - if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") { - pidl "\tndr_pull_$fn->{RETURN_TYPE}(ndr, tree, hf_rc, &r->out.result);\n"; - } + pidl "\tndr_pull_$fn->{NAME}(ndr, NDR_OUT, &ptree, r);\n"; pidl "\n\treturn ndr->offset;\n"; pidl "}\n\n"; @@ -809,7 +765,6 @@ sub ParseInterface($) } FunctionTable($interface); - } sub type2ft($) @@ -990,7 +945,7 @@ sub ParseHeader($$) ##################################################################### # parse a parsed IDL structure back into an IDL file -sub Parse($$) +sub OldParse($$) { my($idl) = shift; my($filename) = shift; @@ -1132,4 +1087,309 @@ sub Parse($$) close(OUT); } +##################################################################### +# rewrite autogenerated header file +sub RewriteHeader($$$) +{ + my($idl) = shift; + my($input) = shift; + my($output) = shift; + + %needed = (); + + # Open files + + open(IN, "<$input") || die "can't open $input for reading"; + open(OUT, ">$output") || die "can't open $output for writing"; + + # Read in entire file + + undef $/; + + while(<IN>) { + + # Not interested in ndr_push or ndr_print routines as they + # define structures we aren't interested in. + + s/^NTSTATUS ndr_push.*?;\n//smg; + s/^void ndr_print.*?;\n//smg; + + # Get rid of async send and receive function. + + s/^NTSTATUS dcerpc_.*?;\n//smg; + s/^struct rpc_request.*?;\n\n//smg; + + # Rewrite librpc includes + + s/^\#include \"librpc\/gen_ndr\/ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg; + + # Convert samba fixed width types to stdint types + + s/((u)?int)([0-9]+)/$1$3_t/smg; + + # Rename struct ndr_pull to struct pidl_pull + + s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg; + + # Change prototypes for public functions + + s/(struct pidl_pull \*ndr, int ndr_flags)/$1, pidl_tree *tree/smg; + + pidl $_; + } + + close(OUT); +} + +##################################################################### +# rewrite autogenerated C file +sub RewriteC($$$) +{ + my($idl) = shift; + my($input) = shift; + my($output) = shift; + + # Open files + + open(IN, "<$input") || die "can't open $input for reading"; + open(OUT, ">$output") || die "can't open $output for writing"; + + # Get name of module + + foreach my $x (@{$idl}) { + if ($x->{TYPE} eq "INTERFACE") { + ModuleHeader($x); + $module = $x->{NAME}; + BuildNeeded($x); + } + } + + pidl "#include \"eparser.h\"\n\n"; + + pidl "extern const value_string NT_errors[];\n\n"; + + # Declarations for hf variables + + pidl "static int hf_opnum = -1;\n"; + pidl "static int hf_ptr = -1;\n"; + pidl "static int hf_array_size = -1;\n"; + pidl "static int hf_result_NTSTATUS = -1;\n"; + + foreach my $y (keys(%needed)) { + pidl "static int $y = -1;\n", if $y =~ /^hf_/; + } + + pidl "\n"; + + foreach my $y (keys(%needed)) { + pidl "static gint $y = -1;\n", if $y =~ /^ett_/; + } + + pidl "\n"; + + # Read in entire file for post-processing + + undef $/; + + while(<IN>) { + + # Ethereal take care of this for us. It also makes the other + # regular expressions easier to write and understand. + + s/NDR_CHECK\((.*)\)/$1/g; + + # We're not interested in ndr_print or ndr_push functions. + + s/^(static )?NTSTATUS (ndr_push[^\(]+).*?^\}\n\n//smg; + s/^void (ndr_print[^\(]+).*?^\}\n\n//smg; + + # Get rid of dcerpc interface structures and functions + + s/^static const struct dcerpc_interface_call .*?^\};\n\n//smg; + s/^static const char \* const ([a-z]+)_endpoint_strings.*?^\};\n\n//smg; + s/^static const struct dcerpc_endpoint_list .*?^\};\n\n\n//smg; + s/^const struct dcerpc_interface_table .*?^\};\n\n//smg; + s/^static NTSTATUS dcerpc_ndr_([a-z]+)_init.*?^\}\n\n//smg; + s/^NTSTATUS dcerpc_([a-z]+)_init.*?^\}\n\n//smg; + + # Include packet-dcerpc-foo.h instead of ndr_foo.h + + s/^\#include \".*?ndr_(.*?).h\"$/\#include \"packet-dcerpc-$1.h\"/smg; + + # Call ethereal wrapper for ndr_pull_ptr() function. + + s/(ndr_pull_ptr\(ndr, ([^\)]*?)\);)/ndr_pull_ptr(ndr, tree, hf_ptr, $2);/smg; + + # Wrap ndr_pull_array_size() - generate wrapper that won't get + # caught by the regex for wrapping scalar values below (i.e + # the leading space in front of the first parameter). + + s/(ndr_pull_array_size\(ndr, ([^\)]*?)\);)/ndr_pull_array_size( ndr, tree, $2);/smg; + + # Add tree argument to ndr_pull_array() + + s/(ndr_pull_array([^\(]*?)\(ndr, (NDR_[^,]*?), ([^\)].*?)\);)/ndr_pull_array$2( ndr, $3, tree, $4);/smg; + + + # Call ethereal wrappers for pull of scalar values in + # structures and functions: + # + # ndr_pull_uint32(ndr, &r->in.access_mask); + # ndr_pull_uint32(ndr, &r->idx); + + s/(ndr_pull_([^\)]*?)\(ndr, (&?r->((in|out)\.)?([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$6_$2, $3);/smg; + + # Pull of "internal" scalars like array sizes, levels, etcetera. + + s/(ndr_pull_(uint32|uint16)\(ndr, (&_([^\)]*?))\);)/ndr_pull_$2(ndr, tree, hf_$4, $3);/smg; + + # Call ethereal wrappers for pull of buffers in structures and + # functions: + # + # ndr_pull_string(ndr, NDR_SCALARS|NDR_BUFFERS, &r->command); + # ndr_pull_atsvc_enum_ctr(ndr, NDR_SCALARS|NDR_BUFFERS, r->in.ctr); + + s/(ndr_pull_([^\)]*?)\(ndr, (NDR_[^,]*?), ([^\(].*?)\);)/ndr_pull_$2(ndr, $3, get_subtree(tree, \"$2\", ndr, ett_$2), $4);/smg; + + # Add proto_tree parameter to pull functions: + # + # static NTSTATUS ndr_pull_atsvc_JobInfo(struct ndr_pull *ndr, int ndr_flags, struct atsvc_JobInfo *r) + + s/^((static )?NTSTATUS ndr_pull_([^\(]*?)\(struct ndr_pull \*ndr, int (ndr_)?flags)/$1, proto_tree \*tree/smg; + + # Get rid of ndr_pull_error() calls. Ethereal should take + # care of buffer overruns and inconsistent array sizes for us. + + s/(return ndr_pull_error([^;]*?);)/return NT_STATUS_OK; \/\/ $1/smg; + + # Rename proto_tree args to pidl_tree + + s/(int (ndr_)?flags), proto_tree \*tree/$1, pidl_tree \*tree/smg; + + # Rename struct ndr_pull to struct pidl_pull + + s/struct ndr_pull \*ndr/struct pidl_pull \*ndr/smg; + + pidl $_; + } + + # Function call table + + foreach my $x (@{$idl}) { + if ($x->{TYPE} eq "INTERFACE") { + foreach my $y (@{$x->{"INHERITED_DATA"}}) { + ($y->{TYPE} eq "FUNCTION") && ParseFunctionPull($y); + } + + FunctionTable($x); + } + } + + # Ethereal protocol registration + + pidl "int proto_dcerpc_pidl_$module = -1;\n\n"; + + pidl "static gint ett_dcerpc_$module = -1;\n\n"; + + if (defined($if_uuid)) { + + pidl "static e_uuid_t uuid_dcerpc_$module = {\n"; + pidl "\t0x" . substr($if_uuid, 1, 8); + pidl ", 0x" . substr($if_uuid, 10, 4); + pidl ", 0x" . substr($if_uuid, 15, 4) . ",\n"; + pidl "\t{ 0x" . substr($if_uuid, 20, 2); + pidl ", 0x" . substr($if_uuid, 22, 2); + pidl ", 0x" . substr($if_uuid, 25, 2); + pidl ", 0x" . substr($if_uuid, 27, 2); + pidl ", 0x" . substr($if_uuid, 29, 2); + pidl ", 0x" . substr($if_uuid, 31, 2); + pidl ", 0x" . substr($if_uuid, 33, 2); + pidl ", 0x" . substr($if_uuid, 35, 2) . " }\n"; + pidl "};\n\n"; + } + + if (defined($if_version)) { + pidl "static guint16 ver_dcerpc_$module = " . $if_version . ";\n\n"; + } + + pidl "void proto_register_dcerpc_pidl_$module(void)\n"; + pidl "{\n"; + + pidl "\tstatic hf_register_info hf[] = {\n"; + pidl "\t{ &hf_opnum, { \"Operation\", \"$module.opnum\", FT_UINT16, BASE_DEC, NULL, 0x0, \"Operation\", HFILL }},\n"; + pidl "\t{ &hf_result_NTSTATUS, { \"Return code\", \"$module.rc\", FT_UINT32, BASE_HEX, VALS(NT_errors), 0x0, \"Return status code\", HFILL }},\n"; + pidl "\t{ &hf_ptr, { \"Pointer\", \"$module.ptr\", FT_UINT32, BASE_HEX, NULL, 0x0, \"Pointer\", HFILL }},\n"; + + foreach my $x (keys(%needed)) { + next, if !($x =~ /^hf_/); + pidl "\t{ &$x,\n"; + pidl "\t { \"$needed{$x}{name}\", \"$x\", $needed{$x}{ft}, $needed{$x}{base}, NULL, 0, \"$x\", HFILL }},\n"; + } + + pidl "\t};\n\n"; + + pidl "\tstatic gint *ett[] = {\n"; + pidl "\t\t&ett_dcerpc_$module,\n"; + foreach my $x (keys(%needed)) { + pidl "\t\t&$x,\n", if $x =~ /^ett_/; + } + pidl "\t};\n\n"; + + if (defined($if_uuid)) { + + pidl "\tproto_dcerpc_pidl_$module = proto_register_protocol(\"pidl_$module\", \"pidl_$module\", \"pidl_$module\");\n\n"; + + pidl "\tproto_register_field_array(proto_dcerpc_pidl_$module, hf, array_length (hf));\n"; + pidl "\tproto_register_subtree_array(ett, array_length(ett));\n"; + + pidl "}\n\n"; + + pidl "void proto_reg_handoff_dcerpc_pidl_$module(void)\n"; + pidl "{\n"; + pidl "\tdcerpc_init_uuid(proto_dcerpc_pidl_$module, ett_dcerpc_$module, \n"; + pidl "\t\t&uuid_dcerpc_$module, ver_dcerpc_$module, \n"; + pidl "\t\tdcerpc_dissectors, hf_opnum);\n"; + pidl "}\n"; + + } else { + + pidl "\tint proto_dcerpc;\n\n"; + pidl "\tproto_dcerpc = proto_get_id_by_filter_name(\"dcerpc\");\n"; + pidl "\tproto_register_field_array(proto_dcerpc, hf, array_length(hf));\n"; + pidl "\tproto_register_subtree_array(ett, array_length(ett));\n"; + + pidl "}\n"; + + } + + close(OUT); +} + +##################################################################### +# parse a parsed IDL structure back into an IDL file +sub Parse($$) +{ + my($idl) = shift; + my($filename) = shift; + + %needed = (); # Clear after generating header file + + open(OUT, ">$filename") || die "can't open $filename"; + + # Look for name of module + + foreach my $x (@{$idl}) { + + if ($x->{TYPE} eq "INTERFACE") { + ModuleHeader($x); + $module = $x->{NAME}; + BuildNeeded($x); + } + } + + pidl "/* parser auto-generated by pidl */\n\n"; + + close(OUT); +} + 1; diff --git a/source4/build/pidl/pidl.pl b/source4/build/pidl/pidl.pl index c430c75236..6d0ff69081 100755 --- a/source4/build/pidl/pidl.pl +++ b/source4/build/pidl/pidl.pl @@ -205,15 +205,23 @@ $dcom } if ($opt_eparser) { - my($parser) = dirname($output) . "/packet-dcerpc-$basename.c"; - IdlEParser::Parse($pidl, $parser); - $parser = dirname($output) . "/packet-dcerpc-proto-$basename.h"; - IdlEParser::ParseHeader($pidl, $parser); - my($header) = dirname($output) . "/packet-dcerpc-proto.h"; - open(OUT, ">>$header") || die "can't open $header"; - print OUT "#include \"ndr_$basename.h\"\n"; - print OUT "#include \"packet-dcerpc-proto-$basename.h\"\n"; - close(OUT); + + # Generate regular .c and .h files for marshaling and + # unmarshaling. + + my($parser) = util::ChangeExtension($output, ".c"); + IdlParser::Parse($pidl, $parser); + + my($header) = util::ChangeExtension($output, ".h"); + util::FileSave($header, IdlHeader::Parse($pidl)); + + # Postprocess to produce ethereal parsers. + + my($eparser) = dirname($output) . "/packet-dcerpc-$basename.c"; + IdlEParser::RewriteC($pidl, $parser, $eparser); + + my($eparserhdr) = dirname($output) . "/packet-dcerpc-$basename.h"; + IdlEParser::RewriteHeader($pidl, $header, $eparserhdr); } if ($opt_swig) { |