#include #include #include #include #ifdef _WIN32 #define popen _popen #define snprintf _snprintf #endif typedef struct _stub { char *name; char *origin; struct _stub *next; } stub; void usage( char *name ) { fprintf( stderr, "Usage: %s [-n nm] [-m make] libs...\n" "nm -- The command used to run nm on reactos objects\n" "make -- The command used to build reactos\n\n" "libs are import libraries (.a files) typically from\n" "dk/lib/nkm and dk/lib/w32\n", name ); } int main( int argc, char **argv ) { char line[1024]; char *make = "make"; char *nm = "nm"; char *origin = "unknown.a"; stub *functions = NULL, *new_f, *imports = NULL, *search; FILE *make_f, *nm_f; int i, libstart = argc; FILE *out = fopen("tests/stubs.tst","w"); if( argc == 1 ) { if( out ) fclose( out ); usage(argv[0]); return 1; } if( !out ) { fprintf( stderr, "Could not write file tests/stubs.tst\n" ); return 1; } fprintf( out, "# Automatically generated by stubgen\n" ); for( i = 1; i < argc; i++ ) { if( !strcmp( argv[i], "-m" ) ) { make = argv[i+1]; i++; } else if( !strcmp( argv[i], "-n" ) ) { nm = argv[i+1]; i++; } else { libstart = i; break; } } snprintf( line, sizeof(line), "%s test 2>&1", make ); make_f = popen( line, "r" ); if( !make_f ) { fclose( out ); fprintf( stderr, "Could not run %s test\n", make ); return 1; } while( fgets( line, sizeof(line), make_f ) ) { char *end_of_location; char *begin_q, *end_q; if( !strstr( line, "undefined reference to" ) ) continue; end_of_location = strrchr( line, ':' ); if( !end_of_location ) continue; begin_q = strchr( end_of_location, '`' ); end_q = strchr( end_of_location, '\'' ); if( !begin_q || !end_q ) continue; begin_q += 2; /* skip `_ */ memmove( line, begin_q, end_q - begin_q ); line[end_q - begin_q] = 0; for( new_f = functions; new_f; new_f = new_f->next ) if( !strcmp( new_f->name, line ) ) break; if( new_f ) continue; new_f = (stub *)malloc( sizeof(stub) ); if( !new_f ) { fprintf( stderr, "Out of memory\n" ); fclose( out ); pclose( make_f ); return 1; } new_f->name = strdup( line ); new_f->next = functions; functions = new_f; } /* Scan libraries and collect available import sections */ for( i = libstart; i < argc; i++ ) { snprintf( line, sizeof(line), "%s %s", nm, argv[i] ); nm_f = popen( line, "r" ); for( origin = argv[i]; *argv[i]; argv[i]++ ) if( *argv[i] == '/' || *argv[i] == '\\' ) origin = argv[i] + 1; if( !nm_f ) { fprintf( stderr, "Could not run %s\n", line ); continue; } while( fgets( line, sizeof(line), nm_f ) ) { char *import_sign, *eol; if( !(import_sign = strstr( line, " I " )) ) continue; import_sign += 3; while( *import_sign && isspace(*import_sign) ) import_sign++; /* Strip ws after name */ for( eol = import_sign; *eol && !isspace(*eol); eol++ ); *eol = 0; for( new_f = imports; new_f; new_f = new_f->next ) if( !strcmp( new_f->name, import_sign ) ) break; if( new_f ) continue; new_f = (stub *)malloc( sizeof(stub) ); if( !new_f ) { fprintf( stderr, "Out of memory\n" ); fclose( out ); pclose( make_f ); pclose( nm_f ); return 1; } new_f->name = strdup( import_sign + 1 ); new_f->origin = origin; new_f->next = imports; imports = new_f; } pclose( nm_f ); } /* Now we have a list of unique functions and a list of imports, lookup each function and output the entry from the import list. */ for( new_f = functions; new_f; new_f = new_f->next ) { for( search = imports; search; search = search->next ) { if( !strcmp( new_f->name, search->name ) ) { fprintf( out, "%s %s\n", search->origin, search->name ); continue; } } } fclose( out ); pclose( make_f ); return 0; }