4 # Generate source files based on .captivesym symbol file
5 # Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; exactly version 2 of June 1991 is required
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 use vars qw($VERSION);
22 $VERSION=do { my @r=(q$Revision$=~/\d+/g); sprintf "%d.".("%03d"x$#r),@r; };
28 while ($ARGV[0] && $ARGV[0]=~/[.]def$/) {
29 map({ open DEF,"<$_" or die "open(\"$_\"): $!"; } shift());
33 next if /^(?:LIBRARY|EXPORTS)\b/s;
34 my($atsign,$symbol,$args,$argscdecl,$isdata)=(/^\s*(\@)?(\S+?)(?:\@(\d+))?(?::(\d+))?(\s+DATA)?\s*$/s);
35 die "Invalid line" if !defined $symbol;
36 # popped args doc *.def *.def2
37 # cdecl no stack _f f f:4
38 # stdcall yes stack _f@4 f@4
39 # fastcall yes ecx,edx,stack @f@4 @f@4
40 die "Invalid attributes for data symbol: $symbol" if $isdata && ($atsign || defined $args);
41 die "\@funcname without \@4 suffix not recognized: $symbol" if $atsign && !defined $args;
42 die "Invalid \@$args number: $symbol" if defined $args && ($args<0 || ($args%4));
44 die "Duplicate symbol: $symbol" if exists $def{$symbol};
47 die "cdecl-fixup without previous declaration: $symbol" if !$def{$symbol};
48 die "cdecl-fixup with non-cdecl previous declaration: $symbol" if $def{$symbol}{"type"} ne "cdecl";
49 die "cdecl-fixup for already fix-uped cdecl: $symbol" if exists $def{$symbol}{"args4"};
53 "type"=>($isdata ? "data" : (!defined $args ? "cdecl" : (!$atsign ? "stdcall" : "fastcall"))),
54 (!defined $args ? () : ("args4"=>$args/4)),
57 close DEF or warn "close(DEF): $!";
61 my %module; # $module{'module'}{'symbol'}=1/""
62 my %symbol; # $symbol{'symbol'}='module'
63 my %patch; # $patch{'module'}=1/undef
64 my %stats; # $stats{'iswhat'}=42
67 next if /^\s*$/s; # empty
68 next if /^\s*#.*/s; # comment
69 my($module,$symbol,$iswhat)=(/^\s*(\S+)\s+(\S+)(?:\s+(undef|pass|wrap))?\s*$/s);
70 $iswhat="" if !defined $iswhat;
71 die "Invalid line" if !defined $symbol;
72 if ($symbol eq "<patch>") {
73 die "Invalid line" if $iswhat;
74 die "Symbols already present during <patch> for: $module" if $module{$module}{$symbol};
78 die "Symbol already exists: $symbol" if exists $symbol{$symbol};
79 if ($iswhat eq "undef") {
80 warn "Undefined symbol not in *.def files; 'data' type risk imminent: $symbol" if !$def{$symbol};
81 die "Undefined 'data' type symbols are not safe: $symbol" if $def{$symbol} && $def{$symbol}{"type"} eq "data";
84 die "Symbol not in *.def files: $symbol" if $iswhat ne "undef" && !$def{$symbol};
85 if ($iswhat eq "pass" || $iswhat eq "wrap") {
86 die "args count not fixed up for '$iswhat' type: ".$symbol."[".$def{$symbol}{"type"}."]"
87 if !$def{$symbol}{"args4"} && $def{$symbol}{"type"} ne "data";
88 die "'$iswhat' not permitted if <patch> not specified for module on symbol: $symbol" if !$patch{$module};
89 $def{$symbol}{$iswhat}=1;
91 $module{$module}{$symbol}=$iswhat ne "undef";
92 $symbol{$symbol}=$module;
98 /* File generated automatically by captivesym.pl from "$ARGV" */
103 #include "captive/ldr_exports.h" /* for captive_ModuleList_add_builtin() */
104 #include <glib/gtypes.h>
105 #include <glib/gmessages.h>
106 #include <glib/gmacros.h>
108 #include <string.h> /* for built-in: strncmp,memmove,strncpy */
113 for my $symbol (sort keys(%symbol)) {
114 my $def=$def{$symbol};
116 # use global symbol named '${symbol}' to cause symbol conflict if it is already defined
118 #define ${symbol}_undef ${symbol}
121 g_error("%s: Function '$symbol' NOT IMPLEMENTED",G_STRLOC);
126 if ($patch{$symbol{$symbol}} && "data" ne $def->{"type"}) {
127 # We do not declare it 'static' as we sometimes make 'extern' references to it
128 # such as 'ExInitializeNPagedLookasideList_patchpoint' in libcaptive/ex/lookas.c.
129 print "struct captive_ModuleList_patchpoint ${symbol}_patchpoint;\n";
131 if ("data" eq $def->{"type"}) {
132 next if $def->{"pass"} || $def->{"wrap"}; # FIXME: export for .so
133 print "extern void/* ==unknown */ ${symbol};\n";
134 print "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
137 if ("cdecl" eq $def->{"type"} && !defined $def->{"args4"} && !$def->{"pass"} && !$def->{"wrap"}) {
138 # g_log(,G_LOG_LEVEL_DEBUG,...) not possible if we do not know the arguments count
139 my %forbidden=map(($_=>1),qw(strncmp memmove strncpy)); # Prevent: conflicting types for built-in function ...
140 print "void/* ==unknown */ ${symbol}(void/* ==unknown */);\n" if !$forbidden{$symbol};
141 print "#define ${symbol}_".$def->{"type"}." ${symbol}\n";
145 die "Needed argument count for: $symbol" if !defined $def->{"args4"};
146 my @args_out=map("arg$_",0..($def->{"args4"}-1));
147 my @args_in=($def->{"type"} ne "fastcall" ? @args_out
148 : ("stub_eax","arg1","arg0",@args_out[2..$#args_out]));
150 ."__attribute__((__".(map(($_ ne "fastcall" ? $_ : "stdcall"),$def->{"type"}))[0]."__)) "
151 .($def->{"type"} ne "fastcall" ? "" : "__attribute__((__regparm__(3)))");
152 for my $type ("clean","attrib") {
155 ." ".($type eq "clean" ? "" : $attrib)
156 ." (${symbol}_t_".$type.")(".(join(",",map("guint32 $_",
157 ($type eq "clean" ? @args_out : @args_in))) || "void").");\n";
159 if ($def->{"wrap"}) {
160 print "${symbol}_t_clean ${symbol}_wrap;\n";
162 elsif (!$def->{"pass"}) { # direct
163 print "${symbol}_t_clean $symbol;\n";
165 my @args_print=@args_out;
166 for my $pass ("outer","clean","inner") {
167 if ($pass eq "inner") {
168 next if !$def->{"wrap"}; # use two passes only for $def->{"wrap"}
169 # swap the roles of @args_in and @args_out
170 my @args_xchg=@args_in;
172 @args_out=@args_xchg;
174 next if $pass eq "clean" && !$def->{"pass"} && !$def->{"wrap"};
176 "guint64".($pass eq "outer" ? " $attrib" : "")
178 .($pass eq "clean" ? "" :
179 ($pass eq "inner" ? "_orig" : "_".$def->{"type"}))
180 ."(".(join(",",map("guint32 $_",($pass eq "clean" ? @args_out : @args_in))) || "void").")\n",
183 ($pass ne "outer" && $def->{"type"} eq "fastcall" ? "guint32 "
184 .join(",",map("$_=0xDEADF00D","stub_eax",
185 ($def->{"args4"}<=0 ? "arg0" : ()),
186 ($def->{"args4"}<=1 ? "arg1" : ())))
188 "\tg_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"
189 ."\"%s".($def->{"wrap"} ? ";$pass" : "")
190 ."(".join(",",map("0x%08x",@args_print)).")...\",".join(",","\"${symbol}\"",map("(unsigned)$_",@args_print))
193 if ($def->{"pass"} || ($def->{"wrap"} && $pass eq "inner")) {
195 "\tg_return_val_if_fail(${symbol}_patchpoint.orig_w32_func!=NULL,0);\n",
196 "\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n",
197 "\t${symbol}_patchpoint.through_w32_func=TRUE;\n",
198 "\tr=(*(${symbol}_t_attrib *)${symbol}_patchpoint.orig_w32_func)(".join(",",@args_in).");\n",
199 "\tg_assert(${symbol}_patchpoint.through_w32_func==FALSE);\n";
203 "\tr=${symbol}".($def->{"wrap"} ? "_wrap" : "")."(".join(",",@args_out).");\n";
206 # We diplay just the lower 32-bit of the result EDX:EAX as it is usually not used,
207 # the only exception are _all{mul,div,*}(); EDX:EAX convention is always compatible.
208 "\tg_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"
209 ."\"... %s".($def->{"wrap"} ? ";$pass" : "")
210 ."(".join(",",map("0x%08x",@args_print)).")=0x%08x\",".join(",","\"${symbol}\"",map("(unsigned)$_",@args_print)).",(guint32)r"
217 # write function captive_kernel_{exports,patches}()
218 for my $functype ("exports","patches") {
221 gboolean captive_kernel_$functype(void)
226 for my $module (sort keys(%module)) {
227 my $moduleref=$module{$module};
228 next if ($functype eq "patches") != defined $patch{$module};
230 .($functype eq "patches" ? "captive_ModuleList_patch" : "captive_ModuleList_add_builtin")
232 for my $symbol (sort keys(%$moduleref)) {
233 next if $functype eq "patches" && !$def{$symbol};
234 print "\t\t\t\"$symbol\",",(($functype eq "patches" && "data" eq $def{$symbol}{"type"}
235 && ($def{$symbol}{"pass"} || $def{$symbol}{"wrap"})) ? ("NULL")
236 : ("&${symbol}_",($def{$symbol}{"type"} || "undef"))),
237 (($functype ne "patches") ? () : (",".("data" eq $def{$symbol}{"type"} ? "NULL" : "&${symbol}_patchpoint"))),
242 g_return_val_if_fail(errbool,FALSE);
254 $total+=$_ for (values(%stats));
256 for my $statname (sort keys(%stats)) {
257 $statstring.=" ".($statname || "define")."=".$stats{$statname}."(".int(100*$stats{$statname}/$total)."%)";
259 print STDERR "$0: Processed ".scalar(keys(%module))." modules:".$statstring."\n";
267 captivesym.pl - Generate source files based on .captivesym symbol file
271 ./captivesym.pl path/to/ntoskrnl.def path/to/hal.def exports.captivesym E<gt>exports.c
275 Source files with symbol call type definitions are identified by matching
276 pattern I<*.def>. The remaining files (I<.captivesym> ones) must
277 consist of lines with whitespace-separated lines as described below.
281 =item (B<module>,E<lt>patchE<gt>)
283 Declare B<module> as mandatory W32 binary file to be patched by libcaptive.
284 Currently being used only for C<ntoskrnl.exe>.
286 Any function call even inside such module is trapped and redirected for
287 libcaptive processing even if it is just for debug-dumping of B<pass> type.
289 =item (B<module>,B<symbol>,[undef|pass|wrap])
295 Name without special attribute declares function fully implemented by GNU/Linux
296 code. Original W32 binary function will never be called.
298 You may fully implement function for both E<lt>patchE<gt>ed and
299 unE<lt>patchE<gt>ed modules.
303 Optional "undef" specifies invocation of a generated stub function displaying
304 C<g_error()> message.
306 For "unpatched" modules you have to specify all the referenced symbols at least
307 as this "undef" symbol. For "patched" modules it is not needed for native
308 W32-PE binary modules importing such symbol but it is still required for W32
309 .so files to satisfy .so dynamic linker.
311 It is forbidden to "undef" C<DATA> type of items; you have to cope with it.
315 Calls of this function are debug-dumped on its entry/exit but they are fully
316 left to be solved by W32 binary file being E<lt>patchE<gt>ed.
318 It is forbidden to specify "pass" for unE<lt>patchE<gt>ed modules.
322 Calls of this function are debug-dumped on its entry/exit. Execution is left
323 to be solved by your GNU/Linux implementation called B<functionname_wrap>.
324 You are allowed to call the original W32 binary function named
325 B<functionname_orig> but you have to use your own prototype declaration for it.
326 Both B<functionname_wrap> and B<functionname_orig> should be used with standard
327 GNU/Linux C compiler function call type notwithstanding any real W32
328 implementation details.
330 It is forbidden to specify "wrap" for unE<lt>patchE<gt>ed modules.
339 podchecker: *** WARNING: node 'http:$_' contains non-escaped | or /
340 pod2html: cannot resolve L.lt.http:$_.gt.
344 Source files I<*.def> are required to have on of three item types described at
345 L<http://msdn.microsoft.com/library/en-us/vclang/html/_core_argument_passing_and_naming_conventions.asp>
346 (B<argslength> must be dividable by B<4>):
350 =item cdecl: functionname
352 =item stdcall: functionname@argslength
354 =item fastcall: @functionname@argslength
356 =item cdecl fixup: functionname:argslength
358 This item must follow (even in some other I<*.def> file) previous B<cdecl>
359 specification to specify the number of arguments as it is required for B<pass>
360 or B<wrap> type of B<cdecl> function calls.
366 Copyright (C) 2002-2003 Jan Kratochvil <project-captive@jankratochvil.net>
368 This program is free software; you can redistribute it and/or modify
369 it under the terms of the GNU General Public License as published by
370 the Free Software Foundation; exactly version 2 of June 1991 is required
372 This program is distributed in the hope that it will be useful,
373 but WITHOUT ANY WARRANTY; without even the implied warranty of
374 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
375 GNU General Public License for more details.
377 You should have received a copy of the GNU General Public License
378 along with this program; if not, write to the Free Software
379 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA