diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 1a4d9231..77b96dac 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -29,6 +29,9 @@ jobs:
with:
dotnet-version: '8.0.x'
dotnet-quality: 'preview'
+
+ - name: List dotnet information
+ run: dotnet --info
- name: Build Vendored Dependencies
if: ${{ !matrix.use-vendored-libs }}
@@ -46,13 +49,8 @@ jobs:
cmake -S . -B artifacts -DCMAKE_BUILD_TYPE=${{ matrix.flavor }} -DINCLUDE_VENDORED_LIBS=${{ matrix.use-vendored-libs }}
cmake --build artifacts --config ${{ matrix.flavor }} --target install
- - name: Build Managed Test Components
- run: dotnet build --configuration ${{ matrix.flavor }}
- working-directory: ./test
-
- - name: Run Unit Tests
- run: dotnet test --configuration ${{ matrix.flavor }} --logger trx --results-directory "TestResults-${{ matrix.os }}-${{ matrix.flavor }}"
- working-directory: ./test/Regression.UnitTests
+ - name: Run Tests
+ run: ctest --test-dir artifacts --output-on-failure -C ${{ matrix.flavor }}
# - name: Upload Test Results
# if: always()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ea98b419..ad428c6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -16,5 +16,8 @@ include_directories(src/inc)
include_directories(src/inc/external) # Hiding the "external" subdirectory due to uses of <...> in cor.h.
add_subdirectory(src/)
+
+enable_testing()
+
add_subdirectory(test/)
diff --git a/Directory.Build.props b/Directory.Build.props
index c1a9124c..c8149211 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,22 +1,12 @@
- Debug
-
-
-
- $(MSBuildThisFileDirectory)
- $(RepoDir)artifacts
- $(BaseArtifactsPath)/$(Configuration)/
-
- $(ArtifactsDir)obj/$(MSBuildProjectName)
- $(ArtifactsDir)bin/$(MSBuildProjectName)
+ true
+ $(MSBuildThisFileDirectory)/artifacts/managed
- $(BaseIntermediateOutputPath)
- $(BaseOutputPath)
$(BaseArtifactsPath)/bin
$(BaseArtifactsPath)/lib
- net8.0
+ net8.0
\ No newline at end of file
diff --git a/src/inc/internal/dnmd_platform.hpp b/src/inc/internal/dnmd_platform.hpp
index 767fc9ef..215a35e9 100644
--- a/src/inc/internal/dnmd_platform.hpp
+++ b/src/inc/internal/dnmd_platform.hpp
@@ -13,6 +13,14 @@
#endif // !BUILD_WINDOWS
+// Machine code masks for native (R2R) images
+// See pedecoder.h in CoreCLR
+#define IMAGE_FILE_MACHINE_OS_MASK_APPLE 0x4644
+#define IMAGE_FILE_MACHINE_OS_MASK_FREEBSD 0xADC4
+#define IMAGE_FILE_MACHINE_OS_MASK_LINUX 0x7B79
+#define IMAGE_FILE_MACHINE_OS_MASK_NETBSD 0x1993
+#define IMAGE_FILE_MACHINE_OS_MASK_SUN 0x1992
+
#include
#include
diff --git a/src/inc/internal/dnmd_tools_platform.hpp b/src/inc/internal/dnmd_tools_platform.hpp
index efb69f18..d7c0de13 100644
--- a/src/inc/internal/dnmd_tools_platform.hpp
+++ b/src/inc/internal/dnmd_tools_platform.hpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include "dnmd_platform.hpp"
#include "span.hpp"
@@ -85,6 +86,33 @@ inline bool write_out_file(char const* file, malloc_span b)
return true;
}
+inline bool find_pe_image_bitness(uint16_t machine, uint8_t& bitness)
+{
+#define MAKE_MACHINE_CASE(x) \
+ case ((x) ^ IMAGE_FILE_MACHINE_OS_MASK_APPLE): \
+ case ((x) ^ IMAGE_FILE_MACHINE_OS_MASK_FREEBSD): \
+ case ((x) ^ IMAGE_FILE_MACHINE_OS_MASK_LINUX): \
+ case ((x) ^ IMAGE_FILE_MACHINE_OS_MASK_NETBSD): \
+ case ((x) ^ IMAGE_FILE_MACHINE_OS_MASK_SUN): \
+ case (x)
+
+ switch (machine)
+ {
+ MAKE_MACHINE_CASE(IMAGE_FILE_MACHINE_I386):
+ MAKE_MACHINE_CASE(IMAGE_FILE_MACHINE_ARM):
+ bitness = 32;
+ return true;
+ MAKE_MACHINE_CASE(IMAGE_FILE_MACHINE_AMD64):
+ MAKE_MACHINE_CASE(IMAGE_FILE_MACHINE_ARM64):
+ bitness = 64;
+ return true;
+ default:
+ return false;
+ }
+
+#undef MAKE_MACHINE_CASE
+}
+
inline bool get_metadata_from_pe(malloc_span& b)
{
if (b.size() < sizeof(IMAGE_DOS_HEADER))
@@ -111,8 +139,13 @@ inline bool get_metadata_from_pe(malloc_span& b)
uint16_t section_header_count;
uint8_t* section_header_begin;
auto nt_header_any = (PIMAGE_NT_HEADERS)(b + dos_header->e_lfanew);
- if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64
- || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM64)
+ uint16_t machine = nt_header_any->FileHeader.Machine;
+
+ uint8_t bitness;
+ if (!find_pe_image_bitness(machine, bitness))
+ return false;
+
+ if (bitness == 64)
{
auto nt_header64 = (PIMAGE_NT_HEADERS64)nt_header_any;
if (remaining_pe_size < sizeof(*nt_header64))
@@ -122,8 +155,7 @@ inline bool get_metadata_from_pe(malloc_span& b)
section_header_begin = (uint8_t*)&nt_header64[1];
dotnet_dir = &nt_header64->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR];
}
- else if (nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_I386
- || nt_header_any->FileHeader.Machine == IMAGE_FILE_MACHINE_ARM)
+ else if (bitness == 32)
{
auto nt_header32 = (PIMAGE_NT_HEADERS32)nt_header_any;
if (remaining_pe_size < sizeof(*nt_header32))
diff --git a/src/interfaces/metadataimport.cpp b/src/interfaces/metadataimport.cpp
index 0c60f1ea..de232412 100644
--- a/src/interfaces/metadataimport.cpp
+++ b/src/interfaces/metadataimport.cpp
@@ -2727,7 +2727,7 @@ HRESULT STDMETHODCALLTYPE MetadataImportRO::GetCustomAttributeByName(
mdcursor_t cursor;
uint32_t count;
if (!md_create_cursor(_md_ptr.get(), mdtid_CustomAttribute, &cursor, &count))
- return CLDB_E_RECORD_NOTFOUND;
+ return S_FALSE; // If no custom attributes are defined, treat it the same as if the attribute is not found.
char buffer[1024];
pal::StringConvert cvt{ szName, buffer };
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 1c4112a8..fb59f89f 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,4 +1,40 @@
# Configure the compiler
include(../configure.cmake)
+include(FindNetHost.cmake)
-add_subdirectory(regnative/)
\ No newline at end of file
+if (POLICY CMP0135)
+ cmake_policy(SET CMP0135 NEW) # Set timestamps in downloaded archives to the time of download.
+endif()
+
+include(FetchContent)
+FetchContent_Declare(
+ googletest
+ GIT_REPOSITORY
+ https://github.com/google/googletest.git
+ GIT_TAG
+ v1.14.0
+)
+# For Windows: Prevent overriding the parent project's compiler/linker settings
+set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
+set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
+
+FetchContent_Declare(
+ benchmark
+ GIT_REPOSITORY
+ https://github.com/google/benchmark.git
+ GIT_TAG
+ v1.8.3
+)
+
+# Don't build the tests for the benchmark library.
+set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
+set(BENCHMARK_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
+FetchContent_MakeAvailable(googletest benchmark)
+
+include(GoogleTest)
+
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_subdirectory(regpal)
+add_subdirectory(regperf)
+add_subdirectory(regtest)
diff --git a/test/DNMD.Tests.sln b/test/DNMD.Tests.sln
index 66062f70..1c895967 100644
--- a/test/DNMD.Tests.sln
+++ b/test/DNMD.Tests.sln
@@ -3,10 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.33026.144
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Regression.UnitTests", "Regression.UnitTests\Regression.UnitTests.csproj", "{D5105B2A-6016-4B1C-A46B-5A841AE5AD26}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Regression.Performance", "Regression.Performance\Regression.Performance.csproj", "{3ED137D0-B5A2-4309-BDA5-BD9DE3FFC752}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Regression.TargetAssembly", "Regression.TargetAssembly\Regression.TargetAssembly.ilproj", "{D3BEEF3D-C137-49AC-96DD-E5B93E2F4C21}"
EndProject
Global
@@ -15,14 +11,6 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {D5105B2A-6016-4B1C-A46B-5A841AE5AD26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D5105B2A-6016-4B1C-A46B-5A841AE5AD26}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D5105B2A-6016-4B1C-A46B-5A841AE5AD26}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D5105B2A-6016-4B1C-A46B-5A841AE5AD26}.Release|Any CPU.Build.0 = Release|Any CPU
- {3ED137D0-B5A2-4309-BDA5-BD9DE3FFC752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3ED137D0-B5A2-4309-BDA5-BD9DE3FFC752}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3ED137D0-B5A2-4309-BDA5-BD9DE3FFC752}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3ED137D0-B5A2-4309-BDA5-BD9DE3FFC752}.Release|Any CPU.Build.0 = Release|Any CPU
{D3BEEF3D-C137-49AC-96DD-E5B93E2F4C21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D3BEEF3D-C137-49AC-96DD-E5B93E2F4C21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D3BEEF3D-C137-49AC-96DD-E5B93E2F4C21}.Release|Any CPU.ActiveCfg = Release|Any CPU
diff --git a/test/FindNetHost.cmake b/test/FindNetHost.cmake
new file mode 100644
index 00000000..c141d7a4
--- /dev/null
+++ b/test/FindNetHost.cmake
@@ -0,0 +1,22 @@
+execute_process(
+ COMMAND ${CMAKE_COMMAND} -E env DOTNET_NOLOGO=1 dotnet msbuild FindNetHostDir.proj -t:OutputNetHostDir -nologo
+ OUTPUT_VARIABLE NET_HOST_DIR
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ COMMAND_ERROR_IS_FATAL ANY
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
+
+string(STRIP ${NET_HOST_DIR} NET_HOST_DIR)
+
+if (WIN32)
+ add_library(nethost IMPORTED SHARED)
+ set_target_properties(nethost PROPERTIES
+ IMPORTED_LOCATION ${NET_HOST_DIR}/nethost.dll
+ IMPORTED_IMPLIB ${NET_HOST_DIR}/nethost.lib)
+else()
+ add_library(nethost IMPORTED STATIC)
+ target_compile_definitions(nethost INTERFACE NETHOST_USE_AS_STATIC)
+ set_target_properties(nethost PROPERTIES
+ IMPORTED_LOCATION ${NET_HOST_DIR}/libnethost.a)
+endif()
+
+target_include_directories(nethost INTERFACE ${NET_HOST_DIR})
\ No newline at end of file
diff --git a/test/FindNetHostDir.proj b/test/FindNetHostDir.proj
new file mode 100644
index 00000000..c2130191
--- /dev/null
+++ b/test/FindNetHostDir.proj
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/test/Regression.Performance/Program.cs b/test/Regression.Performance/Program.cs
deleted file mode 100644
index 411e716e..00000000
--- a/test/Regression.Performance/Program.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using System.Diagnostics;
-using System.Reflection.PortableExecutable;
-using System.Runtime.InteropServices;
-
-using Common;
-
-namespace Regression.Performance
-{
- public unsafe class Compare
- {
- private PEReader _peReader;
- private PEMemoryBlock _metadataBlock;
-
- delegate* unmanaged _Initialize;
-
- private readonly struct Scenario
- {
- public string Name { get; init; }
- public delegate* unmanaged Baseline { get; init; }
- public delegate* unmanaged Current { get; init; }
- }
-
- List _scenarios = new();
-
- public Compare(string currentPath)
- {
- // Load System.Private.CoreLib
- var spcl = typeof(object).Assembly.Location;
- _peReader = new(File.OpenRead(spcl));
- _metadataBlock = _peReader.GetMetadata();
-
- // Acquire native functions
- nint mod = NativeLibrary.Load(currentPath);
- _Initialize = (delegate* unmanaged)NativeLibrary.GetExport(mod, "PerfInitialize");
-
- string[] scenarioNames = new[]
- {
- "CreateImport",
- "EnumTypeDefs",
- "GetScopeProps",
- "EnumUserStrings",
- "GetCustomAttributeByName",
- };
-
- // Look up each scenario test export.
- foreach (var name in scenarioNames)
- {
- _scenarios.Add(new Scenario()
- {
- Name = name,
- Baseline = (delegate* unmanaged)NativeLibrary.GetExport(mod, $"PerfBaseline{name}"),
- Current = (delegate* unmanaged)NativeLibrary.GetExport(mod, $"PerfCurrent{name}"),
- });
- }
-
- int hr = _Initialize(_metadataBlock.Pointer, _metadataBlock.Length, Dispensers.Baseline);
- if (hr < 0)
- {
- throw new Exception($"Initialization failed: 0x{hr:x}");
- }
- }
-
- public void Run(int iter)
- {
- int hr;
- const int width = 12;
- var sw = new Stopwatch();
-
- foreach (var scenario in _scenarios)
- {
- Console.WriteLine(scenario.Name);
- sw.Restart();
- hr = scenario.Baseline(iter);
- Console.WriteLine($" Baseline: {sw.ElapsedMilliseconds,width}");
- if (hr < 0) throw new Exception($"Failure 0x{hr:x}");
- sw.Restart();
- hr = scenario.Current(iter);
- Console.WriteLine($" Current: {sw.ElapsedMilliseconds,width}");
- if (hr < 0) throw new Exception($"Failure 0x{hr:x}");
- }
- }
- }
-
- public class Program
- {
- public static void Main(string[] args)
- {
- string regnativePath;
- if (args.Length > 0)
- {
- regnativePath = args[0];
- }
- else
- {
- regnativePath =
- OperatingSystem.IsWindows() ? "regnative.dll"
- : OperatingSystem.IsMacOS() ? "libregnative.dylib"
- : "libregnative.so";
- regnativePath = Path.Combine(AppContext.BaseDirectory, regnativePath);
- }
-
- var test = new Compare(regnativePath);
-
- Console.WriteLine("Warm-up");
- test.Run(100);
-
- const int iter = 100_000;
- Console.WriteLine($"\nRun iterations - {iter}");
- test.Run(iter);
- }
- }
-}
diff --git a/test/Regression.Performance/Regression.Performance.csproj b/test/Regression.Performance/Regression.Performance.csproj
deleted file mode 100644
index 8e616900..00000000
--- a/test/Regression.Performance/Regression.Performance.csproj
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
- $(TargetFrameworkLatest)
- Exe
- enable
- enable
- true
-
- false
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/Regression.TargetAssembly/Regression.TargetAssembly.ilproj b/test/Regression.TargetAssembly/Regression.TargetAssembly.ilproj
index ed558a53..5f92f5ae 100644
--- a/test/Regression.TargetAssembly/Regression.TargetAssembly.ilproj
+++ b/test/Regression.TargetAssembly/Regression.TargetAssembly.ilproj
@@ -1,6 +1,5 @@
- $(TargetFrameworkLatest)
Library
false
diff --git a/test/Regression.UnitTests/ImportTests.cs b/test/Regression.UnitTests/ImportTests.cs
deleted file mode 100644
index 6eb6a8f1..00000000
--- a/test/Regression.UnitTests/ImportTests.cs
+++ /dev/null
@@ -1,324 +0,0 @@
-using System.Buffers;
-using System.Diagnostics;
-using System.Text;
-using System.Reflection.Metadata;
-using System.Runtime.CompilerServices;
-using System.Reflection.PortableExecutable;
-using System.Runtime.InteropServices;
-using System.Runtime.Versioning;
-
-using Common;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.Emit;
-using Xunit;
-using Xunit.Abstractions;
-
-namespace Regression.UnitTests
-{
- public unsafe class ImportTests
- {
- private delegate* unmanaged _importAPIs;
- private delegate* unmanaged _longRunningAPIs;
- private delegate* unmanaged _findAPIs;
- private delegate* unmanaged _importAPIsIndirectionTables;
-
- public ImportTests(ITestOutputHelper outputHelper)
- {
- Log = outputHelper;
-
- nint mod = NativeLibrary.Load(Path.Combine(AppContext.BaseDirectory, Native.Path));
- var initialize = (delegate* unmanaged)NativeLibrary.GetExport(mod, "UnitInitialize");
- int hr = initialize((void*)Dispensers.Baseline, (void*)Dispensers.DeltaImageBuilder);
- if (hr < 0)
- {
- throw new Exception($"Initialization failed: 0x{hr:x}");
- }
-
- _importAPIs = (delegate* unmanaged)NativeLibrary.GetExport(mod, "UnitImportAPIs");
- _longRunningAPIs = (delegate* unmanaged)NativeLibrary.GetExport(mod, "UnitLongRunningAPIs");
- _findAPIs = (delegate* unmanaged)NativeLibrary.GetExport(mod, "UnitFindAPIs");
- _importAPIsIndirectionTables = (delegate* unmanaged)NativeLibrary.GetExport(mod, "UnitImportAPIsIndirectionTables");
- }
-
- private ITestOutputHelper Log { get; }
-
- public static IEnumerable