Remove nested pod "=over/=back" to workaround Pod::Html bugs.
[captive.git] / src / libcaptive / ke / captivesym.pl
index 980e7c5..b1abc57 100755 (executable)
@@ -28,7 +28,7 @@ my %def;
 while ($ARGV[0] && $ARGV[0]=~/[.]def$/) {
        map({ open DEF,"<$_" or die "open(\"$_\"): $!"; } shift());
        while (<DEF>) {
-               s/;.*//s;
+               s/;.*$//s;
                next if /^\s*$/s;
                next if /^(?:LIBRARY|EXPORTS)\b/s;
                my($atsign,$symbol,$args,$argscdecl,$isdata)=(/^\s*(\@)?(\S+?)(?:\@(\d+))?(?::(\d+))?(\s+DATA)?\s*$/s);
@@ -40,7 +40,7 @@ while ($ARGV[0] && $ARGV[0]=~/[.]def$/) {
                die "Invalid attributes for data symbol: $symbol" if $isdata && ($atsign || defined $args);
                die "\@funcname without \@4 suffix not recognized: $symbol" if $atsign && !defined $args;
                die "Invalid \@$args number: $symbol" if defined $args && ($args<0 || ($args%4));
-               if (!$argscdecl) {
+               if (!defined $argscdecl) {      # beware: $argscdecl may eq "0"
                        die "Duplicate symbol: $symbol" if exists $def{$symbol};
                        }
                else {
@@ -50,7 +50,7 @@ while ($ARGV[0] && $ARGV[0]=~/[.]def$/) {
                        $args=$argscdecl;
                        }
                $def{$symbol}={
-                               "type"=>($isdata ? "data" : (!defined $args ? "cdecl" : (!$atsign ? "stdcall" : "fastcall"))),
+                               "type"=>($isdata ? "data" : (!defined($args) || defined($argscdecl) ? "cdecl" : (!$atsign ? "stdcall" : "fastcall"))),
                                (!defined $args ? () : ("args4"=>$args/4)),
                                };
                }
@@ -61,11 +61,12 @@ while ($ARGV[0] && $ARGV[0]=~/[.]def$/) {
 my %module;    # $module{'module'}{'symbol'}=1/""
 my %symbol;    # $symbol{'symbol'}='module'
 my %patch;     # $patch{'module'}=1/undef
+my %stats;     # $stats{'iswhat'}=42
 while (<>) {
-       chomp;
-       next if /^\s*$/       # empty
-       next if /^\s*#.*/     # comment
-       my($module,$symbol,$iswhat)=(/^\s*(\S+)\s+(\S+)(?:\s+(undef|pass|wrap))?\s*$/);
+       s/#.*$//s;
+       next if /^\s*$/s;       # empty
+       next if /^\s*#.*/s;     # comment
+       my($module,$symbol,$iswhat)=(/^\s*(\S+)\s+(\S+)(?:\s+(undef|pass|wrap))?\s*$/s);
        $iswhat="" if !defined $iswhat;
        die "Invalid line" if !defined $symbol;
        if ($symbol eq "<patch>") {
@@ -82,12 +83,14 @@ while (<>) {
                }
        die "Symbol not in *.def files: $symbol" if $iswhat ne "undef" && !$def{$symbol};
        if ($iswhat eq "pass" || $iswhat eq "wrap") {
-               die "args count not fixed up for '$iswhat' type: ".$symbol."[".$def{$symbol}{"type"}."]" if !$def{$symbol}{"args4"};
+               die "args count not fixed up for '$iswhat' type: ".$symbol."[".$def{$symbol}{"type"}."]"
+                               if !exists $def{$symbol}{"args4"} && $def{$symbol}{"type"} ne "data";   # beware: {"args"} may ==0
                die "'$iswhat' not permitted if <patch> not specified for module on symbol: $symbol" if !$patch{$module};
                $def{$symbol}{$iswhat}=1;
                }
        $module{$module}{$symbol}=$iswhat ne "undef";
        $symbol{$symbol}=$module;
+       $stats{$iswhat}++;
        }
 
 # file header
@@ -102,10 +105,13 @@ print <<"HERE";
 #include <glib/gmessages.h>
 #include <glib/gmacros.h>
 
+#include <string.h>    /* for built-in: strncmp,memmove,strncpy */
+
+
+extern gboolean captive_debug_messages_disabled;
 
 HERE
 
-my $symbols_undef=0;
 for my $symbol (sort keys(%symbol)) {
        my $def=$def{$symbol};
        if (!$def) {
@@ -117,22 +123,24 @@ void ${symbol}(void)
        g_error("%s: Function '$symbol' NOT IMPLEMENTED",G_STRLOC);
 }
 HERE
-               $symbols_undef++;
                next;
                }
        if ($patch{$symbol{$symbol}} && "data" ne $def->{"type"}) {
-               print "static struct captive_ModuleList_patchpoint ${symbol}_patchpoint;\n";
+               # We do not declare it 'static' as we sometimes make 'extern' references to it
+               # such as 'ExInitializeNPagedLookasideList_patchpoint' in libcaptive/ex/lookas.c.
+               print "struct captive_ModuleList_patchpoint ${symbol}_patchpoint;\n";
                }
        if ("data" eq $def->{"type"}) {
-               die "'data' type not pass-able: $symbol" if $def->{"pass"} || $def->{"wrap"};
-               print "extern void/* ==unknown */ ${symbol};\n",
-                               "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
+               next if $def->{"pass"} || $def->{"wrap"};       # FIXME: export for .so
+               print "extern void/* ==unknown */ ${symbol};\n";
+               print "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
                next;
                }
        if ("cdecl" eq $def->{"type"} && !defined $def->{"args4"} && !$def->{"pass"} && !$def->{"wrap"}) {
                # g_log(,G_LOG_LEVEL_DEBUG,...) not possible if we do not know the arguments count
-               print "void/* ==unknown */ ${symbol}(void/* ==unknown */);\n",
-                               "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
+               my %forbidden=map(($_=>1),qw(strncmp memmove strncpy)); # Prevent: conflicting types for built-in function ...
+               print "void/* ==unknown */ ${symbol}(void/* ==unknown */);\n" if !$forbidden{$symbol};
+               print "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
                next;
                }
 
@@ -189,8 +197,20 @@ HERE
                                        "\tg_return_val_if_fail(${symbol}_patchpoint.orig_w32_func!=NULL,0);\n",
                                        "\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n",
                                        "\t${symbol}_patchpoint.through_w32_func=TRUE;\n",
-                                       "\tr=(*(${symbol}_t_attrib *)${symbol}_patchpoint.orig_w32_func)(".join(",",@args_in).");\n",
-                                       "\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n";
+                                       "\tr=(*(${symbol}_t_attrib *)${symbol}_patchpoint.orig_w32_func)(".join(",",@args_in).");\n";
+                       if (!$def->{"pass"}) {
+                               print 
+                                               "\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n";
+                               }
+                       else {
+                               print
+                                               "\tif (!captive_debug_messages_disabled)\n",
+                                               "\t\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n",
+                                               "\telse {\n",
+                                               "\t\tg_assert(${symbol}_patchpoint.through_w32_func==TRUE);\n",
+                                               "\t\t${symbol}_patchpoint.through_w32_func=FALSE;\n",
+                                               "\t\t}\n";
+                               }
                        }
                else {
                        print
@@ -209,7 +229,7 @@ HERE
        }
 
 # write function captive_kernel_{exports,patches}()
-for my $functype ("exports","patches") {
+for my $functype ("exports","patches_debug","patches_nondebug") {
        print <<"HERE";
 
 gboolean captive_kernel_$functype(void)
@@ -219,15 +239,20 @@ gboolean errbool;
 HERE
        for my $module (sort keys(%module)) {
                my $moduleref=$module{$module};
-               next if ($functype eq "patches") != defined $patch{$module};
+               next if ($functype=~/^patches/) != defined $patch{$module};
                print "\t\terrbool="
-                               .($functype eq "patches" ? "captive_ModuleList_patch" : "captive_ModuleList_add_builtin")
+                               .($functype=~/^patches/ ? "captive_ModuleList_patch" : "captive_ModuleList_add_builtin")
                                ."(\"$module\",\n";
                for my $symbol (sort keys(%$moduleref)) {
-                       next if $functype eq "patches" && (!$def{$symbol} || "data" eq $def{$symbol}{"type"});
-                       print "\t\t\t\"$symbol\",&${symbol}_",
-                                       ($def{$symbol}{"type"} || "undef"),
-                                       (($functype ne "patches") ? () : (",&${symbol}_patchpoint")),
+                       next if $functype=~/^patches/ && !$def{$symbol};
+                       (my $symbol_outer=$symbol)=~s/^captive_reactos_//;
+                       print "\t\t\t\"$symbol_outer\",",(($functype=~/^patches/ && "data" eq $def{$symbol}{"type"}
+                                                                                       && ($def{$symbol}{"pass"} || $def{$symbol}{"wrap"})) ? ("NULL")
+                                                       : ("&${symbol}_",($def{$symbol}{"type"} || "undef"))),
+                                       (($functype!~/^patches/) ? () :
+                                                       (",".("data" eq $def{$symbol}{"type"} ? "NULL,NULL" :
+                                                                       ($functype eq "patches_nondebug" && $def{$symbol}{"pass"} ? "&${symbol}_patchpoint,NULL" :
+                                                                                       "&${symbol}_patchpoint,&${symbol}_patchpoint")))),
                                        ",\n";
                        }
                print <<"HERE";
@@ -243,9 +268,13 @@ HERE
        }
 
 # exit
-print STDERR "$0: Processed ".scalar(keys(%module))." modules, ".scalar(keys(%symbol))." symbols",
-               " (".int(100*(1-$symbols_undef/scalar(keys(%symbol)))).'%'." implemented)\n";
-print STDERR "$0: warning: $symbols_undef symbols are NOT IMPLEMENTED yet!\n" if $symbols_undef;
+my $total=0;
+$total+=$_ for (values(%stats));
+my $statstring;
+for my $statname (sort keys(%stats)) {
+       $statstring.=" ".($statname || "define")."=".$stats{$statname}."(".int(100*$stats{$statname}/$total)."%)";
+       }
+print STDERR "$0: Processed ".scalar(keys(%module))." modules:".$statstring."\n";
 exit 0;
 
 
@@ -275,11 +304,7 @@ Currently being used only for C<ntoskrnl.exe>.
 Any function call even inside such module is trapped and redirected for
 libcaptive processing even if it is just for debug-dumping of B<pass> type.
 
-=item (B<module>,B<symbol>,[undef|pass|wrap])
-
-=over
-
-=item ""
+=item (B<module>,B<symbol>)
 
 Name without special attribute declares function fully implemented by GNU/Linux
 code. Original W32 binary function will never be called.
@@ -287,7 +312,7 @@ code. Original W32 binary function will never be called.
 You may fully implement function for both E<lt>patchE<gt>ed and
 unE<lt>patchE<gt>ed modules.
 
-=item undef
+=item (B<module>,B<symbol>,undef)
 
 Optional "undef" specifies invocation of a generated stub function displaying
 C<g_error()> message.
@@ -299,14 +324,14 @@ W32-PE binary modules importing such symbol but it is still required for W32
 
 It is forbidden to "undef" C<DATA> type of items; you have to cope with it.
 
-=item pass
+=item (B<module>,B<symbol>,pass)
 
 Calls of this function are debug-dumped on its entry/exit but they are fully
 left to be solved by W32 binary file being E<lt>patchE<gt>ed.
 
 It is forbidden to specify "pass" for unE<lt>patchE<gt>ed modules.
 
-=item wrap
+=item (B<module>,B<symbol>,wrap)
 
 Calls of this function are debug-dumped on its entry/exit. Execution is left
 to be solved by your GNU/Linux implementation called B<functionname_wrap>.
@@ -320,8 +345,6 @@ It is forbidden to specify "wrap" for unE<lt>patchE<gt>ed modules.
 
 =back
 
-=back
-
 =begin comment
 
        choose one: