Generate hooks and stubs for tests

svn path=/branches/xmlbuildsystem/; revision=15304
This commit is contained in:
Casper Hornstrup 2005-05-15 11:58:48 +00:00
parent c141408f1d
commit 9017f3f4f6
11 changed files with 426 additions and 150 deletions

View file

@ -1,3 +1,19 @@
<module name="kernel32" type="win32dll" baseaddress="${BASEADDRESS_KERNEL32}" installbase="system32" installname="kernel32.dll">
<importlibrary definition="kernel32.def" />
<include base="kernel32">.</include>
<include base="kernel32">include</include>
<define name="_DISABLE_TIDENTS" />
<define name="_SEH_NO_NATIVE_NLG" />
<define name="WINVER">0x0500</define>
<library>kernel32_base</library>
<library>pseh</library>
<library>rosrtl</library>
<library>ntdll</library>
<linkerflag>-lgcc</linkerflag>
<linkerflag>-nostartfiles</linkerflag>
<linkerflag>-nostdlib</linkerflag>
<file>kernel32.rc</file>
</module>
<module name="kernel32_base" type="objectlibrary">
<include base="kernel32_base">.</include>
<include base="kernel32_base">include</include>
@ -104,22 +120,6 @@
<file>tls.c</file>
</directory>
</module>
<module name="kernel32" type="win32dll" baseaddress="${BASEADDRESS_KERNEL32}" installbase="system32" installname="kernel32.dll">
<importlibrary definition="kernel32.def" />
<include base="kernel32">.</include>
<include base="kernel32">include</include>
<define name="_DISABLE_TIDENTS" />
<define name="_SEH_NO_NATIVE_NLG" />
<define name="WINVER">0x0500</define>
<library>kernel32_base</library>
<library>pseh</library>
<library>rosrtl</library>
<library>ntdll</library>
<linkerflag>-lgcc</linkerflag>
<linkerflag>-nostartfiles</linkerflag>
<linkerflag>-nostdlib</linkerflag>
<file>kernel32.rc</file>
</module>
<!--
<directory name="tests">
<xi:include href="tests/kernel32.xml" />

View file

@ -93,7 +93,7 @@ MockNtCreateFile(PHANDLE FileHandle,
static HOOK NtCreateFileHooks[] =
{
{"NtCreateFile", MockNtCreateFile},
NULL, NULL
{NULL, NULL}
};
static void TestFile()

View file

@ -41,18 +41,6 @@ v2s ( const string_list& v, int wrap_at )
}
/* static */ string
Environment::GetVariable ( const string& name )
{
char* value = getenv ( name.c_str () );
if ( value != NULL && strlen ( value ) > 0 )
return ssprintf ( "%s",
value );
else
return "";
}
Directory::Directory ( const string& name_ )
: name(name_)
{
@ -131,45 +119,13 @@ Directory::ReplaceVariable ( string name,
return path;
}
/* static */ string
Directory::GetEnvironmentVariablePathOrDefault ( const string& name,
const string& defaultValue )
{
const string& environmentVariableValue = Environment::GetVariable ( name );
if ( environmentVariableValue.length () > 0 )
return NormalizeFilename ( environmentVariableValue );
else
return defaultValue;
}
/* static */ string
Directory::GetIntermediatePath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
"obj-i386" );
}
/* static */ string
Directory::GetOutputPath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
"output-i386" );
}
/* static */ string
Directory::GetInstallPath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
"reactos" );
}
void
Directory::ResolveVariablesInPath ( char* buf,
string path )
{
string s = ReplaceVariable ( "$(INTERMEDIATE)", GetIntermediatePath (), path );
s = ReplaceVariable ( "$(OUTPUT)", GetOutputPath (), s );
s = ReplaceVariable ( "$(INSTALL)", GetInstallPath (), s );
string s = ReplaceVariable ( "$(INTERMEDIATE)", Environment::GetIntermediatePath (), path );
s = ReplaceVariable ( "$(OUTPUT)", Environment::GetOutputPath (), s );
s = ReplaceVariable ( "$(INSTALL)", Environment::GetInstallPath (), s );
strcpy ( buf, s.c_str () );
}
@ -356,6 +312,7 @@ MingwBackend::Process ()
GenerateDirectoryTargets ();
GenerateDirectories ();
UnpackWineResources ();
GenerateTestSupportCode ();
CheckAutomaticDependencies ();
CloseMakefile ();
}
@ -641,7 +598,7 @@ MingwBackend::GenerateXmlBuildFilesMacro() const
string
MingwBackend::GetBin2ResExecutable ()
{
return NormalizeFilename ( Directory::GetOutputPath () + SSEP + "tools/bin2res/bin2res" + EXEPOSTFIX );
return NormalizeFilename ( Environment::GetOutputPath () + SSEP + "tools/bin2res/bin2res" + EXEPOSTFIX );
}
void
@ -654,6 +611,15 @@ MingwBackend::UnpackWineResources ()
printf ( "done\n" );
}
void
MingwBackend::GenerateTestSupportCode ()
{
printf ( "Generating test support code..." );
TestSupportCode testSupportCode ( ProjectNode );
testSupportCode.GenerateTestSupportCode ( verbose );
printf ( "done\n" );
}
void
MingwBackend::CheckAutomaticDependencies ()
{

View file

@ -18,13 +18,6 @@ v2s ( const string_list& v, int wrap_at );
typedef std::map<std::string,Directory*> directory_map;
class Environment
{
public:
static std::string GetVariable ( const std::string& name );
};
class Directory
{
public:
@ -37,17 +30,12 @@ public:
std::string EscapeSpaces ( std::string path );
void CreateRule ( FILE* f,
const std::string& parent );
static std::string GetIntermediatePath ();
static std::string GetOutputPath ();
static std::string GetInstallPath ();
private:
bool mkdir_p ( const char* path );
std::string ReplaceVariable ( std::string name,
std::string value,
std::string path );
std::string GetEnvironmentVariable ( const std::string& name );
static std::string GetEnvironmentVariablePathOrDefault ( const std::string& name,
const std::string& defaultValue );
void ResolveVariablesInPath ( char* buf,
std::string path );
bool CreateDirectory ( std::string path );
@ -92,6 +80,7 @@ private:
void GenerateXmlBuildFilesMacro() const;
std::string GetBin2ResExecutable ();
void UnpackWineResources ();
void GenerateTestSupportCode ();
void CheckAutomaticDependencies ();
bool IncludeDirectoryTarget ( const std::string& directory ) const;
bool TryToDetectThisCompiler ( const std::string& compiler );

View file

@ -0,0 +1,68 @@
#include "pch.h"
#include <assert.h>
#include "rbuild.h"
using std::string;
/* static */ void
FileSupportCode::WriteIfChanged ( char* outbuf,
string filename )
{
FILE* out;
unsigned int end;
char* cmpbuf;
unsigned int stat;
out = fopen ( filename.c_str (), "rb" );
if ( out == NULL )
{
out = fopen ( filename.c_str (), "wb" );
if ( out == NULL )
throw AccessDeniedException ( filename );
fputs ( outbuf, out );
fclose ( out );
return;
}
fseek ( out, 0, SEEK_END );
end = ftell ( out );
cmpbuf = (char*) malloc ( end );
if ( cmpbuf == NULL )
{
fclose ( out );
throw OutOfMemoryException ();
}
fseek ( out, 0, SEEK_SET );
stat = fread ( cmpbuf, 1, end, out );
if ( stat != end )
{
free ( cmpbuf );
fclose ( out );
throw AccessDeniedException ( filename );
}
if ( end == strlen ( outbuf ) && memcmp ( cmpbuf, outbuf, end ) == 0 )
{
free ( cmpbuf );
fclose ( out );
return;
}
free ( cmpbuf );
fclose ( out );
out = fopen ( filename.c_str (), "wb" );
if ( out == NULL )
{
throw AccessDeniedException ( filename );
}
stat = fwrite ( outbuf, 1, strlen ( outbuf ), out);
if ( strlen ( outbuf ) != stat )
{
fclose ( out );
throw AccessDeniedException ( filename );
}
fclose ( out );
}

View file

@ -7,6 +7,50 @@
using std::string;
using std::vector;
/* static */ string
Environment::GetVariable ( const string& name )
{
char* value = getenv ( name.c_str () );
if ( value != NULL && strlen ( value ) > 0 )
return ssprintf ( "%s",
value );
else
return "";
}
/* static */ string
Environment::GetEnvironmentVariablePathOrDefault ( const string& name,
const string& defaultValue )
{
const string& environmentVariableValue = Environment::GetVariable ( name );
if ( environmentVariableValue.length () > 0 )
return NormalizeFilename ( environmentVariableValue );
else
return defaultValue;
}
/* static */ string
Environment::GetIntermediatePath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_INTERMEDIATE",
"obj-i386" );
}
/* static */ string
Environment::GetOutputPath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_OUTPUT",
"output-i386" );
}
/* static */ string
Environment::GetInstallPath ()
{
return GetEnvironmentVariablePathOrDefault ( "ROS_INSTALL",
"reactos" );
}
Project::Project ( const string& filename )
: xmlfile (filename),
node (NULL),
@ -41,68 +85,6 @@ Project::LookupProperty ( const string& name ) const
return NULL;
}
void
Project::WriteIfChanged ( char* outbuf,
string filename )
{
FILE* out;
unsigned int end;
char* cmpbuf;
unsigned int stat;
out = fopen ( filename.c_str (), "rb" );
if ( out == NULL )
{
out = fopen ( filename.c_str (), "wb" );
if ( out == NULL )
throw AccessDeniedException ( filename );
fputs ( outbuf, out );
fclose ( out );
return;
}
fseek ( out, 0, SEEK_END );
end = ftell ( out );
cmpbuf = (char*) malloc ( end );
if ( cmpbuf == NULL )
{
fclose ( out );
throw OutOfMemoryException ();
}
fseek ( out, 0, SEEK_SET );
stat = fread ( cmpbuf, 1, end, out );
if ( stat != end )
{
free ( cmpbuf );
fclose ( out );
throw AccessDeniedException ( filename );
}
if ( end == strlen ( outbuf ) && memcmp ( cmpbuf, outbuf, end ) == 0 )
{
free ( cmpbuf );
fclose ( out );
return;
}
free ( cmpbuf );
fclose ( out );
out = fopen ( filename.c_str (), "wb" );
if ( out == NULL )
{
throw AccessDeniedException ( filename );
}
stat = fwrite ( outbuf, 1, strlen ( outbuf ), out);
if ( strlen ( outbuf ) != stat )
{
fclose ( out );
throw AccessDeniedException ( filename );
}
fclose ( out );
}
void
Project::SetConfigurationOption ( char* s,
string name,
@ -161,7 +143,7 @@ Project::WriteConfigurationFile ()
s = s + sprintf ( s, "#endif /* __INCLUDE_CONFIG_H */\n" );
WriteIfChanged ( buf, "include" SSEP "roscfg.h" );
FileSupportCode::WriteIfChanged ( buf, "include" SSEP "roscfg.h" );
free ( buf );
}

View file

@ -55,6 +55,7 @@ class If;
class CompilerFlag;
class LinkerFlag;
class Property;
class TestSupportCode;
class WineResource;
class AutomaticDependency;
class Bootstrap;
@ -66,6 +67,25 @@ class StubbedSymbol;
class SourceFileTest;
class Environment
{
public:
static std::string GetVariable ( const std::string& name );
static std::string GetIntermediatePath ();
static std::string GetOutputPath ();
static std::string GetInstallPath ();
static std::string GetEnvironmentVariablePathOrDefault ( const std::string& name,
const std::string& defaultValue );
};
class FileSupportCode
{
public:
static void WriteIfChanged ( char* outbuf,
std::string filename );
};
class IfableData
{
public:
@ -110,8 +130,6 @@ private:
std::string* alternativeName );
void SetConfigurationOption ( char* s,
std::string name );
void WriteIfChanged ( char* outbuf,
std::string filename );
void ReadXml ();
void ProcessXMLSubElement ( const XMLElement& e,
const std::string& path,
@ -422,6 +440,37 @@ public:
};
class TestSupportCode
{
public:
const Project& project;
TestSupportCode ( const Project& project );
~TestSupportCode ();
void GenerateTestSupportCode ( bool verbose );
private:
bool IsTestModule ( const Module& module );
void GenerateTestSupportCodeForModule ( Module& module,
bool verbose );
std::string GetHooksFilename ( Module& module );
char* WriteStubbedSymbolToHooksFile ( char* buffer,
const StubbedComponent& component,
const StubbedSymbol& symbol );
char* WriteStubbedComponentToHooksFile ( char* buffer,
const StubbedComponent& component );
void WriteHooksFile ( Module& module );
std::string GetStubsFilename ( Module& module );
char* WriteStubbedSymbolToStubsFile ( char* buffer,
const StubbedComponent& component,
const StubbedSymbol& symbol,
int stubIndex );
char* WriteStubbedComponentToStubsFile ( char* buffer,
const StubbedComponent& component,
int* stubIndex );
void WriteStubsFile ( Module& module );
};
class WineResource
{
public:
@ -610,10 +659,13 @@ public:
const XMLElement& node;
std::string symbol;
std::string newname;
std::string strippedName;
StubbedSymbol ( const XMLElement& stubbedSymbolNode );
~StubbedSymbol ();
void ProcessXML();
private:
std::string StripSymbol ( std::string symbol );
};
extern std::string

View file

@ -116,6 +116,7 @@ RBUILD_COMMON_SOURCES = \
compilerflag.cpp \
define.cpp \
exception.cpp \
filesupportcode.cpp \
include.cpp \
installfile.cpp \
linkerflag.cpp \
@ -123,6 +124,7 @@ RBUILD_COMMON_SOURCES = \
project.cpp \
ssprintf.cpp \
stubbedcomponent.cpp \
testsupportcode.cpp \
wineresource.cpp \
XML.cpp \
)
@ -230,6 +232,10 @@ $(RBUILD_INT_)exception.o: $(RBUILD_BASE_)exception.cpp $(RBUILD_HEADERS) | $(RB
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@
$(RBUILD_INT_)filesupportcode.o: $(RBUILD_BASE_)filesupportcode.cpp $(RBUILD_HEADERS) | $(RBUILD_INT)
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@
$(RBUILD_INT_)include.o: $(RBUILD_BASE_)include.cpp $(RBUILD_HEADERS) | $(RBUILD_INT)
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@
@ -266,6 +272,10 @@ $(RBUILD_INT_)wineresource.o: $(RBUILD_BASE_)wineresource.cpp $(RBUILD_HEADERS)
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@
$(RBUILD_INT_)testsupportcode.o: $(RBUILD_BASE_)testsupportcode.cpp $(RBUILD_HEADERS) | $(RBUILD_INT)
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@
$(RBUILD_INT_)XML.o: $(RBUILD_BASE_)XML.cpp $(RBUILD_HEADERS) | $(RBUILD_INT)
$(ECHO_CC)
${host_gpp} $(RBUILD_HOST_CXXFLAGS) -c $< -o $@

View file

@ -77,4 +77,23 @@ StubbedSymbol::ProcessXML ()
newname = att->value;
else
newname = symbol;
strippedName = StripSymbol ( symbol );
}
string
StubbedSymbol::StripSymbol ( string symbol )
{
size_t start = 0;
while ( start < symbol.length () && symbol[start] == '@')
start++;
size_t end = symbol.length () - 1;
while ( end > 0 && isdigit ( symbol[end] ) )
end--;
if ( end > 0 and symbol[end] == '@' )
end--;
if ( end > 0 )
return symbol.substr ( start, end - start + 1 );
else
return "";
}

View file

@ -0,0 +1,190 @@
#include "pch.h"
#include <assert.h>
#include "rbuild.h"
using std::string;
using std::vector;
TestSupportCode::TestSupportCode ( const Project& project )
: project ( project )
{
}
TestSupportCode::~TestSupportCode ()
{
}
bool
TestSupportCode::IsTestModule ( const Module& module )
{
return module.type == Test;
}
void
TestSupportCode::GenerateTestSupportCode ( bool verbose )
{
for ( size_t i = 0; i < project.modules.size (); i++ )
{
if ( IsTestModule ( *project.modules[i] ) )
{
GenerateTestSupportCodeForModule ( *project.modules[i],
verbose );
}
}
}
void
TestSupportCode::GenerateTestSupportCodeForModule ( Module& module,
bool verbose )
{
if ( verbose )
{
printf ( "\nGenerating test support code for %s",
module.name.c_str () );
}
WriteHooksFile ( module );
WriteStubsFile ( module );
}
string
TestSupportCode::GetHooksFilename ( Module& module )
{
return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_hooks.c" );
}
char*
TestSupportCode::WriteStubbedSymbolToHooksFile ( char* buffer,
const StubbedComponent& component,
const StubbedSymbol& symbol )
{
buffer = buffer + sprintf ( buffer,
" {\"%s\", \"%s\", NULL, NULL, NULL},\n",
component.name.c_str (),
symbol.strippedName.c_str () );
return buffer;
}
char*
TestSupportCode::WriteStubbedComponentToHooksFile ( char* buffer,
const StubbedComponent& component )
{
for ( size_t i = 0; i < component.symbols.size () ; i++ )
buffer = WriteStubbedSymbolToHooksFile ( buffer,
component,
*component.symbols[i] );
return buffer;
}
void
TestSupportCode::WriteHooksFile ( Module& module )
{
char* buf;
char* s;
buf = (char*) malloc ( 50*1024 );
if ( buf == NULL )
throw OutOfMemoryException ();
s = buf;
s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
s = s + sprintf ( s, "#include <windows.h>\n" );
s = s + sprintf ( s, "#include \"regtests.h\"\n" );
s = s + sprintf ( s, "\n" );
s = s + sprintf ( s, "API_DESCRIPTION ExternalDependencies[] =\n" );
s = s + sprintf ( s, "{\n" );
int symbolCount = 0;
for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
{
s = WriteStubbedComponentToHooksFile ( s,
*module.stubbedComponents[i] );
symbolCount += module.stubbedComponents[i]->symbols.size ();
}
s = s + sprintf ( s, "};\n" );
s = s + sprintf ( s, "\n" );
s = s + sprintf ( s, "#define ExternalDependencyCount %d\n", symbolCount );
s = s + sprintf ( s, "ULONG MaxExternalDependency = ExternalDependencyCount - 1;\n" );
s = s + sprintf ( s, "\n" );
FileSupportCode::WriteIfChanged ( buf, GetHooksFilename ( module ) );
free ( buf );
}
string
TestSupportCode::GetStubsFilename ( Module& module )
{
return NormalizeFilename ( Environment::GetIntermediatePath () + SSEP + module.GetBasePath () + SSEP + "_stubs.S" );
}
char*
TestSupportCode::WriteStubbedSymbolToStubsFile ( char* buffer,
const StubbedComponent& component,
const StubbedSymbol& symbol,
int stubIndex )
{
buffer = buffer + sprintf ( buffer,
".globl _%s\n",
symbol.symbol.c_str () );
buffer = buffer + sprintf ( buffer,
"_%s:\n",
symbol.symbol.c_str () );
buffer = buffer + sprintf ( buffer,
" pushl $%d\n",
stubIndex );
buffer = buffer + sprintf ( buffer,
" jmp passthrough\n" );
buffer = buffer + sprintf ( buffer, "\n" );
return buffer;
}
char*
TestSupportCode::WriteStubbedComponentToStubsFile ( char* buffer,
const StubbedComponent& component,
int* stubIndex )
{
for ( size_t i = 0; i < component.symbols.size () ; i++ )
buffer = WriteStubbedSymbolToStubsFile ( buffer,
component,
*component.symbols[i],
(*stubIndex)++ );
return buffer;
}
void
TestSupportCode::WriteStubsFile ( Module& module )
{
char* buf;
char* s;
buf = (char*) malloc ( 50*1024 );
if ( buf == NULL )
throw OutOfMemoryException ();
s = buf;
s = s + sprintf ( s, "/* This file is automatically generated. */\n" );
s = s + sprintf ( s, "passthrough:\n" );
s = s + sprintf ( s, " call _FrameworkGetHook@4\n" );
s = s + sprintf ( s, " test %%eax, %%eax\n" );
s = s + sprintf ( s, " je .return\n" );
s = s + sprintf ( s, " jmp *%%eax\n" );
s = s + sprintf ( s, ".return:\n" );
s = s + sprintf ( s, " /* This will most likely corrupt the stack */\n" );
s = s + sprintf ( s, " ret\n" );
s = s + sprintf ( s, "\n" );
int stubIndex = 0;
for ( size_t i = 0; i < module.stubbedComponents.size () ; i++ )
{
s = WriteStubbedComponentToStubsFile ( s,
*module.stubbedComponents[i],
&stubIndex );
}
FileSupportCode::WriteIfChanged ( buf, GetStubsFilename ( module ) );
free ( buf );
}

View file

@ -82,7 +82,7 @@ WineResource::UnpackResourcesInModule ( Module& module,
if ( verbose )
{
printf ( "Unpacking resources for %s",
printf ( "\nUnpacking resources for %s",
module.name.c_str () );
}