xref: /reactos/sdk/tools/stubgen.c (revision 1734f297)
1 #include <stdio.h>
2 #include <malloc.h>
3 #include <string.h>
4 #include <ctype.h>
5 
6 #ifdef _WIN32
7 #define popen _popen
8 #define snprintf _snprintf
9 #endif
10 
11 typedef struct _stub {
12     char *name;
13     char *origin;
14     struct _stub *next;
15 } stub;
16 
17 void usage( char *name ) {
18     fprintf( stderr,
19              "Usage: %s [-n nm] [-m make] libs...\n"
20              "nm   -- The command used to run nm on reactos objects\n"
21              "make -- The command used to build reactos\n\n"
22              "libs are import libraries (.a files) typically from\n"
23              "dk/lib/nkm and dk/lib/w32\n",
24              name );
25 }
26 
27 int main( int argc, char **argv ) {
28     char line[1024];
29     char *make = "make";
30     char *nm = "nm";
31     char *origin = "unknown.a";
32     stub *functions = NULL, *new_f, *imports = NULL, *search;
33     FILE *make_f, *nm_f;
34     int i, libstart = argc;
35     FILE *out = fopen("tests/stubs.tst","w");
36 
37     if( argc == 1 ) {
38         if( out ) fclose( out );
39         usage(argv[0]);
40         return 1;
41     }
42 
43     if( !out ) {
44         fprintf( stderr, "Could not write file tests/stubs.tst\n" );
45         return 1;
46     }
47 
48     fprintf( out, "# Automatically generated by stubgen\n" );
49 
50     for( i = 1; i < argc; i++ ) {
51         if( !strcmp( argv[i], "-m" ) ) {
52             make = argv[i+1];
53             i++;
54         } else if( !strcmp( argv[i], "-n" ) ) {
55             nm = argv[i+1];
56             i++;
57         } else { libstart = i; break; }
58     }
59 
60     snprintf( line, sizeof(line), "%s test 2>&1", make );
61     make_f = popen( line, "r" );
62 
63     if( !make_f ) {
64         fclose( out );
65         fprintf( stderr, "Could not run %s test\n", make );
66         return 1;
67     }
68 
69     while( fgets( line, sizeof(line), make_f ) ) {
70         char *end_of_location;
71         char *begin_q, *end_q;
72 
73         if( !strstr( line, "undefined reference to" ) ) continue;
74 
75         end_of_location = strrchr( line, ':' );
76 
77         if( !end_of_location ) continue;
78 
79         begin_q = strchr( end_of_location, '`' );
80         end_q = strchr( end_of_location, '\'' );
81 
82         if( !begin_q || !end_q ) continue;
83 
84         begin_q += 2; /* skip `_ */
85 
86         memmove( line, begin_q, end_q - begin_q );
87         line[end_q - begin_q] = 0;
88 
89         for( new_f = functions; new_f; new_f = new_f->next )
90             if( !strcmp( new_f->name, line ) ) break;
91 
92         if( new_f ) continue;
93 
94         new_f = (stub *)malloc( sizeof(stub) );
95         if( !new_f )
96         {
97             fprintf( stderr, "Out of memory\n" );
98             fclose( out );
99             pclose( make_f );
100             return 1;
101         }
102 
103         new_f->name = strdup( line );
104         new_f->next = functions;
105         functions = new_f;
106     }
107 
108     /* Scan libraries and collect available import sections */
109     for( i = libstart; i < argc; i++ ) {
110         snprintf( line, sizeof(line), "%s %s", nm, argv[i] );
111         nm_f = popen( line, "r" );
112 
113         for( origin = argv[i]; *argv[i]; argv[i]++ )
114             if( *argv[i] == '/' || *argv[i] == '\\' )
115                 origin = argv[i] + 1;
116 
117 
118         if( !nm_f ) {
119             fprintf( stderr, "Could not run %s\n", line );
120             continue;
121         }
122 
123         while( fgets( line, sizeof(line), nm_f ) ) {
124             char *import_sign, *eol;
125 
126             if( !(import_sign = strstr( line, " I " )) ) continue;
127 
128             import_sign += 3;
129             while( *import_sign && isspace(*import_sign) ) import_sign++;
130 
131             /* Strip ws after name */
132             for( eol = import_sign; *eol && !isspace(*eol); eol++ );
133 
134             *eol = 0;
135 
136             for( new_f = imports; new_f; new_f = new_f->next )
137                 if( !strcmp( new_f->name, import_sign ) ) break;
138 
139             if( new_f ) continue;
140 
141             new_f = (stub *)malloc( sizeof(stub) );
142             if( !new_f )
143             {
144                 fprintf( stderr, "Out of memory\n" );
145                 fclose( out );
146                 pclose( make_f );
147                 pclose( nm_f );
148                 return 1;
149             }
150 
151             new_f->name   = strdup( import_sign + 1 );
152             new_f->origin = origin;
153             new_f->next   = imports;
154             imports = new_f;
155         }
156 
157         pclose( nm_f );
158     }
159 
160     /* Now we have a list of unique functions and a list of imports,
161     lookup each function and output the entry from the import list. */
162     for( new_f = functions; new_f; new_f = new_f->next ) {
163         for( search = imports; search; search = search->next ) {
164             if( !strcmp( new_f->name, search->name ) ) {
165                 fprintf( out, "%s %s\n", search->origin, search->name );
166                 continue;
167             }
168         }
169     }
170 
171     fclose( out );
172     pclose( make_f );
173     return 0;
174 }
175