Merge pull request #3686 from lambdageek/dev-format-printf
authorAleksey Kliger (λgeek) <akliger@gmail.com>
Tue, 4 Oct 2016 14:05:33 +0000 (10:05 -0400)
committerGitHub <noreply@github.com>
Tue, 4 Oct 2016 14:05:33 +0000 (10:05 -0400)
Add MONO_ATTR_FORMAT_PRINTF macro

276 files changed:
.gitmodules
acceptance-tests/profiler-stress.mk
acceptance-tests/profiler-stress/runner.cs
configure.ac
external/boringssl [new submodule]
man/mprof-report.1
mcs/build/profiles/monotouch_watch.make
mcs/build/profiles/monotouch_watch_runtime.make
mcs/class/Makefile
mcs/class/Mono.Btls.Interface/Makefile [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface.dll.sources [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsObject.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Chain.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Error.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Format.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Lookup.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Name.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Purpose.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Store.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreCtx.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreManager.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreType.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509TrustKind.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyFlags.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyParam.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/VersionInfo.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/Properties/AssemblyInfo.cs [new file with mode: 0644]
mcs/class/Mono.Btls.Interface/README.md [new file with mode: 0644]
mcs/class/Mono.Debugger.Soft/Makefile
mcs/class/Mono.Debugger.Soft/Test/TypeLoadClass.cs [new file with mode: 0644]
mcs/class/Mono.Debugger.Soft/Test/dtest-app.cs
mcs/class/Mono.Debugger.Soft/Test/dtest.cs
mcs/class/Mono.Security/Mono.Security-net_4_x.csproj
mcs/class/Mono.Security/Mono.Security.Interface/IMonoTlsContext.cs [deleted file]
mcs/class/Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs
mcs/class/Mono.Security/Mono.Security.X509/X509Store.cs
mcs/class/Mono.Security/Mono.Security.X509/X509StoreManager.cs
mcs/class/Mono.Security/Mono.Security.X509/X509Stores.cs
mcs/class/Mono.Security/Mono.Security.dll.sources
mcs/class/System.Core/System.IO.Pipes/AnonymousPipeClientStream.cs
mcs/class/System.Core/System.IO.Pipes/NamedPipeClientStream.cs
mcs/class/System.Core/System.IO.Pipes/NamedPipeServerStream.cs
mcs/class/System.Data/Makefile
mcs/class/System.Data/System.Data.SqlClient/SqlBulkCopy.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlCommandBuilder.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.cs
mcs/class/System.Data/System.Data.SqlClient/SqlConnection.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlDependency.cs
mcs/class/System.Data/System.Data.SqlClient/SqlException.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlParameter.cs
mcs/class/System.Data/System.Data.SqlClient/SqlParameter.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlParameterCollection.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/System.Data.SqlClient/SqlTransaction.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System.Data/Test/System.Data.Common/DbDataAdapterTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlBulkCopyTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlCommandBuilderTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlCommandTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlConnectionTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlDataAdapterTest.cs
mcs/class/System.Data/Test/System.Data.SqlClient/SqlParameterTest.cs
mcs/class/System.Data/monotouch_watch_System.Data.dll.exclude.sources [new file with mode: 0644]
mcs/class/System.Data/monotouch_watch_System.Data.dll.sources
mcs/class/System.IdentityModel/Makefile
mcs/class/System.Security/Makefile
mcs/class/System/Assembly/AssemblyInfo.cs
mcs/class/System/Makefile
mcs/class/System/Mono.Btls/MonoBtlsBio.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsContext.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsError.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsException.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsKey.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsObject.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsPkcs12.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsProvider.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsSsl.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsSslCtx.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsSslError.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsStream.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsUtils.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Chain.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Crl.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Error.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Exception.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509FileType.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Format.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509LookupMono.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509LookupMonoCollection.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509LookupType.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Name.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509NameEntryType.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Purpose.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Revoked.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509Store.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509StoreCtx.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509StoreManager.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509StoreType.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509TrustKind.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509VerifyFlags.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/MonoBtlsX509VerifyParam.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs [new file with mode: 0644]
mcs/class/System/Mono.Btls/X509ChainImplBtls.cs [new file with mode: 0644]
mcs/class/System/Mono.Net.Security/ChainValidationHelper.cs
mcs/class/System/Mono.Net.Security/IMonoTlsProvider.cs
mcs/class/System/Mono.Net.Security/LegacyTlsProvider.cs
mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.Droid.cs
mcs/class/System/Mono.Net.Security/MonoTlsProviderFactory.cs
mcs/class/System/Mono.Net.Security/MonoTlsProviderImpl.cs [deleted file]
mcs/class/System/Mono.Net.Security/MonoTlsProviderWrapper.cs
mcs/class/System/System-bare-net_4_x.csproj
mcs/class/System/System-net_4_x.csproj
mcs/class/System/System-secxml-net_4_x.csproj
mcs/class/System/System.Net.Security/SslStream.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System/System.Net/AuthenticationManager.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System/System.Net/HttpListener.platformnotsupported.cs
mcs/class/System/System.Net/HttpWebRequest.cs
mcs/class/System/System.Net/HttpWebRequest.platformnotsupported.cs
mcs/class/System/System.Net/HttpWebResponse.cs
mcs/class/System/System.Net/ServicePoint.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System/System.Net/ServicePointManager.platformnotsupported.cs [new file with mode: 0644]
mcs/class/System/System.Net/WebConnection.cs
mcs/class/System/System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
mcs/class/System/System.Security.Cryptography.X509Certificates/X509Helper2.cs
mcs/class/System/System.dll.sources
mcs/class/System/System/AndroidPlatform.cs
mcs/class/System/Test/System.Net.Sockets/SocketTest.cs
mcs/class/System/Test/System.Net/ServicePointManagerTest.cs
mcs/class/System/Test/System.Net/ServicePointTest.cs
mcs/class/System/mobile_System.dll.sources
mcs/class/System/monodroid_System.dll.sources
mcs/class/System/monotouch_watch_System.dll.exclude.sources
mcs/class/System/monotouch_watch_System.dll.sources
mcs/class/System/monotouch_watch_runtime_System.dll.exclude.sources [new file with mode: 0644]
mcs/class/System/monotouch_watch_runtime_System.dll.sources
mcs/class/corlib/Assembly/AssemblyInfo.cs
mcs/class/corlib/Mono/Runtime.cs
mcs/class/corlib/ReferenceSources/Type.cs
mcs/class/corlib/ReferenceSources/TypeBuilderInstantiation.cs [deleted file]
mcs/class/corlib/System.Diagnostics.Tracing/EventSource.cs
mcs/class/corlib/System.Reflection.Emit/AssemblyBuilder.cs
mcs/class/corlib/System.Reflection.Emit/ConstructorBuilder.cs
mcs/class/corlib/System.Reflection.Emit/ConstructorOnTypeBuilderInst.cs
mcs/class/corlib/System.Reflection.Emit/DerivedTypes.cs
mcs/class/corlib/System.Reflection.Emit/EventOnTypeBuilderInst.cs
mcs/class/corlib/System.Reflection.Emit/FieldBuilder.cs
mcs/class/corlib/System.Reflection.Emit/FieldOnTypeBuilderInst.cs
mcs/class/corlib/System.Reflection.Emit/GenericTypeParameterBuilder.cs
mcs/class/corlib/System.Reflection.Emit/ILGenerator.cs
mcs/class/corlib/System.Reflection.Emit/MethodBuilder.cs
mcs/class/corlib/System.Reflection.Emit/MethodOnTypeBuilderInst.cs
mcs/class/corlib/System.Reflection.Emit/ModuleBuilder.cs
mcs/class/corlib/System.Reflection.Emit/PropertyOnTypeBuilderInst.cs
mcs/class/corlib/System.Reflection.Emit/TypeBuilder.cs
mcs/class/corlib/System.Reflection.Emit/TypeBuilderInstantiation.cs [new file with mode: 0644]
mcs/class/corlib/System.Reflection/MonoGenericClass.cs [deleted file]
mcs/class/corlib/System.Reflection/MonoGenericMethod.cs [deleted file]
mcs/class/corlib/System/Environment.cs
mcs/class/corlib/Test/System.Reflection.Emit/ModuleBuilderTest.cs
mcs/class/corlib/Test/System.Reflection.Emit/TypeBuilderTest.cs
mcs/class/corlib/corlib-net_4_x.csproj
mcs/class/corlib/corlib.dll.sources
mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/DelegateHelpers.cs
mcs/class/referencesource/System.Data/System/Data/Sql/SqlDataSourceEnumerator.cs
mcs/errors/cs0177-15.cs [new file with mode: 0644]
mcs/mcs/context.cs
mcs/mcs/statement.cs
mcs/tests/test-941.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml
mcs/tools/Makefile
mcs/tools/btls/AssemblyInfo.cs [new file with mode: 0644]
mcs/tools/btls/Makefile [new file with mode: 0644]
mcs/tools/btls/btls-cert-sync.cs [new file with mode: 0644]
mcs/tools/btls/btls-cert-sync.exe.sources [new file with mode: 0644]
mcs/tools/linker/Descriptors/mscorlib.xml
mcs/tools/mkbundle/mkbundle.cs
mcs/tools/security/cert-sync.cs
mono/Makefile.am
mono/btls/.gitignore [new file with mode: 0644]
mono/btls/CMakeLists.txt [new file with mode: 0644]
mono/btls/Makefile.am [new file with mode: 0644]
mono/btls/btls-android-utils.c [new file with mode: 0644]
mono/btls/btls-bio.c [new file with mode: 0644]
mono/btls/btls-bio.h [new file with mode: 0644]
mono/btls/btls-error.c [new file with mode: 0644]
mono/btls/btls-error.h [new file with mode: 0644]
mono/btls/btls-key.c [new file with mode: 0644]
mono/btls/btls-key.h [new file with mode: 0644]
mono/btls/btls-pkcs12.c [new file with mode: 0644]
mono/btls/btls-pkcs12.h [new file with mode: 0644]
mono/btls/btls-ssl-ctx.c [new file with mode: 0644]
mono/btls/btls-ssl-ctx.h [new file with mode: 0644]
mono/btls/btls-ssl.c [new file with mode: 0644]
mono/btls/btls-ssl.h [new file with mode: 0644]
mono/btls/btls-util.c [new file with mode: 0644]
mono/btls/btls-util.h [new file with mode: 0644]
mono/btls/btls-x509-chain.c [new file with mode: 0644]
mono/btls/btls-x509-chain.h [new file with mode: 0644]
mono/btls/btls-x509-crl.c [new file with mode: 0644]
mono/btls/btls-x509-crl.h [new file with mode: 0644]
mono/btls/btls-x509-lookup-mono.c [new file with mode: 0644]
mono/btls/btls-x509-lookup-mono.h [new file with mode: 0644]
mono/btls/btls-x509-lookup.c [new file with mode: 0644]
mono/btls/btls-x509-lookup.h [new file with mode: 0644]
mono/btls/btls-x509-name.c [new file with mode: 0644]
mono/btls/btls-x509-name.h [new file with mode: 0644]
mono/btls/btls-x509-revoked.c [new file with mode: 0644]
mono/btls/btls-x509-revoked.h [new file with mode: 0644]
mono/btls/btls-x509-store-ctx.c [new file with mode: 0644]
mono/btls/btls-x509-store-ctx.h [new file with mode: 0644]
mono/btls/btls-x509-store.c [new file with mode: 0644]
mono/btls/btls-x509-store.h [new file with mode: 0644]
mono/btls/btls-x509-verify-param.c [new file with mode: 0644]
mono/btls/btls-x509-verify-param.h [new file with mode: 0644]
mono/btls/btls-x509.c [new file with mode: 0644]
mono/btls/btls-x509.h [new file with mode: 0644]
mono/btls/create-object-library.sh [new file with mode: 0755]
mono/io-layer/io-layer.h
mono/metadata/Makefile.am
mono/metadata/appdomain.c
mono/metadata/boehm-gc.c
mono/metadata/cominterop.c
mono/metadata/custom-attrs.c
mono/metadata/debug-mono-symfile.c
mono/metadata/domain.c
mono/metadata/dynamic-image.c
mono/metadata/gc-internals.h
mono/metadata/gc.c
mono/metadata/icall-def.h
mono/metadata/icall.c
mono/metadata/marshal.c
mono/metadata/metadata-internals.h
mono/metadata/null-gc.c
mono/metadata/object-internals.h
mono/metadata/object.c
mono/metadata/profiler.c
mono/metadata/reflection.c
mono/metadata/sgen-client-mono.h
mono/metadata/sgen-mono.c
mono/metadata/sre-encode.c
mono/metadata/sre-internals.h
mono/metadata/sre-save.c
mono/metadata/sre.c
mono/metadata/threads.c
mono/mini/main.c
mono/mini/mini-posix.c
mono/profiler/Makefile.am
mono/profiler/decode.c [deleted file]
mono/profiler/mono-profiler-log.c [new file with mode: 0644]
mono/profiler/mono-profiler-log.h [new file with mode: 0644]
mono/profiler/mprof-report.c [new file with mode: 0644]
mono/profiler/proflog.c [deleted file]
mono/profiler/proflog.h [deleted file]
mono/profiler/utils.c [deleted file]
mono/profiler/utils.h [deleted file]
mono/sgen/sgen-layout-stats.c
mono/tests/thread-native-exit.cs
mono/utils/lock-free-alloc.h
mono/utils/mono-compiler.h
mono/utils/mono-os-semaphore.h
mono/utils/mono-publib.h
mono/utils/mono-threads-posix.c
mono/utils/mono-threads-windows.c
mono/utils/mono-threads.h
scripts/.gitignore
scripts/Makefile.am
scripts/ci/run-jenkins.sh
scripts/ci/run-test-default.sh
scripts/ci/run-test-profiler-stress-tests.sh

index d084d3948e49230f088e7e875dd49c409901a7b9..6d87209417eec370475d4ece03cc108c5ea06dd4 100644 (file)
@@ -39,3 +39,7 @@
        path = external/cecil-legacy
        url = git://github.com/mono/cecil.git
        branch = mono-legacy-0.9.5
+[submodule "external/boringssl"]
+       path = external/boringssl
+       url = git://github.com/mono/boringssl.git
+       branch = mono
index 9188b174a9541f5f966e56dd03835705cdb59f23..ff67772a1d47d4ca21296d27cbb66dfcd8162743 100644 (file)
@@ -4,7 +4,8 @@ SYS_REFS = \
        System.Data.dll \
        System.Runtime.Serialization.dll \
        System.Xml.dll \
-       System.Xml.Linq.dll
+       System.Xml.Linq.dll \
+       Mono.Posix.dll
 
 check-profiler-stress:
        @$(MAKE) validate-benchmarker RESET_VERSIONS=1
index b2638c1273a7e4deee08ec2047618bec48d669db..5ef4ab02a2eb198eeb669e3a1fed781af3376828 100644 (file)
@@ -1,7 +1,14 @@
 using System;
+using System.Collections.Generic;
 using System.Diagnostics;
+using System.Globalization;
 using System.IO;
 using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Xml;
+using Mono.Unix.Native;
 using Newtonsoft.Json;
 
 // Shut up CLS compliance warnings from Json.NET.
@@ -10,7 +17,8 @@ using Newtonsoft.Json;
 namespace Mono.Profiling.Tests.Stress {
 
        // https://github.com/xamarin/benchmarker/blob/master/tools/libdbmodel/Benchmark.cs
-       class Benchmark {
+       sealed class Benchmark {
+
                public string Name { get; set; }
                public string TestDirectory { get; set; }
                public bool OnlyExplicit { get; set; }
@@ -24,8 +32,24 @@ namespace Mono.Profiling.Tests.Stress {
                }
        }
 
+       sealed class TestResult {
+
+               public Benchmark Benchmark { get; set; }
+               public ProcessStartInfo StartInfo { get; set; }
+               public Stopwatch Stopwatch { get; set; } = new Stopwatch ();
+               public int? ExitCode { get; set; }
+               public StringBuilder StandardOutput { get; set; } = new StringBuilder ();
+               public StringBuilder StandardError { get; set; } = new StringBuilder ();
+       }
+
        static class Program {
 
+               static readonly TimeSpan _timeout = TimeSpan.FromHours (6);
+
+               static string FilterInvalidXmlChars (string text) {
+                       return Regex.Replace (text, @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", string.Empty);
+               }
+
                static int Main ()
                {
                        var depDir = Path.Combine ("..", "external", "benchmarker");
@@ -44,8 +68,7 @@ namespace Mono.Profiling.Tests.Stress {
                        var rand = new Random ();
                        var cpus = Environment.ProcessorCount;
 
-                       var successes = 0;
-                       var failures = 0;
+                       var results = new List<TestResult> (benchmarks.Length);
 
                        var sw = Stopwatch.StartNew ();
 
@@ -66,6 +89,8 @@ namespace Mono.Profiling.Tests.Stress {
                                        WorkingDirectory = Path.Combine (testDir, bench.TestDirectory),
                                        FileName = monoPath,
                                        Arguments = $"--debug --profile=log:{profOptions} " + string.Join (" ", bench.CommandLine),
+                                       RedirectStandardOutput = true,
+                                       RedirectStandardError = true,
                                };
 
                                info.EnvironmentVariables.Clear ();
@@ -77,32 +102,177 @@ namespace Mono.Profiling.Tests.Stress {
                                Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} Running {bench.Name} with profiler options: {profOptions}");
                                Console.ResetColor ();
 
-                               var sw2 = Stopwatch.StartNew ();
+                               var result = new TestResult {
+                                       Benchmark = bench,
+                                       StartInfo = info,
+                               };
+
+                               using (var proc = new Process ()) {
+                                       proc.StartInfo = info;
+
+                                       proc.OutputDataReceived += (sender, args) => {
+                                               if (args.Data != null)
+                                                       result.StandardOutput.AppendLine (args.Data);
+                                       };
+
+                                       proc.ErrorDataReceived += (sender, args) => {
+                                               if (args.Data != null)
+                                                       result.StandardError.AppendLine (args.Data);
+                                       };
+
+                                       result.Stopwatch.Start ();
 
-                               using (var proc = Process.Start (info)) {
-                                       proc.WaitForExit ();
-                                       sw2.Stop ();
+                                       proc.Start ();
 
-                                       Console.WriteLine ();
+                                       proc.BeginOutputReadLine ();
+                                       proc.BeginErrorReadLine ();
 
-                                       if (proc.ExitCode != 0)
-                                               failures++;
-                                       else
-                                               successes++;
+                                       if (!proc.WaitForExit ((int) _timeout.TotalMilliseconds)) {
+                                               // Force a thread dump.
+                                               Syscall.kill (proc.Id, Signum.SIGQUIT);
+                                               Thread.Sleep (1000);
 
-                                       Console.ForegroundColor = proc.ExitCode != 0 ? ConsoleColor.Red : ConsoleColor.Green;
-                                       Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} {bench.Name} took {sw2.Elapsed.ToString ("G")} and exited with code: {proc.ExitCode}");
+                                               try {
+                                                       proc.Kill ();
+                                               } catch (Exception) {
+                                               }
+                                       } else
+                                               result.ExitCode = proc.ExitCode;
+
+                                       result.Stopwatch.Stop ();
+                               }
+
+                               var resultStr = result.ExitCode == null ? "timed out" : $"exited with code: {result.ExitCode}";
+
+                               Console.ForegroundColor = result.ExitCode != 0 ? ConsoleColor.Red : ConsoleColor.Green;
+                               Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} {bench.Name} took {result.Stopwatch.Elapsed.ToString ("G")} and {resultStr}");
+                               Console.ResetColor ();
+
+                               if (result.ExitCode != 0) {
+                                       Console.ForegroundColor = ConsoleColor.Red;
+                                       Console.WriteLine ("===== stdout =====");
                                        Console.ResetColor ();
+
+                                       Console.WriteLine (result.StandardOutput.ToString ());
+
+                                       Console.ForegroundColor = ConsoleColor.Red;
+                                       Console.WriteLine ("===== stderr =====");
+                                       Console.ResetColor ();
+
+                                       Console.WriteLine (result.StandardError.ToString ());
                                }
+
+                               results.Add (result);
                        }
 
                        sw.Stop ();
 
-                       Console.ForegroundColor = failures != 0 ? ConsoleColor.Red : ConsoleColor.Green;
-                       Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] Finished with {successes}/{benchmarks.Length} passing tests");
+                       var successes = results.Count (r => r.ExitCode == 0);
+                       var failures = results.Count (r => r.ExitCode != null && r.ExitCode != 0);
+                       var timeouts = results.Count (r => r.ExitCode == null);
+
+                       var settings = new XmlWriterSettings {
+                               NewLineOnAttributes = true,
+                               Indent = true,
+                       };
+
+                       using (var writer = XmlWriter.Create ("TestResult-profiler-stress.xml", settings)) {
+                               writer.WriteStartDocument ();
+                               writer.WriteComment ("This file represents the results of running a test suite");
+
+                               writer.WriteStartElement ("test-results");
+                               writer.WriteAttributeString ("name", "profiler-stress-tests.dummy");
+                               writer.WriteAttributeString ("total", results.Count.ToString ());
+                               writer.WriteAttributeString ("failures", failures.ToString ());
+                               writer.WriteAttributeString ("not-run", "0");
+                               writer.WriteAttributeString ("date", DateTime.Now.ToString ("yyyy-MM-dd"));
+                               writer.WriteAttributeString ("time", DateTime.Now.ToString ("HH:mm:ss"));
+
+                               writer.WriteStartElement ("environment");
+                               writer.WriteAttributeString ("nunit-version", "2.4.8.0");
+                               writer.WriteAttributeString ("clr-version", Environment.Version.ToString ());
+                               writer.WriteAttributeString ("os-version", Environment.OSVersion.ToString ());
+                               writer.WriteAttributeString ("platform", Environment.OSVersion.Platform.ToString ());
+                               writer.WriteAttributeString ("cwd", Environment.CurrentDirectory);
+                               writer.WriteAttributeString ("machine-name", Environment.MachineName);
+                               writer.WriteAttributeString ("user", Environment.UserName);
+                               writer.WriteAttributeString ("user-domain", Environment.UserDomainName);
+                               writer.WriteEndElement ();
+
+                               writer.WriteStartElement ("culture-info");
+                               writer.WriteAttributeString ("current-culture", CultureInfo.CurrentCulture.Name);
+                               writer.WriteAttributeString ("current-uiculture", CultureInfo.CurrentUICulture.Name);
+                               writer.WriteEndElement ();
+
+                               writer.WriteStartElement ("test-suite");
+                               writer.WriteAttributeString ("name", "profiler-stress-tests.dummy");
+                               writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
+                               writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
+                               writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
+                               writer.WriteStartElement ("results");
+
+                               writer.WriteStartElement ("test-suite");
+                               writer.WriteAttributeString ("name", "MonoTests");
+                               writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
+                               writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
+                               writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
+                               writer.WriteStartElement ("results");
+
+                               writer.WriteStartElement ("test-suite");
+                               writer.WriteAttributeString ("name", "profiler-stress");
+                               writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ());
+                               writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ());
+                               writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ());
+                               writer.WriteStartElement ("results");
+
+                               foreach (var result in results) {
+                                       var timeoutStr = result.ExitCode == null ? "_timeout" : string.Empty;
+
+                                       writer.WriteStartElement ("test-case");
+                                       writer.WriteAttributeString ("name", $"MonoTests.profiler-stress.{result.Benchmark.Name}{timeoutStr}");
+                                       writer.WriteAttributeString ("executed", "True");
+                                       writer.WriteAttributeString ("success", (result.ExitCode == 0).ToString ());
+                                       writer.WriteAttributeString ("time", ((int) result.Stopwatch.Elapsed.TotalSeconds).ToString ());
+                                       writer.WriteAttributeString ("asserts", result.ExitCode == 0 ? "0" : "1");
+
+                                       if (result.ExitCode != 0) {
+                                               writer.WriteStartElement ("failure");
+
+                                               writer.WriteStartElement ("message");
+                                               writer.WriteCData (FilterInvalidXmlChars (result.StandardOutput.ToString ()));
+                                               writer.WriteEndElement ();
+
+                                               writer.WriteStartElement ("stack-trace");
+                                               writer.WriteCData (FilterInvalidXmlChars (result.StandardError.ToString ()));
+                                               writer.WriteEndElement ();
+
+                                               writer.WriteEndElement ();
+                                       }
+
+                                       writer.WriteEndElement ();
+                               }
+
+                               writer.WriteEndElement ();
+                               writer.WriteEndElement ();
+
+                               writer.WriteEndElement ();
+                               writer.WriteEndElement ();
+
+                               writer.WriteEndElement ();
+                               writer.WriteEndElement ();
+
+                               writer.WriteEndElement ();
+
+                               writer.WriteEndDocument ();
+                       }
+
+                       var failureStr = failures + timeouts != 0 ? $" ({failures} failures, {timeouts} timeouts)" : string.Empty;
+
+                       Console.ForegroundColor = failures + timeouts != 0 ? ConsoleColor.Red : ConsoleColor.Green;
+                       Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] Finished with {successes}/{results.Count} passing tests{failureStr}");
                        Console.ResetColor ();
 
-                       return failures;
+                       return failures + timeouts;
                }
        }
 }
index 0946284c263312177f477509f9048670d0f1751f..f79f320c00987585a5cbd6f560ac52708b967cf2 100644 (file)
@@ -1162,20 +1162,6 @@ AC_COMPILE_IFELSE([
    AC_MSG_RESULT(no)
 ])
 
-AC_MSG_CHECKING(for deprecated __attribute__)
-AC_TRY_COMPILE([
-     int doit (void) __attribute__ ((deprecated));
-     int doit (void) { return 0; }
-], [
-       return 0;
-], [
-   have_deprecated=yes
-   AC_MSG_RESULT(yes)
-], [
-   have_deprecated=no
-   AC_MSG_RESULT(no)
-])
-
 dnl
 dnl Boehm GC configuration
 dnl
@@ -2672,12 +2658,6 @@ fi
 
 AC_ARG_ENABLE(bcl-opt, [  --disable-bcl-opt    BCL is compiled with no optimizations (allows accurate BCL debugging)], test_bcl_opt=$enableval, test_bcl_opt=yes)
 
-AC_ARG_ENABLE(perf-events, [  --enable-perf-events Enable using `perf` for profiling on Linux], test_perf_events=$enableval, test_perf_events=no)
-if test "x$test_perf_events" = "xyes"; then
-       AC_DEFINE(ENABLE_PERF_EVENTS, 1, [Enable using `perf` for profiling on Linux])
-       AC_SUBST(ENABLE_PERF_EVENTS)
-fi
-
 AC_MSG_CHECKING([if big-arrays are to be enabled])
 AC_ARG_ENABLE(big-arrays,  [  --enable-big-arrays      Enable the allocation and indexing of arrays greater than Int32.MaxValue], enable_big_arrays=$enableval, enable_big_arrays=no)
 if test "x$enable_big_arrays" = "xyes" ; then
@@ -3957,7 +3937,11 @@ if test "x$enable_btls" = "xyes"; then
        case "$BTLS_PLATFORM" in
        i386)
                btls_arch=i386
-               btls_cflags="-m32 -arch i386"
+               btls_cflags="-m32"
+               case $host_os in
+                       darwin*)
+                               btls_cflags="$btls_cflags -arch i386"
+               esac
                ;;
        x86_64)
                btls_arch=x86_64
@@ -4245,6 +4229,7 @@ llvm/Makefile
 scripts/mono-find-provides
 scripts/mono-find-requires
 mono/Makefile
+mono/btls/Makefile
 mono/utils/Makefile
 mono/metadata/Makefile
 mono/dis/Makefile
diff --git a/external/boringssl b/external/boringssl
new file mode 160000 (submodule)
index 0000000..432738a
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 432738a3c938b4f751307301c6aa07f2027a8864
index c4fd545dd104c5413ea6a5bcb627a25bccf6fec1..f19a02aa14ea8679cda72518cc466f57ee5a4ad8 100644 (file)
@@ -92,7 +92,7 @@ provided by the Mono runtime and write them to a file named
 \f[I]output.mlpd\f[].
 When no option is specified, it is equivalent to using:
 .PP
-\f[B]--profile=log:calls,alloc,output=output.mlpd,maxframes=8,calldepth=100\f[]
+\f[B]--profile=log:calls,alloc,output=output.mlpd,maxframes=32,calldepth=100\f[]
 .PP
 The following options can be used to modify this default behaviour.
 Each option is separated from the next by a \f[B],\f[] character,
@@ -139,41 +139,16 @@ garbage collections
 to the control port
 .RE
 .IP \[bu] 2
-\f[I]sample[=TYPE[/FREQ]]\f[]: collect statistical samples of the
+\f[I]sample[=FREQ]\f[]: collect statistical samples of the
 program behaviour.
 The default is to collect a 100 times per second (100 Hz) the
 instruction pointer.
-This is equivalent to the value \[lq]cycles/100\[rq].
+This is equivalent to the value \[lq]100\[rq].
 A value of zero for \f[I]FREQ\f[] effectively disables sampling.
-On some systems, like with recent Linux kernels, it is possible to
-cause the sampling to happen for other events provided by the
-performance counters of the cpu.
-In this case, \f[I]TYPE\f[] can be one of:
-.RS 2
-.IP \[bu] 2
-\f[I]cycles\f[]: processor cycles
-.IP \[bu] 2
-\f[I]instr\f[]: executed instructions
-.IP \[bu] 2
-\f[I]cacherefs\f[]: cache references
-.IP \[bu] 2
-\f[I]cachemiss\f[]: cache misses
-.IP \[bu] 2
-\f[I]branches\f[]: executed branches
-.IP \[bu] 2
-\f[I]branchmiss\f[]: mispredicted branches
-.RE
-.IP \[bu] 2
-\f[I]time=TIMER\f[]: use the TIMER timestamp mode.
-TIMER can have the following values:
-.RS 2
-.IP \[bu] 2
-\f[I]fast\f[]: a usually faster but possibly more inaccurate timer
-.RE
 .IP \[bu] 2
 \f[I]maxframes=NUM\f[]: when a stack trace needs to be performed,
 collect \f[I]NUM\f[] frames at the most.
-The default is 8.
+The default is 32.
 .IP \[bu] 2
 \f[I]maxsamples=NUM\f[]: stop allocating reusable sample events
 once \f[I]NUM\f[] events have been allocated (a value of zero for
@@ -234,16 +209,15 @@ The following commands are available:
 \f[I]heapshot\f[]: perform a heapshot as soon as possible
 .RE
 .IP \[bu] 2
-\f[I]counters\f[]: sample counters values every 1 second. This allow
-a really lightweight way to have insight in some of the runtime key
-metrics. Counters displayed in non verbose mode are : Methods from AOT,
-Methods JITted using mono JIT, Methods JITted using LLVM, Total time
-spent JITting (sec), User Time, System Time, Total Time, Working Set,
-Private Bytes, Virtual Bytes, Page Faults and CPU Load Average (1min,
-5min and 15min).
+\f[I]nocounters\f[]: disables sampling of runtime and performance
+counters, which is normally done every 1 second.
 .IP \[bu] 2
 \f[I]coverage\f[]: collect code coverage data. This implies enabling
 the \f[I]calls\f[] option.
+.IP \[bu] 2
+\f[I]onlycoverage\f[]: can only be used with \f[I]coverage\f[]. This
+disables most other events so that the profiler mostly only collects
+coverage data.
 .RE
 .SS Analyzing the profile data
 .PP
@@ -274,10 +248,6 @@ with the \f[I]--maxframes=NUM\f[] option:
 The stack trace info will be available if method enter/leave events
 have been recorded or if stack trace collection wasn't explicitly
 disabled with the \f[I]maxframes=0\f[] profiler option.
-Note that the profiler will collect up to 8 frames by default at
-specific events when the \f[I]nocalls\f[] option is used, so in
-that case, if more stack frames are required in mprof-report, a
-bigger value for maxframes when profiling must be used, too.
 .PP
 The \f[I]--traces\f[] option also controls the reverse reference
 feature in the heapshot report: for each class it reports how many
@@ -487,15 +457,6 @@ option: especially if the managed heap is big, since every object
 needs to be inspected.
 The \f[I]MODE\f[] parameter of the \f[I]heapshot\f[] option can be
 used to reduce the frequency of the heap shots.
-.IP "\f[I]Reduce the timestamp overhead\f[]" 4
-.Sp
-On many operating systems or architectures what actually slows down
-profiling is the function provided by the system to get timestamp
-information.
-The \f[I]time=fast\f[] profiler option can be usually used to speed
-up this operation, but, depending on the system, time accounting
-may have some level of approximation (though statistically the data
-should be still fairly valuable).
 .SS Dealing with the size of the data files
 .PP
 When collecting a lot of information about a profiled program, huge
index 02c934b62e6ae89fb558f05a9bd942c4ecbfcc99..4bba2f421ac849b4f0869f32b72a1b4d57f51e3c 100644 (file)
@@ -8,3 +8,4 @@ NO_THREAD_ABORT=1
 NO_THREAD_SUSPEND_RESUME=1
 NO_MULTIPLE_APPDOMAINS=1
 NO_PROCESS_START=1
+NO_MONO_SECURITY=1
index cb6bf304b99fdfe255e5cc5ac78e0c8703090751..e826c7e7e31e1b734fbd5625532536f3184d787a 100644 (file)
@@ -9,3 +9,4 @@ NO_THREAD_SUSPEND_RESUME=1
 # The binding generator (bwatch) still needs to execute processes,
 # so we need a System.dll that can do that.
 #NO_PROCESS_START=1
+NO_MONO_SECURITY=1
index e9c0a1621512da713432a917ee93e659d16bd5d0..f8f0b0a9396c0061111da1316a13812edea6936a 100644 (file)
@@ -83,7 +83,7 @@ monodroid_dirs := \
 monotouch_dirs := \
        $(mobile_static_dirs)
 
-monotouch_watch_dirs := $(monotouch_dirs)
+monotouch_watch_dirs := $(filter-out Mono.Security Mono.Data.Tds,$(monotouch_dirs))
 monotouch_tv_dirs   := $(monotouch_dirs)
 
 monotouch_runtime_dirs := \
@@ -94,7 +94,7 @@ monotouch_runtime_dirs := \
        System.XML \
        Mono.CSharp
 
-monotouch_watch_runtime_dirs := $(monotouch_runtime_dirs)
+monotouch_watch_runtime_dirs := $(filter-out Mono.Security Mono.Data.Tds,$(monotouch_runtime_dirs))
 monotouch_tv_runtime_dirs := $(monotouch_runtime_dirs)
 
 xammac_4_5_dirs := \
@@ -141,6 +141,7 @@ xammac_4_5_dirs := \
        System.Data.Linq                \
        System.Net.Http \
        System.Net.Http.WebRequest \
+       Mono.Btls.Interface \
        System.Runtime.InteropServices.RuntimeInformation \
        System.Reflection.Context       \
        System.Net.Http.WinHttpHandler  \
@@ -236,6 +237,7 @@ net_4_x_dirs := \
 net_4_x_parallel_dirs := \
        PEAPI                           \
        I18N                            \
+       Mono.Btls.Interface             \
        Mono.Http                       \
        Mono.Cairo                      \
        Mono.Cecil                      \
diff --git a/mcs/class/Mono.Btls.Interface/Makefile b/mcs/class/Mono.Btls.Interface/Makefile
new file mode 100644 (file)
index 0000000..ea7e128
--- /dev/null
@@ -0,0 +1,12 @@
+thisdir = class/Mono.Btls.Interface
+SUBDIRS = 
+include ../../build/rules.make
+
+LIBRARY = Mono.Btls.Interface.dll
+LIB_REFS = System Mono.Security
+LIB_MCS_FLAGS = -unsafe -nowarn:1030 -keyfile:../mono.pub -delaysign -d:SECURITY_DEP
+
+include ../../build/library.make
+
+$(the_lib): ../Mono.Security/Makefile
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface.dll.sources b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface.dll.sources
new file mode 100644 (file)
index 0000000..710e06d
--- /dev/null
@@ -0,0 +1,22 @@
+./Properties/AssemblyInfo.cs
+../../build/common/Consts.cs
+../../build/common/Locale.cs
+../../build/common/MonoTODOAttribute.cs
+
+Mono.Btls.Interface/BtlsObject.cs
+Mono.Btls.Interface/BtlsProvider.cs
+Mono.Btls.Interface/BtlsX509.cs
+Mono.Btls.Interface/BtlsX509Chain.cs
+Mono.Btls.Interface/BtlsX509Error.cs
+Mono.Btls.Interface/BtlsX509Format.cs
+Mono.Btls.Interface/BtlsX509Lookup.cs
+Mono.Btls.Interface/BtlsX509Name.cs
+Mono.Btls.Interface/BtlsX509Purpose.cs
+Mono.Btls.Interface/BtlsX509Store.cs
+Mono.Btls.Interface/BtlsX509StoreCtx.cs
+Mono.Btls.Interface/BtlsX509StoreManager.cs
+Mono.Btls.Interface/BtlsX509StoreType.cs
+Mono.Btls.Interface/BtlsX509TrustKind.cs
+Mono.Btls.Interface/BtlsX509VerifyFlags.cs
+Mono.Btls.Interface/BtlsX509VerifyParam.cs
+Mono.Btls.Interface/VersionInfo.cs
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsObject.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsObject.cs
new file mode 100644 (file)
index 0000000..b2e607c
--- /dev/null
@@ -0,0 +1,73 @@
+//
+// BtlsObject.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace Mono.Btls.Interface
+{
+       public abstract class BtlsObject : IDisposable
+       {
+               MonoBtlsObject instance;
+
+               internal MonoBtlsObject Instance {
+                       get {
+                               if (!IsValid)
+                                       throw new ObjectDisposedException (GetType ().Name);
+                               return instance;
+                       }
+               }
+
+               internal BtlsObject (MonoBtlsObject instance)
+               {
+                       this.instance = instance;
+               }
+
+               public bool IsValid {
+                       get { return instance != null && instance.IsValid; }
+               }
+
+               protected void Dispose (bool disposing)
+               {
+                       if (disposing) {
+                               if (instance != null) {
+                                       instance.Dispose ();
+                                       instance = null;
+                               }
+                       }
+               }
+
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+
+               ~BtlsObject ()
+               {
+                       Dispose (false);
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsProvider.cs
new file mode 100644 (file)
index 0000000..6a8d810
--- /dev/null
@@ -0,0 +1,106 @@
+//
+// BtlsProvider.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using Mono.Security.Interface;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Mono.Btls.Interface
+{
+       public static class BtlsProvider
+       {
+               public static bool IsSupported ()
+               {
+                       return MonoBtlsProvider.IsSupported ();
+               }
+
+               public static MonoTlsProvider GetProvider ()
+               {
+                       return new MonoBtlsProvider ();
+               }
+
+               public static BtlsX509 CreateNative (byte[] data, BtlsX509Format format)
+               {
+                       var x509 = MonoBtlsX509.LoadFromData (data, (MonoBtlsX509Format)format);
+                       return new BtlsX509 (x509);
+               }
+
+               public static X509Certificate CreateCertificate (byte[] data, BtlsX509Format format, bool disallowFallback = false)
+               {
+                       return MonoBtlsProvider.CreateCertificate (data, (MonoBtlsX509Format)format, disallowFallback);
+               }
+
+               public static X509Certificate2 CreateCertificate2 (byte[] data, BtlsX509Format format, bool disallowFallback = false)
+               {
+                       return MonoBtlsProvider.CreateCertificate2 (data, (MonoBtlsX509Format)format, disallowFallback);
+               }
+
+               public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false)
+               {
+                       return MonoBtlsProvider.CreateCertificate2 (data, password, disallowFallback);
+               }
+
+               public static BtlsX509Chain CreateNativeChain ()
+               {
+                       return new BtlsX509Chain (new MonoBtlsX509Chain ());
+               }
+
+               public static BtlsX509Store CreateNativeStore ()
+               {
+                       return new BtlsX509Store (new MonoBtlsX509Store ());
+               }
+
+               public static BtlsX509StoreCtx CreateNativeStoreCtx ()
+               {
+                       return new BtlsX509StoreCtx (new MonoBtlsX509StoreCtx ());
+               }
+
+               public static X509Chain CreateChain ()
+               {
+                       return MonoBtlsProvider.CreateChain ();
+               }
+
+               public static string GetSystemStoreLocation ()
+               {
+                       return MonoBtlsProvider.GetSystemStoreLocation ();
+               }
+
+               public static BtlsX509VerifyParam GetVerifyParam_SslClient ()
+               {
+                       return new BtlsX509VerifyParam (MonoBtlsX509VerifyParam.GetSslClient ());
+               }
+
+               public static BtlsX509VerifyParam GetVerifyParam_SslServer ()
+               {
+                       return new BtlsX509VerifyParam (MonoBtlsX509VerifyParam.GetSslServer ());
+               }
+
+               public static X509Chain GetManagedChain (BtlsX509Chain chain)
+               {
+                       return MonoBtlsProvider.GetManagedChain (chain.Instance);
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509.cs
new file mode 100644 (file)
index 0000000..abcdafb
--- /dev/null
@@ -0,0 +1,132 @@
+//
+// BtlsX509.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509 : BtlsObject
+       {
+               new internal MonoBtlsX509 Instance {
+                       get { return (MonoBtlsX509)base.Instance; }
+               }
+
+               internal BtlsX509 (MonoBtlsX509 x509)
+                       : base (x509)
+               {
+               }
+
+               public BtlsX509Name GetSubjectName ()
+               {
+                       return new BtlsX509Name (Instance.GetSubjectName ());
+               }
+
+               public BtlsX509Name GetIssuerName ()
+               {
+                       return new BtlsX509Name (Instance.GetIssuerName ());
+               }
+
+               public string GetSubjectNameString ()
+               {
+                       return Instance.GetSubjectNameString ();
+               }
+
+               public string GetIssuerNameString ()
+               {
+                       return Instance.GetIssuerNameString ();
+               }
+
+               public byte[] GetRawData (BtlsX509Format format)
+               {
+                       return Instance.GetRawData ((MonoBtlsX509Format)format);
+               }
+
+               public byte[] GetCertHash ()
+               {
+                       return Instance.GetCertHash ();
+               }
+
+               public DateTime GetNotBefore ()
+               {
+                       return Instance.GetNotBefore ();
+               }
+
+               public DateTime GetNotAfter ()
+               {
+                       return Instance.GetNotAfter ();
+               }
+
+               public byte[] GetPublicKeyData ()
+               {
+                       return Instance.GetPublicKeyData ();
+               }
+
+               public byte[] GetSerialNumber (bool mono_style)
+               {
+                       return Instance.GetSerialNumber (mono_style);
+               }
+
+               public int GetVersion ()
+               {
+                       return Instance.GetVersion ();
+               }
+
+               public Oid GetSignatureAlgorithm ()
+               {
+                       return Instance.GetSignatureAlgorithm ();
+               }
+
+               public AsnEncodedData GetPublicKeyAsn1 ()
+               {
+                       return Instance.GetPublicKeyAsn1 ();
+               }
+
+               public AsnEncodedData GetPublicKeyParameters ()
+               {
+                       return Instance.GetPublicKeyParameters (); 
+               }
+
+               public long GetSubjectNameHash ()
+               {
+                       using (var name = GetSubjectName ())
+                               return name.GetHash ();
+               }
+
+               public void Print (Stream stream)
+               {
+                       using (var bio = MonoBtlsBio.CreateMonoStream (stream))
+                               Instance.Print (bio);
+               }
+
+               public void ExportAsPEM (Stream stream, bool includeHumanReadableForm)
+               {
+                       using (var bio = MonoBtlsBio.CreateMonoStream (stream))
+                               Instance.ExportAsPEM (bio, includeHumanReadableForm);
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Chain.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Chain.cs
new file mode 100644 (file)
index 0000000..38e9ec5
--- /dev/null
@@ -0,0 +1,58 @@
+//
+// BtlsX509Chain.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509Chain : BtlsObject
+       {
+               new internal MonoBtlsX509Chain Instance {
+                       get { return (MonoBtlsX509Chain)base.Instance; }
+               }
+
+               internal BtlsX509Chain (MonoBtlsX509Chain chain)
+                       : base (chain)
+               {
+               }
+
+               public int Count {
+                       get { return Instance.Count; }
+               }
+
+               public BtlsX509 this[int index] {
+                       get {
+                               var x509 = Instance.GetCertificate (index);
+                               return new BtlsX509 (x509.Copy ());
+                       }
+               }
+
+               public void Add (BtlsX509 x509)
+               {
+                       Instance.AddCertificate (x509.Instance);
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Error.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Error.cs
new file mode 100644 (file)
index 0000000..089b4f2
--- /dev/null
@@ -0,0 +1,110 @@
+//
+// BtlsX509Error.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with NativeBoringX509Error
+       public enum BtlsX509Error
+       {
+               OK = 0,
+               /* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+
+               UNABLE_TO_GET_ISSUER_CERT = 2,
+               UNABLE_TO_GET_CRL = 3,
+               UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4,
+               UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5,
+               UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6,
+               CERT_SIGNATURE_FAILURE = 7,
+               CRL_SIGNATURE_FAILURE = 8,
+               CERT_NOT_YET_VALID = 9,
+               CERT_HAS_EXPIRED = 10,
+               CRL_NOT_YET_VALID = 11,
+               CRL_HAS_EXPIRED = 12,
+               ERROR_IN_CERT_NOT_BEFORE_FIELD = 13,
+               ERROR_IN_CERT_NOT_AFTER_FIELD = 14,
+               ERROR_IN_CRL_LAST_UPDATE_FIELD = 15,
+               ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16,
+               OUT_OF_MEM = 17,
+               DEPTH_ZERO_SELF_SIGNED_CERT = 18,
+               SELF_SIGNED_CERT_IN_CHAIN = 19,
+               UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20,
+               UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21,
+               CERT_CHAIN_TOO_LONG = 22,
+               CERT_REVOKED = 23,
+               INVALID_CA = 24,
+               PATH_LENGTH_EXCEEDED = 25,
+               INVALID_PURPOSE = 26,
+               CERT_UNTRUSTED = 27,
+               CERT_REJECTED = 28,
+               /* These are 'informational' when looking for issuer cert */
+               SUBJECT_ISSUER_MISMATCH = 29,
+               AKID_SKID_MISMATCH = 30,
+               AKID_ISSUER_SERIAL_MISMATCH = 31,
+               KEYUSAGE_NO_CERTSIGN = 32,
+
+               UNABLE_TO_GET_CRL_ISSUER = 33,
+               UNHANDLED_CRITICAL_EXTENSION = 34,
+               KEYUSAGE_NO_CRL_SIGN = 35,
+               UNHANDLED_CRITICAL_CRL_EXTENSION = 36,
+               INVALID_NON_CA = 37,
+               PROXY_PATH_LENGTH_EXCEEDED = 38,
+               KEYUSAGE_NO_DIGITAL_SIGNATURE = 39,
+               PROXY_CERTIFICATES_NOT_ALLOWED = 40,
+
+               INVALID_EXTENSION = 41,
+               INVALID_POLICY_EXTENSION = 42,
+               NO_EXPLICIT_POLICY = 43,
+               DIFFERENT_CRL_SCOPE = 44,
+               UNSUPPORTED_EXTENSION_FEATURE = 45,
+
+               UNNESTED_RESOURCE = 46,
+
+               PERMITTED_VIOLATION = 47,
+               EXCLUDED_VIOLATION = 48,
+               SUBTREE_MINMAX = 49,
+               UNSUPPORTED_CONSTRAINT_TYPE = 51,
+               UNSUPPORTED_CONSTRAINT_SYNTAX = 52,
+               UNSUPPORTED_NAME_SYNTAX = 53,
+               CRL_PATH_VALIDATION_ERROR = 54,
+
+               /* Suite B mode algorithm violation */
+               SUITE_B_INVALID_VERSION = 56,
+               SUITE_B_INVALID_ALGORITHM = 57,
+               SUITE_B_INVALID_CURVE = 58,
+               SUITE_B_INVALID_SIGNATURE_ALGORITHM = 59,
+               SUITE_B_LOS_NOT_ALLOWED = 60,
+               SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 61,
+
+               /* Host, email and IP check errors */
+               HOSTNAME_MISMATCH = 62,
+               EMAIL_MISMATCH = 63,
+               IP_ADDRESS_MISMATCH = 64,
+
+               /* The application is not happy */
+               APPLICATION_VERIFICATION = 50
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Format.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Format.cs
new file mode 100644 (file)
index 0000000..6ff63ce
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// BtlsX509Format.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with NativeBoringX509Format
+       public enum BtlsX509Format
+       {
+               DER = 1,
+               PEM = 2
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Lookup.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Lookup.cs
new file mode 100644 (file)
index 0000000..836088f
--- /dev/null
@@ -0,0 +1,72 @@
+//
+// BtlsX509Lookup.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509Lookup : BtlsObject
+       {
+               new internal MonoBtlsX509Lookup Instance {
+                       get { return (MonoBtlsX509Lookup)base.Instance; }
+               }
+
+               internal BtlsX509Lookup (MonoBtlsX509Lookup lookup)
+                       : base (lookup)
+               {
+               }
+
+               public void Initialize ()
+               {
+                       Instance.Initialize ();
+               }
+
+               public void Shutdown ()
+               {
+                       Instance.Shutdown ();
+               }
+
+               public BtlsX509 LookupBySubject (BtlsX509Name name)
+               {
+                       var x509 = Instance.LookupBySubject (name.Instance);
+                       if (x509 == null)
+                               return null;
+
+                       return new BtlsX509 (x509);
+               }
+
+               public void LoadFile (string file, BtlsX509Format type)
+               {
+                       Instance.LoadFile (file, (MonoBtlsX509FileType)type);
+               }
+
+               public void AddDirectory (string dir, BtlsX509Format type)
+               {
+                       Instance.AddDirectory (dir, (MonoBtlsX509FileType)type);
+               }
+       }
+}
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Name.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Name.cs
new file mode 100644 (file)
index 0000000..69ca5a9
--- /dev/null
@@ -0,0 +1,62 @@
+//
+// BtlsX509Name.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509Name : BtlsObject
+       {
+               new internal MonoBtlsX509Name Instance {
+                       get { return (MonoBtlsX509Name)base.Instance; }
+               }
+
+               internal BtlsX509Name (MonoBtlsX509Name name)
+                       : base (name)
+               {
+               }
+
+               public string GetString ()
+               {
+                       return Instance.GetString ();
+               }
+
+               public byte[] GetRawData (bool use_canon_enc)
+               {
+                       return Instance.GetRawData (use_canon_enc);
+               }
+
+               public long GetHash ()
+               {
+                       return Instance.GetHash ();
+               }
+
+               public long GetHashOld ()
+               {
+                       return Instance.GetHashOld ();
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Purpose.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Purpose.cs
new file mode 100644 (file)
index 0000000..ac906df
--- /dev/null
@@ -0,0 +1,43 @@
+//
+// BtlsX509Purpose.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with NativeBoringX509Purpose
+       public enum BtlsX509Purpose
+       {
+               SSL_CLIENT = 1,
+               SSL_SERVER = 2,
+               NS_SSL_SERVER = 3,
+               SMIME_SIGN = 4,
+               SMIME_ENCRYPT = 5,
+               CRL_SIGN = 6,
+               ANY = 7,
+               OCSP_HELPER = 8,
+               TIMESTAMP_SIGN = 9,
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Store.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509Store.cs
new file mode 100644 (file)
index 0000000..7b8f03f
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// BtlsX509Store.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509Store : BtlsObject
+       {
+               new internal MonoBtlsX509Store Instance {
+                       get { return (MonoBtlsX509Store)base.Instance; }
+               }
+
+               internal BtlsX509Store (MonoBtlsX509Store store)
+                       : base (store)
+               {
+               }
+
+               public void LoadLocations (string file, string path)
+               {
+                       Instance.LoadLocations (file, path);
+               }
+
+               public void AddTrustedRoots ()
+               {
+                       Instance.AddTrustedRoots ();
+               }
+
+               public void AddCertificate (BtlsX509 x509)
+               {
+                       Instance.AddCertificate (x509.Instance);
+               }
+
+               public int GetCount ()
+               {
+                       return Instance.GetCount ();
+               }
+
+               public void AddLookup (X509CertificateCollection certificates, BtlsX509TrustKind trust)
+               {
+                       Instance.AddCollection (certificates, (MonoBtlsX509TrustKind)trust);
+               }
+
+               static MonoBtlsX509FileType GetFileType (BtlsX509Format format)
+               {
+                       switch (format) {
+                       case BtlsX509Format.DER:
+                               return MonoBtlsX509FileType.ASN1;
+                       case BtlsX509Format.PEM:
+                               return MonoBtlsX509FileType.PEM;
+                       default:
+                               throw new NotSupportedException ();
+                       }
+               }
+
+               public void AddDirectoryLookup (string dir, BtlsX509Format format)
+               {
+                       Instance.AddDirectoryLookup (dir, GetFileType (format));
+               }
+
+               public void AddFileLookup (string file, BtlsX509Format format)
+               {
+                       Instance.AddFileLookup (file, GetFileType (format));
+               }
+
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreCtx.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreCtx.cs
new file mode 100644 (file)
index 0000000..97d4a06
--- /dev/null
@@ -0,0 +1,71 @@
+//
+// BtlsX509StoreCtx.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509StoreCtx : BtlsObject
+       {
+               new internal MonoBtlsX509StoreCtx Instance {
+                       get { return (MonoBtlsX509StoreCtx)base.Instance; }
+               }
+
+               internal BtlsX509StoreCtx (MonoBtlsX509StoreCtx ctx)
+                       : base (ctx)
+               {
+               }
+
+               public void Initialize (BtlsX509Store store, BtlsX509Chain chain)
+               {
+                       Instance.Initialize (store.Instance, chain.Instance);
+               }
+
+               public void SetVerifyParam (BtlsX509VerifyParam param)
+               {
+                       Instance.SetVerifyParam (param.Instance);
+               }
+
+               public int Verify ()
+               {
+                       return Instance.Verify ();
+               }
+
+               public BtlsX509Error GetError ()
+               {
+                       return (BtlsX509Error)Instance.GetError ();
+               }
+
+               public Exception GetException ()
+               {
+                       return Instance.GetException ();
+               }
+
+               public BtlsX509Chain GetChain ()
+               {
+                       return new BtlsX509Chain (Instance.GetChain ());
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreManager.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreManager.cs
new file mode 100644 (file)
index 0000000..1989ff4
--- /dev/null
@@ -0,0 +1,44 @@
+//
+// BtlsX509StoreManager.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+namespace Mono.Btls.Interface
+{
+       public static class BtlsX509StoreManager
+       {
+               public static bool HasStore (BtlsX509StoreType type)
+               {
+                       return MonoBtlsX509StoreManager.HasStore ((MonoBtlsX509StoreType)type);
+               }
+
+               public static string GetStorePath (BtlsX509StoreType type)
+               {
+                       return MonoBtlsX509StoreManager.GetStorePath ((MonoBtlsX509StoreType)type);
+               }
+       }
+}
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreType.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509StoreType.cs
new file mode 100644 (file)
index 0000000..acdfb98
--- /dev/null
@@ -0,0 +1,43 @@
+//
+// BtlsX509StoreType.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.IO;
+using System.Security.Cryptography;
+
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with MonoBtlsX509StoreType
+       public enum BtlsX509StoreType
+       {
+               Custom,
+               MachineTrustedRoots,
+               MachineIntermediateCA,
+               MachineUntrusted,
+               UserTrustedRoots,
+               UserIntermediateCA,
+               UserUntrusted
+       }
+}
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509TrustKind.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509TrustKind.cs
new file mode 100644 (file)
index 0000000..9338ec6
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// BtlsX509TrustKind.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with MonoBtlsX509TrustKind
+       [Flags]
+       public enum BtlsX509TrustKind
+       {
+               DEFAULT         = 0,
+               TRUST_CLIENT    = 1,
+               TRUST_SERVER    = 2,
+               TRUST_ALL       = 4,
+               REJECT_CLIENT   = 32,
+               REJECT_SERVER   = 64,
+               REJECT_ALL      = 128
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyFlags.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyFlags.cs
new file mode 100644 (file)
index 0000000..02640c8
--- /dev/null
@@ -0,0 +1,38 @@
+//
+// BtlsX509VerifyFlags.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       // Keep in sync with NativeBoringX509VerifyFlags
+       public enum BtlsX509VerifyFlags
+       {
+               DEFAULT = 0,
+               CRL_CHECK = 1,
+               CRL_CHECK_ALL = 2,
+               X509_STRIC = 4
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyParam.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/BtlsX509VerifyParam.cs
new file mode 100644 (file)
index 0000000..8d4e5eb
--- /dev/null
@@ -0,0 +1,91 @@
+//
+// BtlsX509VerifyParam.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       public class BtlsX509VerifyParam : BtlsObject
+       {
+               new internal MonoBtlsX509VerifyParam Instance {
+                       get { return (MonoBtlsX509VerifyParam)base.Instance; }
+               }
+
+               internal BtlsX509VerifyParam (MonoBtlsX509VerifyParam param)
+                       : base (param)
+               {
+               }
+
+               public BtlsX509VerifyParam Copy ()
+               {
+                       return new BtlsX509VerifyParam (Instance.Copy ());
+               }
+
+               public void SetName (string name)
+               {
+                       Instance.SetName (name);
+               }
+
+               public void SetHost (string name)
+               {
+                       Instance.SetHost (name);
+               }
+
+               public void AddHost (string name)
+               {
+                       Instance.AddHost (name);
+               }
+
+               public BtlsX509VerifyFlags GetFlags ()
+               {
+                       return (BtlsX509VerifyFlags)Instance.GetFlags ();
+               }
+
+               public void SetFlags (BtlsX509VerifyFlags flags)
+               {
+                       Instance.SetFlags ((ulong)flags);
+               }
+
+               public void SetPurpose (BtlsX509Purpose purpose)
+               {
+                       Instance.SetPurpose ((MonoBtlsX509Purpose)purpose);
+               }
+
+               public int GetDepth ()
+               {
+                       return Instance.GetDepth ();
+               }
+
+               public void SetDepth (int depth)
+               {
+                       Instance.SetDepth (depth);
+               }
+
+               public void SetTime (DateTime time)
+               {
+                       Instance.SetTime (time);
+               }
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/VersionInfo.cs b/mcs/class/Mono.Btls.Interface/Mono.Btls.Interface/VersionInfo.cs
new file mode 100644 (file)
index 0000000..726c4ba
--- /dev/null
@@ -0,0 +1,34 @@
+//
+// VersionInfo.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+namespace Mono.Btls.Interface
+{
+       public static class VersionInfo
+       {
+               public const string Version = "1.0.0";
+       }
+}
+
diff --git a/mcs/class/Mono.Btls.Interface/Properties/AssemblyInfo.cs b/mcs/class/Mono.Btls.Interface/Properties/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..5ff0bcb
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// AssemblyInfo.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Reflection;
+using System.Resources;
+using System.Security;
+using System.Security.Permissions;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about the system assembly
+
+[assembly: AssemblyVersion (Consts.FxVersion)]
+
+[assembly: AssemblyCompany ("MONO development team")]
+[assembly: AssemblyCopyright ("(c) 2016 Xamarin")]
+[assembly: AssemblyDescription ("Mono.Btls.Interface")]
+[assembly: AssemblyProduct ("MONO CLI")]
+[assembly: AssemblyTitle ("Mono.Btls.Interface")]
+[assembly: CLSCompliant (true)]
+[assembly: ComVisible (false)]
+[assembly: NeutralResourcesLanguage ("en-US")]
+
diff --git a/mcs/class/Mono.Btls.Interface/README.md b/mcs/class/Mono.Btls.Interface/README.md
new file mode 100644 (file)
index 0000000..81e169c
--- /dev/null
@@ -0,0 +1,9 @@
+Mono.Btls.Interface
+===================
+
+The purpose of this assembly is to allow test suites such as xamarin/web-tests
+(https://github.com/xamarin/web-tests/tree/stable) to test parts of BTLS without
+making System.dll internals visible.
+
+It should not be considered a stable and maintained API for third parties.
+
index 1f20c1f89c63b6dceeb793a7241f8a2d4a6d34c2..e2fa98dcebe04e7629af935ed7847e9df90bfd16 100644 (file)
@@ -16,7 +16,8 @@ VALID_TEST_PROFILE := $(filter net_4_x, $(PROFILE))
 ifdef VALID_TEST_PROFILE
 
 TEST_HELPERS_SOURCES = \
-       ../test-helpers/NetworkHelpers.cs
+       ../test-helpers/NetworkHelpers.cs \
+       Test/TypeLoadClass.cs
 
 test-local: dtest-app.exe dtest-excfilter.exe
 
diff --git a/mcs/class/Mono.Debugger.Soft/Test/TypeLoadClass.cs b/mcs/class/Mono.Debugger.Soft/Test/TypeLoadClass.cs
new file mode 100644 (file)
index 0000000..dfe4c3e
--- /dev/null
@@ -0,0 +1,11 @@
+
+class TypeLoadClass
+{
+       static TypeLoadClass ()
+       {
+       }
+}
+
+class TypeLoadClass2
+{
+}
\ No newline at end of file
index cc2ab66960fa5f3ed36e6e70c52278f6a27d6fac..532a6b207a1183216167b4439aed53d7db5e1465 100644 (file)
@@ -1589,12 +1589,6 @@ public class Tests : TestsBase, ITest2
        }
 }
 
-class TypeLoadClass {
-}
-
-class TypeLoadClass2 {
-}
-
 public class SentinelClass : MarshalByRefObject {
 }
 
@@ -1620,6 +1614,25 @@ public class Foo
        public ProcessStartInfo info;
 }
 
+class LocalReflectClass
+{
+       public static void RunMe ()
+       {
+               var reflectMe = new someClass ();
+               var temp = reflectMe; // Breakpoint location
+               reflectMe.someMethod ();
+       }
+
+       class someClass : ContextBoundObject
+       {
+               public object someField;
+
+               public void someMethod ()
+               {
+               }
+       }
+}
+
 // Class used for line number info testing, don't change its layout
 public class LineNumbers
 {
@@ -1643,22 +1656,5 @@ public class LineNumbers
        }
 }
 
-class LocalReflectClass
-{
-       public static void RunMe ()
-       {
-               var reflectMe = new someClass ();
-               reflectMe.someMethod ();
-       }
-
-       class someClass : ContextBoundObject
-       {
-               public object someField;
-
-               public void someMethod ()
-               {
-               }
-       }
-}
 
 
index 505ab2abdbed718b6c4b74e583045da1a0fc4ab2..af994790ea00b44e9eedcf6e4d6af2467ee3e232 100644 (file)
@@ -558,7 +558,11 @@ public class DebuggerTests
                MethodMirror m = entry_point.DeclaringType.Assembly.GetType ("LocalReflectClass").GetMethod ("RunMe");
 
                Assert.IsNotNull (m);
-               //Console.WriteLine ("X: " + name + " " + m.ILOffsets.Count + " " + m.Locations.Count);
+
+//             foreach (var x in m.Locations) {
+//                     Console.WriteLine (x);
+//             }
+
                var offset = -1;
                int method_base_linum = m.Locations [0].LineNumber;
                foreach (var location in m.Locations)
@@ -586,7 +590,11 @@ public class DebuggerTests
                e = single_step (e.Thread);
 
                var frame = e.Thread.GetFrames ()[0];
-               Value variable = frame.GetValue (frame.Method.GetLocal ("reflectMe"));
+
+               Assert.IsNotNull (frame);
+               var field = frame.Method.GetLocal ("reflectMe");
+               Assert.IsNotNull (field);
+               Value variable = frame.GetValue (field);
 
                ObjectMirror thisObj = (ObjectMirror)variable;
                TypeMirror thisType = thisObj.Type;
@@ -3593,6 +3601,8 @@ public class DebuggerTests
                        return;
 
                string srcfile = (e as BreakpointEvent).Method.DeclaringType.GetSourceFiles (true)[0];
+               srcfile = srcfile.Replace ("dtest-app.cs", "TypeLoadClass.cs");
+               Assert.IsTrue (srcfile.Contains ("TypeLoadClass.cs"));
 
                var req = vm.CreateTypeLoadRequest ();
                req.SourceFileFilter = new string [] { srcfile.ToUpper () };
index e6e48767bf6173f7e82fe65dc206f5ef05123932..70678d2f0ca39e3d36eefc4f9dcf8c88446b46f3 100644 (file)
@@ -92,7 +92,6 @@
     <Compile Include=".\Mono.Security.Interface\HashAlgorithmType.cs" />\r
     <Compile Include=".\Mono.Security.Interface\IBufferOffsetSize.cs" />\r
     <Compile Include=".\Mono.Security.Interface\IMonoSslStream.cs" />\r
-    <Compile Include=".\Mono.Security.Interface\IMonoTlsContext.cs" />\r
     <Compile Include=".\Mono.Security.Interface\IMonoTlsEventSink.cs" />\r
     <Compile Include=".\Mono.Security.Interface\MonoTlsConnectionInfo.cs" />\r
     <Compile Include=".\Mono.Security.Interface\MonoTlsProvider.cs" />\r
diff --git a/mcs/class/Mono.Security/Mono.Security.Interface/IMonoTlsContext.cs b/mcs/class/Mono.Security/Mono.Security.Interface/IMonoTlsContext.cs
deleted file mode 100644 (file)
index d1ac4e2..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-//
-// IMonoTlsContext.cs
-//
-// Author:
-//       Martin Baulig <martin.baulig@xamarin.com>
-//
-// Copyright (c) 2015 Xamarin, Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-using System;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-
-namespace Mono.Security.Interface
-{
-       interface IMonoTlsContext : IDisposable
-       {
-               bool IsServer {
-                       get;
-               }
-
-               bool IsValid {
-                       get;
-               }
-
-               void Initialize (IMonoTlsEventSink eventSink);
-
-               bool HasCredentials {
-                       get;
-               }
-
-               void SetCertificate (X509Certificate certificate, AsymmetricAlgorithm privateKey);
-
-               int GenerateNextToken (IBufferOffsetSize incoming, out IBufferOffsetSize outgoing);
-
-               int EncryptMessage (ref IBufferOffsetSize incoming);
-
-               int DecryptMessage (ref IBufferOffsetSize incoming);
-
-               bool ReceivedCloseNotify {
-                       get;
-               }
-
-               byte[] CreateCloseNotify ();
-
-               byte[] CreateHelloRequest ();
-
-               X509Certificate GetRemoteCertificate (out X509CertificateCollection remoteCertificateStore);
-
-               bool VerifyRemoteCertificate ();
-
-               MonoTlsConnectionInfo GetConnectionInfo ();
-       }
-}
-
index 089d8447a78993d3a4015cf4ad40b6a47cb6f6ed..0d7a7512d6a758659c5d10268874eaae2e726b02 100644 (file)
@@ -145,14 +145,6 @@ namespace Mono.Security.Interface
 #endregion
 
 #region Certificate Validation
-
-               /*
-                * Allows a TLS provider to provide a custom system certificiate validator.
-                */
-               internal virtual bool HasCustomSystemCertificateValidator {
-                       get { return false; }
-               }
-
                /*
                 * If @serverMode is true, then we're a server and want to validate a certificate
                 * that we received from a client.
@@ -162,32 +154,10 @@ namespace Mono.Security.Interface
                 * Returns `true` if certificate validation has been performed and `false` to invoke the
                 * default system validator.
                 */
-               internal virtual bool InvokeSystemCertificateValidator (
+               internal abstract bool ValidateCertificate (
                        ICertificateValidator2 validator, string targetHost, bool serverMode,
                        X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
-                       out bool success, ref MonoSslPolicyErrors errors, ref int status11)
-               {
-                       throw new InvalidOperationException ();
-               }
-
-#endregion
-
-#region Manged SSPI
-
-               /*
-                * The managed SSPI implementation from the new TLS code.
-                */
-
-               internal abstract bool SupportsTlsContext {
-                       get;
-               }
-
-               internal abstract IMonoTlsContext CreateTlsContext (
-                       string hostname, bool serverMode, TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, MonoEncryptionPolicy encryptionPolicy,
-                       MonoTlsSettings settings);
-
+                       ref MonoSslPolicyErrors errors, ref int status11);
 #endregion
        }
 }
index cb96ce12e4626fcb93c168b0d84a461f2b3a5a57..e74c7be0dd9773ce6f048fadc031d3178e8cc40e 100644 (file)
@@ -38,6 +38,8 @@ using System.Security.Cryptography;
 using Mono.Security.Cryptography;
 using Mono.Security.X509.Extensions;
 
+using SSCX = System.Security.Cryptography.X509Certificates;
+
 namespace Mono.Security.X509 {
 
 #if INSIDE_CORLIB
@@ -51,12 +53,14 @@ namespace Mono.Security.X509 {
                private X509CertificateCollection _certificates;
                private ArrayList _crls;
                private bool _crl;
+               private bool _newFormat;
                private string _name;
 
-               internal X509Store (string path, bool crl
+               internal X509Store (string path, bool crl, bool newFormat)
                {
                        _storePath = path;
                        _crl = crl;
+                       _newFormat = newFormat;
                }
 
                // properties
@@ -126,6 +130,11 @@ namespace Mono.Security.X509 {
                {
                        CheckStore (_storePath, true);
 
+                       if (_newFormat) {
+                               ImportNewFormat (certificate);
+                               return;
+                       }
+
                        string filename = Path.Combine (_storePath, GetUniqueName (certificate));
                        if (!File.Exists (filename)) {
                                filename = Path.Combine (_storePath, GetUniqueNameWithSerial (certificate));
@@ -165,6 +174,9 @@ namespace Mono.Security.X509 {
                {
                        CheckStore (_storePath, true);
 
+                       if (_newFormat)
+                               throw new NotSupportedException ();
+
                        string filename = Path.Combine (_storePath, GetUniqueName (crl));
                        if (!File.Exists (filename)) {
                                using (FileStream fs = File.Create (filename)) {
@@ -177,6 +189,11 @@ namespace Mono.Security.X509 {
 
                public void Remove (X509Certificate certificate) 
                {
+                       if (_newFormat) {
+                               RemoveNewFormat (certificate);
+                               return;
+                       }
+
                        string filename = Path.Combine (_storePath, GetUniqueNameWithSerial (certificate));
                        if (File.Exists (filename)) {
                                File.Delete (filename);
@@ -192,6 +209,9 @@ namespace Mono.Security.X509 {
 
                public void Remove (X509Crl crl) 
                {
+                       if (_newFormat)
+                               throw new NotSupportedException ();
+
                        string filename = Path.Combine (_storePath, GetUniqueName (crl));
                        if (File.Exists (filename)) {
                                File.Delete (filename);
@@ -199,6 +219,41 @@ namespace Mono.Security.X509 {
                        }
                }
 
+               // new format
+
+               void ImportNewFormat (X509Certificate certificate)
+               {
+#if INSIDE_CORLIB
+                       throw new NotSupportedException ();
+#else
+                       using (var sscxCert = new SSCX.X509Certificate (certificate.RawData)) {
+                               var hash = SSCX.X509Helper2.GetSubjectNameHash (sscxCert);
+                               var filename = Path.Combine (_storePath, string.Format ("{0:x8}.0", hash));
+                               if (!File.Exists (filename)) {
+                                       using (FileStream fs = File.Create (filename))
+                                               SSCX.X509Helper2.ExportAsPEM (sscxCert, fs, true);
+                                       ClearCertificates ();
+                               }
+                       }
+#endif
+               }
+
+               void RemoveNewFormat (X509Certificate certificate)
+               {
+#if INSIDE_CORLIB
+                       throw new NotSupportedException ();
+#else
+                       using (var sscxCert = new SSCX.X509Certificate (certificate.RawData)) {
+                               var hash = SSCX.X509Helper2.GetSubjectNameHash (sscxCert);
+                               var filename = Path.Combine (_storePath, string.Format ("{0:x8}.0", hash));
+                               if (File.Exists (filename)) {
+                                       File.Delete (filename);
+                                       ClearCertificates ();
+                               }
+                       }
+#endif
+               }
+
                // private stuff
 
                private string GetUniqueNameWithSerial (X509Certificate certificate)
index db735834acd4ca39c0310cca71612eeadac7a7c9..7f31713b1b226e6aed757774cbd181afb28c159a 100644 (file)
@@ -45,8 +45,12 @@ namespace Mono.Security.X509 {
 
                static private string _userPath;
                static private string _localMachinePath;
+               static private string _newUserPath;
+               static private string _newLocalMachinePath;
                static private X509Stores _userStore;
                static private X509Stores _machineStore;
+               static private X509Stores _newUserStore;
+               static private X509Stores _newMachineStore;
 
                private X509StoreManager ()
                {
@@ -55,10 +59,10 @@ namespace Mono.Security.X509 {
                internal static string CurrentUserPath {
                        get {
                                if (_userPath == null) {
-                                       _userPath = Path.Combine(
-                                                       Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+                                       _userPath = Path.Combine (
+                                                       Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
                                                        ".mono");
-                                       _userPath = Path.Combine(_userPath, "certs");
+                                       _userPath = Path.Combine (_userPath, "certs");
                                }
                                return _userPath;
                        }
@@ -76,10 +80,34 @@ namespace Mono.Security.X509 {
                        }
                }
 
+               internal static string NewCurrentUserPath {
+                       get {
+                               if (_newUserPath == null) {
+                                       _newUserPath = Path.Combine (
+                                                       Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData),
+                                                       ".mono");
+                                       _newUserPath = Path.Combine (_newUserPath, "new-certs");
+                               }
+                               return _newUserPath;
+                       }
+               }
+
+               internal static string NewLocalMachinePath {
+                       get {
+                               if (_newLocalMachinePath == null) {
+                                       _newLocalMachinePath = Path.Combine (
+                                               Environment.GetFolderPath (Environment.SpecialFolder.CommonApplicationData),
+                                               ".mono");
+                                       _newLocalMachinePath = Path.Combine (_newLocalMachinePath, "new-certs");
+                               }
+                               return _newLocalMachinePath;
+                       }
+               }
+
                static public X509Stores CurrentUser {
                        get { 
                                if (_userStore == null)
-                                       _userStore = new X509Stores(CurrentUserPath);
+                                       _userStore = new X509Stores (CurrentUserPath, false);
                                
                                return _userStore;
                        }
@@ -88,12 +116,30 @@ namespace Mono.Security.X509 {
                static public X509Stores LocalMachine {
                        get {
                                if (_machineStore == null) 
-                                       _machineStore = new X509Stores (LocalMachinePath);
+                                       _machineStore = new X509Stores (LocalMachinePath, false);
 
                                return _machineStore;
                        }
                }
 
+               static public X509Stores NewCurrentUser {
+                       get {
+                               if (_newUserStore == null)
+                                       _newUserStore = new X509Stores (NewCurrentUserPath, true);
+
+                               return _newUserStore;
+                       }
+               }
+
+               static public X509Stores NewLocalMachine {
+                       get {
+                               if (_newMachineStore == null)
+                                       _newMachineStore = new X509Stores (NewLocalMachinePath, true);
+
+                               return _newMachineStore;
+                       }
+               }
+
                // Merged stores collections
                // we need to look at both the user and the machine (entreprise)
                // certificates/CRLs when building/validating a chain
index bfe7451b5dee1c229ac4ff2ae990ff92a60af0b8..071faa70dddefdf8aa7c6f8f7b33f2f80dad92e4 100644 (file)
@@ -44,15 +44,17 @@ namespace Mono.Security.X509 {
        class X509Stores {
 
                private string _storePath;
+               private bool _newFormat;
                private X509Store _personal;
                private X509Store _other;
                private X509Store _intermediate;
                private X509Store _trusted;
                private X509Store _untrusted;
 
-               internal X509Stores (string path
+               internal X509Stores (string path, bool newFormat)
                {
                        _storePath = path;
+                       _newFormat = newFormat;
                }
 
                // properties
@@ -61,7 +63,7 @@ namespace Mono.Security.X509 {
                        get { 
                                if (_personal == null) {
                                        string path = Path.Combine (_storePath, Names.Personal);
-                                       _personal = new X509Store (path, false);
+                                       _personal = new X509Store (path, false, false);
                                }
                                return _personal; 
                        }
@@ -71,7 +73,7 @@ namespace Mono.Security.X509 {
                        get { 
                                if (_other == null) {
                                        string path = Path.Combine (_storePath, Names.OtherPeople);
-                                       _other = new X509Store (path, false);
+                                       _other = new X509Store (path, false, false);
                                }
                                return _other; 
                        }
@@ -81,7 +83,7 @@ namespace Mono.Security.X509 {
                        get { 
                                if (_intermediate == null) {
                                        string path = Path.Combine (_storePath, Names.IntermediateCA);
-                                       _intermediate = new X509Store (path, true);
+                                       _intermediate = new X509Store (path, true, _newFormat);
                                }
                                return _intermediate; 
                        }
@@ -91,7 +93,7 @@ namespace Mono.Security.X509 {
                        get { 
                                if (_trusted == null) {
                                        string path = Path.Combine (_storePath, Names.TrustedRoot);
-                                       _trusted = new X509Store (path, true);
+                                       _trusted = new X509Store (path, true, _newFormat);
                                }
                                return _trusted; 
                        }
@@ -101,7 +103,7 @@ namespace Mono.Security.X509 {
                        get { 
                                if (_untrusted == null) {
                                        string path = Path.Combine (_storePath, Names.Untrusted);
-                                       _untrusted = new X509Store (path, false);
+                                       _untrusted = new X509Store (path, false, _newFormat);
                                }
                                return _untrusted; 
                        }
@@ -138,7 +140,7 @@ namespace Mono.Security.X509 {
                        if (!create && !Directory.Exists (path))
                                return null;
 
-                       return new X509Store (path, true);
+                       return new X509Store (path, true, false);
                }
 
                // names
@@ -151,7 +153,7 @@ namespace Mono.Security.X509 {
                        public const string IntermediateCA = "CA";
                        public const string TrustedRoot = "Trust";
                        public const string Untrusted = "Disallowed";
-                       
+
                        public Names () {}
                }
        }
index 652115f85a3b524b73977d9143b9aba4d30f45e1..65d146e17e50d7f944ec03e44f1b8080fbd53f43 100644 (file)
 ./Mono.Security.Interface/HashAlgorithmType.cs
 ./Mono.Security.Interface/IBufferOffsetSize.cs
 ./Mono.Security.Interface/IMonoTlsEventSink.cs
-./Mono.Security.Interface/IMonoTlsContext.cs
 ./Mono.Security.Interface/IMonoSslStream.cs
 ./Mono.Security.Interface/MonoTlsConnectionInfo.cs
 ./Mono.Security.Interface/MonoTlsProvider.cs
index 23bf26f7482bb7654e1e5043f8381c937000f460..a4818f76049ea471ba429953552c602269a8a6b3 100644 (file)
@@ -77,8 +77,8 @@ namespace System.IO.Pipes
                        throw new NotImplementedException ();
 #else
                        InitializeHandle (safePipeHandle, false, false);
-#endif
                        IsConnected = true;
+#endif
                }
 
                ~AnonymousPipeClientStream ()
index a823217957dcd384dd2f14db6d07cdbc1b06fa3d..a27c4dc0b4d3697f8aca9edf8f2cad7bf8d10499 100644 (file)
@@ -120,8 +120,10 @@ namespace System.IO.Pipes
                ~NamedPipeClientStream () {
                        Dispose (false);
                }
-               
+
+#if !MOBILE
                INamedPipeClient impl;
+#endif
 
                public void Connect ()
                {
@@ -172,7 +174,11 @@ namespace System.IO.Pipes
                public int NumberOfServerInstances {
                        get {
                                CheckPipePropertyOperations ();
+#if MOBILE
+                               throw new NotImplementedException ();
+#else
                                return impl.NumberOfServerInstances;
+#endif
                        }
                }
        }
index e402a8a2620193f7b966b300ddb7cb2f219a431f..d4d02ade208f4f415a2a1d817ac3c6598b103895 100644 (file)
@@ -97,11 +97,12 @@ namespace System.IO.Pipes
                public NamedPipeServerStream (string pipeName, PipeDirection direction, int maxNumberOfServerInstances, PipeTransmissionMode transmissionMode, PipeOptions options, int inBufferSize, int outBufferSize, PipeSecurity pipeSecurity, HandleInheritability inheritability, PipeAccessRights additionalAccessRights)
                        : base (direction, transmissionMode, outBufferSize)
                {
-                       var rights = ToAccessRights (direction) | additionalAccessRights;
-                       // FIXME: reject some rights declarations (for ACL).
 #if MOBILE
                        throw new NotImplementedException ();
 #else
+                       var rights = ToAccessRights (direction) | additionalAccessRights;
+                       // FIXME: reject some rights declarations (for ACL).
+
                        if (IsWindows)
                                impl = new Win32NamedPipeServer (this, pipeName, maxNumberOfServerInstances, transmissionMode,
                                                                 rights, options, inBufferSize, outBufferSize,
index b5bd23a7cbe8cb79f73e38af70f4a38447fa87ee..e8a641299b351597bbcaaa4cfc549055fa665dbc 100644 (file)
@@ -6,17 +6,23 @@ LIBRARY = System.Data.dll
 
 LIB_REFS = System System.Xml System.Core System.Numerics
 LIB_MCS_FLAGS = \
-       -nowarn:169,219,414,649 \
+       -nowarn:219,414,649 \
        -d:PLATFORM_UNIX \
        -d:USEOFFSET \
        -d:MONO_PARTIAL_DATA_IMPORT \
        -unsafe
 
+ifdef NO_MONO_SECURITY
+MONO_DATA_TDS=
+else
+MONO_DATA_TDS=Mono.Data.Tds
+endif
+
 ifdef MOBILE_PROFILE
-LIB_REFS += Mono.Data.Tds System.Transactions
+LIB_REFS += $(MONO_DATA_TDS) System.Transactions
 LIB_MCS_FLAGS += -d:NO_CODEDOM -d:NO_OLEDB -d:NO_ODBC -d:NO_CONFIGURATION
 else
-LIB_REFS += System.EnterpriseServices Mono.Data.Tds System.Configuration System.Transactions
+LIB_REFS += System.EnterpriseServices $(MONO_DATA_TDS) System.Configuration System.Transactions
 BUILT_SOURCES = \
        gen_OdbcConnection.cs \
        gen_OleDbConnection.cs \
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlBulkCopy.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlBulkCopy.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..95d6801
--- /dev/null
@@ -0,0 +1,136 @@
+//
+// SqlBulkCopy.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Data.Common;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Data.SqlClient {
+       public sealed class SqlBulkCopy : IDisposable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlBulkCopy is not supported on the current platform.";
+
+               public SqlBulkCopy (SqlConnection connection)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlBulkCopy (string connectionString)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlBulkCopy (string connectionString, SqlBulkCopyOptions copyOptions)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlBulkCopy (SqlConnection connection, SqlBulkCopyOptions copyOptions, SqlTransaction externalTransaction)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public int BatchSize {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int BulkCopyTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlBulkCopyColumnMappingCollection ColumnMappings  {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string DestinationTableName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool EnableStreaming {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int NotifyAfter {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public void Close ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void WriteToServer (DataRow [] rows)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void WriteToServer (DataTable table)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void WriteToServer (IDataReader reader)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void WriteToServer (DataTable table, DataRowState rowState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void WriteToServer (DbDataReader reader)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public Task WriteToServerAsync (DbDataReader reader)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public Task WriteToServerAsync (DbDataReader reader, CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               private void RowsCopied (long rowsCopied)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public event SqlRowsCopiedEventHandler SqlRowsCopied;
+
+               void IDisposable.Dispose ()
+               {
+               }
+       }
+}
index c6dc7712baea19fa4846ae2da30eb5529c284944..1fd5443df85192ea7e3fcffd5461c19356952b59 100644 (file)
@@ -510,40 +510,104 @@ namespace System.Data.SqlClient {
                        }
                }
 
-               [MonoTODO]
                public new Task<SqlDataReader> ExecuteReaderAsync ()
                {
-                       throw new NotImplementedException ();
+                       return ExecuteReaderAsync (CommandBehavior.Default, CancellationToken.None);
                }
 
-               [MonoTODO]
                public new Task<SqlDataReader> ExecuteReaderAsync (CancellationToken cancellationToken)
                {
-                       throw new NotImplementedException ();
+                       return ExecuteReaderAsync (behavior, CancellationToken.None);
                }
 
-               [MonoTODO]
                public new Task<SqlDataReader> ExecuteReaderAsync (CommandBehavior behavior)
                {
-                       throw new NotImplementedException ();
+                       return ExecuteReaderAsync (CommandBehavior.Default, CancellationToken.None);
                }
 
-               [MonoTODO]
                public new Task<SqlDataReader> ExecuteReaderAsync (CommandBehavior behavior, CancellationToken cancellationToken)
                {
-                       throw new NotImplementedException ();
+                       TaskCompletionSource<SqlDataReader> source = new TaskCompletionSource<SqlDataReader>();
+
+                       CancellationTokenRegistration registration = new CancellationTokenRegistration();
+                       if (cancellationToken.CanBeCanceled) {
+                               if (cancellationToken.IsCancellationRequested) {
+                                       source.SetCanceled();
+                                       return source.Task;
+                               }
+                               registration = cancellationToken.Register(CancelIgnoreFailure);
+                       }
+
+                       Task<SqlDataReader> returnedTask = source.Task;
+                       try {
+                               // TODO: RegisterForConnectionCloseNotification(ref returnedTask);
+
+                               Task<SqlDataReader>.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReader, behavior, null).ContinueWith((t) => {
+                                       registration.Dispose();
+                                       if (t.IsFaulted) {
+                                               Exception e = t.Exception.InnerException;
+                                               source.SetException(e);
+                                       }
+                                       else {
+                                               if (t.IsCanceled) {
+                                                       source.SetCanceled();
+                                               }
+                                               else {
+                                                       source.SetResult(t.Result);
+                                               }
+                                       }
+                               }, TaskScheduler.Default);
+                       }
+                       catch (Exception e) {
+                               source.SetException(e);
+                       }
+
+                       return returnedTask;
                }
 
-               [MonoTODO]
                public Task<XmlReader> ExecuteXmlReaderAsync ()
                {
-                       throw new NotImplementedException ();
+                       return ExecuteXmlReaderAsync (CancellationToken.None);
                }
  
-               [MonoTODO]
                public Task<XmlReader> ExecuteXmlReaderAsync (CancellationToken cancellationToken)
                {
-                       throw new NotImplementedException ();
+                       TaskCompletionSource<XmlReader> source = new TaskCompletionSource<XmlReader>();
+
+                       CancellationTokenRegistration registration = new CancellationTokenRegistration();
+                       if (cancellationToken.CanBeCanceled) {
+                               if (cancellationToken.IsCancellationRequested) {
+                                       source.SetCanceled();
+                                       return source.Task;
+                               }
+                               registration = cancellationToken.Register(CancelIgnoreFailure);
+                       }
+
+                       Task<XmlReader> returnedTask = source.Task;
+                       try {
+                               // TODO: RegisterForConnectionCloseNotification(ref returnedTask);
+
+                               Task<XmlReader>.Factory.FromAsync(BeginExecuteXmlReader, EndExecuteXmlReader, null).ContinueWith((t) => {
+                                       registration.Dispose();
+                                       if (t.IsFaulted) {
+                                               Exception e = t.Exception.InnerException;
+                                               source.SetException(e);
+                                       }
+                                       else {
+                                               if (t.IsCanceled) {
+                                                       source.SetCanceled();
+                                               }
+                                               else {
+                                                       source.SetResult(t.Result);
+                                               }
+                                       }
+                               }, TaskScheduler.Default);
+                       }
+                       catch (Exception e) {
+                               source.SetException(e);
+                       }
+
+                       return returnedTask;
                }
 
                public
@@ -846,6 +910,11 @@ namespace System.Data.SqlClient {
                        return BeginExecuteReader (callback, stateObject, CommandBehavior.Default);
                }
 
+               IAsyncResult BeginExecuteReaderAsync(CommandBehavior behavior, AsyncCallback callback, object stateObject)
+               {
+                       return BeginExecuteReader (callback, stateObject, behavior);
+               }
+
                public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject, CommandBehavior behavior)
                {
                        ValidateCommand ("BeginExecuteReader", true);
@@ -925,6 +994,9 @@ namespace System.Data.SqlClient {
 
                #endregion // Asynchronous Methods
 
+#pragma warning disable 0067
+               // TODO: Not implemented
                public event StatementCompletedEventHandler StatementCompleted;
+#pragma warning restore
        }
 }
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlCommand.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..491483e
--- /dev/null
@@ -0,0 +1,277 @@
+//
+// SqlCommand.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Data.Common;
+using System.Data.Sql;
+using System.Threading.Tasks;
+using System.Threading;
+using System.Xml;
+
+namespace System.Data.SqlClient {
+       public sealed class SqlCommand : DbCommand, IDbCommand, ICloneable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlCommand is not supported on the current platform.";
+
+               public SqlCommand()
+                       : this (String.Empty, null, null)
+               {
+               }
+
+               public SqlCommand (string cmdText)
+                       : this (cmdText, null, null)
+               {
+               }
+
+               public SqlCommand (string cmdText, SqlConnection connection)
+                       : this (cmdText, connection, null)
+               {
+               }
+
+               public SqlCommand (string cmdText, SqlConnection connection, SqlTransaction transaction)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string CommandText {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int CommandTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override CommandType CommandType {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public new SqlConnection Connection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool DesignTimeVisible {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public new SqlParameterCollection Parameters {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public new SqlTransaction Transaction {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override UpdateRowSource UpdatedRowSource {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlNotificationRequest Notification {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool NotificationAutoEnlist {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override void Cancel ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand Clone ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new SqlParameter CreateParameter ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int ExecuteNonQuery ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new SqlDataReader ExecuteReader ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new SqlDataReader ExecuteReader (CommandBehavior behavior)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new Task<SqlDataReader> ExecuteReaderAsync ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new Task<SqlDataReader> ExecuteReaderAsync (CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new Task<SqlDataReader> ExecuteReaderAsync (CommandBehavior behavior)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new Task<SqlDataReader> ExecuteReaderAsync (CommandBehavior behavior, CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public Task<XmlReader> ExecuteXmlReaderAsync ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public Task<XmlReader> ExecuteXmlReaderAsync (CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override object ExecuteScalar ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public XmlReader ExecuteXmlReader ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               object ICloneable.Clone ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+               }
+
+               public override void Prepare ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void ResetCommandTimeout ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbParameter CreateDbParameter ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbConnection DbConnection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               protected override DbParameterCollection DbParameterCollection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               protected override DbTransaction DbTransaction {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public IAsyncResult BeginExecuteNonQuery ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteNonQuery (AsyncCallback callback, object stateObject)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public int EndExecuteNonQuery (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteReader ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteReader (CommandBehavior behavior)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteReader (AsyncCallback callback, object stateObject, CommandBehavior behavior)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlDataReader EndExecuteReader (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteXmlReader (AsyncCallback callback, object stateObject)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IAsyncResult BeginExecuteXmlReader ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public XmlReader EndExecuteXmlReader (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public event StatementCompletedEventHandler StatementCompleted;
+       }
+}
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlCommandBuilder.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlCommandBuilder.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..155ddab
--- /dev/null
@@ -0,0 +1,158 @@
+//
+// SqlCommandBuilder.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlClient;
+
+namespace System.Data.SqlClient
+{
+       public class SqlCommandBuilder : DbCommandBuilder 
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlCommandBuilder is not supported on the current platform.";
+
+               public SqlCommandBuilder ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommandBuilder (SqlDataAdapter adapter)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void DeriveParameters (SqlCommand command)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetDeleteCommand ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetInsertCommand ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetUpdateCommand ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetUpdateCommand (bool useColumnsForParameterNames)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetDeleteCommand (bool useColumnsForParameterNames)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlCommand GetInsertCommand (bool useColumnsForParameterNames)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string QuoteIdentifier (string unquotedIdentifier)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string UnquoteIdentifier (string quotedIdentifier)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void ApplyParameterInfo (DbParameter parameter, DataRow datarow, StatementType statementType, bool whereClause)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override string GetParameterName (int parameterOrdinal)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override string GetParameterName (string parameterName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override string GetParameterPlaceholder (int parameterOrdinal)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void SetRowUpdatingHandler (DbDataAdapter adapter)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DataTable GetSchemaTable (DbCommand srcCommand)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbCommand InitializeCommand (DbCommand command)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlDataAdapter DataAdapter {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string QuotePrefix {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string QuoteSuffix {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string CatalogSeparator {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string SchemaSeparator {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override CatalogLocation CatalogLocation {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+       }
+}
index 9af24e650543168cb7543aee345b08dafcf815a9..415f5832e863fbb51dd0606f4129b71a03c3f3ef 100644 (file)
@@ -138,7 +138,9 @@ namespace System.Data.SqlClient
 
                [DefaultValue ("")]
                [EditorAttribute ("Microsoft.VSDesigner.Data.SQL.Design.SqlConnectionStringEditor, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+ Consts.AssemblySystem_Drawing )]
-               [RecommendedAsConfigurable (true)]
+#pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
+               [RecommendedAsConfigurable(true)]
+#pragma warning restore 618
                [RefreshProperties (RefreshProperties.All)]
                public override string ConnectionString {
                        get {
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlConnection.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..bb35026
--- /dev/null
@@ -0,0 +1,214 @@
+//
+// SqlConnection.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Collections;
+using System.Data.Common;
+
+namespace System.Data.SqlClient
+{
+       public sealed class SqlConnection : DbConnection, IDbConnection, ICloneable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlConnection is not supported on the current platform.";
+
+               public SqlConnection () : this (null)
+               {
+               }
+
+               public SqlConnection (string connectionString)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlConnection (string connectionString, SqlCredential cred)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string ConnectionString {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlCredential Credentials {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public Guid ClientConnectionId {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int ConnectionTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string Database {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string DataSource {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int PacketSize {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string ServerVersion {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override ConnectionState State {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string WorkstationId {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool FireInfoMessageEventOnUserErrors {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool StatisticsEnabled {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               protected override DbProviderFactory DbProviderFactory {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public event SqlInfoMessageEventHandler InfoMessage;
+
+               public new SqlTransaction BeginTransaction ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new SqlTransaction BeginTransaction (IsolationLevel iso)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlTransaction BeginTransaction (string transactionName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlTransaction BeginTransaction (IsolationLevel iso, string transactionName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void ChangeDatabase (string database)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Close ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public new SqlCommand CreateCommand ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+               }
+
+#if !MOBILE
+               public void EnlistDistributedTransaction (ITransaction transaction)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+#endif
+
+               object ICloneable.Clone ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbTransaction BeginDbTransaction (IsolationLevel isolationLevel)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbCommand CreateDbCommand ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Open ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DataTable GetSchema ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DataTable GetSchema (String collectionName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DataTable GetSchema (String collectionName, string [] restrictionValues)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void ChangePassword (string connectionString, string newPassword)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void ClearAllPools ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void ClearPool (SqlConnection connection)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void ResetStatistics ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public IDictionary RetrieveStatistics ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+       }
+}
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..395e97a
--- /dev/null
@@ -0,0 +1,363 @@
+//
+// SqlDataReader.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections;
+using System.Data.Common;
+using System.Data.SqlClient;
+using System.Data.SqlTypes;
+using System.Data;
+using System.IO;
+using System.Threading.Tasks;
+using System.Threading;
+using System.Xml;
+
+
+namespace System.Data.SqlClient
+{
+       public class SqlDataReader : DbDataReader , IDataReader, IDisposable, IDataRecord
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlDataReader is not supported on the current platform.";
+
+               SqlDataReader () {}
+
+               protected bool IsCommandBehavior (CommandBehavior condition)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Close ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool GetBoolean (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override byte GetByte (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override long GetBytes (int i, long dataIndex, byte [] buffer, int bufferIndex, int length)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override char GetChar (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override long GetChars (int i, long dataIndex, char [] buffer, int bufferIndex, int length)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string GetDataTypeName (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DateTime GetDateTime (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual DateTimeOffset GetDateTimeOffset (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual TimeSpan GetTimeSpan (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlChars GetSqlChars (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Decimal GetDecimal (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Double GetDouble (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Type GetFieldType (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Single GetFloat (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Guid GetGuid (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override short GetInt16 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int GetInt32 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override long GetInt64 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string GetName (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int GetOrdinal (string name)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DataTable GetSchemaTable ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlBinary GetSqlBinary (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlBoolean GetSqlBoolean (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlByte GetSqlByte (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlDateTime GetSqlDateTime (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlDecimal GetSqlDecimal (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlDouble GetSqlDouble (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlGuid GetSqlGuid (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlInt16 GetSqlInt16 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlInt32 GetSqlInt32 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlInt64 GetSqlInt64 (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlMoney GetSqlMoney (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlSingle GetSqlSingle (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlString GetSqlString (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlXml GetSqlXml (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual object GetSqlValue (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual int GetSqlValues (object [] values)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override string GetString (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override object GetValue (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int GetValues (object [] values)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override IEnumerator GetEnumerator ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool IsDBNull (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool NextResult ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool Read ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Type GetProviderSpecificFieldType (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override object GetProviderSpecificValue (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int GetProviderSpecificValues (object [] values)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual SqlBytes GetSqlBytes (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override T GetFieldValue<T> (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual XmlReader GetXmlReader (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Task<T> GetFieldValueAsync<T> (int i, CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Stream GetStream (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override TextReader GetTextReader (int i)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override Task<bool> IsDBNullAsync (int i, CancellationToken cancellationToken)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int Depth {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int FieldCount {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsClosed {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override object this [int i] {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override object this [string name] {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int RecordsAffected {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool HasRows {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int VisibleFieldCount {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               protected SqlConnection Connection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+       }
+}
index 3962bf4f55c9fa193525a4f35a2e51b7d4a617d5..5cb920c0e9a0beaf226613ae01367810f81c3603 100644 (file)
@@ -65,8 +65,11 @@ namespace System.Data.SqlClient
                public bool HasChanges {
                        get { return true; }
                }
-               
+
+#pragma warning disable 0067
+               [MonoTODO]
                public event OnChangeEventHandler OnChange;
+#pragma warning restore
 
                [MonoTODO]
                public void AddCommandDependency(SqlCommand command)
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlException.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlException.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..24d102d
--- /dev/null
@@ -0,0 +1,102 @@
+//
+// SqlException.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Data.Common;
+using System.Data.SqlClient;
+using System.Runtime.Serialization;
+
+namespace System.Data.SqlClient
+{
+       public class SqlException : DbException 
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlException is not supported on the current platform.";
+
+               internal bool _doNotReconnect;
+
+               static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, SqlInternalConnectionTds internalConnection, Exception innerException = null)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               static internal SqlException CreateException(SqlErrorCollection errorCollection, string serverVersion, Guid conId, Exception innerException = null)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               SqlException () {}
+
+               public override void GetObjectData (SerializationInfo si, StreamingContext context)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public byte Class {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public Guid ClientConnectionId {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlErrorCollection Errors {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int LineNumber {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string Message {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int Number {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string Procedure {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string Server {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string Source {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public byte State {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+       }
+}
index f6153fb60b55074b71511c3baae109d00f466b7f..33531b7c1fff5de910f931d1aa6f872d8e67bd04 100644 (file)
@@ -361,13 +361,13 @@ namespace System.Data.SqlClient {
                }
 
                [DefaultValue (0)]
-               public byte Precision {
+               public new byte Precision {
                        get { return metaParameter.Precision; }
                        set { metaParameter.Precision = value; }
                }
 
                [DefaultValue (0)]
-               public byte Scale {
+               public new byte Scale {
                        get { return metaParameter.Scale; }
                        set { metaParameter.Scale = value; }
                }
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlParameter.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlParameter.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..79f6f95
--- /dev/null
@@ -0,0 +1,198 @@
+//
+// SqlParameter.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlTypes;
+
+namespace System.Data.SqlClient
+{
+       public class SqlParameter : DbParameter , IDbDataParameter, IDataParameter, ICloneable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlParameter is not supported on the current platform.";
+
+               public SqlParameter ()
+                       : this (String.Empty, SqlDbType.NVarChar, 0, ParameterDirection.Input, false, 0, 0, String.Empty, DataRowVersion.Current, null)
+               {
+               }
+
+               public SqlParameter (string parameterName, object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter (string parameterName, SqlDbType dbType) 
+                       : this (parameterName, dbType, 0, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
+               {
+               }
+
+               public SqlParameter (string parameterName, SqlDbType dbType, int size) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, null, DataRowVersion.Current, null)
+               {
+               }
+
+               public SqlParameter (string parameterName, SqlDbType dbType, int size, string sourceColumn) 
+                       : this (parameterName, dbType, size, ParameterDirection.Input, false, 0, 0, sourceColumn, DataRowVersion.Current, null)
+               {
+               }
+
+               public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, bool isNullable, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, object value) 
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter (string parameterName, SqlDbType dbType, int size, ParameterDirection direction, byte precision, byte scale, string sourceColumn, DataRowVersion sourceVersion, bool sourceColumnNullMapping, Object value, string xmlSchemaCollectionDatabase, string xmlSchemaCollectionOwningSchema, string xmlSchemaCollectionName)
+                       : this (parameterName, dbType, size, direction, false, precision, scale, sourceColumn, sourceVersion, value)
+               {
+               }
+
+               public override string ToString ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void ResetDbType ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void ResetSqlDbType ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override DbType DbType {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override ParameterDirection Direction {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsNullable {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int Offset {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string ParameterName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public byte Precision {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public byte Scale {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int Size {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override string SourceColumn {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override DataRowVersion SourceVersion {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlDbType SqlDbType {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override object Value {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlCompareOptions CompareInfo {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int LocaleId {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public object SqlValue {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool SourceColumnNullMapping {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string XmlSchemaCollectionDatabase {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string XmlSchemaCollectionName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string XmlSchemaCollectionOwningSchema {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string UdtTypeName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string TypeName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               object ICloneable.Clone ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+       }
+}
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlParameterCollection.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlParameterCollection.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..cc3a6ab
--- /dev/null
@@ -0,0 +1,216 @@
+//
+// SqlParameterCollection.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Collections;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlClient;
+
+namespace System.Data.SqlClient
+{
+       public class SqlParameterCollection : DbParameterCollection , IDataParameterCollection, IList, ICollection, IEnumerable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlParameterCollection is not supported on the current platform.";
+
+               SqlParameterCollection () {}
+
+               protected override DbParameter GetParameter (int index)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override DbParameter GetParameter (string parameterName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void SetParameter (int index, DbParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void SetParameter (string parameterName, DbParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int Add (object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter Add (SqlParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter Add (string parameterName, object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter AddWithValue (string parameterName, object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter Add (string parameterName, SqlDbType sqlDbType)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter Add (string parameterName, SqlDbType sqlDbType, int size)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlParameter Add (string parameterName, SqlDbType sqlDbType, int size, string sourceColumn)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Clear ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool Contains (object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool Contains (string value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public bool Contains (SqlParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void CopyTo (Array array, int index)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override IEnumerator GetEnumerator ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int IndexOf (object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int IndexOf (string parameterName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public int IndexOf (SqlParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Insert (int index, object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void Insert (int index, SqlParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Remove (object value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void Remove (SqlParameter value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void RemoveAt (int index)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void RemoveAt (string parameterName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void AddRange (Array values)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void AddRange (SqlParameter [] values)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void CopyTo (SqlParameter [] array, int index)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int Count {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsFixedSize {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsReadOnly {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsSynchronized {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override object SyncRoot {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlParameter this [int index] {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public SqlParameter this [string parameterName] {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+       }
+}
diff --git a/mcs/class/System.Data/System.Data.SqlClient/SqlTransaction.platformnotsupported.cs b/mcs/class/System.Data/System.Data.SqlClient/SqlTransaction.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..880b740
--- /dev/null
@@ -0,0 +1,77 @@
+//
+// SqlTransaction.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System;
+using System.Data;
+using System.Data.Common;
+using System.Data.SqlClient;
+
+namespace System.Data.SqlClient
+{
+       public class SqlTransaction : DbTransaction , IDbTransaction, IDisposable
+       {
+               const string EXCEPTION_MESSAGE = "System.Data.SqlClient.SqlTransaction is not supported on the current platform.";
+
+               SqlTransaction () {}
+
+               public override void Commit ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Rollback ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void Rollback (string transactionName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void Save (string savePointName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SqlConnection Connection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override IsolationLevel IsolationLevel {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               protected override DbConnection DbConnection {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+       }
+}
index 3749af5091222bf0b8dce37071dbb1a947749f3f..a8974949973e3fc8afcd95fc9b88c3a91b5f588e 100644 (file)
@@ -96,10 +96,14 @@ namespace MonoTests.System.Data.Common
                        try {
                                da.AddToBatch (new SqlCommand ());
                                Assert.Fail ("#1");
+#if FEATURE_NO_BSD_SOCKETS
+                       } catch (PlatformNotSupportedException) {
+#else
                        } catch (NotSupportedException ex) {
                                Assert.AreEqual (typeof (NotSupportedException), ex.GetType (), "#2");
                                Assert.IsNull (ex.InnerException, "#3");
                                Assert.IsNotNull (ex.Message, "#4");
+#endif
                        }
                }
 
index b65ba7abab6fdd5c63cd9118676cf9393fc4f524..4fbbbbefe4aa6eb41f5da888b4026a4a4da4b09f 100644 (file)
@@ -39,21 +39,33 @@ namespace MonoTests.System.Data.SqlClient {
                private const string testFailParamNameMessage = "We have to provide the same parameter name as in original .NET";
                
                [Test] // .ctor(SqlConnection connection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull1 ()
                {
                        new SqlBulkCopy ((SqlConnection)null);
                }
                
                [Test] // .ctor(string connectionString)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull2 ()
                {
                        new SqlBulkCopy ((string)null);
                }
                
                [Test] // .ctor(SqlConnection connection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull3 ()
                {
                        try {
@@ -65,7 +77,11 @@ namespace MonoTests.System.Data.SqlClient {
                }
                
                [Test] // .ctor(string connectionString)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull4 ()
                {
                        try {
@@ -77,7 +93,11 @@ namespace MonoTests.System.Data.SqlClient {
                }
                
                [Test] // .ctor(string connectionString)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull5 ()
                {
                        try {
@@ -89,7 +109,11 @@ namespace MonoTests.System.Data.SqlClient {
                }
                
                [Test] // .ctor(string connectionString)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#else
                [ExpectedException (typeof(ArgumentNullException))]
+#endif
                public void ConstructorNotNull6 ()
                {
                        try {
index c2d788bd3f54d734c82e581e0f6905f6cadd77e5..49abd6064dcead039e99b1450d308127e8f71086 100644 (file)
@@ -38,6 +38,9 @@ namespace MonoTests.System.Data.Odbc
        public class SqlCommandBuilderTest
        {
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CatalogLocationTest ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -47,6 +50,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CatalogLocation_Value_Invalid ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -82,6 +88,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CatalogSeparator ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -89,6 +98,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CatalogSeparator_Value_Invalid ()
                {
                        string [] separators = new string [] {
@@ -118,6 +130,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ConflictOptionTest ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -127,6 +142,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ConflictOption_Value_Invalid ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -147,6 +165,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test] // QuoteIdentifier (String)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuoteIdentifier ()
                {
                        SqlCommandBuilder cb;
@@ -173,6 +194,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuoteIdentifier_PrefixSuffix_NoMatch ()
                {
                        SqlCommandBuilder cb;
@@ -211,6 +235,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test] // QuoteIdentifier (String)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuoteIdentifier_UnquotedIdentifier_Null ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -226,6 +253,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuotePrefix ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -240,6 +270,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuotePrefix_Value_Invalid ()
                {
                        string [] prefixes = new string [] {
@@ -268,6 +301,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuoteSuffix ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -282,6 +318,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void QuoteSuffix_Value_Invalid ()
                {
                        string [] suffixes = new string [] {
@@ -310,6 +349,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SchemaSeparator ()
                {
                        SqlCommandBuilder cb = new SqlCommandBuilder ();
@@ -319,6 +361,9 @@ namespace MonoTests.System.Data.Odbc
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SchemaSeparator_Value_Invalid ()
                {
                        string [] separators = new string [] {
index d02532a45d9d0804d73ed5255084fda83cfcb1b8..be36ba383c1bcf6fec1d5d15b7f04d057c365e7d 100644 (file)
@@ -42,6 +42,9 @@ namespace MonoTests.System.Data.SqlClient
                const string COMMAND_TEXT = "SELECT * FROM Authors";
 
                [Test] // SqlCommand ()
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor1 ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -61,6 +64,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlCommand (string)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor2 ()
                {
                        SqlCommand cmd = new SqlCommand (COMMAND_TEXT);
@@ -95,6 +101,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlCommand (string, SqlConnection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor3 ()
                {
                        SqlConnection conn = new SqlConnection ();
@@ -147,6 +156,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlCommand (string, SqlConnection, SqlTransaction)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor4 ()
                {
                        SqlConnection conn = new SqlConnection ();
@@ -199,6 +211,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Clone ()
                {
                        SqlNotificationRequest notificationReq = new SqlNotificationRequest ();
@@ -237,6 +252,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CommandText ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -251,6 +269,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CommandTimeout ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -263,6 +284,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CommandTimeout_Value_Negative ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -279,6 +303,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CommandType_Value_Invalid ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -296,6 +323,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // bug #324386
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Dispose ()
                {
                        string connectionString = "Initial Catalog=a;Server=b;User ID=c;"
@@ -307,6 +337,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteNonQuery_Connection_Closed ()
                {
                        string connectionString = "Initial Catalog=a;Server=b;User ID=c;"
@@ -329,6 +362,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteNonQuery_Connection_Null ()
                {
                        SqlCommand cmd = new SqlCommand ("delete from whatever");
@@ -346,6 +382,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteReader_Connection_Closed ()
                {
                        string connectionString = "Initial Catalog=a;Server=b;User ID=c;"
@@ -368,6 +407,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteReader_Connection_Null ()
                {
                        SqlCommand cmd = new SqlCommand ("select * from whatever");
@@ -385,6 +427,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteScalar_Connection_Closed ()
                {
                        string connectionString = "Initial Catalog=a;Server=b;User ID=c;"
@@ -407,6 +452,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // bug #412584
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ExecuteScalar_Connection_Null ()
                {
                        SqlCommand cmd = new SqlCommand ("select count(*) from whatever");
@@ -425,6 +473,9 @@ namespace MonoTests.System.Data.SqlClient
 
                // FIXME: this actually doesn't match .NET behavior. It shouldn't throw NRE.
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Prepare_Connection_Null ()
                {
                        SqlCommand cmd;
@@ -477,6 +528,9 @@ namespace MonoTests.System.Data.SqlClient
                }
                
                [Test] // bug #412586
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Prepare_Connection_Closed ()
                {
                        string connectionString = "Initial Catalog=a;Server=b;User ID=c;"
@@ -527,6 +581,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ResetCommandTimeout ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -537,6 +594,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void UpdatedRowSource ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -547,6 +607,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void UpdatedRowSource_Value_Invalid ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -565,6 +628,9 @@ namespace MonoTests.System.Data.SqlClient
 
 
                [Test] // bug #381100
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ParameterCollectionTest ()
                {
                        SqlCommand cmd = new SqlCommand();
index 04a4b99871cc8f8af14614167cb6f3e35482eb5a..9511be24f7535375f8298d0c559a174d70452296 100644 (file)
@@ -39,6 +39,9 @@ namespace MonoTests.System.Data.SqlClient
        public class SqlConnectionTest\r
        {\r
                [Test] // SqlConnection ()\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Constructor1 ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -57,6 +60,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test] // SqlConnection (string)\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Constructor2 ()\r
                {\r
                        string connectionString = "server=SQLSRV; database=Mono;";\r
@@ -89,6 +95,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Constructor2_ConnectionString_Invalid ()\r
                {\r
                        try {\r
@@ -181,6 +190,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void BeginTransaction_Connection_Closed ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -247,6 +259,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangeDatabase_Connection_Closed ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -264,6 +279,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangePassword_ConnectionString_Empty ()\r
                {\r
                        try {\r
@@ -279,6 +297,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangePassword_ConnectionString_Null ()\r
                {\r
                        try {\r
@@ -293,7 +314,10 @@ namespace MonoTests.System.Data.SqlClient
                        }\r
                }\r
 \r
-               [Test]\r
+               \r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangePassword_NewPassword_Empty ()\r
                {\r
                        try {\r
@@ -309,6 +333,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangePassword_NewPassword_ExceedMaxLength ()\r
                {\r
                        try {\r
@@ -328,6 +355,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ChangePassword_NewPassword_Null ()\r
                {\r
                        try {\r
@@ -343,6 +373,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ClearPool_Connection_Null ()\r
                {\r
                        try {\r
@@ -357,6 +390,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -371,6 +407,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_Value_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -403,6 +442,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void CreateCommand ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -424,6 +466,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Dispose ()\r
                {\r
                        SqlConnection cn = new SqlConnection ("Server=SQLSRV;Database=master;Timeout=25;Packet Size=512;Workstation ID=DUMMY");\r
@@ -443,6 +488,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void GetSchema_Connection_Closed ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -519,6 +567,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_AsynchronousProcessing ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -527,6 +578,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_ConnectTimeout ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -543,6 +597,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_ConnectTimeout_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -600,6 +657,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_Database_Synonyms ()\r
                {\r
                        SqlConnection cn = null;\r
@@ -614,6 +674,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_DataSource_Synonyms ()\r
                {\r
                        SqlConnection cn = null;\r
@@ -640,6 +703,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MaxPoolSize ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -649,6 +715,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MaxPoolSize_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -733,6 +802,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MinPoolSize ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -742,6 +814,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MinPoolSize_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -799,6 +874,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MultipleActiveResultSets ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -806,6 +884,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_MultipleActiveResultSets_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -823,6 +904,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_NetworkLibrary_Synonyms ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -832,6 +916,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_PacketSize ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -848,6 +935,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_PacketSize_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -901,6 +991,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_Password_Synonyms ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -909,6 +1002,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_PersistSecurityInfo_Synonyms ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -917,6 +1013,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_UserID_Synonyms ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -926,6 +1025,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_UserInstance ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -933,6 +1035,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_UserInstance_Invalid ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -950,6 +1055,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ConnectionString_OtherKeywords ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -973,6 +1081,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Open_ConnectionString_Empty ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -991,6 +1102,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Open_ConnectionString_Null ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -1009,6 +1123,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void Open_ConnectionString_Whitespace ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -1027,6 +1144,9 @@ namespace MonoTests.System.Data.SqlClient
                }\r
 \r
                [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+               [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
                public void ServerVersion_Connection_Closed ()\r
                {\r
                        SqlConnection cn = new SqlConnection ();\r
@@ -1051,3 +1171,4 @@ namespace MonoTests.System.Data.SqlClient
                }\r
        }\r
 }\r
+\r
index 301f62bf7f22efba750f3a3ac4cc9d7c46183bd3..3a8b619baa1bb64e0c1525c50bf271ee41f3b6c0 100644 (file)
@@ -63,6 +63,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (SqlCommand)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor2 ()
                {
                        SqlCommand cmd = new SqlCommand ();
@@ -109,6 +112,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, SqlConnection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor3 ()
                {
                        string selectCommandText = "SELECT * FROM Authors";
@@ -137,6 +143,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, SqlConnection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor3_SelectCommandText_Null ()
                {
                        SqlConnection selectConnection = new SqlConnection ();
@@ -165,6 +174,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, SqlConnection)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor3_SelectConnection_Null ()
                {
                        string selectCommandText = "SELECT * FROM Authors";
@@ -192,6 +204,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, string)]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor4 ()
                {
                        string selectCommandText = "SELECT * FROM Authors";
@@ -221,6 +236,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, string)]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor4_SelectCommandText_Null ()
                {
                        string selectConnectionString = "server=SQLSRV;database=Mono";
@@ -250,6 +268,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // SqlDataAdapter (string, string)]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor4_SelectConnectionString_Null ()
                {
                        string selectCommandText = "SELECT * FROM Authors";
@@ -278,6 +299,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void DeleteCommand ()
                {
                        SqlDataAdapter da = new SqlDataAdapter ();
@@ -293,6 +317,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Dispose ()
                {
                        SqlDataAdapter da = new SqlDataAdapter ();
@@ -311,6 +338,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InsertCommand ()
                {
                        SqlDataAdapter da = new SqlDataAdapter ();
@@ -326,6 +356,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SelectCommand ()
                {
                        SqlDataAdapter da = new SqlDataAdapter ();
@@ -369,6 +402,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void UpdateCommand ()
                {
                        SqlDataAdapter da = new SqlDataAdapter ();
index 27e6fd1bf4ad9b4a5a884af737c5581aba5d4a71..e2048cfb9baf86b0b814c3a06f73248d0559cb1a 100644 (file)
@@ -45,6 +45,9 @@ namespace MonoTests.System.Data.SqlClient
        public class SqlParameterTest
        {
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor1 ()
                {
                        SqlParameter p = new SqlParameter ();
@@ -68,6 +71,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor2_Value_DateTime ()
                {
                        DateTime value = new DateTime (2004, 8, 24);
@@ -94,6 +100,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor2_Value_DBNull ()
                {
                        SqlParameter p = new SqlParameter ("address", DBNull.Value);
@@ -118,6 +127,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor2_Value_Null ()
                {
                        SqlParameter p = new SqlParameter ("address", (Object) null);
@@ -141,6 +153,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // .ctor (String, SqlDbType, Int32, ParameterDirection, Byte, Byte, String, DataRowVersion, Boolean, Object, String, String, String)
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Constructor7 ()
                {
                        SqlParameter p1 = new SqlParameter ("p1Name", SqlDbType.VarChar, 20,
@@ -167,6 +182,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void CompareInfo ()
                {
                        SqlParameter parameter = new SqlParameter ();
@@ -176,6 +194,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Byte ()
                {
                        Byte value = 0x0a;
@@ -187,6 +208,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_ByteArray ()
                {
                        Byte [] value = new Byte [] { 0x0a, 0x0d };
@@ -289,6 +313,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_DateTime ()
                {
                        DateTime value;
@@ -314,6 +341,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Decimal ()
                {
                        Decimal value;
@@ -339,6 +369,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Double ()
                {
                        Double value;
@@ -364,6 +397,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Enum ()
                {
                        SqlParameter param;
@@ -380,6 +416,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Guid ()
                {
                        Guid value = Guid.NewGuid ();
@@ -391,6 +430,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Int16 ()
                {
                        Int16 value;
@@ -416,6 +458,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Int32 ()
                {
                        Int32 value;
@@ -441,6 +486,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Int64 ()
                {
                        Int64 value;
@@ -506,6 +554,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Object ()
                {
                        Object value = new Object ();
@@ -517,6 +568,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Single ()
                {
                        Single value = Single.MaxValue;
@@ -528,6 +582,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_String ()
                {
                        String value = "some text";
@@ -551,6 +608,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void LocaleId ()
                {
                        SqlParameter parameter = new SqlParameter ();
@@ -560,6 +620,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test] // bug #320196
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ParameterNullTest ()
                {
                        SqlParameter param = new SqlParameter ("param", SqlDbType.Decimal);
@@ -574,6 +637,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ParameterType ()
                {
                        SqlParameter p;
@@ -632,6 +698,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void InferType_Boolean ()
                {
                        Boolean value;
@@ -651,6 +720,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ParameterName ()
                {
                        SqlParameter p = new SqlParameter ();
@@ -676,6 +748,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ResetDbType ()
                {
                        SqlParameter p;
@@ -739,6 +814,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void ResetSqlDbType ()
                {
                        //Parameter with an assigned value but no SqlDbType specified
@@ -779,6 +857,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SourceColumn ()
                {
                        SqlParameter p = new SqlParameter ();
@@ -804,6 +885,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SourceColumnNullMapping ()
                {
                        SqlParameter p = new SqlParameter ();
@@ -815,6 +899,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlDbTypeTest ()
                {
                        SqlParameter p = new SqlParameter ("zipcode", 3510);
@@ -829,6 +916,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlDbTypeTest_Value_Invalid ()
                {
                        SqlParameter p = new SqlParameter ("zipcode", 3510);
@@ -847,6 +937,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlValue ()
                {
                        SqlParameter parameter = new SqlParameter ();
@@ -970,6 +1063,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlBinary ()
                {
                        SqlParameter parameter;
@@ -995,6 +1091,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlBoolean ()
                {
                        SqlParameter parameter;
@@ -1020,6 +1119,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlByte ()
                {
                        SqlParameter parameter;
@@ -1107,6 +1209,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlDateTime ()
                {
                        SqlParameter parameter;
@@ -1132,6 +1237,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlDecimal ()
                {
                        SqlParameter parameter;
@@ -1157,6 +1265,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlDouble ()
                {
                        SqlParameter parameter;
@@ -1182,6 +1293,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlGuid ()
                {
                        SqlParameter parameter;
@@ -1207,6 +1321,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlInt16 ()
                {
                        SqlParameter parameter;
@@ -1232,6 +1349,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlInt32 ()
                {
                        SqlParameter parameter;
@@ -1257,6 +1377,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlInt64 ()
                {
                        SqlParameter parameter;
@@ -1282,6 +1405,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlMoney ()
                {
                        SqlParameter parameter;
@@ -1307,6 +1433,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlSingle ()
                {
                        SqlParameter parameter;
@@ -1332,6 +1461,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlString ()
                {
                        SqlParameter parameter;
@@ -1357,6 +1489,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SqlTypes_SqlXml ()
                {
                        SqlParameter parameter;
@@ -1386,6 +1521,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void Value ()
                {
                        SqlParameter p;
@@ -1429,6 +1567,9 @@ namespace MonoTests.System.Data.SqlClient
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void XmlSchemaTest ()
                {
                        SqlParameter p1 = new SqlParameter ();
diff --git a/mcs/class/System.Data/monotouch_watch_System.Data.dll.exclude.sources b/mcs/class/System.Data/monotouch_watch_System.Data.dll.exclude.sources
new file mode 100644 (file)
index 0000000..2782624
--- /dev/null
@@ -0,0 +1,11 @@
+System.Data.SqlClient/SqlBulkCopy.cs
+System.Data.SqlClient/SqlCommand.cs
+System.Data.SqlClient/SqlCommandBuilder.cs
+System.Data.SqlClient/SqlConnection.cs
+System.Data.SqlClient/SqlDataReader.cs
+System.Data.SqlClient/SqlDecimalExtensions.cs
+System.Data.SqlClient/SqlException.cs
+System.Data.SqlClient/SqlParameter.cs
+System.Data.SqlClient/SqlParameterCollection.cs
+System.Data.SqlClient/SqlTransaction.cs
+System.Data.SqlClient/SqlXmlTextReader.cs
index bbc860b8cd783f47398a9a084950cde37d3e6221..f279aec80605393212efc69e5caf5703d0a8480c 100644 (file)
@@ -1 +1,10 @@
 #include mobile_System.Data.dll.sources
+System.Data.SqlClient/SqlBulkCopy.platformnotsupported.cs
+System.Data.SqlClient/SqlCommand.platformnotsupported.cs
+System.Data.SqlClient/SqlCommandBuilder.platformnotsupported.cs
+System.Data.SqlClient/SqlConnection.platformnotsupported.cs
+System.Data.SqlClient/SqlDataReader.platformnotsupported.cs
+System.Data.SqlClient/SqlException.platformnotsupported.cs
+System.Data.SqlClient/SqlParameter.platformnotsupported.cs
+System.Data.SqlClient/SqlParameterCollection.platformnotsupported.cs
+System.Data.SqlClient/SqlTransaction.platformnotsupported.cs
index 7eea754cfa905116418953dd58a636f7fbea109f..29bb7acd6ee63617f77795f248bccf18f87da3ff 100644 (file)
@@ -2,8 +2,12 @@ thisdir = class/System.IdentityModel
 SUBDIRS = 
 include ../../build/rules.make
 
+ifndef NO_MONO_SECURITY
+MONO_SECURITY=Mono.Security
+endif
+
 LIBRARY = System.IdentityModel.dll
-LIB_REFS = System System.Xml System.Security Mono.Security System.Runtime.Serialization
+LIB_REFS = System System.Xml System.Security $(MONO_SECURITY) System.Runtime.Serialization
 LIB_MCS_FLAGS = \
                /d:NET_3_0      \
                $(OTHER_LIB_MCS_FLAGS)
index 5c009acb56608c1d391e86faea97071af7e3f33e..145f30f4b6ccd9d7acf6a9c1650b765c85b89d6e 100644 (file)
@@ -2,8 +2,13 @@ thisdir = class/System.Security
 SUBDIRS = 
 include ../../build/rules.make
 
+ifndef NO_MONO_SECURITY
+MONO_SECURITY_DLL=$(the_libdir_base)/Mono.Security.dll
+MONO_SECURITY=Mono.Security
+endif
+
 LIBRARY = System.Security.dll
-LIB_REFS = secxml/System bare/System.Xml Mono.Security
+LIB_REFS = secxml/System bare/System.Xml $(MONO_SECURITY)
 LIB_MCS_FLAGS = -nowarn:618 \
        -d:SECURITY_DEP \
        -nowarn:414
@@ -22,7 +27,7 @@ EXTRA_DISTFILES = \
 
 include ../../build/library.make
 
-$(build_lib): $(secxml_libdir)/System.dll $(the_libdir_base)/Mono.Security.dll
+$(build_lib): $(secxml_libdir)/System.dll $(MONO_SECURITY_DLL)
 
 $(secxml_libdir)/System.dll:
        (cd ../System; $(MAKE) $@)
index a80606ef6681ab5fb206f56beb846e816f5bc309..6ed83d7c1e03020ffe63c8d68f4d129ec468b6bd 100644 (file)
@@ -74,5 +74,7 @@ using System.Runtime.InteropServices;
        [assembly: StringFreezing]
        [assembly: DefaultDependency (LoadHint.Always)]
 
+       [assembly: InternalsVisibleTo ("btls-cert-sync, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
+       [assembly: InternalsVisibleTo ("Mono.Btls.Interface, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
        [assembly: InternalsVisibleTo ("Mono.Security, PublicKey=002400000480000094000000060200000024000052534131000400000100010079159977d2d03a8e6bea7a2e74e8d1afcc93e8851974952bb480a12c9134474d04062447c37e0e68c080536fcf3c3fbe2ff9c979ce998475e506e8ce82dd5b0f350dc10e93bf2eeecf874b24770c5081dbea7447fddafa277b22de47d6ffea449674a4f9fccf84d15069089380284dbdd35f46cdff12a1bd78e4ef0065d016df")]
 
index fe01d7e4317c78eaa7a368f31ccd41952da83cb4..fdfb7c293a4ecd9d2bff6567df57c55c2a693683 100644 (file)
@@ -19,10 +19,16 @@ TEST_RESOURCES = \
        Test/System/test-uri-props-manual.txt \
        Test/System/test-uri-relative-props.txt
 
+ifndef NO_MONO_SECURITY
+MONO_SECURITY=Mono.Security
+MONO_SECURITY_REF=MonoSecurity=Mono.Security
+MONO_SECURITY_DLL=$(the_libdir_base)Mono.Security.dll
+endif
+
 ifndef MOBILE_PROFILE
-TEST_LIB_REFS = System.Drawing Mono.Security System.Data System.Xml System.Core System.Configuration
+TEST_LIB_REFS = System.Drawing $(MONO_SECURITY) System.Data System.Xml System.Core System.Configuration
 else
-TEST_LIB_REFS = Mono.Security System.Data System.Xml System.Core
+TEST_LIB_REFS = $(MONO_SECURITY) System.Data System.Xml System.Core
 endif
 
 TEST_MCS_FLAGS = -nowarn:618,672,219,67,169,612 \
@@ -67,7 +73,7 @@ endif
 #
 ifeq (secxml/, $(intermediate))
 LOCAL_MCS_FLAGS =
-LIB_REFS += bare/System.Xml MonoSecurity=Mono.Security
+LIB_REFS += bare/System.Xml $(MONO_SECURITY_REF)
 LIB_MCS_FLAGS += -d:SECURITY_DEP -d:XML_DEP $(EXTERN_ALIAS_FLAGS)
 endif
 
@@ -75,7 +81,7 @@ endif
 # Flags used to build the final version of System (when intermediate is not defined)
 #
 ifndef intermediate
-LIB_REFS += System.Xml MonoSecurity=Mono.Security
+LIB_REFS += System.Xml $(MONO_SECURITY_REF)
 LIB_MCS_FLAGS += -d:SECURITY_DEP -d:XML_DEP $(EXTERN_ALIAS_FLAGS)
 
 ifndef MOBILE_PROFILE
@@ -99,7 +105,7 @@ include ../../build/library.make
 system_library_deps := \
        $(secxml_libdir)/System.dll             \
        $(the_libdir_base)System.Xml.dll        \
-       $(the_libdir_base)Mono.Security.dll     \
+       $(MONO_SECURITY_DLL)                            \
        $(bare_libdir)/System.dll
 
 ifndef MOBILE_PROFILE
@@ -108,7 +114,7 @@ endif
 
 artifacts = $(system_library_deps)                     \
        $(bare_libdir)/System.Xml.dll                   \
-       $(the_libdir_base)Mono.Security.dll             \
+       $(MONO_SECURITY_DLL)                            \
        $(the_libdir_base)System.Configuration.dll
 
 .NOTPARALLEL: $(system_library_deps)
@@ -123,7 +129,7 @@ $(bare_libdir)/System.dll:
 endif
 
 ifneq (secxml/,$(intermediate))
-$(secxml_libdir)/System.dll: $(bare_libdir)/System.dll $(bare_libdir)/System.Xml.dll $(the_libdir_base)Mono.Security.dll $(bare_libdir)/System.dll
+$(secxml_libdir)/System.dll: $(bare_libdir)/System.dll $(bare_libdir)/System.Xml.dll $(MONO_SECURITY_DLL) $(bare_libdir)/System.dll
        $(MAKE) intermediate=secxml/ $(secxml_libdir)/System.dll
 else
 build-sec:
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsBio.cs b/mcs/class/System/Mono.Btls/MonoBtlsBio.cs
new file mode 100644 (file)
index 0000000..1fbe471
--- /dev/null
@@ -0,0 +1,449 @@
+//
+// MonoBtlsBio.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+#if MONOTOUCH
+using MonoTouch;
+#endif
+
+namespace Mono.Btls
+{
+       class MonoBtlsBio : MonoBtlsObject
+       {
+               internal MonoBtlsBio (BoringBioHandle handle)
+                       : base (handle)
+               {
+               }
+
+               new protected internal BoringBioHandle Handle {
+                       get { return (BoringBioHandle)base.Handle; }
+               }
+
+               protected internal class BoringBioHandle : MonoBtlsHandle
+               {
+                       public BoringBioHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (handle != IntPtr.Zero) {
+                                       mono_btls_bio_free (handle);
+                                       handle = IntPtr.Zero;
+                               }
+                               return true;
+                       }
+
+               }
+
+               public static MonoBtlsBio CreateMonoStream (Stream stream)
+               {
+                       return MonoBtlsBioMono.CreateStream (stream, false);
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_read (IntPtr bio, IntPtr data, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_write (IntPtr bio, IntPtr data, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_flush (IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_indent (IntPtr bio, uint indent, uint max_indent);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_hexdump (IntPtr bio, IntPtr data, int len, uint indent);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_bio_print_errors (IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_bio_free (IntPtr handle);
+
+               public int Read (byte[] buffer, int offset, int size)
+               {
+                       CheckThrow ();
+                       var data = Marshal.AllocHGlobal (size);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               var ret = mono_btls_bio_read (Handle.DangerousGetHandle (), data, size);
+                               if (ret > 0)
+                                       Marshal.Copy (data, buffer,offset, ret);
+                               return ret;
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public int Write (byte[] buffer, int offset, int size)
+               {
+                       CheckThrow ();
+                       var data = Marshal.AllocHGlobal (size);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               Marshal.Copy (buffer, offset, data, size);
+                               return mono_btls_bio_write (Handle.DangerousGetHandle (), data, size);
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public int Flush ()
+               {
+                       CheckThrow ();
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               return mono_btls_bio_flush (Handle.DangerousGetHandle ());
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                       }
+               }
+
+               public int Indent (uint indent, uint max_indent)
+               {
+                       CheckThrow ();
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               return mono_btls_bio_indent (Handle.DangerousGetHandle (), indent, max_indent);
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                       }
+               }
+
+               public int HexDump (byte[] buffer, uint indent)
+               {
+                       CheckThrow ();
+                       var data = Marshal.AllocHGlobal (buffer.Length);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               Marshal.Copy (buffer, 0, data, buffer.Length);
+                               return mono_btls_bio_hexdump (Handle.DangerousGetHandle (), data, buffer.Length, indent);
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public void PrintErrors ()
+               {
+                       CheckThrow ();
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               mono_btls_bio_print_errors (Handle.DangerousGetHandle ());
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                       }
+               }
+       }
+
+       class MonoBtlsBioMemory : MonoBtlsBio
+       {
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_bio_mem_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_bio_mem_get_data (IntPtr handle, out IntPtr data);
+
+               public MonoBtlsBioMemory ()
+                       : base (new BoringBioHandle (mono_btls_bio_mem_new ()))
+               {
+               }
+
+               public byte[] GetData ()
+               {
+                       IntPtr data;
+                       bool release = false;
+                       try {
+                               Handle.DangerousAddRef (ref release);
+                               var size = mono_btls_bio_mem_get_data (Handle.DangerousGetHandle (), out data);
+                               CheckError (size > 0);
+                               var buffer = new byte[size];
+                               Marshal.Copy (data, buffer, 0, size);
+                               return buffer;
+                       } finally {
+                               if (release)
+                                       Handle.DangerousRelease ();
+                       }
+               }
+       }
+
+       interface IMonoBtlsBioMono
+       {
+               int Read (byte[] buffer, int offset, int size, out bool wantMore);
+
+               bool Write (byte[] buffer, int offset, int size);
+
+               void Flush ();
+
+               void Close ();
+       }
+
+       class MonoBtlsBioMono : MonoBtlsBio
+       {
+               GCHandle handle;
+               IntPtr instance;
+               BioReadFunc readFunc;
+               BioWriteFunc writeFunc;
+               BioControlFunc controlFunc;
+               IntPtr readFuncPtr;
+               IntPtr writeFuncPtr;
+               IntPtr controlFuncPtr;
+               IMonoBtlsBioMono backend;
+
+               public MonoBtlsBioMono (IMonoBtlsBioMono backend)
+                       : base (new BoringBioHandle (mono_btls_bio_mono_new ()))
+               {
+                       this.backend = backend;
+                       handle = GCHandle.Alloc (this);
+                       instance = GCHandle.ToIntPtr (handle);
+                       readFunc = OnRead;
+                       writeFunc = OnWrite;
+                       controlFunc = Control;
+                       readFuncPtr = Marshal.GetFunctionPointerForDelegate (readFunc);
+                       writeFuncPtr = Marshal.GetFunctionPointerForDelegate (writeFunc);
+                       controlFuncPtr = Marshal.GetFunctionPointerForDelegate (controlFunc);
+                       mono_btls_bio_mono_initialize (Handle.DangerousGetHandle (), instance, readFuncPtr, writeFuncPtr, controlFuncPtr);
+               }
+
+               public static MonoBtlsBioMono CreateStream (Stream stream, bool ownsStream)
+               {
+                       return new MonoBtlsBioMono (new StreamBackend (stream, ownsStream));
+               }
+
+               public static MonoBtlsBioMono CreateString (StringWriter writer)
+               {
+                       return new MonoBtlsBioMono (new StringBackend (writer));
+               }
+
+               enum ControlCommand
+               {
+                       Flush = 1
+               }
+
+               delegate int BioReadFunc (IntPtr bio, IntPtr data, int dataLength, out int wantMore);
+               delegate int BioWriteFunc (IntPtr bio, IntPtr data, int dataLength);
+               delegate long BioControlFunc (IntPtr bio, ControlCommand command, long arg);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_bio_mono_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_bio_mono_initialize (IntPtr handle, IntPtr instance, IntPtr readFunc, IntPtr writeFunc, IntPtr controlFunc);
+
+               long Control (ControlCommand command, long arg)
+               {
+                       switch (command) {
+                       case ControlCommand.Flush:
+                               backend.Flush ();
+                               return 1;
+
+                       default:
+                               throw new NotImplementedException ();
+                       }
+               }
+
+               int OnRead (IntPtr data, int dataLength, out int wantMore)
+               {
+                       bool wantMoreBool;
+                       var buffer = new byte[dataLength];
+                       var ret = backend.Read (buffer, 0, dataLength, out wantMoreBool);
+                       wantMore = wantMoreBool ? 1 : 0;
+                       if (ret <= 0)
+                               return ret;
+                       Marshal.Copy (buffer, 0, data, ret);
+                       return ret;
+               }
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (BioReadFunc))]
+#endif
+               static int OnRead (IntPtr instance, IntPtr data, int dataLength, out int wantMore)
+               {
+                       var c = (MonoBtlsBioMono)GCHandle.FromIntPtr (instance).Target;
+                       try {
+                               return c.OnRead (data, dataLength, out wantMore);
+                       } catch (Exception ex) {
+                               c.SetException (ex);
+                               wantMore = 0;
+                               return -1;
+                       }
+               }
+
+               int OnWrite (IntPtr data, int dataLength)
+               {
+                       var buffer = new byte[dataLength];
+                       Marshal.Copy (data, buffer, 0, dataLength);
+                       var ok = backend.Write (buffer, 0, dataLength);
+                       return ok ? dataLength : -1;
+               }
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (BioWriteFunc))]
+#endif
+               static int OnWrite (IntPtr instance, IntPtr data, int dataLength)
+               {
+                       var c = (MonoBtlsBioMono)GCHandle.FromIntPtr (instance).Target;
+                       try {
+                               return c.OnWrite (data, dataLength);
+                       } catch (Exception ex) {
+                               c.SetException (ex);
+                               return -1;
+                       }
+               }
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (BioControlFunc))]
+#endif
+               static long Control (IntPtr instance, ControlCommand command, long arg)
+               {
+                       var c = (MonoBtlsBioMono)GCHandle.FromIntPtr (instance).Target;
+                       try {
+                               return c.Control (command, arg);
+                       } catch (Exception ex) {
+                               c.SetException (ex);
+                               return -1;
+                       }
+               }
+
+               protected override void Close ()
+               {
+                       try {
+                               if (backend != null) {
+                                       backend.Close ();
+                                       backend = null;
+                               }
+                               if (handle.IsAllocated)
+                                       handle.Free ();
+                       } finally {
+                               base.Close ();
+                       }
+               }
+
+               class StreamBackend : IMonoBtlsBioMono
+               {
+                       Stream stream;
+                       bool ownsStream;
+
+                       public Stream InnerStream {
+                               get { return stream; }
+                       }
+
+                       public StreamBackend (Stream stream, bool ownsStream)
+                       {
+                               this.stream = stream;
+                               this.ownsStream = ownsStream;
+                       }
+
+                       public int Read (byte[] buffer, int offset, int size, out bool wantMore)
+                       {
+                               wantMore = false;
+                               return stream.Read (buffer, offset, size);
+                       }
+
+                       public bool Write (byte[] buffer, int offset, int size)
+                       {
+                               stream.Write (buffer, offset, size);
+                               return true;
+                       }
+
+                       public void Flush ()
+                       {
+                               stream.Flush ();
+                       }
+
+                       public void Close ()
+                       {
+                               if (ownsStream && stream != null)
+                                       stream.Dispose ();
+                               stream = null;
+                       }
+               }
+
+               class StringBackend : IMonoBtlsBioMono
+               {
+                       StringWriter writer;
+                       Encoding encoding = new UTF8Encoding ();
+
+                       public StringBackend (StringWriter writer)
+                       {
+                               this.writer = writer;
+                       }
+
+                       public int Read (byte[] buffer, int offset, int size, out bool wantMore)
+                       {
+                               wantMore = false;
+                               return -1;
+                       }
+
+                       public bool Write (byte[] buffer, int offset, int size)
+                       {
+                               var text = encoding.GetString (buffer, offset, size);
+                               writer.Write (text);
+                               return true;
+                       }
+
+                       public void Flush ()
+                       {
+                       }
+
+                       public void Close ()
+                       {
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsContext.cs b/mcs/class/System/Mono.Btls/MonoBtlsContext.cs
new file mode 100644 (file)
index 0000000..daacffa
--- /dev/null
@@ -0,0 +1,464 @@
+//
+// MonoBtlsContext.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+#endif
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Authentication;
+using System.Runtime.InteropServices;
+
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+#else
+using Mono.Security.Interface;
+#endif
+
+using MNS = Mono.Net.Security;
+
+namespace Mono.Btls
+{
+       class MonoBtlsContext : MNS.MobileTlsContext, IMonoBtlsBioMono
+       {
+               X509Certificate remoteCertificate;
+               X509Certificate clientCertificate;
+               X509CertificateImplBtls nativeServerCertificate;
+               X509CertificateImplBtls nativeClientCertificate;
+               MonoBtlsSslCtx ctx;
+               MonoBtlsSsl ssl;
+               MonoBtlsBio bio;
+               MonoBtlsBio errbio;
+
+               MonoTlsConnectionInfo connectionInfo;
+               bool certificateValidated;
+               bool isAuthenticated;
+               bool connected;
+
+               public MonoBtlsContext (
+                       MNS.MobileAuthenticatedStream parent,
+                       bool serverMode, string targetHost,
+                       SslProtocols enabledProtocols, X509Certificate serverCertificate,
+                       X509CertificateCollection clientCertificates, bool askForClientCert)
+                       : base (parent, serverMode, targetHost, enabledProtocols,
+                               serverCertificate, clientCertificates, askForClientCert)
+               {
+                       if (serverMode)
+                               nativeServerCertificate = GetPrivateCertificate (serverCertificate);
+               }
+
+               static X509CertificateImplBtls GetPrivateCertificate (X509Certificate certificate)
+               {
+                       var impl = certificate.Impl as X509CertificateImplBtls;
+                       if (impl != null)
+                               return (X509CertificateImplBtls)impl.Clone ();
+
+                       var password = Guid.NewGuid ().ToString ();
+                       var buffer = certificate.Export (X509ContentType.Pfx, password);
+
+                       impl = new X509CertificateImplBtls ();
+                       impl.Import (buffer, password, X509KeyStorageFlags.DefaultKeySet);
+                       return impl;
+               }
+
+               new public MonoBtlsProvider Provider {
+                       get { return (MonoBtlsProvider)base.Provider; }
+               }
+
+               int VerifyCallback (MonoBtlsX509StoreCtx storeCtx)
+               {
+                       using (var chainImpl = new X509ChainImplBtls (storeCtx))
+                       using (var managedChain = new X509Chain (chainImpl)) {
+                               var leaf = managedChain.ChainElements[0].Certificate;
+                               var result = ValidateCertificate (leaf, managedChain);
+                               certificateValidated = true;
+                               return result ? 1 : 0;
+                       }
+               }
+
+               int SelectCallback ()
+               {
+                       Debug ("SELECT CALLBACK!");
+
+                       GetPeerCertificate ();
+                       if (remoteCertificate == null)
+                               throw new TlsException (AlertDescription.InternalError, "Cannot request client certificate before receiving one from the server.");
+
+                       var clientCert = SelectClientCertificate (remoteCertificate, null);
+                       Debug ("SELECT CALLBACK #1: {0}", clientCert);
+                       if (clientCert == null)
+                               return 1;
+
+                       nativeClientCertificate = GetPrivateCertificate (clientCert);
+                       Debug ("SELECT CALLBACK #2: {0}", nativeClientCertificate);
+                       clientCertificate = new X509Certificate (nativeClientCertificate);
+                       SetPrivateCertificate (nativeClientCertificate);
+                       return 1;
+               }
+
+               public override void StartHandshake ()
+               {
+                       InitializeConnection ();
+
+                       ssl = new MonoBtlsSsl (ctx);
+
+                       bio = new MonoBtlsBioMono (this);
+                       ssl.SetBio (bio);
+
+                       if (IsServer) {
+                               SetPrivateCertificate (nativeServerCertificate);
+                       } else {
+                               ssl.SetServerName (TargetHost);
+                       }
+               }
+
+               void SetPrivateCertificate (X509CertificateImplBtls privateCert)
+               {
+                       Debug ("SetPrivateCertificate: {0}", privateCert);
+                       ssl.SetCertificate (privateCert.X509);
+                       ssl.SetPrivateKey (privateCert.NativePrivateKey);
+                       var intermediate = privateCert.IntermediateCertificates;
+                       if (intermediate == null)
+                               return;
+                       for (int i = 0; i < intermediate.Count; i++) {
+                               var impl = (X509CertificateImplBtls)intermediate [i];
+                               Debug ("SetPrivateCertificate - add intermediate: {0}", impl);
+                               ssl.AddIntermediateCertificate (impl.X509);
+                       }
+               }
+
+               Exception GetException (MonoBtlsSslError status)
+               {
+                       var error = MonoBtlsError.GetError ();
+                       if (error == null)
+                               return new MonoBtlsException (status);
+
+                       var text = MonoBtlsError.GetErrorString (error);
+                       return new MonoBtlsException ("{0} {1}", status, text);
+               }
+
+               public override bool ProcessHandshake ()
+               {
+                       var done = false;
+                       while (!done) {
+                               Debug ("ProcessHandshake");
+                               MonoBtlsError.ClearError ();
+                               var status = DoProcessHandshake ();
+                               Debug ("ProcessHandshake #1: {0}", status);
+
+                               switch (status) {
+                               case MonoBtlsSslError.None:
+                                       if (connected)
+                                               done = true;
+                                       else
+                                               connected = true;
+                                       break;
+                               case MonoBtlsSslError.WantRead:
+                               case MonoBtlsSslError.WantWrite:
+                                       return false;
+                               default:
+                                       throw GetException (status);
+                               }
+                       }
+
+                       ssl.PrintErrors ();
+
+                       return true;
+               }
+
+               MonoBtlsSslError DoProcessHandshake ()
+               {
+                       if (connected)
+                               return ssl.Handshake ();
+                       else if (IsServer)
+                               return ssl.Accept ();
+                       else
+                               return ssl.Connect ();
+               }
+
+               public override void FinishHandshake ()
+               {
+                       InitializeSession ();
+
+                       isAuthenticated = true;
+               }
+
+               void SetupCertificateStore ()
+               {
+#if MONODROID
+                       ctx.CertificateStore.SetDefaultPaths ();
+                       ctx.CertificateStore.AddAndroidLookup ();
+#else
+                       var userPath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.UserTrustedRoots);
+                       if (Directory.Exists (userPath))
+                               ctx.CertificateStore.AddDirectoryLookup (userPath, MonoBtlsX509FileType.PEM);
+                       var machinePath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.MachineTrustedRoots);
+                       if (Directory.Exists (machinePath))
+                               ctx.CertificateStore.AddDirectoryLookup (machinePath, MonoBtlsX509FileType.PEM);
+#endif
+
+                       if (Settings != null && Settings.TrustAnchors != null) {
+                               var trust = IsServer ? MonoBtlsX509TrustKind.TRUST_CLIENT : MonoBtlsX509TrustKind.TRUST_SERVER;
+                               ctx.CertificateStore.AddCollection (Settings.TrustAnchors, trust);
+                       }
+               }
+
+               void InitializeConnection ()
+               {
+                       ctx = new MonoBtlsSslCtx ();
+
+#if MARTIN_DEBUG
+                       errbio = MonoBtlsBio.CreateMonoStream (Console.OpenStandardError ());
+                       ctx.SetDebugBio (errbio);
+#endif
+
+                       SetupCertificateStore ();
+
+                       if (!IsServer || AskForClientCertificate)
+                               ctx.SetVerifyCallback (VerifyCallback, false);
+                       if (!IsServer)
+                               ctx.SetSelectCallback (SelectCallback);
+
+                       var host = TargetHost;
+                       if (!string.IsNullOrEmpty (host)) {
+                               var pos = TargetHost.IndexOf (':');
+                               if (pos > 0)
+                                       host = host.Substring (0, pos);
+                       }
+
+                       ctx.SetVerifyParam (MonoBtlsProvider.GetVerifyParam (host, IsServer));
+
+                       TlsProtocolCode minProtocol, maxProtocol;
+                       GetProtocolVersions (out minProtocol, out maxProtocol);
+
+                       ctx.SetMinVersion ((int)minProtocol);
+                       ctx.SetMaxVersion ((int)maxProtocol);
+
+                       if (Settings != null && Settings.EnabledCiphers != null) {
+                               var ciphers = new short [Settings.EnabledCiphers.Length];
+                               for (int i = 0; i < ciphers.Length; i++)
+                                       ciphers [i] = (short)Settings.EnabledCiphers [i];
+                               ctx.SetCiphers (ciphers, true);
+                       }
+               }
+
+               void GetPeerCertificate ()
+               {
+                       if (remoteCertificate != null)
+                               return;
+                       using (var remoteCert = ssl.GetPeerCertificate ()) {
+                               if (remoteCert != null)
+                                       remoteCertificate = MonoBtlsProvider.CreateCertificate (remoteCert);
+                       }
+               }
+
+               void InitializeSession ()
+               {
+                       GetPeerCertificate ();
+
+                       if (IsServer && AskForClientCertificate && !certificateValidated) {
+                               if (!ValidateCertificate (null, null))
+                                       throw new TlsException (AlertDescription.CertificateUnknown);
+                       }
+
+                       var cipher = (CipherSuiteCode)ssl.GetCipher ();
+                       var protocol = (TlsProtocolCode)ssl.GetVersion ();
+                       Debug ("GET CONNECTION INFO: {0:x}:{0} {1:x}:{1} {2}", cipher, protocol, (TlsProtocolCode)protocol);
+
+                       connectionInfo = new MonoTlsConnectionInfo {
+                               CipherSuiteCode = cipher,
+                               ProtocolVersion = GetProtocol (protocol)
+                       };
+               }
+
+               static TlsProtocols GetProtocol (TlsProtocolCode protocol)
+               {
+                       switch (protocol) {
+                       case TlsProtocolCode.Tls10:
+                               return TlsProtocols.Tls10;
+                       case TlsProtocolCode.Tls11:
+                               return TlsProtocols.Tls11;
+                       case TlsProtocolCode.Tls12:
+                               return TlsProtocols.Tls12;
+                       default:
+                               throw new NotSupportedException ();
+                       }
+               }
+
+               public override void Flush ()
+               {
+                       throw new NotImplementedException ();
+               }
+
+               public override int Read (byte[] buffer, int offset, int size, out bool wantMore)
+               {
+                       Debug ("Read: {0} {1} {2}", buffer.Length, offset, size);
+
+                       var data = Marshal.AllocHGlobal (size);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       try {
+                               MonoBtlsError.ClearError ();
+                               var status = ssl.Read (data, ref size);
+                               Debug ("Read done: {0} {1}", status, size);
+
+                               if (status == MonoBtlsSslError.WantRead) {
+                                       wantMore = true;
+                                       return 0;
+                               } else if (status != MonoBtlsSslError.None) {
+                                       throw GetException (status);
+                               }
+
+                               if (size > 0)
+                                       Marshal.Copy (data, buffer, offset, size);
+
+                               wantMore = false;
+                               return size;
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public override int Write (byte[] buffer, int offset, int size, out bool wantMore)
+               {
+                       Debug ("Write: {0} {1} {2}", buffer.Length, offset, size);
+
+                       var data = Marshal.AllocHGlobal (size);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       try {
+                               MonoBtlsError.ClearError ();
+                               Marshal.Copy (buffer, offset, data, size);
+                               var status = ssl.Write (data, ref size);
+                               Debug ("Write done: {0} {1}", status, size);
+
+                               if (status == MonoBtlsSslError.WantWrite) {
+                                       wantMore = true;
+                                       return 0;
+                               } else if (status != MonoBtlsSslError.None) {
+                                       throw GetException (status);
+                               }
+
+                               wantMore = false;
+                               return size;
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public override void Close ()
+               {
+                       Debug ("Close!");
+                       ssl.Dispose ();
+               }
+
+               void Dispose<T> (ref T disposable)
+                       where T : class, IDisposable
+               {
+                       try {
+                               if (disposable != null)
+                                       disposable.Dispose ();
+                       } catch {
+                               ;
+                       } finally {
+                               disposable = null;
+                       }
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+                       try {
+                               if (disposing) {
+                                       Dispose (ref remoteCertificate);
+                                       Dispose (ref nativeServerCertificate);
+                                       Dispose (ref nativeClientCertificate);
+                                       Dispose (ref clientCertificate);
+                                       Dispose (ref ctx);
+                                       Dispose (ref ssl);
+                                       Dispose (ref bio);
+                                       Dispose (ref errbio);
+                               }
+                       } finally {
+                               base.Dispose (disposing);
+                       }
+               }
+
+               int IMonoBtlsBioMono.Read (byte[] buffer, int offset, int size, out bool wantMore)
+               {
+                       Debug ("InternalRead: {0} {1}", offset, size);
+                       var ret = Parent.InternalRead (buffer, offset, size, out wantMore);
+                       Debug ("InternalReadDone: {0} {1}", ret, wantMore);
+                       return ret;
+               }
+
+               bool IMonoBtlsBioMono.Write (byte[] buffer, int offset, int size)
+               {
+                       Debug ("InternalWrite: {0} {1}", offset, size);
+                       var ret = Parent.InternalWrite (buffer, offset, size);
+                       Debug ("InternalWrite done: {0}", ret);
+                       return ret;
+               }
+
+               void IMonoBtlsBioMono.Flush ()
+               {
+                       ;
+               }
+
+               void IMonoBtlsBioMono.Close ()
+               {
+                       ;
+               }
+
+               public override bool HasContext {
+                       get { return ssl != null && ssl.IsValid; }
+               }
+               public override bool IsAuthenticated {
+                       get { return isAuthenticated; }
+               }
+               public override MonoTlsConnectionInfo ConnectionInfo {
+                       get { return connectionInfo; }
+               }
+               internal override bool IsRemoteCertificateAvailable {
+                       get { return remoteCertificate != null; }
+               }
+               internal override X509Certificate LocalClientCertificate {
+                       get { return clientCertificate; }
+               }
+               public override X509Certificate RemoteCertificate {
+                       get { return remoteCertificate; }
+               }
+               public override TlsProtocols NegotiatedProtocol {
+                       get { return connectionInfo.ProtocolVersion; }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsError.cs b/mcs/class/System/Mono.Btls/MonoBtlsError.cs
new file mode 100644 (file)
index 0000000..2645a92
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// MonoBtlsError.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+// #if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+#if MONOTOUCH
+using MonoTouch;
+#endif
+
+namespace Mono.Btls
+{
+       static class MonoBtlsError
+       {
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_error_peek_error ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_error_get_error ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_error_clear_error ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_error_get_error_string_n (int error, IntPtr buf, int len);
+
+               public static int PeekError ()
+               {
+                       return mono_btls_error_peek_error ();
+               }
+
+               public static int GetError ()
+               {
+                       return mono_btls_error_get_error ();
+               }
+
+               public static void ClearError ()
+               {
+                       mono_btls_error_clear_error ();
+               }
+
+               public static string GetErrorString (int error)
+               {
+                       var size = 1024;
+                       var buffer = Marshal.AllocHGlobal (size);
+                       if (buffer == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+                       try {
+                               mono_btls_error_get_error_string_n (error, buffer, size);
+                               return Marshal.PtrToStringAnsi (buffer);
+                       } finally {
+                               Marshal.FreeHGlobal (buffer);
+                       }
+               }
+       }
+}
+// #endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsException.cs b/mcs/class/System/Mono.Btls/MonoBtlsException.cs
new file mode 100644 (file)
index 0000000..bf6b163
--- /dev/null
@@ -0,0 +1,53 @@
+//
+// MonoBtlsException.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+
+namespace Mono.Btls
+{
+       class MonoBtlsException : Exception
+       {
+               public MonoBtlsException ()
+               {
+               }
+
+               public MonoBtlsException (MonoBtlsSslError error)
+                       : base (error.ToString ())
+               {
+               }
+
+               public MonoBtlsException (string message)
+                       : base (message)
+               {
+               }
+
+               public MonoBtlsException (string format, params object[] args)
+                       : base (string.Format (format, args))
+               {
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsKey.cs b/mcs/class/System/Mono.Btls/MonoBtlsKey.cs
new file mode 100644 (file)
index 0000000..e3e3def
--- /dev/null
@@ -0,0 +1,98 @@
+//
+// MonoBtlsKey.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsKey : MonoBtlsObject
+       {
+               internal class BoringKeyHandle : MonoBtlsHandle
+               {
+                       internal BoringKeyHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_key_free (handle);
+                               return true;
+                       }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_key_free (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_key_up_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_key_get_bytes (IntPtr handle, out IntPtr data, out int size, int include_private_bits);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_key_get_bits (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_key_is_rsa (IntPtr handle);
+
+               new internal BoringKeyHandle Handle {
+                       get { return (BoringKeyHandle)base.Handle; }
+               }
+
+               internal MonoBtlsKey (BoringKeyHandle handle)
+                       : base (handle)
+               {
+               }
+
+               public byte[] GetBytes (bool include_private_bits)
+               {
+                       int size;
+                       IntPtr data;
+
+                       var ret = mono_btls_key_get_bytes (Handle.DangerousGetHandle (), out data, out size, include_private_bits ? 1 : 0);
+                       CheckError (ret);
+
+                       var buffer = new byte [size];
+                       Marshal.Copy (data, buffer, 0, size);
+                       FreeDataPtr (data);
+                       return buffer;
+               }
+
+               public MonoBtlsKey Copy ()
+               {
+                       CheckThrow ();
+                       var copy = mono_btls_key_up_ref (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsKey (new BoringKeyHandle (copy));
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsObject.cs b/mcs/class/System/Mono.Btls/MonoBtlsObject.cs
new file mode 100644 (file)
index 0000000..8f30543
--- /dev/null
@@ -0,0 +1,143 @@
+//
+// MonoBtlsObject.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.Threading;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       abstract class MonoBtlsObject : IDisposable
+       {
+               internal MonoBtlsObject (MonoBtlsHandle handle)
+               {
+                       this.handle = handle;
+               }
+
+               protected internal abstract class MonoBtlsHandle : SafeHandle
+               {
+                       internal MonoBtlsHandle ()
+                               : base (IntPtr.Zero, true)
+                       {
+                       }
+
+                       internal MonoBtlsHandle (IntPtr handle, bool ownsHandle)
+                               : base (handle, ownsHandle)
+                       {
+                       }
+
+                       public override bool IsInvalid {
+                               get { return handle == IntPtr.Zero; }
+                       }
+               }
+
+               internal MonoBtlsHandle Handle {
+                       get {
+                               CheckThrow ();
+                               return handle;
+                       }
+               }
+
+               public bool IsValid {
+                       get { return handle != null && !handle.IsInvalid; }
+               }
+
+               MonoBtlsHandle handle;
+               Exception lastError;
+
+               protected void CheckThrow ()
+               {
+                       if (lastError != null)
+                               throw lastError;
+                       if (handle == null || handle.IsInvalid)
+                               throw new ObjectDisposedException ("MonoBtlsSsl");
+               }
+
+               protected Exception SetException (Exception ex)
+               {
+                       if (lastError == null)
+                               lastError = ex;
+                       return ex;
+               }
+
+               protected void CheckError (bool ok, [CallerMemberName] string callerName = null)
+               {
+                       if (!ok) {
+                               if (callerName != null)
+                                       throw new MonoBtlsException ("{0}.{1} failed.", GetType ().Name, callerName);
+                               else
+                                       throw new MonoBtlsException ();
+                       }
+
+               }
+
+               protected void CheckError (int ret, [CallerMemberName] string callerName = null)
+               {
+                       CheckError (ret == 1, callerName);
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_free (IntPtr data);
+
+               protected void FreeDataPtr (IntPtr data)
+               {
+                       mono_btls_free (data);
+               }
+
+               protected virtual void Close ()
+               {
+               }
+
+               protected void Dispose (bool disposing)
+               {
+                       if (disposing) {
+                               try {
+                                       if (handle != null) {
+                                               Close ();
+                                               handle.Dispose ();
+                                               handle = null;
+                                       }
+                               } finally {
+                                       var disposedExc = new ObjectDisposedException (GetType ().Name);
+                                       Interlocked.CompareExchange (ref lastError, disposedExc, null);
+                               }
+                       }
+               }
+
+               public void Dispose ()
+               {
+                       Dispose (true);
+                       GC.SuppressFinalize (this);
+               }
+
+               ~MonoBtlsObject ()
+               {
+                       Dispose (false);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsPkcs12.cs b/mcs/class/System/Mono.Btls/MonoBtlsPkcs12.cs
new file mode 100644 (file)
index 0000000..93ea137
--- /dev/null
@@ -0,0 +1,144 @@
+//
+// MonoBtlsPkcs12.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsPkcs12 : MonoBtlsObject
+       {
+               internal class BoringPkcs12Handle : MonoBtlsHandle
+               {
+                       public BoringPkcs12Handle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_pkcs12_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringPkcs12Handle Handle {
+                       get { return (BoringPkcs12Handle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_pkcs12_free (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_pkcs12_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_pkcs12_get_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_pkcs12_get_cert (IntPtr Handle, int index);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_pkcs12_add_cert (IntPtr chain, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern unsafe static int mono_btls_pkcs12_import (IntPtr chain, void* data, int len, IntPtr password);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_pkcs12_has_private_key (IntPtr pkcs12);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_pkcs12_get_private_key (IntPtr pkcs12);
+
+               internal MonoBtlsPkcs12 ()
+                       : base (new BoringPkcs12Handle (mono_btls_pkcs12_new ()))
+               {
+               }
+
+               internal MonoBtlsPkcs12 (BoringPkcs12Handle handle)
+                       : base (handle)
+               {
+               }
+
+               MonoBtlsKey privateKey;
+
+               public int Count {
+                       get { return mono_btls_pkcs12_get_count (Handle.DangerousGetHandle ()); }
+               }
+
+               public MonoBtlsX509 GetCertificate (int index)
+               {
+                       if (index >= Count)
+                               throw new IndexOutOfRangeException ();
+                       var handle = mono_btls_pkcs12_get_cert (Handle.DangerousGetHandle (), index);
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (handle));
+               }
+
+               public void AddCertificate (MonoBtlsX509 x509)
+               {
+                       mono_btls_pkcs12_add_cert (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+               }
+
+               public unsafe void Import (byte[] buffer, string password)
+               {
+                       var passptr = IntPtr.Zero;
+                       fixed (void* ptr = buffer)
+                       try {
+                               passptr = Marshal.StringToHGlobalAnsi (password ?? string.Empty);
+                               var ret = mono_btls_pkcs12_import (
+                                       Handle.DangerousGetHandle (), ptr,
+                                       buffer.Length, passptr);
+                               CheckError (ret);
+                       } finally {
+                               if (passptr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (passptr);
+                       }
+               }
+
+               public bool HasPrivateKey {
+                       get { return mono_btls_pkcs12_has_private_key (Handle.DangerousGetHandle ()) != 0; }
+               }
+
+               public MonoBtlsKey GetPrivateKey ()
+               {
+                       if (!HasPrivateKey)
+                               throw new InvalidOperationException ();
+                       if (privateKey == null) {
+                               var handle = mono_btls_pkcs12_get_private_key (Handle.DangerousGetHandle ());
+                               CheckError (handle != IntPtr.Zero);
+                               privateKey = new MonoBtlsKey (new MonoBtlsKey.BoringKeyHandle (handle));
+                       }
+                       return privateKey;
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs b/mcs/class/System/Mono.Btls/MonoBtlsProvider.cs
new file mode 100644 (file)
index 0000000..fd3f2be
--- /dev/null
@@ -0,0 +1,268 @@
+//
+// MonoBtlsProvider.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+#endif
+
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Authentication;
+
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using Mono.Security.Interface;
+using MX = Mono.Security.X509;
+#endif
+
+using MNS = Mono.Net.Security;
+
+namespace Mono.Btls
+{
+       class MonoBtlsProvider : MonoTlsProvider
+       {
+               static readonly Guid id = new Guid ("432d18c9-9348-4b90-bfbf-9f2a10e1f15b");
+
+               public override Guid ID {
+                       get { return id; }
+               }
+               public override string Name {
+                       get { return "btls"; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               public extern static bool IsSupported ();
+
+               internal MonoBtlsProvider ()
+               {
+                       if (!IsSupported ())
+                               throw new NotSupportedException ("BTLS is not supported in this runtime.");
+               }
+
+               public override bool SupportsSslStream {
+                       get { return true; }
+               }
+
+               public override bool SupportsMonoExtensions {
+                       get { return true; }
+               }
+
+               public override bool SupportsConnectionInfo {
+                       get { return true; }
+               }
+
+               public override SslProtocols SupportedProtocols {
+                       get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
+               }
+
+               public override IMonoSslStream CreateSslStream (
+                       Stream innerStream, bool leaveInnerStreamOpen,
+                       MonoTlsSettings settings = null)
+               {
+                       return new MonoBtlsStream (
+                               innerStream, leaveInnerStreamOpen, settings, this);
+               }
+
+               internal override bool HasNativeCertificates {
+                       get { return true; }
+               }
+
+               internal override X509Certificate2Impl GetNativeCertificate (
+                       byte[] data, string password, X509KeyStorageFlags flags)
+               {
+                       var impl = new X509CertificateImplBtls (true);
+                       impl.Import (data, password, flags);
+                       return impl;
+               }
+
+               internal override X509Certificate2Impl GetNativeCertificate (
+                       X509Certificate certificate)
+               {
+                       var impl = certificate.Impl as X509CertificateImplBtls;
+                       if (impl != null)
+                               return (X509Certificate2Impl)impl.Clone ();
+
+                       var data = certificate.GetRawCertData ();
+                       return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false);
+               }
+
+               internal static MonoBtlsX509VerifyParam GetVerifyParam (string targetHost, bool serverMode)
+               {
+                       MonoBtlsX509VerifyParam param;
+                       if (serverMode)
+                               param = MonoBtlsX509VerifyParam.GetSslClient ();
+                       else
+                               param = MonoBtlsX509VerifyParam.GetSslServer ();
+
+                       if (string.IsNullOrEmpty (targetHost))
+                               return param;
+
+                       try {
+                               var copy = param.Copy ();
+                               copy.SetHost (targetHost);
+                               return copy;
+                       } finally {
+                               param.Dispose ();
+                       }
+               }
+
+               internal override bool ValidateCertificate (
+                       ICertificateValidator2 validator, string targetHost, bool serverMode,
+                       X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
+                       ref MonoSslPolicyErrors errors, ref int status11)
+               {
+                       if (chain != null) {
+                               var chainImpl = (X509ChainImplBtls)chain.Impl;
+                               var success = chainImpl.StoreCtx.VerifyResult == 1;
+                               CheckValidationResult (
+                                       validator, targetHost, serverMode, certificates,
+                                       wantsChain, chain, chainImpl.StoreCtx,
+                                       success, ref errors, ref status11);
+                               return success;
+                       }
+
+                       using (var store = new MonoBtlsX509Store ())
+                       using (var nativeChain = MonoBtlsProvider.GetNativeChain (certificates))
+                       using (var param = GetVerifyParam (targetHost, serverMode))
+                       using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
+                               store.LoadLocations (null, GetSystemStoreLocation ());
+                               store.SetDefaultPaths ();
+
+                               storeCtx.Initialize (store, nativeChain);
+
+                               storeCtx.SetVerifyParam (param);
+
+                               var ret = storeCtx.Verify ();
+
+                               var success = ret == 1;
+
+                               if (wantsChain && chain == null) {
+                                       chain = GetManagedChain (nativeChain);
+                               }
+
+                               CheckValidationResult (
+                                       validator, targetHost, serverMode, certificates,
+                                       wantsChain, null, storeCtx,
+                                       success, ref errors, ref status11);
+                               return success;
+                       }
+               }
+
+               void CheckValidationResult (
+                       ICertificateValidator validator, string targetHost, bool serverMode,
+                       X509CertificateCollection certificates, bool wantsChain,
+                       X509Chain chain, MonoBtlsX509StoreCtx storeCtx,
+                       bool success, ref MonoSslPolicyErrors errors, ref int status11)
+               {
+                       if (!success) {
+                               errors = MonoSslPolicyErrors.RemoteCertificateChainErrors;
+                               status11 = unchecked((int)0x800B010B);
+                       }
+               }
+
+               public static string GetSystemStoreLocation ()
+               {
+#if ANDROID
+                       return "/system/etc/security/cacerts";
+#else
+                       var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+                       var path = Path.Combine (appData, ".mono", "certs", "NewTrust");
+                       return path;
+#endif
+               }
+
+               public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
+               {
+                       using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
+                               return new X509Certificate (impl);
+                       }
+               }
+
+               public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
+               {
+                       using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
+                               return new X509Certificate2 (impl);
+                       }
+               }
+
+               public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false)
+               {
+                       using (var impl = new X509CertificateImplBtls (disallowFallback)) {
+                               impl.Import (data, password, X509KeyStorageFlags.DefaultKeySet);
+                               return new X509Certificate2 (impl);
+                       }
+               }
+
+               public static X509Certificate CreateCertificate (MonoBtlsX509 x509)
+               {
+                       using (var impl = new X509CertificateImplBtls (x509, true))
+                               return new X509Certificate (impl);
+               }
+
+               public static X509Chain CreateChain ()
+               {
+                       using (var impl = new X509ChainImplBtls ())
+                               return new X509Chain (impl);
+               }
+
+               public static X509Chain GetManagedChain (MonoBtlsX509Chain chain)
+               {
+                       var impl = new X509ChainImplBtls (chain);
+                       return new X509Chain (impl);
+               }
+
+               public static MonoBtlsX509 GetBtlsCertificate (X509Certificate certificate)
+               {
+                       var impl = certificate.Impl as X509CertificateImplBtls;
+                       if (impl != null)
+                               return impl.X509.Copy ();
+
+                       return MonoBtlsX509.LoadFromData (certificate.GetRawCertData (), MonoBtlsX509Format.DER);
+               }
+
+               public static MonoBtlsX509Chain GetNativeChain (X509CertificateCollection certificates)
+               {
+                       var chain = new MonoBtlsX509Chain ();
+                       try {
+                               foreach (var cert in certificates) {
+                                       using (var x509 = GetBtlsCertificate (cert))
+                                               chain.AddCertificate (x509);
+                               }
+                               return chain;
+                       } catch {
+                               chain.Dispose ();
+                               throw;
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsSsl.cs b/mcs/class/System/Mono.Btls/MonoBtlsSsl.cs
new file mode 100644 (file)
index 0000000..b24ed07
--- /dev/null
@@ -0,0 +1,418 @@
+//
+// MonoBtlsSsl.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+#if MONOTOUCH
+using MonoTouch;
+#endif
+
+namespace Mono.Btls
+{
+       delegate int MonoBtlsVerifyCallback (MonoBtlsX509StoreCtx ctx);
+       delegate int MonoBtlsSelectCallback ();
+
+       class MonoBtlsSsl : MonoBtlsObject
+       {
+               internal class BoringSslHandle : MonoBtlsHandle
+               {
+                       public BoringSslHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_ssl_destroy (handle);
+                               return true;
+                       }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_destroy (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_ssl_new (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_use_certificate (IntPtr handle, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_use_private_key (IntPtr handle, IntPtr key);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_add_chain_certificate (IntPtr handle, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_accept (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_connect (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_handshake (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_close (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_set_bio (IntPtr handle, IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_read (IntPtr handle, IntPtr data, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_write (IntPtr handle, IntPtr data, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_get_error (IntPtr handle, int ret_code);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_get_version (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_set_min_version (IntPtr handle, int version);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_set_max_version (IntPtr handle, int version);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_get_cipher (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_get_ciphers (IntPtr handle, out IntPtr data);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_ssl_get_peer_certificate (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_set_cipher_list (IntPtr handle, IntPtr str);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_print_errors_cb (IntPtr func, IntPtr ctx);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_set_verify_param (IntPtr handle, IntPtr param);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_set_server_name (IntPtr handle, IntPtr name);
+
+               static BoringSslHandle Create_internal (MonoBtlsSslCtx ctx)
+               {
+                       var handle = mono_btls_ssl_new (ctx.Handle.DangerousGetHandle ());
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringSslHandle (handle);
+               }
+
+               PrintErrorsCallbackFunc printErrorsFunc;
+               IntPtr printErrorsFuncPtr;
+
+               public MonoBtlsSsl (MonoBtlsSslCtx ctx)
+                       : base (Create_internal (ctx))
+               {
+                       printErrorsFunc = PrintErrorsCallback;
+                       printErrorsFuncPtr = Marshal.GetFunctionPointerForDelegate (printErrorsFunc);
+               }
+
+               new internal BoringSslHandle Handle {
+                       get { return (BoringSslHandle)base.Handle; }
+               }
+
+               public void SetBio (MonoBtlsBio bio)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_set_bio (
+                               Handle.DangerousGetHandle (),
+                               bio.Handle.DangerousGetHandle ());
+               }
+
+               Exception ThrowError ([CallerMemberName] string callerName = null)
+               {
+                       string errors;
+                       try {
+                               if (callerName == null)
+                                       callerName = GetType ().Name;
+                               errors = GetErrors ();
+                       } catch {
+                               errors = null;
+                       }
+
+                       if (errors != null) {
+                               Console.Error.WriteLine ("ERROR: {0} failed: {1}", callerName, errors);
+                               throw new MonoBtlsException ("{0} failed: {1}.", callerName, errors);
+                       } else {
+                               Console.Error.WriteLine ("ERROR: {0} failed.", callerName);
+                               throw new MonoBtlsException ("{0} failed.", callerName);
+                       }
+               }
+
+               MonoBtlsSslError GetError (int ret_code)
+               {
+                       CheckThrow ();
+                       var error = mono_btls_ssl_get_error (
+                               Handle.DangerousGetHandle (), ret_code);
+                       return (MonoBtlsSslError)error;
+               }
+
+               public void SetCertificate (MonoBtlsX509 x509)
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_use_certificate (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+                       if (ret <= 0)
+                               throw ThrowError ();
+               }
+
+               public void SetPrivateKey (MonoBtlsKey key)
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_use_private_key (
+                               Handle.DangerousGetHandle (),
+                               key.Handle.DangerousGetHandle ());
+                       if (ret <= 0)
+                               throw ThrowError ();
+               }
+
+               public void AddIntermediateCertificate (MonoBtlsX509 x509)
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_add_chain_certificate (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+                       if (ret <= 0)
+                               throw ThrowError ();
+               }
+
+               public MonoBtlsSslError Accept ()
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_accept (Handle.DangerousGetHandle ());
+
+                       var error = GetError (ret);
+                       return error;
+               }
+
+               public MonoBtlsSslError Connect ()
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_connect (Handle.DangerousGetHandle ());
+
+                       var error = GetError (ret);
+                       return error;
+               }
+
+               public MonoBtlsSslError Handshake ()
+               {
+                       CheckThrow ();
+
+                       var ret = mono_btls_ssl_handshake (Handle.DangerousGetHandle ());
+
+                       var error = GetError (ret);
+                       return error;
+               }
+
+               delegate int PrintErrorsCallbackFunc (IntPtr str, IntPtr len, IntPtr ctx);
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (PrintErrorsCallbackFunc))]
+#endif
+               static int PrintErrorsCallback (IntPtr str, IntPtr len, IntPtr ctx)
+               {
+                       var sb = (StringBuilder)GCHandle.FromIntPtr (ctx).Target;
+                       try {
+                               var text = Marshal.PtrToStringAnsi (str, (int)len);
+                               sb.Append (text);
+                               return 1;
+                       } catch {
+                               return 0;
+                       }
+               }
+
+               public string GetErrors ()
+               {
+                       var text = new StringBuilder ();
+                       var handle = GCHandle.Alloc (text);
+
+                       try {
+                               mono_btls_ssl_print_errors_cb (printErrorsFuncPtr, GCHandle.ToIntPtr (handle));
+                               return text.ToString ();
+                       } finally {
+                               if (handle.IsAllocated)
+                                       handle.Free ();
+                       }
+               }
+
+               public void PrintErrors ()
+               {
+                       var errors = GetErrors ();
+                       if (string.IsNullOrEmpty (errors))
+                               return;
+                       Console.Error.WriteLine (errors);
+               }
+
+               public MonoBtlsSslError Read (IntPtr data, ref int dataSize)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_ssl_read (
+                               Handle.DangerousGetHandle (), data, dataSize);
+
+                       if (ret >= 0) {
+                               dataSize = ret;
+                               return MonoBtlsSslError.None;
+                       }
+
+                       var error = mono_btls_ssl_get_error (
+                               Handle.DangerousGetHandle (), ret);
+                       dataSize = 0;
+                       return (MonoBtlsSslError)error;
+               }
+
+               public MonoBtlsSslError Write (IntPtr data, ref int dataSize)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_ssl_write (
+                               Handle.DangerousGetHandle (), data, dataSize);
+
+                       if (ret >= 0) {
+                               dataSize = ret;
+                               return MonoBtlsSslError.None;
+                       }
+
+                       var error = mono_btls_ssl_get_error (
+                               Handle.DangerousGetHandle (), ret);
+                       dataSize = 0;
+                       return (MonoBtlsSslError)error;
+               }
+
+               public int GetVersion ()
+               {
+                       CheckThrow ();
+                       return mono_btls_ssl_get_version (Handle.DangerousGetHandle ());
+               }
+
+               public void SetMinVersion (int version)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_set_min_version (Handle.DangerousGetHandle (), version);
+               }
+
+               public void SetMaxVersion (int version)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_set_max_version (Handle.DangerousGetHandle (), version);
+               }
+
+               public int GetCipher ()
+               {
+                       CheckThrow ();
+                       var cipher = mono_btls_ssl_get_cipher (Handle.DangerousGetHandle ());
+                       CheckError (cipher > 0);
+                       return cipher;
+               }
+
+               public short[] GetCiphers ()
+               {
+                       CheckThrow ();
+                       IntPtr data;
+                       var count = mono_btls_ssl_get_ciphers (
+                               Handle.DangerousGetHandle (), out data);
+                       CheckError (count > 0);
+                       try {
+                               short[] ciphers = new short[count];
+                               Marshal.Copy (data, ciphers, 0, count);
+                               return ciphers;
+                       } finally {
+                               FreeDataPtr (data);
+                       }
+               }
+
+               public void SetCipherList (string str)
+               {
+                       CheckThrow ();
+                       IntPtr strPtr = IntPtr.Zero;
+                       try {
+                               strPtr = Marshal.StringToHGlobalAnsi (str);
+                               var ret = mono_btls_ssl_set_cipher_list (
+                                       Handle.DangerousGetHandle (), strPtr);
+                               CheckError (ret);
+                       } finally {
+                               if (strPtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (strPtr);
+                       }
+               }
+
+               public MonoBtlsX509 GetPeerCertificate ()
+               {
+                       CheckThrow ();
+                       var x509 = mono_btls_ssl_get_peer_certificate (
+                               Handle.DangerousGetHandle ());
+                       if (x509 == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (x509));
+               }
+
+               public void SetVerifyParam (MonoBtlsX509VerifyParam param)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_ssl_set_verify_param (
+                               Handle.DangerousGetHandle (),
+                               param.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public void SetServerName (string name)
+               {
+                       CheckThrow ();
+                       IntPtr namePtr = IntPtr.Zero;
+                       try {
+                               namePtr = Marshal.StringToHGlobalAnsi (name);
+                               var ret = mono_btls_ssl_set_server_name (
+                                       Handle.DangerousGetHandle (), namePtr);
+                               CheckError (ret);
+                       } finally {
+                               if (namePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (namePtr);
+                       }
+               }
+
+               protected override void Close ()
+               {
+                       mono_btls_ssl_close (Handle.DangerousGetHandle ());
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsSslCtx.cs b/mcs/class/System/Mono.Btls/MonoBtlsSslCtx.cs
new file mode 100644 (file)
index 0000000..517b158
--- /dev/null
@@ -0,0 +1,260 @@
+//
+// MonoBtlsSslCtx.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+#if MONOTOUCH
+using MonoTouch;
+#endif
+
+namespace Mono.Btls
+{
+       class MonoBtlsSslCtx : MonoBtlsObject
+       {
+               internal class BoringSslCtxHandle : MonoBtlsHandle
+               {
+                       public BoringSslCtxHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_ssl_ctx_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringSslCtxHandle Handle {
+                       get { return (BoringSslCtxHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_ssl_ctx_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_ctx_free (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_ssl_ctx_up_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_initialize (IntPtr handle, IntPtr instance);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_set_debug_bio (IntPtr handle, IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_set_cert_verify_callback (IntPtr handle, IntPtr func, int cert_required);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_set_cert_select_callback (IntPtr handle, IntPtr func);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_set_min_version (IntPtr handle, int version);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_ssl_ctx_set_max_version (IntPtr handle, int version);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_ctx_is_cipher_supported (IntPtr handle, short value);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_ctx_set_ciphers (IntPtr handle, int count, IntPtr data, int allow_unsupported);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_ssl_ctx_set_verify_param (IntPtr handle, IntPtr param);
+
+               delegate int NativeVerifyFunc (IntPtr instance, int preverify_ok, IntPtr ctx);
+               delegate int NativeSelectFunc (IntPtr instance);
+
+               NativeVerifyFunc verifyFunc;
+               NativeSelectFunc selectFunc;
+               IntPtr verifyFuncPtr;
+               IntPtr selectFuncPtr;
+               MonoBtlsVerifyCallback verifyCallback;
+               MonoBtlsSelectCallback selectCallback;
+               MonoBtlsX509Store store;
+               GCHandle instance;
+               IntPtr instancePtr;
+
+               public MonoBtlsSslCtx ()
+                       : this (new BoringSslCtxHandle (mono_btls_ssl_ctx_new ()))
+               {
+               }
+
+               internal MonoBtlsSslCtx (BoringSslCtxHandle handle)
+                       : base (handle)
+               {
+                       instance = GCHandle.Alloc (this);
+                       instancePtr = GCHandle.ToIntPtr (instance);
+                       mono_btls_ssl_ctx_initialize (
+                               handle.DangerousGetHandle (), instancePtr);
+
+                       verifyFunc = NativeVerifyCallback;
+                       selectFunc = NativeSelectCallback;
+                       verifyFuncPtr = Marshal.GetFunctionPointerForDelegate (verifyFunc);
+                       selectFuncPtr = Marshal.GetFunctionPointerForDelegate (selectFunc);
+
+                       store = new MonoBtlsX509Store (Handle);
+               }
+
+               internal MonoBtlsSslCtx Copy ()
+               {
+                       var copy = mono_btls_ssl_ctx_up_ref (Handle.DangerousGetHandle ());
+                       return new MonoBtlsSslCtx (new BoringSslCtxHandle (copy));
+               }
+
+               public MonoBtlsX509Store CertificateStore {
+                       get { return store; }
+               }
+
+               int VerifyCallback (bool preverify_ok, MonoBtlsX509StoreCtx ctx)
+               {
+                       if (verifyCallback != null)
+                               return verifyCallback (ctx);
+                       return 0;
+               }
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (NativeVerifyFunc))]
+#endif
+               static int NativeVerifyCallback (IntPtr instance, int preverify_ok, IntPtr store_ctx)
+               {
+                       var c = (MonoBtlsSslCtx)GCHandle.FromIntPtr (instance).Target;
+                       using (var ctx = new MonoBtlsX509StoreCtx (preverify_ok, store_ctx)) {
+                               try {
+                                       return c.VerifyCallback (preverify_ok != 0, ctx);
+                               } catch (Exception ex) {
+                                       c.SetException (ex);
+                               }
+                       }
+                       return 0;
+               }
+
+               int SelectCallback ()
+               {
+                       if (selectCallback != null)
+                               return selectCallback ();
+                       return 1;
+               }
+
+#if MONOTOUCH
+               [MonoPInvokeCallback (typeof (NativeSelectFunc))]
+#endif
+               static int NativeSelectCallback (IntPtr instance)
+               {
+                       var c = (MonoBtlsSslCtx)GCHandle.FromIntPtr (instance).Target;
+                       try {
+                               return c.SelectCallback ();
+                       } catch (Exception ex) {
+                               c.SetException (ex);
+                               return 0;
+                       }
+               }
+
+               public void SetDebugBio (MonoBtlsBio bio)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_ctx_set_debug_bio (Handle.DangerousGetHandle (), bio.Handle.DangerousGetHandle ());
+               }
+
+               public void SetVerifyCallback (MonoBtlsVerifyCallback callback, bool client_cert_required)
+               {
+                       CheckThrow ();
+
+                       verifyCallback = callback;
+                       mono_btls_ssl_ctx_set_cert_verify_callback (
+                               Handle.DangerousGetHandle (), verifyFuncPtr,
+                               client_cert_required ? 1 : 0);
+               }
+
+               public void SetSelectCallback (MonoBtlsSelectCallback callback)
+               {
+                       CheckThrow ();
+
+                       selectCallback = callback;
+                       mono_btls_ssl_ctx_set_cert_select_callback (
+                               Handle.DangerousGetHandle (), selectFuncPtr);
+               }
+
+               public void SetMinVersion (int version)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_ctx_set_min_version (Handle.DangerousGetHandle (), version);
+               }
+
+               public void SetMaxVersion (int version)
+               {
+                       CheckThrow ();
+                       mono_btls_ssl_ctx_set_max_version (Handle.DangerousGetHandle (), version);
+               }
+
+               public bool IsCipherSupported (short value)
+               {
+                       CheckThrow ();
+                       return mono_btls_ssl_ctx_is_cipher_supported (Handle.DangerousGetHandle (), value) != 0;
+               }
+
+               public void SetCiphers (short[] ciphers, bool allow_unsupported)
+               {
+                       CheckThrow ();
+                       var data = Marshal.AllocHGlobal (ciphers.Length * 2);
+                       try {
+                               Marshal.Copy (ciphers, 0, data, ciphers.Length);
+                               var ret = mono_btls_ssl_ctx_set_ciphers (
+                                       Handle.DangerousGetHandle (),
+                                       ciphers.Length, data, allow_unsupported ? 1 : 0);
+                               CheckError (ret > 0);
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public void SetVerifyParam (MonoBtlsX509VerifyParam param)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_ssl_ctx_set_verify_param (
+                               Handle.DangerousGetHandle (),
+                               param.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               protected override void Close ()
+               {
+                       if (store != null) {
+                               store.Dispose ();
+                               store = null;
+                       }
+                       if (instance.IsAllocated)
+                               instance.Free ();
+                       base.Close ();
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsSslError.cs b/mcs/class/System/Mono.Btls/MonoBtlsSslError.cs
new file mode 100644 (file)
index 0000000..38f6f4f
--- /dev/null
@@ -0,0 +1,47 @@
+//
+// MonoBtlsSslError.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+namespace Mono.Btls
+{
+       // keep in sync with boringssl/include/ssl.h
+       enum MonoBtlsSslError
+       {
+               None = 0,
+               Ssl = 1,
+               WantRead = 2,
+               WantWrite = 3,
+               WantX509Lookup = 4,
+               Syscall = 5,
+               ZeroReturn = 6,
+               WantConnect = 7,
+               WantAccept = 8,
+               WantChannelIdLookup = 9,
+               PendingSession = 11,
+               PendingCertificate = 12,
+               WantPrivateKeyOperation = 13
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsStream.cs b/mcs/class/System/Mono.Btls/MonoBtlsStream.cs
new file mode 100644 (file)
index 0000000..d2f32e9
--- /dev/null
@@ -0,0 +1,65 @@
+//
+// MonoBtlsStream.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+#endif
+
+using System;
+using System.IO;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+#else
+using Mono.Security.Interface;
+#endif
+
+using MNS = Mono.Net.Security;
+
+namespace Mono.Btls
+{
+       class MonoBtlsStream : MNS.MobileAuthenticatedStream
+       {
+               public MonoBtlsStream (Stream innerStream, bool leaveInnerStreamOpen, MonoTlsSettings settings, MonoTlsProvider provider)
+                       : base (innerStream, leaveInnerStreamOpen, settings, provider)
+               {
+               }
+
+               protected override MNS.MobileTlsContext CreateContext (
+                       MNS.MobileAuthenticatedStream parent, bool serverMode, string targetHost,
+                       SslProtocols enabledProtocols, X509Certificate serverCertificate,
+                       X509CertificateCollection clientCertificates, bool askForClientCert)
+               {
+                       return new MonoBtlsContext (
+                               parent, serverMode, targetHost,
+                               enabledProtocols, serverCertificate,
+                               clientCertificates, askForClientCert);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsUtils.cs b/mcs/class/System/Mono.Btls/MonoBtlsUtils.cs
new file mode 100644 (file)
index 0000000..c3dae84
--- /dev/null
@@ -0,0 +1,186 @@
+//
+// MonoBtlsUtils.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.Text;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Mono.Btls
+{
+       static class MonoBtlsUtils
+       {
+               static byte[] emailOid = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
+
+               public static bool Compare (byte[] a, byte[] b)
+               {
+                       if (a.Length != b.Length)
+                               return false;
+                       for (int i = 0; i < a.Length; i++) {
+                               if (a[i] != b[i])
+                                       return false;
+                       }
+                       return true;
+               }
+
+               static bool AppendEntry (StringBuilder sb, MonoBtlsX509Name name, int index, string separator, bool quotes)
+               {
+                       var type = name.GetEntryType (index);
+                       if (type < 0)
+                               return false;
+                       else if (type == 0) {
+                               var oidValue = name.GetEntryOidData (index);
+                               if (Compare (oidValue, emailOid))
+                                       type = MonoBtlsX509NameEntryType.Email;
+                       }
+                       var text = name.GetEntryValue (index);
+                       if (text == null)
+                               return false;
+                       var oid = name.GetEntryOid (index);
+                       if (oid == null)
+                               return false;
+
+                       if (sb.Length > 0)
+                               sb.Append (separator);
+
+                       switch (type) {
+                       case MonoBtlsX509NameEntryType.CountryName:
+                               sb.Append ("C=");
+                               break;
+                       case MonoBtlsX509NameEntryType.OrganizationName:
+                               sb.Append ("O=");
+                               break;
+                       case MonoBtlsX509NameEntryType.OrganizationalUnitName:
+                               sb.Append ("OU=");
+                               break;
+                       case MonoBtlsX509NameEntryType.CommonName:
+                               sb.Append ("CN=");
+                               break;
+                       case MonoBtlsX509NameEntryType.LocalityName:
+                               sb.Append ("L=");
+                               break;
+                       case MonoBtlsX509NameEntryType.StateOrProvinceName:
+                               sb.Append ("S=");       // NOTE: RFC2253 uses ST=
+                               break;
+                       case MonoBtlsX509NameEntryType.StreetAddress:
+                               sb.Append ("STREET=");
+                               break;
+                       case MonoBtlsX509NameEntryType.DomainComponent:
+                               sb.Append ("DC=");
+                               break;
+                       case MonoBtlsX509NameEntryType.UserId:
+                               sb.Append ("UID=");
+                               break;
+                       case MonoBtlsX509NameEntryType.Email:
+                               sb.Append ("E=");       // NOTE: Not part of RFC2253
+                               break;
+                       case MonoBtlsX509NameEntryType.DnQualifier:
+                               sb.Append ("dnQualifier=");
+                               break;
+                       case MonoBtlsX509NameEntryType.Title:
+                               sb.Append ("T=");
+                               break;
+                       case MonoBtlsX509NameEntryType.Surname:
+                               sb.Append ("SN=");
+                               break;
+                       case MonoBtlsX509NameEntryType.GivenName:
+                               sb.Append ("G=");
+                               break;
+                       case MonoBtlsX509NameEntryType.Initial:
+                               sb.Append ("I=");
+                               break;
+                       default:
+                               // unknown OID
+                               sb.Append ("OID.");     // NOTE: Not present as RFC2253
+                               sb.Append (oid);
+                               sb.Append ("=");
+                               break;
+                       }
+
+                       // 16bits or 8bits string ? TODO not complete (+special chars!)
+                       char[] specials = { ',', '+', '"', '\\', '<', '>', ';' };
+                       if (quotes) {
+                               if ((text.IndexOfAny (specials, 0, text.Length) > 0) ||
+                                   text.StartsWith (" ") || (text.EndsWith (" ")))
+                                       text = "\"" + text + "\"";
+                       }
+
+                       sb.Append (text);
+                       return true;
+               }
+
+               const X500DistinguishedNameFlags AllFlags = X500DistinguishedNameFlags.Reversed |
+                       X500DistinguishedNameFlags.UseSemicolons | X500DistinguishedNameFlags.DoNotUsePlusSign |
+                       X500DistinguishedNameFlags.DoNotUseQuotes | X500DistinguishedNameFlags.UseCommas |
+                       X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.UseUTF8Encoding |
+                       X500DistinguishedNameFlags.UseT61Encoding | X500DistinguishedNameFlags.ForceUTF8Encoding;
+
+               static string GetSeparator (X500DistinguishedNameFlags flag)
+               {
+                       if ((flag & X500DistinguishedNameFlags.UseSemicolons) != 0)
+                               return "; ";
+                       if ((flag & X500DistinguishedNameFlags.UseCommas) != 0)
+                               return ", ";
+                       if ((flag & X500DistinguishedNameFlags.UseNewLines) != 0)
+                               return Environment.NewLine;
+                       return ", "; //default
+               }
+
+               public static string FormatName (MonoBtlsX509Name name, X500DistinguishedNameFlags flag)
+               {
+                       if ((flag != 0) && ((flag & AllFlags) == 0))
+                               throw new ArgumentException ("flag");
+
+                       if (name.GetEntryCount () == 0)
+                               return String.Empty;
+
+                       // Mono.Security reversed isn't the same as fx 2.0 (which is the reverse of 1.x)
+                       bool reversed = ((flag & X500DistinguishedNameFlags.Reversed) != 0);
+                       bool quotes = ((flag & X500DistinguishedNameFlags.DoNotUseQuotes) == 0);
+                       string separator = GetSeparator (flag);
+
+                       return FormatName (name, reversed, separator, quotes);
+               }
+
+               public static string FormatName (MonoBtlsX509Name name, bool reversed, string separator, bool quotes)
+               {
+                       var count = name.GetEntryCount ();
+                       StringBuilder sb = new StringBuilder ();
+
+                       if (reversed) {
+                               for (int i = count - 1; i >= 0; i--) {
+                                       AppendEntry (sb, name, i, separator, quotes);
+                               }
+                       } else {
+                               for (int i = 0; i < count; i++) {
+                                       AppendEntry (sb, name, i, separator, quotes);
+                               }
+                       }
+
+                       return sb.ToString ();
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509.cs
new file mode 100644 (file)
index 0000000..4d451b9
--- /dev/null
@@ -0,0 +1,465 @@
+//
+// MonoBtlsX509.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509 : MonoBtlsObject
+       {
+               internal class BoringX509Handle : MonoBtlsHandle
+               {
+                       public BoringX509Handle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (handle != IntPtr.Zero)
+                                       mono_btls_x509_free (handle);
+                               return true;
+                       }
+
+                       public IntPtr StealHandle ()
+                       {
+                               var retval = Interlocked.Exchange (ref handle, IntPtr.Zero);
+                               return retval;
+                       }
+               }
+
+               new internal BoringX509Handle Handle {
+                       get { return (BoringX509Handle)base.Handle; }
+               }
+
+               internal MonoBtlsX509 (BoringX509Handle handle) 
+                       : base (handle)
+               {
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_up_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_from_data (IntPtr data, int len, MonoBtlsX509Format format);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_get_subject_name (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_get_issuer_name (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_subject_name_string (IntPtr handle, IntPtr buffer, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_issuer_name_string (IntPtr handle, IntPtr buffer, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_raw_data (IntPtr handle, IntPtr bio, MonoBtlsX509Format format);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_cmp (IntPtr a, IntPtr b);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_hash (IntPtr handle, out IntPtr data);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_get_not_before (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_get_not_after (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_public_key (IntPtr handle, IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_serial_number (IntPtr handle, IntPtr data, int size, int mono_style);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_version (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_signature_algorithm (IntPtr handle, IntPtr buffer, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_public_key_asn1 (IntPtr handle, IntPtr oid, int oid_size, out IntPtr data, out int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_public_key_parameters (IntPtr handle, IntPtr oid, int oid_size, out IntPtr data, out int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_get_pubkey (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_get_subject_key_identifier (IntPtr handle, out IntPtr data, out int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_print (IntPtr handle, IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_free (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_dup (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_add_trust_object (IntPtr handle, MonoBtlsX509Purpose purpose);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_add_reject_object (IntPtr handle, MonoBtlsX509Purpose purpose);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_add_explicit_trust (IntPtr handle, MonoBtlsX509TrustKind kind);
+
+               internal MonoBtlsX509 Copy ()
+               {
+                       var copy = mono_btls_x509_up_ref (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsX509 (new BoringX509Handle (copy));
+               }
+
+               // This will actually duplicate the underlying 'X509 *' object instead of
+               // simply increasing the reference count.
+               internal MonoBtlsX509 Duplicate ()
+               {
+                       var copy = mono_btls_x509_dup (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsX509 (new BoringX509Handle (copy));
+               }
+
+               public static MonoBtlsX509 LoadFromData (byte[] buffer, MonoBtlsX509Format format)
+               {
+                       var data = Marshal.AllocHGlobal (buffer.Length);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       try {
+                               Marshal.Copy (buffer, 0, data, buffer.Length);
+                               var x509 = mono_btls_x509_from_data (data, buffer.Length, format);
+                               if (x509 == IntPtr.Zero)
+                                       throw new MonoBtlsException ("Failed to read certificate from data.");
+
+                               return new MonoBtlsX509 (new BoringX509Handle (x509));
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public MonoBtlsX509Name GetSubjectName ()
+               {
+                       var handle = mono_btls_x509_get_subject_name (Handle.DangerousGetHandle ());
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsX509Name (new MonoBtlsX509Name.BoringX509NameHandle (handle, false));
+               }
+
+               public string GetSubjectNameString ()
+               {
+                       const int size = 4096;
+                       var data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_get_subject_name_string (
+                                       Handle.DangerousGetHandle (), data, size);
+                               CheckError (ret);
+                               return Marshal.PtrToStringAnsi (data);
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public long GetSubjectNameHash ()
+               {
+                       CheckThrow ();
+                       using (var subject = GetSubjectName ())
+                               return subject.GetHash ();
+               }
+
+               public MonoBtlsX509Name GetIssuerName ()
+               {
+                       var handle = mono_btls_x509_get_issuer_name (Handle.DangerousGetHandle ());
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsX509Name (new MonoBtlsX509Name.BoringX509NameHandle (handle, false));
+               }
+
+               public string GetIssuerNameString ()
+               {
+                       const int size = 4096;
+                       var data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_get_issuer_name_string (
+                                       Handle.DangerousGetHandle (), data, size);
+                               CheckError (ret);
+                               return Marshal.PtrToStringAnsi (data);
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public byte[] GetRawData (MonoBtlsX509Format format)
+               {
+                       using (var bio = new MonoBtlsBioMemory ()) {
+                               var ret = mono_btls_x509_get_raw_data (
+                                       Handle.DangerousGetHandle (),
+                                       bio.Handle.DangerousGetHandle (),
+                                       format);
+                               CheckError (ret);
+                               return bio.GetData ();
+                       }
+               }
+
+               public void GetRawData (MonoBtlsBio bio, MonoBtlsX509Format format)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_x509_get_raw_data (
+                               Handle.DangerousGetHandle (),
+                               bio.Handle.DangerousGetHandle (),
+                               format);
+                       CheckError (ret);
+               }
+
+               public static int Compare (MonoBtlsX509 a, MonoBtlsX509 b)
+               {
+                       return mono_btls_x509_cmp (
+                               a.Handle.DangerousGetHandle (),
+                               b.Handle.DangerousGetHandle ());
+               }
+
+               public byte[] GetCertHash ()
+               {
+                       IntPtr data;
+                       var ret = mono_btls_x509_get_hash (Handle.DangerousGetHandle (), out data);
+                       CheckError (ret > 0);
+                       var buffer = new byte [ret];
+                       Marshal.Copy (data, buffer, 0, ret);
+                       return buffer;
+               }
+
+               public DateTime GetNotBefore ()
+               {
+                       var ticks = mono_btls_x509_get_not_before (Handle.DangerousGetHandle ());
+                       return new DateTime (1970, 1, 1).AddSeconds (ticks);
+               }
+
+               public DateTime GetNotAfter ()
+               {
+                       var ticks = mono_btls_x509_get_not_after (Handle.DangerousGetHandle ());
+                       return new DateTime (1970, 1, 1).AddSeconds (ticks);
+               }
+
+               public byte[] GetPublicKeyData ()
+               {
+                       using (var bio = new MonoBtlsBioMemory ()) {
+                               var ret = mono_btls_x509_get_public_key (
+                                       Handle.DangerousGetHandle (),
+                                       bio.Handle.DangerousGetHandle ());
+                               CheckError (ret > 0);
+                               return bio.GetData ();
+                       }
+               }
+
+               public byte[] GetSerialNumber (bool mono_style)
+               {
+                       int size = 256;
+                       IntPtr data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_get_serial_number (
+                                       Handle.DangerousGetHandle (), data,
+                                       size, mono_style ? 1 : 0);
+                               CheckError (ret > 0);
+                               var buffer = new byte [ret];
+                               Marshal.Copy (data, buffer, 0, ret);
+                               return buffer;
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public int GetVersion ()
+               {
+                       return mono_btls_x509_get_version (Handle.DangerousGetHandle ());
+               }
+
+               public Oid GetSignatureAlgorithm ()
+               {
+                       int size = 256;
+                       IntPtr data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_get_signature_algorithm (
+                                       Handle.DangerousGetHandle (), data, size);
+                               CheckError (ret > 0);
+                               return new Oid (Marshal.PtrToStringAnsi (data));
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public AsnEncodedData GetPublicKeyAsn1 ()
+               {
+                       int size;
+                       IntPtr data;
+
+                       int oidSize = 256;
+                       var oidData = Marshal.AllocHGlobal (256);
+                       string oid;
+
+                       try {
+                               var ret = mono_btls_x509_get_public_key_asn1 (
+                                       Handle.DangerousGetHandle (), oidData, oidSize,
+                                       out data, out size);
+                               CheckError (ret);
+                               oid = Marshal.PtrToStringAnsi (oidData);
+                       } finally {
+                               Marshal.FreeHGlobal (oidData);
+                       }
+
+                       try {
+                               var buffer = new byte[size];
+                               Marshal.Copy (data, buffer, 0, size);
+                               return new AsnEncodedData (oid.ToString (), buffer);
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       FreeDataPtr (data);
+                       }
+               }
+
+               public AsnEncodedData GetPublicKeyParameters ()
+               {
+                       int size;
+                       IntPtr data;
+
+                       int oidSize = 256;
+                       var oidData = Marshal.AllocHGlobal (256);
+                       string oid;
+
+                       try {
+                               var ret = mono_btls_x509_get_public_key_parameters (
+                                       Handle.DangerousGetHandle (), oidData, oidSize,
+                                       out data, out size);
+                               CheckError (ret);
+                               oid = Marshal.PtrToStringAnsi (oidData);
+                       } finally {
+                               Marshal.FreeHGlobal (oidData);
+                       }
+
+                       try {
+                               var buffer = new byte[size];
+                               Marshal.Copy (data, buffer, 0, size);
+                               return new AsnEncodedData (oid.ToString (), buffer);
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       FreeDataPtr (data);
+                       }
+               }
+
+               public byte[] GetSubjectKeyIdentifier ()
+               {
+                       int size;
+                       IntPtr data = IntPtr.Zero;
+
+                       try {
+                               var ret = mono_btls_x509_get_subject_key_identifier (
+                                       Handle.DangerousGetHandle (), out data, out size);
+                               CheckError (ret);
+                               var buffer = new byte[size];
+                               Marshal.Copy (data, buffer, 0, size);
+                               return buffer;
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       FreeDataPtr (data);
+                       }
+               }
+
+               public MonoBtlsKey GetPublicKey ()
+               {
+                       var handle = mono_btls_x509_get_pubkey (Handle.DangerousGetHandle ());
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsKey (new MonoBtlsKey.BoringKeyHandle (handle));
+               }
+
+               public void Print (MonoBtlsBio bio)
+               {
+                       var ret = mono_btls_x509_print (
+                               Handle.DangerousGetHandle (),
+                               bio.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public void ExportAsPEM (MonoBtlsBio bio, bool includeHumanReadableForm)
+               {
+                       GetRawData (bio, MonoBtlsX509Format.PEM);
+
+                       if (!includeHumanReadableForm)
+                               return;
+
+                       Print (bio);
+
+                       var hash = GetCertHash ();
+                       var output = new StringBuilder ();
+                       output.Append ("SHA1 Fingerprint=");
+                       for (int i = 0; i < hash.Length; i++) {
+                               if (i > 0)
+                                       output.Append (":");
+                               output.AppendFormat ("{0:X2}", hash [i]);
+                       }
+                       output.AppendLine ();
+                       var outputData = Encoding.ASCII.GetBytes (output.ToString ());
+                       bio.Write (outputData, 0, outputData.Length);
+               }
+
+               public void AddTrustObject (MonoBtlsX509Purpose purpose)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_x509_add_trust_object (
+                               Handle.DangerousGetHandle (), purpose);
+                       CheckError (ret);
+               }
+
+               public void AddRejectObject (MonoBtlsX509Purpose purpose)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_x509_add_reject_object (
+                               Handle.DangerousGetHandle (), purpose);
+                       CheckError (ret);
+               }
+
+               public void AddExplicitTrust (MonoBtlsX509TrustKind kind)
+               {
+                       CheckThrow ();
+                       var ret = mono_btls_x509_add_explicit_trust (
+                               Handle.DangerousGetHandle (), kind);
+                       CheckError (ret);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Chain.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Chain.cs
new file mode 100644 (file)
index 0000000..6926ae7
--- /dev/null
@@ -0,0 +1,122 @@
+//
+// MonoBtlsX509Chain.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Chain : MonoBtlsObject
+       {
+               internal class BoringX509ChainHandle : MonoBtlsHandle
+               {
+                       public BoringX509ChainHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_x509_chain_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringX509ChainHandle Handle {
+                       get { return (BoringX509ChainHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_chain_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_chain_get_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_chain_get_cert (IntPtr Handle, int index);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_chain_add_cert (IntPtr chain, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_chain_up_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_chain_free (IntPtr handle);
+
+               public MonoBtlsX509Chain ()
+                       : base (new BoringX509ChainHandle (mono_btls_x509_chain_new ()))
+               {
+               }
+
+               internal MonoBtlsX509Chain (BoringX509ChainHandle handle)
+                       : base (handle)
+               {
+               }
+
+               public int Count {
+                       get { return mono_btls_x509_chain_get_count (Handle.DangerousGetHandle ()); }
+               }
+
+               public MonoBtlsX509 GetCertificate (int index)
+               {
+                       if (index >= Count)
+                               throw new IndexOutOfRangeException ();
+                       var handle = mono_btls_x509_chain_get_cert (
+                               Handle.DangerousGetHandle (), index);
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (handle));
+               }
+
+               public void Dump ()
+               {
+                       Console.Error.WriteLine ("CHAIN: {0:x} {1}", Handle, Count);
+                       for (int i = 0; i < Count; i++) {
+                               using (var cert = GetCertificate (i)) {
+                                       Console.Error.WriteLine ("  CERT #{0}: {1}", i, cert.GetSubjectNameString ());
+                               }
+                       }
+               }
+
+               public void AddCertificate (MonoBtlsX509 x509)
+               {
+                       mono_btls_x509_chain_add_cert (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+               }
+
+               internal MonoBtlsX509Chain Copy ()
+               {
+                       var copy = mono_btls_x509_chain_up_ref (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsX509Chain (new BoringX509ChainHandle (copy));
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Crl.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Crl.cs
new file mode 100644 (file)
index 0000000..7b4ab7d
--- /dev/null
@@ -0,0 +1,185 @@
+//
+// MonoBtlsX509Crl.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Crl : MonoBtlsObject
+       {
+               internal class BoringX509CrlHandle : MonoBtlsHandle
+               {
+                       public BoringX509CrlHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (handle != IntPtr.Zero)
+                                       mono_btls_x509_crl_free (handle);
+                               return true;
+                       }
+
+                       public IntPtr StealHandle ()
+                       {
+                               var retval = Interlocked.Exchange (ref handle, IntPtr.Zero);
+                               return retval;
+                       }
+               }
+
+               new internal BoringX509CrlHandle Handle {
+                       get { return (BoringX509CrlHandle)base.Handle; }
+               }
+
+               internal MonoBtlsX509Crl (BoringX509CrlHandle handle) 
+                       : base (handle)
+               {
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_crl_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_crl_from_data (IntPtr data, int len, MonoBtlsX509Format format);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_crl_get_by_cert (IntPtr handle, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               unsafe extern static IntPtr mono_btls_x509_crl_get_by_serial (IntPtr handle, void *serial, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_crl_get_revoked_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_crl_get_revoked (IntPtr handle, int index);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_crl_get_last_update (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_crl_get_next_update (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_crl_get_version (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_crl_get_issuer (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_crl_free (IntPtr handle);
+
+               public static MonoBtlsX509Crl LoadFromData (byte[] buffer, MonoBtlsX509Format format)
+               {
+                       var data = Marshal.AllocHGlobal (buffer.Length);
+                       if (data == IntPtr.Zero)
+                               throw new OutOfMemoryException ();
+
+                       try {
+                               Marshal.Copy (buffer, 0, data, buffer.Length);
+                               var crl = mono_btls_x509_crl_from_data (data, buffer.Length, format);
+                               if (crl == IntPtr.Zero)
+                                       throw new MonoBtlsException ("Failed to read CRL from data.");
+
+                               return new MonoBtlsX509Crl (new BoringX509CrlHandle (crl));
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public MonoBtlsX509Revoked GetByCert (MonoBtlsX509 x509)
+               {
+                       var revoked = mono_btls_x509_crl_get_by_cert (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+                       if (revoked == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509Revoked (new MonoBtlsX509Revoked.BoringX509RevokedHandle (revoked));
+               }
+
+               public unsafe MonoBtlsX509Revoked GetBySerial (byte[] serial)
+               {
+                       fixed (void *ptr = serial)
+                       {
+                               var revoked = mono_btls_x509_crl_get_by_serial (
+                                       Handle.DangerousGetHandle (), ptr, serial.Length);
+                               if (revoked == IntPtr.Zero)
+                                       return null;
+                               return new MonoBtlsX509Revoked (new MonoBtlsX509Revoked.BoringX509RevokedHandle (revoked));
+                       }
+               }
+
+               public int GetRevokedCount ()
+               {
+                       return mono_btls_x509_crl_get_revoked_count (Handle.DangerousGetHandle ());
+               }
+
+               public MonoBtlsX509Revoked GetRevoked (int index)
+               {
+                       if (index >= GetRevokedCount ())
+                               throw new ArgumentOutOfRangeException ();
+
+                       var revoked = mono_btls_x509_crl_get_revoked (
+                               Handle.DangerousGetHandle (), index);
+                       if (revoked == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509Revoked (new MonoBtlsX509Revoked.BoringX509RevokedHandle (revoked));
+               }
+
+               public DateTime GetLastUpdate ()
+               {
+                       var ticks = mono_btls_x509_crl_get_last_update (Handle.DangerousGetHandle ());
+                       return new DateTime (1970, 1, 1).AddSeconds (ticks);
+               }
+
+               public DateTime GetNextUpdate ()
+               {
+                       var ticks = mono_btls_x509_crl_get_next_update (Handle.DangerousGetHandle ());
+                       return new DateTime (1970, 1, 1).AddSeconds (ticks);
+               }
+
+               public long GetVersion ()
+               {
+                       return mono_btls_x509_crl_get_version (Handle.DangerousGetHandle ());
+               }
+
+               public MonoBtlsX509Name GetIssuerName ()
+               {
+                       var handle = mono_btls_x509_crl_get_issuer (Handle.DangerousGetHandle ());
+                       CheckError (handle != IntPtr.Zero);
+                       return new MonoBtlsX509Name (new MonoBtlsX509Name.BoringX509NameHandle (handle, false));
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Error.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Error.cs
new file mode 100644 (file)
index 0000000..50196bf
--- /dev/null
@@ -0,0 +1,111 @@
+//
+// MonoBtlsX509Error.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       // Keep in sync with x509_vfy.h
+       enum MonoBtlsX509Error
+       {
+               OK = 0,
+               /* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+
+               UNABLE_TO_GET_ISSUER_CERT = 2,
+               UNABLE_TO_GET_CRL = 3,
+               UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4,
+               UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5,
+               UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6,
+               CERT_SIGNATURE_FAILURE = 7,
+               CRL_SIGNATURE_FAILURE = 8,
+               CERT_NOT_YET_VALID = 9,
+               CERT_HAS_EXPIRED = 10,
+               CRL_NOT_YET_VALID = 11,
+               CRL_HAS_EXPIRED = 12,
+               ERROR_IN_CERT_NOT_BEFORE_FIELD = 13,
+               ERROR_IN_CERT_NOT_AFTER_FIELD = 14,
+               ERROR_IN_CRL_LAST_UPDATE_FIELD = 15,
+               ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16,
+               OUT_OF_MEM = 17,
+               DEPTH_ZERO_SELF_SIGNED_CERT = 18,
+               SELF_SIGNED_CERT_IN_CHAIN = 19,
+               UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20,
+               UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21,
+               CERT_CHAIN_TOO_LONG = 22,
+               CERT_REVOKED = 23,
+               INVALID_CA = 24,
+               PATH_LENGTH_EXCEEDED = 25,
+               INVALID_PURPOSE = 26,
+               CERT_UNTRUSTED = 27,
+               CERT_REJECTED = 28,
+               /* These are 'informational' when looking for issuer cert */
+               SUBJECT_ISSUER_MISMATCH = 29,
+               AKID_SKID_MISMATCH = 30,
+               AKID_ISSUER_SERIAL_MISMATCH = 31,
+               KEYUSAGE_NO_CERTSIGN = 32,
+
+               UNABLE_TO_GET_CRL_ISSUER = 33,
+               UNHANDLED_CRITICAL_EXTENSION = 34,
+               KEYUSAGE_NO_CRL_SIGN = 35,
+               UNHANDLED_CRITICAL_CRL_EXTENSION = 36,
+               INVALID_NON_CA = 37,
+               PROXY_PATH_LENGTH_EXCEEDED = 38,
+               KEYUSAGE_NO_DIGITAL_SIGNATURE = 39,
+               PROXY_CERTIFICATES_NOT_ALLOWED = 40,
+
+               INVALID_EXTENSION = 41,
+               INVALID_POLICY_EXTENSION = 42,
+               NO_EXPLICIT_POLICY = 43,
+               DIFFERENT_CRL_SCOPE = 44,
+               UNSUPPORTED_EXTENSION_FEATURE = 45,
+
+               UNNESTED_RESOURCE = 46,
+
+               PERMITTED_VIOLATION = 47,
+               EXCLUDED_VIOLATION = 48,
+               SUBTREE_MINMAX = 49,
+               UNSUPPORTED_CONSTRAINT_TYPE = 51,
+               UNSUPPORTED_CONSTRAINT_SYNTAX = 52,
+               UNSUPPORTED_NAME_SYNTAX = 53,
+               CRL_PATH_VALIDATION_ERROR = 54,
+
+               /* Suite B mode algorithm violation */
+               SUITE_B_INVALID_VERSION = 56,
+               SUITE_B_INVALID_ALGORITHM = 57,
+               SUITE_B_INVALID_CURVE = 58,
+               SUITE_B_INVALID_SIGNATURE_ALGORITHM = 59,
+               SUITE_B_LOS_NOT_ALLOWED = 60,
+               SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 61,
+
+               /* Host, email and IP check errors */
+               HOSTNAME_MISMATCH = 62,
+               EMAIL_MISMATCH = 63,
+               IP_ADDRESS_MISMATCH = 64,
+
+               /* The application is not happy */
+               APPLICATION_VERIFICATION = 50
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Exception.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Exception.cs
new file mode 100644 (file)
index 0000000..588e7a7
--- /dev/null
@@ -0,0 +1,56 @@
+//
+// MonoBtlsX509Exception.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Exception : Exception
+       {
+               public MonoBtlsX509Error ErrorCode {
+                       get;
+                       private set;
+               }
+
+               public string ErrorMessage {
+                       get;
+                       private set;
+               }
+
+               public MonoBtlsX509Exception (MonoBtlsX509Error code, string message)
+                       : base (message)
+               {
+                       ErrorCode = code;
+                       ErrorMessage = message;
+               }
+
+               public override string ToString ()
+               {
+                       return string.Format ("[MonoBtlsX509Exception: ErrorCode={0}, ErrorMessage={1}]", ErrorCode, ErrorMessage);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509FileType.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509FileType.cs
new file mode 100644 (file)
index 0000000..67d26e6
--- /dev/null
@@ -0,0 +1,37 @@
+//
+// MonoBtlsX509FileType.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       enum MonoBtlsX509FileType
+       {
+               PEM = 1,
+               ASN1 = 2,
+               DEFAULT = 3
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Format.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Format.cs
new file mode 100644 (file)
index 0000000..551da69
--- /dev/null
@@ -0,0 +1,36 @@
+//
+// MonoBtlsX509Format.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       enum MonoBtlsX509Format
+       {
+               DER = 1,
+               PEM = 2
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Lookup.cs
new file mode 100644 (file)
index 0000000..3e8fb29
--- /dev/null
@@ -0,0 +1,217 @@
+//
+// MonoBtlsX509Lookup.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Lookup : MonoBtlsObject
+       {
+               internal class BoringX509LookupHandle : MonoBtlsHandle
+               {
+                       public BoringX509LookupHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_x509_lookup_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringX509LookupHandle Handle {
+                       get { return (BoringX509LookupHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_lookup_new (IntPtr store, MonoBtlsX509LookupType type);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_load_file (IntPtr handle, IntPtr file, MonoBtlsX509FileType type);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_add_dir (IntPtr handle, IntPtr dir, MonoBtlsX509FileType type);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_add_mono (IntPtr handle, IntPtr monoLookup);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_lookup_method_mono_init (
+                       IntPtr handle, IntPtr instance, IntPtr by_subject_func);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_init (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_shutdown (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_lookup_by_subject (IntPtr handle, IntPtr name);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_lookup_by_fingerprint (IntPtr handle, IntPtr bytes, int len);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_lookup_free (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_lookup_peek_lookup (IntPtr handle);
+
+               MonoBtlsX509LookupType type;
+               List<MonoBtlsX509LookupMono> monoLookups;
+
+#if FIXME
+               // Do we need this?
+               internal MonoBtlsX509Lookup (BoringX509LookupHandle handle)
+                       : base (handle)
+               {
+               }
+#endif
+
+               static BoringX509LookupHandle Create_internal (MonoBtlsX509Store store, MonoBtlsX509LookupType type)
+               {
+                       var handle = mono_btls_x509_lookup_new (
+                               store.Handle.DangerousGetHandle (), type);
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509LookupHandle (handle);
+               }
+
+               internal MonoBtlsX509Lookup (MonoBtlsX509Store store, MonoBtlsX509LookupType type)
+                       : base (Create_internal (store, type))
+               {
+                       this.type = type;
+               }
+
+               internal IntPtr GetNativeLookup ()
+               {
+                       return mono_btls_x509_lookup_peek_lookup (Handle.DangerousGetHandle ());
+               }
+
+               public void LoadFile (string file, MonoBtlsX509FileType type)
+               {
+                       IntPtr filePtr = IntPtr.Zero;
+                       try {
+                               if (file != null)
+                                       filePtr = Marshal.StringToHGlobalAnsi (file);
+                               var ret = mono_btls_x509_lookup_load_file (
+                                       Handle.DangerousGetHandle (), filePtr, type);
+                               CheckError (ret);
+                       } finally {
+                               if (filePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (filePtr);
+                       }
+               }
+
+               public void AddDirectory (string dir, MonoBtlsX509FileType type)
+               {
+                       IntPtr dirPtr = IntPtr.Zero;
+                       try {
+                               if (dir != null)
+                                       dirPtr = Marshal.StringToHGlobalAnsi (dir);
+                               var ret = mono_btls_x509_lookup_add_dir (
+                                       Handle.DangerousGetHandle (), dirPtr, type);
+                               CheckError (ret);
+                       } finally {
+                               if (dirPtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (dirPtr);
+                       }
+               }
+
+               // Takes ownership of the 'monoLookup'.
+               internal void AddMono (MonoBtlsX509LookupMono monoLookup)
+               {
+                       if (type != MonoBtlsX509LookupType.MONO)
+                               throw new NotSupportedException ();
+                       var ret = mono_btls_x509_lookup_add_mono (
+                               Handle.DangerousGetHandle (), monoLookup.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+
+                       if (monoLookups == null)
+                               monoLookups = new List<MonoBtlsX509LookupMono> ();
+                       monoLookups.Add (monoLookup);
+               }
+
+               public void Initialize ()
+               {
+                       var ret = mono_btls_x509_lookup_init (Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public void Shutdown ()
+               {
+                       var ret = mono_btls_x509_lookup_shutdown (Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public MonoBtlsX509 LookupBySubject (MonoBtlsX509Name name)
+               {
+                       var handle = mono_btls_x509_lookup_by_subject (
+                               Handle.DangerousGetHandle (),
+                               name.Handle.DangerousGetHandle ());
+                       if (handle == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (handle));
+               }
+
+               public MonoBtlsX509 LookupByFingerPrint (byte[] fingerprint)
+               {
+                       var bytes = Marshal.AllocHGlobal (fingerprint.Length);
+                       try {
+                               Marshal.Copy (fingerprint, 0, bytes, fingerprint.Length);
+                               var handle = mono_btls_x509_lookup_by_fingerprint (
+                                       Handle.DangerousGetHandle (),
+                                       bytes, fingerprint.Length);
+                               if (handle == IntPtr.Zero)
+                                       return null;
+                               return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (handle));
+                       } finally {
+                               if (bytes != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (bytes);
+                       }
+               }
+
+               protected override void Close ()
+               {
+                       try {
+                               if (monoLookups != null) {
+                                       foreach (var monoLookup in monoLookups)
+                                               monoLookup.Dispose ();
+                               monoLookups = null;
+                               }
+                       } finally {
+                               base.Close ();
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509LookupAndroid.cs
new file mode 100644 (file)
index 0000000..45f365c
--- /dev/null
@@ -0,0 +1,43 @@
+//
+// MonoBtlsX509LookupAndroid.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP && MONODROID
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Mono.Btls
+{
+       internal class MonoBtlsX509LookupAndroid : MonoBtlsX509LookupMono
+       {
+               protected override MonoBtlsX509 OnGetBySubject (MonoBtlsX509Name name)
+               {
+                       return AndroidPlatform.CertStoreLookup (name);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509LookupMono.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509LookupMono.cs
new file mode 100644 (file)
index 0000000..30b2ee3
--- /dev/null
@@ -0,0 +1,128 @@
+//
+// MonoBtlsX509LookupMono.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       abstract class MonoBtlsX509LookupMono : MonoBtlsObject
+       {
+               internal class BoringX509LookupMonoHandle : MonoBtlsHandle
+               {
+                       public BoringX509LookupMonoHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_x509_lookup_mono_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringX509LookupMonoHandle Handle {
+                       get { return (BoringX509LookupMonoHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_lookup_mono_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_lookup_mono_init (
+                       IntPtr handle, IntPtr instance, IntPtr by_subject_func);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_lookup_mono_free (IntPtr handle);
+
+               delegate int BySubjectFunc (IntPtr instance, IntPtr name, out IntPtr x509_ptr);
+
+               GCHandle gch;
+               IntPtr instance;
+               BySubjectFunc bySubjectFunc;
+               IntPtr bySubjectFuncPtr;
+
+               internal MonoBtlsX509LookupMono ()
+                       : base (new BoringX509LookupMonoHandle (mono_btls_x509_lookup_mono_new ()))
+               {
+                       gch = GCHandle.Alloc (this);
+                       instance = GCHandle.ToIntPtr (gch);
+                       bySubjectFunc = OnGetBySubject;
+                       bySubjectFuncPtr = Marshal.GetFunctionPointerForDelegate (bySubjectFunc);
+                       mono_btls_x509_lookup_mono_init (Handle.DangerousGetHandle (), instance, bySubjectFuncPtr);
+               }
+
+               protected abstract MonoBtlsX509 OnGetBySubject (MonoBtlsX509Name name);
+
+#if MONOTOUCH
+               [MonoTouch.MonoPInvokeCallback (typeof (BySubjectFunc))]
+#endif
+               static int OnGetBySubject (IntPtr instance, IntPtr name_ptr, out IntPtr x509_ptr)
+               {
+                       try {
+                               MonoBtlsX509LookupMono obj;
+                               MonoBtlsX509Name.BoringX509NameHandle name_handle = null;
+                               try {
+                                       obj = (MonoBtlsX509LookupMono)GCHandle.FromIntPtr (instance).Target;
+                                       name_handle = new MonoBtlsX509Name.BoringX509NameHandle (name_ptr, false);
+                                       MonoBtlsX509Name name_obj = new MonoBtlsX509Name (name_handle);
+                                       var x509 = obj.OnGetBySubject (name_obj);
+                                       if (x509 != null) {
+                                               x509_ptr = x509.Handle.StealHandle ();
+                                               return 1;
+                                       } else {
+                                               x509_ptr = IntPtr.Zero;
+                                               return 0;
+                                       }
+                               } finally {
+                                       if (name_handle != null)
+                                               name_handle.Dispose ();
+                               }
+                       } catch (Exception ex) {
+                               Console.WriteLine ("LOOKUP METHOD - GET BY SUBJECT EX: {0}", ex);
+                               x509_ptr = IntPtr.Zero;
+                               return 0;
+                       }
+               }
+
+               protected override void Close ()
+               {
+                       try {
+                               if (gch.IsAllocated)
+                                       gch.Free ();
+                       } finally {
+                               instance = IntPtr.Zero;
+                               bySubjectFunc = null;
+                               bySubjectFuncPtr = IntPtr.Zero;
+                               base.Close ();
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509LookupMonoCollection.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509LookupMonoCollection.cs
new file mode 100644 (file)
index 0000000..8a854f6
--- /dev/null
@@ -0,0 +1,102 @@
+//
+// MonoBtlsX509LookupMonoCollection.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+
+#if MONOTOUCH
+using MonoTouch;
+#endif
+
+namespace Mono.Btls
+{
+       internal class MonoBtlsX509LookupMonoCollection : MonoBtlsX509LookupMono
+       {
+               long[] hashes;
+               MonoBtlsX509[] certificates;
+               X509CertificateCollection collection;
+               MonoBtlsX509TrustKind trust;
+
+               internal MonoBtlsX509LookupMonoCollection (X509CertificateCollection collection, MonoBtlsX509TrustKind trust)
+               {
+                       this.collection = collection;
+                       this.trust = trust;
+               }
+
+               void Initialize ()
+               {
+                       if (certificates != null)
+                               return;
+
+                       hashes = new long [collection.Count];
+                       certificates = new MonoBtlsX509 [collection.Count];
+                       for (int i = 0; i < collection.Count; i++) {
+                               // Create new 'X509 *' instance since we need to modify it to add the
+                               // trust settings.
+                               var data = collection [i].GetRawCertData ();
+                               certificates [i] = MonoBtlsX509.LoadFromData (data, MonoBtlsX509Format.DER);
+                               certificates [i].AddExplicitTrust (trust);
+                               hashes [i] = certificates [i].GetSubjectNameHash ();
+                       }
+               }
+
+               protected override MonoBtlsX509 OnGetBySubject (MonoBtlsX509Name name)
+               {
+                       Console.WriteLine ("COLLECTION LOOKUP: {0:x} - {1}", name.GetHash (), name.GetString ());
+                       Initialize ();
+
+                       var hash = name.GetHash ();
+                       for (int i = 0; i < certificates.Length; i++) {
+                               if (hashes [i] == hash)
+                                       return certificates [i];
+                       }
+
+                       return null;
+               }
+
+               protected override void Close ()
+               {
+                       try {
+                               if (certificates != null) {
+                                       for (int i = 0; i < certificates.Length; i++) {
+                                               if (certificates [i] != null) {
+                                                       certificates [i].Dispose ();
+                                                       certificates [i] = null;
+                                               }
+                                       }
+                                       certificates = null;
+                                       hashes = null;
+                               }
+                       } finally {
+                               base.Close ();
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509LookupType.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509LookupType.cs
new file mode 100644 (file)
index 0000000..2cbdf7c
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// MonoBtlsX509LookupCollection.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+
+namespace Mono.Btls
+{
+       enum MonoBtlsX509LookupType
+       {
+               UNKNOWN = 0,
+               FILE,
+               HASH_DIR,
+               MONO
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Name.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Name.cs
new file mode 100644 (file)
index 0000000..9b3b723
--- /dev/null
@@ -0,0 +1,216 @@
+//
+// MonoBtlsX509Name.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Name : MonoBtlsObject
+       {
+               internal class BoringX509NameHandle : MonoBtlsHandle
+               {
+                       bool dontFree;
+
+                       internal BoringX509NameHandle (IntPtr handle, bool ownsHandle)
+                               : base (handle, ownsHandle)
+                       {
+                               this.dontFree = !ownsHandle;
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (!dontFree)
+                                       mono_btls_x509_name_free (handle);
+                               return true;
+                       }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_print_bio (IntPtr handle, IntPtr bio);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_print_string (IntPtr handle, IntPtr buffer, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_get_raw_data (IntPtr handle, out IntPtr buffer, int use_canon_enc);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_name_hash (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_name_hash_old (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_get_entry_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static MonoBtlsX509NameEntryType mono_btls_x509_name_get_entry_type (IntPtr name, int index);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_get_entry_oid (IntPtr name, int index, IntPtr buffer, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_get_entry_oid_data (IntPtr name, int index, out IntPtr data);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_get_entry_value (IntPtr name, int index, out IntPtr str);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern unsafe static IntPtr mono_btls_x509_name_from_data (void* data, int len, int use_canon_enc);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_name_free (IntPtr handle);
+
+               new internal BoringX509NameHandle Handle {
+                       get { return (BoringX509NameHandle)base.Handle; }
+               }
+
+               internal MonoBtlsX509Name (BoringX509NameHandle handle)
+                       : base (handle)
+               {
+               }
+
+               public string GetString ()
+               {
+                       const int size = 4096;
+                       var data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_name_print_string (
+                                       Handle.DangerousGetHandle (), data, size);
+                               CheckError (ret);
+                               return Marshal.PtrToStringAnsi (data);
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public void PrintBio (MonoBtlsBio bio)
+               {
+                       var ret = mono_btls_x509_name_print_bio (
+                               Handle.DangerousGetHandle (),
+                               bio.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public byte[] GetRawData (bool use_canon_enc)
+               {
+                       IntPtr data;
+                       var ret = mono_btls_x509_name_get_raw_data (
+                               Handle.DangerousGetHandle (),
+                               out data, use_canon_enc ? 1 : 0);
+                       CheckError (ret > 0);
+                       var buffer = new byte [ret];
+                       Marshal.Copy (data, buffer, 0, ret);
+                       FreeDataPtr (data);
+                       return buffer;
+               }
+
+               public long GetHash ()
+               {
+                       return mono_btls_x509_name_hash (Handle.DangerousGetHandle ());
+               }
+
+               public long GetHashOld ()
+               {
+                       return mono_btls_x509_name_hash_old (Handle.DangerousGetHandle ());
+               }
+
+               public int GetEntryCount ()
+               {
+                       return mono_btls_x509_name_get_entry_count (Handle.DangerousGetHandle ());
+               }
+
+               public MonoBtlsX509NameEntryType GetEntryType (int index)
+               {
+                       if (index >= GetEntryCount ())
+                               throw new ArgumentOutOfRangeException ();
+                       return mono_btls_x509_name_get_entry_type (
+                               Handle.DangerousGetHandle (), index);
+               }
+
+               public string GetEntryOid (int index)
+               {
+                       if (index >= GetEntryCount ())
+                               throw new ArgumentOutOfRangeException ();
+
+                       const int size = 4096;
+                       var data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_name_get_entry_oid (
+                                       Handle.DangerousGetHandle (),
+                                       index, data, size);
+                               CheckError (ret > 0);
+                               return Marshal.PtrToStringAnsi (data);
+                       } finally {
+                               Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public byte[] GetEntryOidData (int index)
+               {
+                       IntPtr data;
+                       var ret = mono_btls_x509_name_get_entry_oid_data (
+                               Handle.DangerousGetHandle (), index, out data);
+                       CheckError (ret > 0);
+
+                       var bytes = new byte[ret];
+                       Marshal.Copy (data, bytes, 0, ret);
+                       return bytes;
+               }
+
+               public unsafe string GetEntryValue (int index)
+               {
+                       if (index >= GetEntryCount ())
+                               throw new ArgumentOutOfRangeException ();
+                       IntPtr data;
+                       var ret = mono_btls_x509_name_get_entry_value (
+                               Handle.DangerousGetHandle (), index, out data);
+                       if (ret <= 0)
+                               return null;
+                       try {
+                               return new UTF8Encoding ().GetString ((byte*)data, ret);
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       FreeDataPtr (data);
+                       }
+               }
+
+               public static unsafe MonoBtlsX509Name CreateFromData (byte[] data, bool use_canon_enc)
+               {
+                       fixed (void *ptr = data) {
+                               var handle = mono_btls_x509_name_from_data (ptr, data.Length, use_canon_enc ? 1 : 0);
+                               if (handle == IntPtr.Zero)
+                                       throw new MonoBtlsException ("mono_btls_x509_name_from_data() failed.");
+                               return new MonoBtlsX509Name (new BoringX509NameHandle (handle, false));
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509NameEntryType.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509NameEntryType.cs
new file mode 100644 (file)
index 0000000..781d691
--- /dev/null
@@ -0,0 +1,51 @@
+//
+// MonoBtlsX509NameEntryType.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       enum MonoBtlsX509NameEntryType : int
+       {
+               Unknown = 0,
+               CountryName,
+               OrganizationName,
+               OrganizationalUnitName,
+               CommonName,
+               LocalityName,
+               StateOrProvinceName,
+               StreetAddress,
+               SerialNumber,
+               DomainComponent,
+               UserId,
+               Email,
+               DnQualifier,
+               Title,
+               Surname,
+               GivenName,
+               Initial
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509NameList.cs
new file mode 100644 (file)
index 0000000..cccc005
--- /dev/null
@@ -0,0 +1,121 @@
+//
+// MonoBtlsX509NameList.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509NameList : MonoBtlsObject
+       {
+               internal class BoringX509NameListHandle : MonoBtlsHandle
+               {
+                       bool dontFree;
+
+                       internal BoringX509NameListHandle (IntPtr handle, bool ownsHandle)
+                               : base (handle, ownsHandle)
+                       {
+                               this.dontFree = !ownsHandle;
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (!dontFree)
+                                       mono_btls_x509_name_list_free (handle);
+                               return true;
+                       }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_name_list_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_list_get_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_name_list_add (IntPtr handle, IntPtr name);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_name_list_get_item (IntPtr handle, int index);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_name_list_free (IntPtr handle);
+
+               new internal BoringX509NameListHandle Handle {
+                       get { return (BoringX509NameListHandle)base.Handle; }
+               }
+
+               internal MonoBtlsX509NameList (BoringX509NameListHandle handle)
+                       : base (handle)
+               {
+               }
+
+               internal MonoBtlsX509NameList ()
+                       : this (Create_internal ())
+               {
+               }
+
+               static BoringX509NameListHandle Create_internal ()
+               {
+                       var handle = mono_btls_x509_name_list_new ();
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509NameListHandle (handle, true);
+               }
+
+               public int GetCount ()
+               {
+                       CheckThrow ();
+                       return mono_btls_x509_name_list_get_count (
+                               Handle.DangerousGetHandle ());
+               }
+
+               public MonoBtlsX509Name GetItem (int index)
+               {
+                       CheckThrow ();
+                       if (index < 0 || index >= GetCount ())
+                               throw new ArgumentOutOfRangeException ();
+                       var ptr = mono_btls_x509_name_list_get_item (
+                               Handle.DangerousGetHandle (), index);
+                       if (ptr == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509Name (
+                               new MonoBtlsX509Name.BoringX509NameHandle (ptr, true));
+               }
+
+               public void Add (MonoBtlsX509Name name)
+               {
+                       CheckThrow ();
+                       mono_btls_x509_name_list_add (
+                               Handle.DangerousGetHandle (),
+                               name.Handle.DangerousGetHandle ());
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Purpose.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Purpose.cs
new file mode 100644 (file)
index 0000000..d80957c
--- /dev/null
@@ -0,0 +1,43 @@
+//
+// MonoBtlsX509Purpose.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       enum MonoBtlsX509Purpose
+       {
+               SSL_CLIENT = 1,
+               SSL_SERVER = 2,
+               NS_SSL_SERVER = 3,
+               SMIME_SIGN = 4,
+               SMIME_ENCRYPT = 5,
+               CRL_SIGN = 6,
+               ANY = 7,
+               OCSP_HELPER = 8,
+               TIMESTAMP_SIGN = 9,
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Revoked.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Revoked.cs
new file mode 100644 (file)
index 0000000..00aafa2
--- /dev/null
@@ -0,0 +1,120 @@
+//
+// MonoBtlsX509Revoked.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Revoked : MonoBtlsObject
+       {
+               internal class BoringX509RevokedHandle : MonoBtlsHandle
+               {
+                       public BoringX509RevokedHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (handle != IntPtr.Zero)
+                                       mono_btls_x509_revoked_free (handle);
+                               return true;
+                       }
+
+                       public IntPtr StealHandle ()
+                       {
+                               var retval = Interlocked.Exchange (ref handle, IntPtr.Zero);
+                               return retval;
+                       }
+               }
+
+               new internal BoringX509RevokedHandle Handle {
+                       get { return (BoringX509RevokedHandle)base.Handle; }
+               }
+
+               internal MonoBtlsX509Revoked (BoringX509RevokedHandle handle)
+                       : base (handle)
+               {
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_revoked_get_serial_number (IntPtr handle, IntPtr data, int size);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static long mono_btls_x509_revoked_get_revocation_date (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_revoked_get_reason (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_revoked_get_sequence (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_revoked_free (IntPtr handle);
+
+               public byte[] GetSerialNumber ()
+               {
+                       int size = 256;
+                       IntPtr data = Marshal.AllocHGlobal (size);
+                       try {
+                               var ret = mono_btls_x509_revoked_get_serial_number (
+                                       Handle.DangerousGetHandle (), data, size);
+                               CheckError (ret > 0);
+                               var buffer = new byte[ret];
+                               Marshal.Copy (data, buffer, 0, ret);
+                               return buffer;
+                       } finally {
+                               if (data != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (data);
+                       }
+               }
+
+               public DateTime GetRevocationDate ()
+               {
+                       var ticks = mono_btls_x509_revoked_get_revocation_date (
+                               Handle.DangerousGetHandle ());
+                       return new DateTime (1970, 1, 1).AddSeconds (ticks);
+               }
+
+               public int GetReason ()
+               {
+                       return mono_btls_x509_revoked_get_reason (Handle.DangerousGetHandle ());
+               }
+
+               public int GetSequence ()
+               {
+                       return mono_btls_x509_revoked_get_sequence (Handle.DangerousGetHandle ());
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509Store.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509Store.cs
new file mode 100644 (file)
index 0000000..2e03715
--- /dev/null
@@ -0,0 +1,230 @@
+//
+// MonoBtlsX509Store.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509Store : MonoBtlsObject
+       {
+               internal class BoringX509StoreHandle : MonoBtlsHandle
+               {
+                       public BoringX509StoreHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_x509_store_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringX509StoreHandle Handle {
+                       get { return (BoringX509StoreHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_from_ctx (IntPtr ctx);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_from_ssl_ctx (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_load_locations (IntPtr handle, IntPtr file, IntPtr path);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_set_default_paths (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_add_cert (IntPtr handle, IntPtr x509);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_get_count (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_store_free (IntPtr handle);
+
+               Dictionary<IntPtr,MonoBtlsX509Lookup> lookupHash;
+
+               public void LoadLocations (string file, string path)
+               {
+                       IntPtr filePtr = IntPtr.Zero;
+                       IntPtr pathPtr = IntPtr.Zero;
+                       try {
+                               if (file != null)
+                                       filePtr = Marshal.StringToHGlobalAnsi (file);
+                               if (path != null)
+                                       pathPtr = Marshal.StringToHGlobalAnsi (path);
+                               var ret = mono_btls_x509_store_load_locations (
+                                       Handle.DangerousGetHandle (), filePtr, pathPtr);
+                               CheckError (ret);
+                       } finally {
+                               if (filePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (filePtr);
+                               if (pathPtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (pathPtr);
+                       }
+               }
+
+               public void SetDefaultPaths ()
+               {
+                       var ret = mono_btls_x509_store_set_default_paths (Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               static BoringX509StoreHandle Create_internal ()
+               {
+                       var handle = mono_btls_x509_store_new ();
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509StoreHandle (handle);
+               }
+
+               static BoringX509StoreHandle Create_internal (IntPtr store_ctx)
+               {
+                       var handle = mono_btls_x509_store_from_ssl_ctx (store_ctx);
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509StoreHandle (handle);
+               }
+
+               static BoringX509StoreHandle Create_internal (MonoBtlsSslCtx.BoringSslCtxHandle ctx)
+               {
+                       var handle = mono_btls_x509_store_from_ssl_ctx (ctx.DangerousGetHandle ());
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509StoreHandle (handle);
+               }
+
+               internal MonoBtlsX509Store ()
+                       : base (Create_internal ())
+               {
+               }
+
+               internal MonoBtlsX509Store (IntPtr store_ctx)
+                       : base (Create_internal (store_ctx))
+               {
+               }
+
+               internal MonoBtlsX509Store (MonoBtlsSslCtx.BoringSslCtxHandle ctx)
+                       : base (Create_internal (ctx))
+               {
+               }
+
+               public void AddCertificate (MonoBtlsX509 x509)
+               {
+                       var ret = mono_btls_x509_store_add_cert (
+                               Handle.DangerousGetHandle (),
+                               x509.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public int GetCount ()
+               {
+                       return mono_btls_x509_store_get_count (Handle.DangerousGetHandle ());
+               }
+
+               internal void AddTrustedRoots ()
+               {
+                       var systemRoot = MonoBtlsProvider.GetSystemStoreLocation ();
+                       LoadLocations (null, systemRoot);
+               }
+
+               public MonoBtlsX509Lookup AddLookup (MonoBtlsX509LookupType type)
+               {
+                       if (lookupHash == null)
+                               lookupHash = new Dictionary<IntPtr,MonoBtlsX509Lookup> ();
+
+                       /*
+                        * X509_STORE_add_lookup() returns the same 'X509_LOOKUP *' for each
+                        * unique 'X509_LOOKUP_METHOD *' (which is supposed to be a static struct)
+                        * and we want to use the same managed object for each unique 'X509_LOOKUP *'.
+                       */
+                       var lookup = new MonoBtlsX509Lookup (this, type);
+                       var nativeLookup = lookup.GetNativeLookup ();
+                       if (lookupHash.ContainsKey (nativeLookup)) {
+                               lookup.Dispose ();
+                               lookup = lookupHash [nativeLookup];
+                       } else {
+                               lookupHash.Add (nativeLookup, lookup);
+                       }
+
+                       return lookup;
+               }
+
+               public void AddDirectoryLookup (string dir, MonoBtlsX509FileType type)
+               {
+                       var lookup = AddLookup (MonoBtlsX509LookupType.HASH_DIR);
+                       lookup.AddDirectory (dir, type);
+               }
+
+               public void AddFileLookup (string file, MonoBtlsX509FileType type)
+               {
+                       var lookup = AddLookup (MonoBtlsX509LookupType.FILE);
+                       lookup.LoadFile (file, type);
+               }
+
+               public void AddCollection (X509CertificateCollection collection, MonoBtlsX509TrustKind trust)
+               {
+                       var monoLookup = new MonoBtlsX509LookupMonoCollection (collection, trust);
+                       var lookup = new MonoBtlsX509Lookup (this, MonoBtlsX509LookupType.MONO);
+                       lookup.AddMono (monoLookup);
+               }
+
+#if MONODROID
+               public void AddAndroidLookup ()
+               {
+                       var androidLookup = new MonoBtlsX509LookupAndroid ();
+                       var lookup = new MonoBtlsX509Lookup (this, MonoBtlsX509LookupType.MONO);
+                       lookup.AddMono (androidLookup);
+               }
+#endif
+
+               protected override void Close ()
+               {
+                       try {
+                               if (lookupHash != null) {
+                                       foreach (var lookup in lookupHash.Values)
+                                               lookup.Dispose ();
+                                       lookupHash = null;
+                               }
+                       } finally {
+                               base.Close ();
+                       }
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509StoreCtx.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509StoreCtx.cs
new file mode 100644 (file)
index 0000000..41df129
--- /dev/null
@@ -0,0 +1,244 @@
+//
+// MonoBtlsX509StoreCtx.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509StoreCtx : MonoBtlsObject
+       {
+               internal class BoringX509StoreCtxHandle : MonoBtlsHandle
+               {
+                       bool dontFree;
+
+                       internal BoringX509StoreCtxHandle (IntPtr handle, bool ownsHandle = true)
+                               : base (handle, ownsHandle)
+                       {
+                               dontFree = !ownsHandle;
+                       }
+
+                       #if FIXME
+                       internal BoringX509StoreCtxHandle (IntPtr handle)
+                               : base ()
+                       {
+                               base.handle = handle;
+                               this.dontFree = true;
+                       }
+                       #endif
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               if (!dontFree)
+                                       mono_btls_x509_store_ctx_free (handle);
+                               return true;
+                       }
+               }
+
+               int? verifyResult;
+
+               new internal BoringX509StoreCtxHandle Handle {
+                       get { return (BoringX509StoreCtxHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_from_ptr (IntPtr ctx);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static MonoBtlsX509Error mono_btls_x509_store_ctx_get_error (IntPtr handle, out IntPtr error_string);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_ctx_get_error_depth (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_chain (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_ctx_init (IntPtr handle, IntPtr store, IntPtr chain);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_ctx_set_param (IntPtr handle, IntPtr param);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_store_ctx_verify_cert (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_by_subject (IntPtr handle, IntPtr name);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_current_cert (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_current_issuer (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_verify_param (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_get_untrusted (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_store_ctx_up_ref (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_store_ctx_free (IntPtr handle);
+
+               internal MonoBtlsX509StoreCtx ()
+                       : base (new BoringX509StoreCtxHandle (mono_btls_x509_store_ctx_new ()))
+               {
+               }
+
+               static BoringX509StoreCtxHandle Create_internal (IntPtr store_ctx)
+               {
+                       var handle = mono_btls_x509_store_ctx_from_ptr (store_ctx);
+                       if (handle == IntPtr.Zero)
+                               throw new MonoBtlsException ();
+                       return new BoringX509StoreCtxHandle (handle);
+               }
+
+               internal MonoBtlsX509StoreCtx (int preverify_ok, IntPtr store_ctx)
+                       : base (Create_internal (store_ctx))
+               {
+                       verifyResult = preverify_ok;
+               }
+
+               internal MonoBtlsX509StoreCtx (BoringX509StoreCtxHandle ptr, int? verifyResult)
+                       : base (ptr)
+               {
+                       this.verifyResult = verifyResult;
+               }
+
+               public MonoBtlsX509Error GetError ()
+               {
+                       IntPtr error_string_ptr;
+                       return mono_btls_x509_store_ctx_get_error (Handle.DangerousGetHandle (), out error_string_ptr);
+               }
+
+               public MonoBtlsX509Exception GetException ()
+               {
+                       IntPtr error_string_ptr;
+                       var error = mono_btls_x509_store_ctx_get_error (Handle.DangerousGetHandle (), out error_string_ptr);
+                       if (error == 0)
+                               return null;
+                       if (error_string_ptr != IntPtr.Zero) {
+                               var error_string = Marshal.PtrToStringAnsi (error_string_ptr);
+                               return new MonoBtlsX509Exception (error, error_string);
+                       }
+                       return new MonoBtlsX509Exception (error, "Unknown verify error.");
+               }
+
+               public MonoBtlsX509Chain GetChain ()
+               {
+                       var chain = mono_btls_x509_store_ctx_get_chain (Handle.DangerousGetHandle ());
+                       CheckError (chain != IntPtr.Zero);
+                       return new MonoBtlsX509Chain (new MonoBtlsX509Chain.BoringX509ChainHandle (chain));
+               }
+
+               public MonoBtlsX509Chain GetUntrusted ()
+               {
+                       var chain = mono_btls_x509_store_ctx_get_untrusted (Handle.DangerousGetHandle ());
+                       CheckError (chain != IntPtr.Zero);
+                       return new MonoBtlsX509Chain (new MonoBtlsX509Chain.BoringX509ChainHandle (chain));
+               }
+
+               public void Initialize (MonoBtlsX509Store store, MonoBtlsX509Chain chain)
+               {
+                       var ret = mono_btls_x509_store_ctx_init (
+                               Handle.DangerousGetHandle (),
+                               store.Handle.DangerousGetHandle (),
+                               chain.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public void SetVerifyParam (MonoBtlsX509VerifyParam param)
+               {
+                       var ret = mono_btls_x509_store_ctx_set_param (
+                               Handle.DangerousGetHandle (),
+                               param.Handle.DangerousGetHandle ());
+                       CheckError (ret);
+               }
+
+               public int VerifyResult {
+                       get {
+                               if (verifyResult == null)
+                                       throw new InvalidOperationException ();
+                               return verifyResult.Value;
+                       }
+               }
+
+               public int Verify ()
+               {
+                       verifyResult = mono_btls_x509_store_ctx_verify_cert (Handle.DangerousGetHandle ());
+                       return verifyResult.Value;
+               }
+
+               public MonoBtlsX509 LookupBySubject (MonoBtlsX509Name name)
+               {
+                       var handle = mono_btls_x509_store_ctx_get_by_subject (
+                               Handle.DangerousGetHandle (), name.Handle.DangerousGetHandle ());
+                       if (handle == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (handle));
+               }
+
+               public MonoBtlsX509 GetCurrentCertificate ()
+               {
+                       var x509 = mono_btls_x509_store_ctx_get_current_cert (Handle.DangerousGetHandle ());
+                       if (x509 == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (x509));
+               }
+
+               public MonoBtlsX509 GetCurrentIssuer ()
+               {
+                       var x509 = mono_btls_x509_store_ctx_get_current_issuer (Handle.DangerousGetHandle ());
+                       if (x509 == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509 (new MonoBtlsX509.BoringX509Handle (x509));
+               }
+
+               public MonoBtlsX509VerifyParam GetVerifyParam ()
+               {
+                       var param = mono_btls_x509_store_ctx_get_verify_param (Handle.DangerousGetHandle ());
+                       if (param == IntPtr.Zero)
+                               return null;
+                       return new MonoBtlsX509VerifyParam (new MonoBtlsX509VerifyParam.BoringX509VerifyParamHandle (param));
+               }
+
+               public MonoBtlsX509StoreCtx Copy ()
+               {
+                       var copy = mono_btls_x509_store_ctx_up_ref (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsX509StoreCtx (new BoringX509StoreCtxHandle (copy), verifyResult);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509StoreManager.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509StoreManager.cs
new file mode 100644 (file)
index 0000000..13c92a2
--- /dev/null
@@ -0,0 +1,120 @@
+//
+// MonoBtlsX509StoreManager.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+#endif
+
+using System;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+
+#if MONO_SECURITY_ALIAS
+using MonoSecurity::Mono.Security.Interface;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using Mono.Security.Interface;
+using MX = Mono.Security.X509;
+#endif
+
+namespace Mono.Btls
+{
+       static class MonoBtlsX509StoreManager
+       {
+               static bool initialized;
+               static string machineTrustedRootPath;
+               static string machineIntermediateCAPath;
+               static string machineUntrustedPath;
+               static string userTrustedRootPath;
+               static string userIntermediateCAPath;
+               static string userUntrustedPath;
+
+               static void Initialize ()
+               {
+                       if (initialized)
+                               return;
+
+                       try {
+                               DoInitialize ();
+                       } catch (Exception ex) {
+                               Console.Error.WriteLine ("MonoBtlsX509StoreManager.Initialize() threw exception: {0}", ex);
+                       } finally {
+                               initialized = true;
+                       }
+               }
+
+               static void DoInitialize ()
+               {
+#if !ANDROID
+                       var userPath = MX.X509StoreManager.NewCurrentUserPath;
+                       userTrustedRootPath = Path.Combine (userPath, MX.X509Stores.Names.TrustedRoot);
+                       userIntermediateCAPath = Path.Combine (userPath, MX.X509Stores.Names.IntermediateCA);
+                       userUntrustedPath = Path.Combine (userPath, MX.X509Stores.Names.Untrusted);
+
+                       var machinePath = MX.X509StoreManager.NewLocalMachinePath;
+                       machineTrustedRootPath = Path.Combine (userPath, MX.X509Stores.Names.TrustedRoot);
+                       machineIntermediateCAPath = Path.Combine (userPath, MX.X509Stores.Names.IntermediateCA);
+                       machineUntrustedPath = Path.Combine (userPath, MX.X509Stores.Names.Untrusted);
+#endif
+               }
+
+               public static bool HasStore (MonoBtlsX509StoreType type)
+               {
+#if ANDROID
+                       return false;
+#else
+                       var path = GetStorePath (type);
+                       return path != null && Directory.Exists (path);
+#endif
+               }
+
+               public static string GetStorePath (MonoBtlsX509StoreType type)
+               {
+#if ANDROID
+                       throw new NotSupportedException ();
+#else
+                       Initialize ();
+                       switch (type) {
+                       case MonoBtlsX509StoreType.MachineTrustedRoots:
+                               return machineTrustedRootPath;
+                       case MonoBtlsX509StoreType.MachineIntermediateCA:
+                               return machineIntermediateCAPath;
+                       case MonoBtlsX509StoreType.MachineUntrusted:
+                               return machineUntrustedPath;
+                       case MonoBtlsX509StoreType.UserTrustedRoots:
+                               return userTrustedRootPath;
+                       case MonoBtlsX509StoreType.UserIntermediateCA:
+                               return userIntermediateCAPath;
+                       case MonoBtlsX509StoreType.UserUntrusted:
+                               return userUntrustedPath;
+                       default:
+                               throw new NotSupportedException ();
+                       }
+#endif
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509StoreType.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509StoreType.cs
new file mode 100644 (file)
index 0000000..22cc072
--- /dev/null
@@ -0,0 +1,40 @@
+//
+// MonoBtlsX509StoreType.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+namespace Mono.Btls
+{
+       enum MonoBtlsX509StoreType
+       {
+               Custom,
+               MachineTrustedRoots,
+               MachineIntermediateCA,
+               MachineUntrusted,
+               UserTrustedRoots,
+               UserIntermediateCA,
+               UserUntrusted
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509TrustKind.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509TrustKind.cs
new file mode 100644 (file)
index 0000000..e207683
--- /dev/null
@@ -0,0 +1,42 @@
+//
+// MonoBtlsX509TrustKind.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       [Flags]
+       enum MonoBtlsX509TrustKind
+       {
+               DEFAULT         = 0,
+               TRUST_CLIENT    = 1,
+               TRUST_SERVER    = 2,
+               TRUST_ALL       = 4,
+               REJECT_CLIENT   = 32,
+               REJECT_SERVER   = 64,
+               REJECT_ALL      = 128
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509VerifyFlags.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509VerifyFlags.cs
new file mode 100644 (file)
index 0000000..628633b
--- /dev/null
@@ -0,0 +1,39 @@
+//
+// MonoBtlsX509VerifyFlags.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+namespace Mono.Btls
+{
+       [Flags]
+       enum MonoBtlsX509VerifyFlags
+       {
+               DEFAULT         = 0,
+               CRL_CHECK       = 1,
+               CRL_CHECK_ALL   = 2,
+               X509_STRIC      = 4
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/MonoBtlsX509VerifyParam.cs b/mcs/class/System/Mono.Btls/MonoBtlsX509VerifyParam.cs
new file mode 100644 (file)
index 0000000..59c210b
--- /dev/null
@@ -0,0 +1,277 @@
+//
+// MonoBtlsX509VerifyParam.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.CompilerServices;
+
+namespace Mono.Btls
+{
+       class MonoBtlsX509VerifyParam : MonoBtlsObject
+       {
+               internal class BoringX509VerifyParamHandle : MonoBtlsHandle
+               {
+                       public BoringX509VerifyParamHandle (IntPtr handle)
+                               : base (handle, true)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               mono_btls_x509_verify_param_free (handle);
+                               return true;
+                       }
+               }
+
+               new internal BoringX509VerifyParamHandle Handle {
+                       get { return (BoringX509VerifyParamHandle)base.Handle; }
+               }
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_verify_param_new ();
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_verify_param_copy (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_verify_param_lookup (IntPtr name);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_can_modify (IntPtr param);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_name (IntPtr handle, IntPtr name);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_host (IntPtr handle, IntPtr name, int namelen);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_add_host (IntPtr handle, IntPtr name, int namelen);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static ulong mono_btls_x509_verify_param_get_flags (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_flags (IntPtr handle, ulong flags);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static MonoBtlsX509VerifyFlags mono_btls_x509_verify_param_get_mono_flags (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_mono_flags (IntPtr handle, MonoBtlsX509VerifyFlags flags);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_purpose (IntPtr handle, MonoBtlsX509Purpose purpose);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_get_depth (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_depth (IntPtr handle, int depth);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static int mono_btls_x509_verify_param_set_time (IntPtr handle, long time);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static IntPtr mono_btls_x509_verify_param_get_peername (IntPtr handle);
+
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               extern static void mono_btls_x509_verify_param_free (IntPtr handle);
+
+               internal MonoBtlsX509VerifyParam ()
+                       : base (new BoringX509VerifyParamHandle (mono_btls_x509_verify_param_new ()))
+               {
+               }
+
+               internal MonoBtlsX509VerifyParam (BoringX509VerifyParamHandle handle)
+                       : base (handle)
+               {
+               }
+
+               public MonoBtlsX509VerifyParam Copy ()
+               {
+                       var copy = mono_btls_x509_verify_param_copy (Handle.DangerousGetHandle ());
+                       CheckError (copy != IntPtr.Zero);
+                       return new MonoBtlsX509VerifyParam (new BoringX509VerifyParamHandle (copy));
+               }
+
+               public static MonoBtlsX509VerifyParam GetSslClient ()
+               {
+                       return Lookup ("ssl_client", true);
+               }
+
+               public static MonoBtlsX509VerifyParam GetSslServer ()
+               {
+                       return Lookup ("ssl_server", true);
+               }
+
+               public static MonoBtlsX509VerifyParam Lookup (string name, bool fail = false)
+               {
+                       IntPtr namePtr = IntPtr.Zero;
+                       IntPtr handle = IntPtr.Zero;
+
+                       try {
+                               namePtr = Marshal.StringToHGlobalAnsi (name);
+                               handle = mono_btls_x509_verify_param_lookup (namePtr);
+                               if (handle == IntPtr.Zero) {
+                                       if (!fail)
+                                               return null;
+                                       throw new MonoBtlsException ("X509_VERIFY_PARAM_lookup() could not find '{0}'.", name);
+                               }
+
+                               return new MonoBtlsX509VerifyParam (new BoringX509VerifyParamHandle (handle));
+                       } finally {
+                               if (namePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (namePtr);
+                       }
+               }
+
+               public bool CanModify {
+                       get {
+                               return mono_btls_x509_verify_param_can_modify (Handle.DangerousGetHandle ()) != 0;
+                       }
+               }
+
+               void WantToModify ()
+               {
+                       if (!CanModify)
+                               throw new MonoBtlsException ("Attempting to modify read-only MonoBtlsX509VerifyParam instance.");
+               }
+
+               public void SetName (string name)
+               {
+                       WantToModify ();
+                       IntPtr namePtr = IntPtr.Zero;
+                       try {
+                               namePtr = Marshal.StringToHGlobalAnsi (name);
+                               var ret = mono_btls_x509_verify_param_set_name (
+                                       Handle.DangerousGetHandle (), namePtr);
+                               CheckError (ret);
+                       } finally {
+                               if (namePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (namePtr);
+                       }
+               }
+
+               public void SetHost (string name)
+               {
+                       WantToModify ();
+                       IntPtr namePtr = IntPtr.Zero;
+                       try {
+                               namePtr = Marshal.StringToHGlobalAnsi (name);
+                               var ret = mono_btls_x509_verify_param_set_host (
+                                       Handle.DangerousGetHandle (), namePtr, name.Length);
+                               CheckError (ret);
+                       } finally {
+                               if (namePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (namePtr);
+                       }
+               }
+
+               public void AddHost (string name)
+               {
+                       WantToModify ();
+                       IntPtr namePtr = IntPtr.Zero;
+                       try {
+                               namePtr = Marshal.StringToHGlobalAnsi (name);
+                               var ret = mono_btls_x509_verify_param_add_host (
+                                       Handle.DangerousGetHandle (), namePtr, name.Length);
+                               CheckError (ret);
+                       } finally {
+                               if (namePtr != IntPtr.Zero)
+                                       Marshal.FreeHGlobal (namePtr);
+                       }
+               }
+
+               public ulong GetFlags ()
+               {
+                       return mono_btls_x509_verify_param_get_flags (Handle.DangerousGetHandle ());
+               }
+
+               public void SetFlags (ulong flags)
+               {
+                       WantToModify ();
+                       var ret = mono_btls_x509_verify_param_set_flags (
+                               Handle.DangerousGetHandle (), flags);
+                       CheckError (ret);
+               }
+
+               public MonoBtlsX509VerifyFlags GetMonoFlags ()
+               {
+                       return mono_btls_x509_verify_param_get_mono_flags (
+                               Handle.DangerousGetHandle ());
+               }
+
+               public void SetMonoFlags (MonoBtlsX509VerifyFlags flags)
+               {
+                       WantToModify ();
+                       var ret = mono_btls_x509_verify_param_set_mono_flags (
+                               Handle.DangerousGetHandle (), flags);
+                       CheckError (ret);
+               }
+
+               public void SetPurpose (MonoBtlsX509Purpose purpose)
+               {
+                       WantToModify ();
+                       var ret = mono_btls_x509_verify_param_set_purpose (
+                               Handle.DangerousGetHandle (), purpose);
+                       CheckError (ret);
+               }
+
+               public int GetDepth ()
+               {
+                       return mono_btls_x509_verify_param_get_depth (Handle.DangerousGetHandle ());
+               }
+
+               public void SetDepth (int depth)
+               {
+                       WantToModify ();
+                       var ret = mono_btls_x509_verify_param_set_depth (
+                               Handle.DangerousGetHandle (), depth);
+                       CheckError (ret);
+               }
+
+               public void SetTime (DateTime time)
+               {
+                       WantToModify ();
+                       var epoch = new DateTime (1970, 1, 1);
+                       var ticks = (long)time.Subtract (epoch).TotalSeconds;
+                       var ret = mono_btls_x509_verify_param_set_time (
+                               Handle.DangerousGetHandle (), ticks);
+                       CheckError (ret);
+               }
+
+               public string GetPeerName ()
+               {
+                       var peer = mono_btls_x509_verify_param_get_peername (Handle.DangerousGetHandle ());
+                       if (peer == IntPtr.Zero)
+                               return null;
+                       return Marshal.PtrToStringAnsi (peer);
+               }
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs b/mcs/class/System/Mono.Btls/X509CertificateImplBtls.cs
new file mode 100644 (file)
index 0000000..022eb11
--- /dev/null
@@ -0,0 +1,390 @@
+//
+// X509CertificateImplBtls.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.Text;
+using System.Security;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using MX = Mono.Security.X509;
+
+namespace Mono.Btls
+{
+       class X509CertificateImplBtls : X509Certificate2Impl
+       {
+               MonoBtlsX509 x509;
+               MonoBtlsKey privateKey;
+               X500DistinguishedName subjectName;
+               X500DistinguishedName issuerName;
+               X509CertificateImplCollection intermediateCerts;
+               PublicKey publicKey;
+               bool archived;
+               bool disallowFallback;
+
+               internal X509CertificateImplBtls (bool disallowFallback = false)
+               {
+                       this.disallowFallback = disallowFallback;
+               }
+
+               internal X509CertificateImplBtls (MonoBtlsX509 x509, bool disallowFallback = false)
+               {
+                       this.disallowFallback = disallowFallback;
+                       this.x509 = x509.Copy ();
+               }
+
+               X509CertificateImplBtls (X509CertificateImplBtls other)
+               {
+                       disallowFallback = other.disallowFallback;
+                       x509 = other.x509 != null ? other.x509.Copy () : null;
+                       privateKey = other.privateKey != null ? other.privateKey.Copy () : null;
+                       if (other.intermediateCerts != null)
+                               intermediateCerts = other.intermediateCerts.Clone ();
+               }
+
+               internal X509CertificateImplBtls (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
+               {
+                       this.disallowFallback = disallowFallback;
+                       x509 = MonoBtlsX509.LoadFromData (data, format);
+               }
+
+               public override bool IsValid {
+                       get { return x509 != null && x509.IsValid; }
+               }
+
+               public override IntPtr Handle {
+                       get { return x509.Handle.DangerousGetHandle (); }
+               }
+
+               public override IntPtr GetNativeAppleCertificate ()
+               {
+                       return IntPtr.Zero;
+               }
+
+               internal MonoBtlsX509 X509 {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return x509;
+                       }
+               }
+
+               internal MonoBtlsKey NativePrivateKey {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return privateKey;
+                       }
+               }
+
+               public override X509CertificateImpl Clone ()
+               {
+                       ThrowIfContextInvalid ();
+                       return new X509CertificateImplBtls (this);
+               }
+
+               public override bool Equals (X509CertificateImpl other, out bool result)
+               {
+                       var otherBoringImpl = other as X509CertificateImplBtls;
+                       if (otherBoringImpl == null) {
+                               result = false;
+                               return false;
+                       }
+
+                       result = MonoBtlsX509.Compare (X509, otherBoringImpl.X509) == 0;
+                       return true;
+               }
+
+               protected override byte [] GetCertHash (bool lazy)
+               {
+                       return X509.GetCertHash ();
+               }
+
+               public override byte [] GetRawCertData ()
+               {
+                       return X509.GetRawData (MonoBtlsX509Format.DER);
+               }
+
+               public override string GetSubjectName (bool legacyV1Mode)
+               {
+                       if (legacyV1Mode)
+                               return SubjectName.Decode (X500DistinguishedNameFlags.None);
+                       return SubjectName.Name;
+               }
+
+               public override string GetIssuerName (bool legacyV1Mode)
+               {
+                       if (legacyV1Mode)
+                               return IssuerName.Decode (X500DistinguishedNameFlags.None);
+                       return IssuerName.Name;
+               }
+
+               public override DateTime GetValidFrom ()
+               {
+                       return X509.GetNotBefore ().ToLocalTime ();
+               }
+
+               public override DateTime GetValidUntil ()
+               {
+                       return X509.GetNotAfter ().ToLocalTime ();
+               }
+
+               public override byte[] GetPublicKey ()
+               {
+                       return X509.GetPublicKeyData ();
+               }
+
+               public override byte[] GetSerialNumber ()
+               {
+                       return X509.GetSerialNumber (true);
+               }
+
+               public override string GetKeyAlgorithm ()
+               {
+                       return PublicKey.Oid.Value;
+               }
+
+               public override byte[] GetKeyAlgorithmParameters ()
+               {
+                       return PublicKey.EncodedParameters.RawData;
+               }
+
+               public override byte [] Export (X509ContentType contentType, byte [] password)
+               {
+                       ThrowIfContextInvalid ();
+
+                       switch (contentType) {
+                       case X509ContentType.Cert:
+                               return GetRawCertData ();
+                       case X509ContentType.Pfx: // this includes Pkcs12
+                               // TODO
+                               throw new NotSupportedException ();
+                       case X509ContentType.SerializedCert:
+                               // TODO
+                               throw new NotSupportedException ();
+                       default:
+                               string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+                               throw new CryptographicException (msg);
+                       }
+               }
+
+               internal override X509CertificateImplCollection IntermediateCertificates {
+                       get { return intermediateCerts; }
+               }
+
+               public override string ToString (bool full)
+               {
+                       ThrowIfContextInvalid ();
+
+                       if (!full) {
+                               var summary = GetSubjectName (false);
+                               return string.Format ("[X509Certificate: {0}]", summary);
+                       }
+
+                       string nl = Environment.NewLine;
+                       StringBuilder sb = new StringBuilder ();
+                       sb.AppendFormat ("[Subject]{0}  {1}{0}{0}", nl, GetSubjectName (false));
+
+                       sb.AppendFormat ("[Issuer]{0}  {1}{0}{0}", nl, GetIssuerName (false));
+                       sb.AppendFormat ("[Not Before]{0}  {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+                       sb.AppendFormat ("[Not After]{0}  {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
+                       sb.AppendFormat ("[Thumbprint]{0}  {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+
+                       sb.Append (nl);
+                       return sb.ToString ();
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+                       if (x509 != null) {
+                               x509.Dispose ();
+                               x509 = null;
+                       }
+               }
+
+#region X509Certificate2Impl
+
+               X509Certificate2Impl fallback;
+
+               void MustFallback ()
+               {
+                       if (disallowFallback)
+                               throw new InvalidOperationException ();
+                       if (fallback != null)
+                               return;
+                       fallback = X509Helper2.Import (GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet);
+               }
+
+               internal X509Certificate2Impl FallbackImpl {
+                       get {
+                               MustFallback ();
+                               return fallback;
+                       }
+               }
+
+               [MonoTODO]
+               public override bool Archived {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return archived;
+                       }
+                       set {
+                               ThrowIfContextInvalid ();
+                               archived = value;
+                       }
+               }
+
+               public override X509ExtensionCollection Extensions {
+                       get { return FallbackImpl.Extensions; }
+               }
+
+               public override bool HasPrivateKey {
+                       get { return FallbackImpl.HasPrivateKey; }
+               }
+
+               public override X500DistinguishedName IssuerName {
+                       get {
+                               ThrowIfContextInvalid ();
+                               if (issuerName == null) {
+                                       using (var xname = x509.GetIssuerName ()) {
+                                               var encoding = xname.GetRawData (false);
+                                               var canonEncoding = xname.GetRawData (true);
+                                               var name = MonoBtlsUtils.FormatName (xname, true, ", ", true);
+                                               issuerName = new X500DistinguishedName (encoding, canonEncoding, name);
+                                       }
+                               }
+                               return issuerName;
+                       }
+               }
+
+               public override AsymmetricAlgorithm PrivateKey {
+                       get { return FallbackImpl.PrivateKey; }
+                       set { FallbackImpl.PrivateKey = value; }
+               }
+
+               public override PublicKey PublicKey {
+                       get {
+                               ThrowIfContextInvalid ();
+                               if (publicKey == null) {
+                                       var keyAsn = X509.GetPublicKeyAsn1 ();
+                                       var keyParamAsn = X509.GetPublicKeyParameters ();
+                                       publicKey = new PublicKey (keyAsn.Oid, keyParamAsn, keyAsn);
+                               }
+                               return publicKey;
+                       }
+               }
+
+               public override Oid SignatureAlgorithm {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return X509.GetSignatureAlgorithm ();
+                       }
+               }
+
+               public override X500DistinguishedName SubjectName {
+                       get {
+                               ThrowIfContextInvalid ();
+                               if (subjectName == null) {
+                                       using (var xname = x509.GetSubjectName ()) {
+                                               var encoding = xname.GetRawData (false);
+                                               var canonEncoding = xname.GetRawData (true);
+                                               var name = MonoBtlsUtils.FormatName (xname, true, ", ", true);
+                                               subjectName = new X500DistinguishedName (encoding, canonEncoding, name);
+                                       }
+                               }
+                               return subjectName;
+                       }
+               }
+
+               public override int Version {
+                       get { return X509.GetVersion (); }
+               }
+
+               public override string GetNameInfo (X509NameType nameType, bool forIssuer)
+               {
+                       return FallbackImpl.GetNameInfo (nameType, forIssuer);
+               }
+
+               public override void Import (byte [] data, string password, X509KeyStorageFlags keyStorageFlags)
+               {
+                       if (password == null) {
+                               // Does it look like PEM?
+                               if ((data.Length > 0) && (data [0] != 0x30))
+                                       x509 = MonoBtlsX509.LoadFromData (data, MonoBtlsX509Format.PEM);
+                               else
+                                       x509 = MonoBtlsX509.LoadFromData (data, MonoBtlsX509Format.DER);
+                               return;
+                       }
+
+                       using (var pkcs12 = new MonoBtlsPkcs12 ()) {
+                               pkcs12.Import (data, password);
+                               x509 = pkcs12.GetCertificate (0);
+                               if (pkcs12.HasPrivateKey)
+                                       privateKey = pkcs12.GetPrivateKey ();
+                               if (pkcs12.Count > 1) {
+                                       intermediateCerts = new X509CertificateImplCollection ();
+                                       for (int i = 0; i < pkcs12.Count; i++) {
+                                               using (var ic = pkcs12.GetCertificate (i)) {
+                                                       if (MonoBtlsX509.Compare (ic, x509) == 0)
+                                                               continue;
+                                                       var impl = new X509CertificateImplBtls (ic, true);
+                                                       intermediateCerts.Add (impl, true);
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               public override byte [] Export (X509ContentType contentType, string password)
+               {
+                       return FallbackImpl.Export (contentType, password);
+               }
+
+               public override bool Verify (X509Certificate2 thisCertificate)
+               {
+                       return FallbackImpl.Verify (thisCertificate);
+               }
+
+               public override void Reset ()
+               {
+                       if (x509 != null) {
+                               x509.Dispose ();
+                               x509 = null;
+                       }
+                       if (privateKey != null) {
+                               privateKey = null;
+                               privateKey = null;
+                       }
+                       subjectName = null;
+                       issuerName = null;
+                       archived = false;
+                       publicKey = null;
+                       intermediateCerts = null;
+                       if (fallback != null)
+                               fallback.Reset ();
+               }
+
+#endregion
+       }
+}
+#endif
diff --git a/mcs/class/System/Mono.Btls/X509ChainImplBtls.cs b/mcs/class/System/Mono.Btls/X509ChainImplBtls.cs
new file mode 100644 (file)
index 0000000..79a985c
--- /dev/null
@@ -0,0 +1,172 @@
+//
+// X509ChainImplBtls.cs
+//
+// Author:
+//       Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+#if SECURITY_DEP
+using System;
+using System.Text;
+using System.Security;
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using MX = Mono.Security.X509;
+
+namespace Mono.Btls
+{
+       class X509ChainImplBtls : X509ChainImpl
+       {
+               MonoBtlsX509StoreCtx storeCtx;
+               MonoBtlsX509Chain chain;
+               MonoBtlsX509Chain untrustedChain;
+               X509ChainElementCollection elements;
+               X509Certificate2Collection untrusted;
+               X509Certificate2[] certificates;
+               X509ChainPolicy policy;
+
+               internal X509ChainImplBtls (MonoBtlsX509Chain chain)
+               {
+                       this.chain = chain.Copy ();
+                       policy = new X509ChainPolicy ();
+               }
+
+               internal X509ChainImplBtls (MonoBtlsX509StoreCtx storeCtx)
+               {
+                       this.storeCtx = storeCtx.Copy ();
+                       this.chain = storeCtx.GetChain ();
+
+                       policy = new X509ChainPolicy ();
+
+                       untrustedChain = storeCtx.GetUntrusted ();
+
+                       if (untrustedChain != null) {
+                               untrusted = new X509Certificate2Collection ();
+                               policy.ExtraStore = untrusted;
+                               for (int i = 0; i < untrustedChain.Count; i++) {
+                                       using (var cert = untrustedChain.GetCertificate (i))
+                                       using (var impl = new X509CertificateImplBtls (cert))
+                                               untrusted.Add (new X509Certificate2 (impl));
+                               }
+                       }
+               }
+
+               internal X509ChainImplBtls ()
+               {
+                       chain = new MonoBtlsX509Chain ();
+                       elements = new X509ChainElementCollection ();
+                       policy = new X509ChainPolicy ();
+               }
+
+               public override bool IsValid {
+                       get { return chain != null && chain.IsValid; }
+               }
+
+               public override IntPtr Handle {
+                       get { return chain.Handle.DangerousGetHandle (); }
+               }
+
+               internal MonoBtlsX509Chain Chain {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return chain;
+                       }
+               }
+
+               internal MonoBtlsX509StoreCtx StoreCtx {
+                       get {
+                               ThrowIfContextInvalid ();
+                               return storeCtx;
+                       }
+               }
+
+               public override X509ChainElementCollection ChainElements {
+                       get {
+                               ThrowIfContextInvalid ();
+                               if (elements != null)
+                                       return elements;
+
+                               elements = new X509ChainElementCollection ();
+                               certificates = new X509Certificate2 [chain.Count];
+
+                               for (int i = 0; i < certificates.Length; i++) {
+                                       var cert = chain.GetCertificate (i);
+                                       var impl = new X509CertificateImplBtls (cert);
+                                       certificates [i] = new X509Certificate2 (impl);
+                                       elements.Add (certificates [i]);
+                               }
+
+                               return elements;
+                       }
+               }
+
+               public override X509ChainPolicy ChainPolicy {
+                       get { return policy; }
+                       set { policy = value; }
+               }
+
+               public override X509ChainStatus[] ChainStatus {
+                       get { throw new NotImplementedException (); }
+               }
+
+               public override bool Build (X509Certificate2 certificate)
+               {
+                       return false;
+               }
+
+               public override void Reset ()
+               {
+                       if (certificates != null) {
+                               foreach (var certificate in certificates)
+                                       certificate.Dispose ();
+                               certificates = null;
+                       }
+                       if (elements != null) {
+                               elements.Clear ();
+                               elements = null;
+                       }
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+                       if (disposing) {
+                               if (chain != null) {
+                                       chain.Dispose ();
+                                       chain = null;
+                               }
+                               if (storeCtx != null) {
+                                       storeCtx.Dispose ();
+                                       storeCtx = null;
+                               }
+                               if (untrustedChain != null) {
+                                       untrustedChain.Dispose ();
+                                       untrustedChain = null;
+                               }
+                               if (untrusted != null) {
+                                       foreach (var cert in untrusted)
+                                               cert.Dispose ();
+                               }
+                       }
+                       base.Dispose (disposing);
+               }
+       }
+}
+#endif
index 024b86a0f72e01ff27ff37c6543b606b0bdb8fc7..b1921208fc85962e2152d26a75af67518eb98e37 100644 (file)
@@ -314,6 +314,13 @@ namespace Mono.Net.Security
                                return new ValidationResult (result, user_denied, 0, (MonoSslPolicyErrors)errors);
                        }
 
+                       // Ignore port number when validating certificates.
+                       if (!string.IsNullOrEmpty (host)) {
+                               var pos = host.IndexOf (':');
+                               if (pos > 0)
+                                       host = host.Substring (0, pos);
+                       }
+
                        ICertificatePolicy policy = ServicePointManager.GetLegacyCertificatePolicy ();
 
                        int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
@@ -324,17 +331,9 @@ namespace Mono.Net.Security
                                        wantsChain = true;
                        }
 
-                       bool providerValidated = false;
-                       if (provider != null && provider.HasCustomSystemCertificateValidator) {
-                               var xerrors = (MonoSslPolicyErrors)errors;
-                               providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, wantsChain, ref chain, out result, ref xerrors, ref status11);
-                               errors = (SslPolicyErrors)xerrors;
-                       } else if (wantsChain) {
-                               chain = SystemCertificateValidator.CreateX509Chain (certs);
-                       }
-
-                       if (!providerValidated)
-                               result = SystemCertificateValidator.Evaluate (settings, host, certs, chain, ref errors, ref status11);
+                       var xerrors = (MonoSslPolicyErrors)errors;
+                       result = provider.ValidateCertificate (this, host, server, certs, wantsChain, ref chain, ref xerrors, ref status11);
+                       errors = (SslPolicyErrors)xerrors;
 
                        if (policy != null && (!(policy is DefaultCertificatePolicy) || certValidationCallback == null)) {
                                ServicePoint sp = null;
index cf84a406548c10749d4d6a5dc159c90453410323..942b5065ce90cf35c4fec30c7d5371f13b73e794 100644 (file)
@@ -69,12 +69,6 @@ namespace Mono.Net.Security
                IMonoSslStream CreateSslStream (
                        Stream innerStream, bool leaveInnerStreamOpen,
                        MonoTlsSettings settings);
-
-               IMonoTlsContext CreateTlsContext (
-                       string hostname, bool serverMode, TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus,
-                       MonoEncryptionPolicy encryptionPolicy, MonoTlsSettings settings);
 #endif
        }
 }
index 72996ded8e8ab1b9c4b023a9b64e5411fc33fbf3..7048f44c7b29d1310a6653149f0f8480ccf653ad 100644 (file)
@@ -70,10 +70,6 @@ namespace Mono.Net.Security
                        get { return false; }
                }
 
-               internal override bool SupportsTlsContext {
-                       get { return false; }
-               }
-
                public override SslProtocols SupportedProtocols {
                        get { return SslProtocols.Tls; }
                }
@@ -86,13 +82,17 @@ namespace Mono.Net.Security
                        return new Private.MonoSslStreamImpl (impl);
                }
 
-               internal override MSI.IMonoTlsContext CreateTlsContext (
-                       string hostname, bool serverMode, MSI.TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, MSI.MonoEncryptionPolicy encryptionPolicy,
-                       MSI.MonoTlsSettings settings)
+               internal override bool ValidateCertificate (
+                       MSI.ICertificateValidator2 validator, string targetHost, bool serverMode,
+                       X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
+                       ref MSI.MonoSslPolicyErrors errors, ref int status11)
                {
-                       throw new NotSupportedException ();
+                       if (wantsChain)
+                               chain = SystemCertificateValidator.CreateX509Chain (certificates);
+                       var xerrors = (SslPolicyErrors)errors;
+                       var result = SystemCertificateValidator.Evaluate (validator.Settings, targetHost, certificates, chain, ref xerrors, ref status11);
+                       errors = (MSI.MonoSslPolicyErrors)xerrors;
+                       return result;
                }
        }
 }
index 7ba425257f592e7432baac6850c980b0a5d22f94..6849b160bf35017241bdf78e4e6290bbf24748a8 100644 (file)
@@ -2,9 +2,7 @@
 #if SECURITY_DEP
 using System;
 using MSI = Mono.Security.Interface;
-#if HAVE_BTLS
 using Mono.Btls;
-#endif
 
 namespace Mono.Net.Security
 {
@@ -20,13 +18,9 @@ namespace Mono.Net.Security
                        case "legacy":
                                return new LegacyTlsProvider ();
                        case "btls":
-#if HAVE_BTLS
                                if (!MonoBtlsProvider.IsSupported ())
                                        throw new NotSupportedException ("BTLS in not supported!");
                                return new MonoBtlsProvider ();
-#else
-                               throw new NotSupportedException ("BTLS in not supported!");
-#endif
                        default:
                                throw new NotSupportedException (string.Format ("Invalid TLS Provider: `{0}'.", provider));
                        }
index 34d64334c1583e1ebe40d52830aabf5c1e07c8c4..ab6a536f2606730d1dee9361dae3479bf29ae50d 100644 (file)
@@ -156,10 +156,9 @@ namespace Mono.Net.Security
                                        return;
                                providerRegistration = new Dictionary<string,string> ();
                                providerRegistration.Add ("legacy", "Mono.Net.Security.LegacyTlsProvider");
-#if HAVE_BTLS
+                               providerRegistration.Add ("default", "Mono.Net.Security.LegacyTlsProvider");
                                if (Mono.Btls.MonoBtlsProvider.IsSupported ())
                                        providerRegistration.Add ("btls", "Mono.Btls.MonoBtlsProvider");
-#endif
                                X509Helper2.Initialize ();
                        }
                }
@@ -168,11 +167,8 @@ namespace Mono.Net.Security
                static MSI.MonoTlsProvider TryDynamicLoad ()
                {
                        var variable = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
-                       if (variable == null)
-                               return null;
-
-                       if (string.Equals (variable, "default", StringComparison.OrdinalIgnoreCase))
-                               return null;
+                       if (string.IsNullOrEmpty (variable))
+                               variable = "default";
 
                        return LookupProvider (variable, true);
                }
diff --git a/mcs/class/System/Mono.Net.Security/MonoTlsProviderImpl.cs b/mcs/class/System/Mono.Net.Security/MonoTlsProviderImpl.cs
deleted file mode 100644 (file)
index 94f86ca..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// MonoTlsProviderImpl.cs
-//
-// Author:
-//       Martin Baulig <martin.baulig@xamarin.com>
-//
-// Copyright (c) 2015 Xamarin, Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-#if SECURITY_DEP
-
-#if MONO_SECURITY_ALIAS
-extern alias MonoSecurity;
-#endif
-
-#if MONO_SECURITY_ALIAS
-using MSI = MonoSecurity::Mono.Security.Interface;
-#else
-using MSI = Mono.Security.Interface;
-#endif
-
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Security;
-using System.Security.Cryptography.X509Certificates;
-
-namespace Mono.Net.Security.Private
-{
-       /*
-        * Strictly private - do not use outside the Mono.Net.Security directory.
-        */
-       abstract class MonoTlsProviderImpl : MSI.MonoTlsProvider, IMonoTlsProvider
-       {
-               MSI.MonoTlsProvider IMonoTlsProvider.Provider {
-                       get { return this; }
-               }
-
-               IMonoSslStream IMonoTlsProvider.CreateSslStream (
-                       Stream innerStream, bool leaveInnerStreamOpen,
-                       MSI.MonoTlsSettings settings)
-               {
-                       return CreateSslStreamImpl (innerStream, leaveInnerStreamOpen, settings);
-               }
-
-               protected abstract IMonoSslStream CreateSslStreamImpl (
-                       Stream innerStream, bool leaveInnerStreamOpen,
-                       MSI.MonoTlsSettings settings);
-
-               public override MSI.IMonoSslStream CreateSslStream (
-                       Stream innerStream, bool leaveInnerStreamOpen,
-                       MSI.MonoTlsSettings settings = null)
-               {
-                       var sslStream = CreateSslStreamImpl (innerStream, leaveInnerStreamOpen, settings);
-                       return new MonoSslStreamImpl (sslStream);
-               }
-
-               MSI.IMonoTlsContext IMonoTlsProvider.CreateTlsContext (
-                       string hostname, bool serverMode, MSI.TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus,
-                       MSI.MonoEncryptionPolicy encryptionPolicy, MSI.MonoTlsSettings settings)
-               {
-                       return CreateTlsContextImpl (
-                               hostname, serverMode, protocolFlags,
-                               serverCertificate, clientCertificates,
-                               remoteCertRequired, encryptionPolicy, settings);
-               }
-
-               protected abstract MSI.IMonoTlsContext CreateTlsContextImpl (
-                       string hostname, bool serverMode, MSI.TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, MSI.MonoEncryptionPolicy encryptionPolicy,
-                       MSI.MonoTlsSettings settings);
-
-               internal override MSI.IMonoTlsContext CreateTlsContext (
-                       string hostname, bool serverMode, MSI.TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, MSI.MonoEncryptionPolicy encryptionPolicy,
-                       MSI.MonoTlsSettings settings)
-               {
-                       return CreateTlsContextImpl (
-                               hostname, serverMode, (MSI.TlsProtocols)protocolFlags,
-                               serverCertificate, clientCertificates,
-                               remoteCertRequired, (MSI.MonoEncryptionPolicy)encryptionPolicy,
-                               settings);
-               }
-       }
-}
-
-#endif
index 15283200590899b85f606eb3a2acfc9a08c6a9bb..0a81f4ff932ca159d11aa89a01ca09e9bbfd5240 100644 (file)
@@ -73,19 +73,6 @@ namespace Mono.Net.Security.Private
                                return monoSslStreamImpl.Impl;
                        return new MonoSslStreamWrapper (sslStream);
                }
-
-               public MSI.IMonoTlsContext CreateTlsContext (
-                       string hostname, bool serverMode, MSI.TlsProtocols protocolFlags,
-                       X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
-                       bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus,
-                       MSI.MonoEncryptionPolicy encryptionPolicy, MSI.MonoTlsSettings settings)
-               {
-                       return provider.CreateTlsContext (
-                               hostname, serverMode, protocolFlags,
-                               serverCertificate, clientCertificates,
-                               remoteCertRequired, (MSI.MonoEncryptionPolicy)encryptionPolicy,
-                               settings);
-               }
        }
 }
 
index eae64de07b8d7281931d2d9f0adec20318741f6e..62a424bb669ffd473e05aafea342bf3713a9fabc 100644 (file)
     <Compile Include="Mono.Net.Security\MonoSslStreamImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoSslStreamWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderFactory.cs" />\r
-    <Compile Include="Mono.Net.Security\MonoTlsProviderImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsStream.cs" />\r
     <Compile Include="Mono.Net.Security\NoReflectionHelper.cs" />\r
index 07dfdfa6fb3f05df163c9b8c046e7cf6b197215a..bd89dd5b2868dc0c1f469f9e68cc97e41f7c6fd3 100644 (file)
     <Compile Include="Mono.Net.Security\MonoSslStreamImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoSslStreamWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderFactory.cs" />\r
-    <Compile Include="Mono.Net.Security\MonoTlsProviderImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsStream.cs" />\r
     <Compile Include="Mono.Net.Security\NoReflectionHelper.cs" />\r
index 16f5809c7082d25214ec7087fe319d915e2bc3f0..29567cd320bf9946eb614e97f6b90f44804b1779 100644 (file)
     <Compile Include="Mono.Net.Security\MonoSslStreamImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoSslStreamWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderFactory.cs" />\r
-    <Compile Include="Mono.Net.Security\MonoTlsProviderImpl.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsProviderWrapper.cs" />\r
     <Compile Include="Mono.Net.Security\MonoTlsStream.cs" />\r
     <Compile Include="Mono.Net.Security\NoReflectionHelper.cs" />\r
diff --git a/mcs/class/System/System.Net.Security/SslStream.platformnotsupported.cs b/mcs/class/System/System.Net.Security/SslStream.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..1d3f040
--- /dev/null
@@ -0,0 +1,287 @@
+//
+// SslStream.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.IO;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+
+namespace System.Net.Security
+{
+       public class SslStream : AuthenticatedStream
+       {
+               const string EXCEPTION_MESSAGE = "System.Net.Security.SslStream is not supported on the current platform.";
+
+               public SslStream (Stream innerStream)
+                       : this (innerStream, false, null, null)
+               {
+               }
+
+               public SslStream (Stream innerStream, bool leaveInnerStreamOpen)
+                       : this (innerStream, leaveInnerStreamOpen, null, null)
+               {
+               }
+
+               public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback)
+                       : this (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, null)
+               {
+               }
+
+               public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback)
+                       : base (innerStream, leaveInnerStreamOpen)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public SslStream (Stream innerStream, bool leaveInnerStreamOpen, RemoteCertificateValidationCallback userCertificateValidationCallback, LocalCertificateSelectionCallback userCertificateSelectionCallback, EncryptionPolicy encryptionPolicy)
+                       : this (innerStream, leaveInnerStreamOpen, userCertificateValidationCallback, userCertificateSelectionCallback)
+               {
+               }
+
+               public virtual void AuthenticateAsClient (string targetHost)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual void AuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual IAsyncResult BeginAuthenticateAsClient (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual void EndAuthenticateAsClient (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual void AuthenticateAsServer (X509Certificate serverCertificate)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual void AuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual IAsyncResult BeginAuthenticateAsServer (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual void EndAuthenticateAsServer (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public TransportContext TransportContext {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual Task AuthenticateAsClientAsync (string targetHost)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual Task AuthenticateAsClientAsync (string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public virtual Task AuthenticateAsServerAsync (X509Certificate serverCertificate, bool clientCertificateRequired, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override bool IsAuthenticated {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsMutuallyAuthenticated {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsEncrypted {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsSigned {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool IsServer {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual SslProtocols SslProtocol {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual bool CheckCertRevocationStatus {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual X509Certificate LocalCertificate {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual X509Certificate RemoteCertificate {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual CipherAlgorithmType CipherAlgorithm {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual int CipherStrength {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual HashAlgorithmType HashAlgorithm {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual int HashStrength {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual ExchangeAlgorithmType KeyExchangeAlgorithm {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual int KeyExchangeStrength {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool CanSeek {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool CanRead {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool CanTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override bool CanWrite {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int ReadTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override int WriteTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override long Length {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override long Position {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public override void SetLength (long value)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override long Seek (long offset, SeekOrigin origin)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Flush ()
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               protected override void Dispose (bool disposing)
+               {
+               }
+
+               public override int Read (byte[] buffer, int offset, int count)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public void Write (byte[] buffer)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void Write (byte[] buffer, int offset, int count)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override IAsyncResult BeginRead (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override int EndRead (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override IAsyncResult BeginWrite (byte[] buffer, int offset, int count, AsyncCallback asyncCallback, object asyncState)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public override void EndWrite (IAsyncResult asyncResult)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+       }
+}
diff --git a/mcs/class/System/System.Net/AuthenticationManager.platformnotsupported.cs b/mcs/class/System/System.Net/AuthenticationManager.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..1572ce7
--- /dev/null
@@ -0,0 +1,77 @@
+//
+// AuthenticationManager.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Collections;
+using System.Collections.Specialized;
+
+namespace System.Net
+{
+       public class AuthenticationManager {
+               const string EXCEPTION_MESSAGE = "System.Net.AuthenticationManager is not supported on the current platform.";
+
+               private AuthenticationManager ()
+               {
+               }
+
+               public static ICredentialPolicy CredentialPolicy {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static StringDictionary CustomTargetNameDictionary {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static IEnumerator RegisteredModules {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static Authorization Authenticate (string challenge, WebRequest request, ICredentials credentials)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static Authorization PreAuthenticate (WebRequest request, ICredentials credentials)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void Register (IAuthenticationModule authenticationModule)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void Unregister (IAuthenticationModule authenticationModule)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static void Unregister (string authenticationScheme)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+       }
+}
index b37b9d30bfb1cdcb3adea83df147d9ac07ada83e..bffdfbc7011f2d24dfd17d0a671e48101d8e9154 100644 (file)
@@ -38,11 +38,6 @@ namespace System.Net {
                        throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
                }
 
-               internal HttpListener (System.Security.Cryptography.X509Certificates.X509Certificate certificate, Mono.Net.Security.IMonoTlsProvider tlsProvider, Mono.Security.Interface.MonoTlsSettings tlsSettings)
-               {
-                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
-               }
-
                public AuthenticationSchemes AuthenticationSchemes {
                        get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
                        set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
index 1d48dfe0b87af4f3729fa0b14caf4dc9558ab373..a57c579250ed33e6f27cb11ad04469840f3a06b3 100644 (file)
@@ -1320,8 +1320,11 @@ namespace System.Net
                                        msg = "Error: " + status;
                                        wex = new WebException (msg, status);
                                } else {
-                                       msg = String.Format ("Error: {0} ({1})", status, exc.Message);
-                                       wex = new WebException (msg, status, WebExceptionInternalStatus.RequestFatal, exc);
+                                       wex = exc as WebException;
+                                       if (wex == null) {
+                                               msg = String.Format ("Error: {0} ({1})", status, exc.Message);
+                                               wex = new WebException (msg, status, WebExceptionInternalStatus.RequestFatal, exc);
+                                       }
                                }
                                r.SetCompleted (false, wex);
                                r.DoCallback ();
index 5fc016498d277eb98522fbdfa334ff4fa096a960..3977c7bad9c96a0bad0ae81c01931ac9a2ab4e6d 100644 (file)
@@ -38,11 +38,6 @@ namespace System.Net
        {
                internal const string EXCEPTION_MESSAGE = "System.Net.HttpWebRequest is not supported on the current platform.";
 
-               internal WebConnection WebConnection {
-                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-               }
-
 #if MOBILE
                public
 #else
@@ -96,14 +91,6 @@ namespace System.Net
                        get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
                }
 
-               internal Mono.Net.Security.IMonoTlsProvider TlsProvider {
-                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-               }
-
-               internal Mono.Security.Interface.MonoTlsSettings TlsSettings {
-                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-               }
-
                public X509CertificateCollection ClientCertificates {
                        get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
                        set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
@@ -431,30 +418,5 @@ namespace System.Net
                {
                        throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
                }
-
-               internal void SetWriteStream (WebConnectionStream stream)
-               {
-                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
-               }
-
-               internal void SetResponseData (WebConnectionData data)
-               {
-                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
-               }
-
-               internal void SetResponseError (WebExceptionStatus status, Exception e, string where)
-               {
-                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
-               }
-
-               internal bool ReuseConnection {
-                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-               }
-
-               internal WebConnection StoredConnection {
-                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
-               }
        }
 }
index 9f7daa6c4523b2b5b3e9ef6585d0d19b7d5602d5..5402d58f522a0f413aac15f2dc281e19a66d4827 100644 (file)
@@ -225,7 +225,7 @@ namespace System.Net
                public string Server {
                        get {
                                CheckDisposed ();
-                               return webHeaders ["Server"]
+                               return webHeaders ["Server"] ?? "";
                        }
                }
                
diff --git a/mcs/class/System/System.Net/ServicePoint.platformnotsupported.cs b/mcs/class/System/System.Net/ServicePoint.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..d744a55
--- /dev/null
@@ -0,0 +1,127 @@
+//
+// ServicePoint.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Net.Sockets;
+using System.Security.Cryptography.X509Certificates;
+
+namespace System.Net
+{
+       public class ServicePoint
+       {
+               const string EXCEPTION_MESSAGE = "System.Net.ServicePoint is not supported on the current platform.";
+
+               ServicePoint () {}
+
+               public Uri Address {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               static Exception GetMustImplement ()
+               {
+                       return new NotImplementedException ();
+               }
+
+               public BindIPEndPoint BindIPEndPointDelegate
+               {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int ConnectionLeaseTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int ConnectionLimit {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public string ConnectionName {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int CurrentConnections {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public DateTime IdleSince {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int MaxIdleTime {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public virtual Version ProtocolVersion {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public int ReceiveBufferSize {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool SupportsPipelining {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool Expect100Continue {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public bool UseNagleAlgorithm {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public bool CloseConnectionGroup (string connectionGroupName)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public  X509Certificate Certificate {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public  X509Certificate ClientCertificate {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               // For reference source
+               internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
+}
diff --git a/mcs/class/System/System.Net/ServicePointManager.platformnotsupported.cs b/mcs/class/System/System.Net/ServicePointManager.platformnotsupported.cs
new file mode 100644 (file)
index 0000000..2593b65
--- /dev/null
@@ -0,0 +1,129 @@
+//
+// ServicePointManager.cs
+//
+// Author:
+//       Rolf Bjarne Kvinge <rolf@xamarin.com>
+//
+// Copyright (c) 2016 Xamarin, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+using System.Net.Security;
+
+namespace System.Net
+{
+       public partial class ServicePointManager {
+               const string EXCEPTION_MESSAGE = "System.Net.ServicePointManager is not supported on the current platform.";
+
+               public const int DefaultNonPersistentConnectionLimit = 4;
+#if MOBILE
+               public const int DefaultPersistentConnectionLimit = 10;
+#else
+               public const int DefaultPersistentConnectionLimit = 2;
+#endif
+
+               private ServicePointManager ()
+               {
+               }
+
+               public static ICertificatePolicy CertificatePolicy {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static bool CheckCertificateRevocationList {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static int DefaultConnectionLimit {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static int DnsRefreshTimeout {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static bool EnableDnsRoundRobin {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static int MaxServicePointIdleTime {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static int MaxServicePoints {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static bool ReusePort {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static SecurityProtocolType SecurityProtocol {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static RemoteCertificateValidationCallback ServerCertificateValidationCallback {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static EncryptionPolicy EncryptionPolicy {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static bool Expect100Continue {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static bool UseNagleAlgorithm {
+                       get { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+                       set { throw new PlatformNotSupportedException (EXCEPTION_MESSAGE); }
+               }
+
+               public static void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static ServicePoint FindServicePoint (Uri address)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static ServicePoint FindServicePoint (string uriString, IWebProxy proxy)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+
+               public static ServicePoint FindServicePoint (Uri address, IWebProxy proxy)
+               {
+                       throw new PlatformNotSupportedException (EXCEPTION_MESSAGE);
+               }
+       }
+}
index c1bd5271adf78ba7dbb25aac7638d8cb7a676378..afc452f7cc62474d137383f7941f292974007762 100644 (file)
@@ -293,6 +293,7 @@ namespace System.Net
 
                                Data.StatusCode = status;
                                Data.Challenge = result.GetValues ("Proxy-Authentic");
+                               Data.Headers = result;
                                return false;
                        } else if (status != 200) {
                                string msg = String.Format ("The remote server returned a {0} status code.", status);
@@ -368,6 +369,9 @@ namespace System.Net
                                        }
 
                                        status = (int)UInt32.Parse (parts [1]);
+                                       if (parts.Length >= 3)
+                                               Data.StatusDescription = String.Join (" ", parts, 2, parts.Length - 2);
+
                                        gotStatus = true;
                                }
                        }
@@ -738,7 +742,11 @@ namespace System.Net
                                Exception cnc_exc = connect_exception;
                                if (cnc_exc == null && (Data.StatusCode == 401 || Data.StatusCode == 407)) {
                                        st = WebExceptionStatus.ProtocolError;
-                                       cnc_exc = new WebException (Data.StatusCode == 407 ? "(407) Proxy Authentication Required" : "(401) Unauthorized" , st);
+                                       if (Data.Headers == null)
+                                               Data.Headers = new WebHeaderCollection ();
+
+                                       var webResponse = new HttpWebResponse (sPoint.Address, "CONNECT", Data, null);
+                                       cnc_exc = new WebException (Data.StatusCode == 407 ? "(407) Proxy Authentication Required" : "(401) Unauthorized", null, st, webResponse);
                                }
                        
                                connect_exception = null;
index 1dc234575b86a3cb6806c7b471f8d0ba8ec9f694..2fcdd982f33366e8b1b163a1aa178947232fbd74 100644 (file)
@@ -91,6 +91,9 @@ namespace System.Security.Cryptography.X509Certificates {
                                }
                                return store2;
                        }
+                       internal set {
+                               store2 = value;
+                       }
                }
 
                public X509RevocationFlag RevocationFlag {
index 2a9163a346f89ae143e7477b9215c67659f5e875..337dcaf9ed2dfa175757a106f15ec849a087f06e 100644 (file)
@@ -34,13 +34,54 @@ extern alias MonoSecurity;
 #if MONO_SECURITY_ALIAS
 using MonoSecurity::Mono.Security.Interface;
 #else
+#if !FEATURE_NO_BSD_SOCKETS
 using Mono.Security.Interface;
 #endif
+#endif
+
+#if !FEATURE_NO_BSD_SOCKETS
+using Mono.Btls;
+#endif
+#endif
+
+using System.IO;
+using System.Text;
 
 namespace System.Security.Cryptography.X509Certificates
 {
        internal static class X509Helper2
        {
+               internal static long GetSubjectNameHash (X509Certificate certificate)
+               {
+                       return GetSubjectNameHash (certificate.Impl);
+               }
+
+               internal static long GetSubjectNameHash (X509CertificateImpl impl)
+               {
+#if SECURITY_DEP
+                       using (var x509 = GetNativeInstance (impl))
+                               return GetSubjectNameHash (x509);
+#else
+                       throw new NotSupportedException ();
+#endif
+               }
+
+               internal static void ExportAsPEM (X509Certificate certificate, Stream stream, bool includeHumanReadableForm)
+               {
+                       ExportAsPEM (certificate.Impl, stream, includeHumanReadableForm);
+               }
+
+               internal static void ExportAsPEM (X509CertificateImpl impl, Stream stream, bool includeHumanReadableForm)
+               {
+#if SECURITY_DEP
+                       using (var x509 = GetNativeInstance (impl))
+                               ExportAsPEM (x509, stream, includeHumanReadableForm);
+#else
+                       throw new NotSupportedException ();
+#endif
+               }
+
+#if SECURITY_DEP
                internal static void Initialize ()
                {
                        X509Helper.InstallNativeHelper (new MyNativeHelper ());
@@ -51,26 +92,59 @@ namespace System.Security.Cryptography.X509Certificates
                        X509Helper.ThrowIfContextInvalid (impl);
                }
 
+#if FEATURE_NO_BSD_SOCKETS
+               static X509Certificate GetNativeInstance (X509CertificateImpl impl)
+               {
+                       throw new PlatformNotSupportedException ();
+               }
+#else
+               static MonoBtlsX509 GetNativeInstance (X509CertificateImpl impl)
+               {
+                       ThrowIfContextInvalid (impl);
+                       var btlsImpl = impl as X509CertificateImplBtls;
+                       if (btlsImpl != null)
+                               return btlsImpl.X509.Copy ();
+                       else
+                               return MonoBtlsX509.LoadFromData (impl.GetRawCertData (), MonoBtlsX509Format.DER);
+               }
+
+               internal static long GetSubjectNameHash (MonoBtlsX509 x509)
+               {
+                       using (var subject = x509.GetSubjectName ())
+                               return subject.GetHash ();
+               }
+
+               internal static void ExportAsPEM (MonoBtlsX509 x509, Stream stream, bool includeHumanReadableForm)
+               {
+                       using (var bio = MonoBtlsBio.CreateMonoStream (stream)) {
+                               x509.ExportAsPEM (bio, includeHumanReadableForm);
+                       }
+               }
+#endif // !FEATURE_NO_BSD_SOCKETS
+
                internal static X509Certificate2Impl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
                {
+#if !FEATURE_NO_BSD_SOCKETS
                        var provider = MonoTlsProviderFactory.GetProvider ();
                        if (provider.HasNativeCertificates) {
                                var impl = provider.GetNativeCertificate (rawData, password, keyStorageFlags);
                                return impl;
-                       } else {
-                               var impl = new X509Certificate2ImplMono ();
-                               impl.Import (rawData, password, keyStorageFlags);
-                               return impl;
                        }
+#endif // FEATURE_NO_BSD_SOCKETS
+                       var impl2 = new X509Certificate2ImplMono ();
+                       impl2.Import (rawData, password, keyStorageFlags);
+                       return impl2;
                }
 
                internal static X509Certificate2Impl Import (X509Certificate cert)
                {
+#if !FEATURE_NO_BSD_SOCKETS
                        var provider = MonoTlsProviderFactory.GetProvider ();
                        if (provider.HasNativeCertificates) {
                                var impl = provider.GetNativeCertificate (cert);
                                return impl;
                        }
+#endif // FEATURE_NO_BSD_SOCKETS
                        var impl2 = cert.Impl as X509Certificate2Impl;
                        if (impl2 != null)
                                return (X509Certificate2Impl)impl2.Clone ();
@@ -111,6 +185,6 @@ namespace System.Security.Cryptography.X509Certificates
                                return X509Helper2.Import (cert);
                        }
                }
+#endif
        }
 }
-#endif
index 9019abc8e34a18ed382844b4056e84da5468422e..eca011f5bae7492477124fe6e7ff515c19d7c35a 100644 (file)
@@ -538,6 +538,45 @@ System.Windows.Input/ICommand.cs
 
 System/IOSelector.cs
 
+Mono.Btls/MonoBtlsBio.cs
+Mono.Btls/MonoBtlsContext.cs
+Mono.Btls/MonoBtlsError.cs
+Mono.Btls/MonoBtlsException.cs
+Mono.Btls/MonoBtlsKey.cs
+Mono.Btls/MonoBtlsObject.cs
+Mono.Btls/MonoBtlsPkcs12.cs
+Mono.Btls/MonoBtlsProvider.cs
+Mono.Btls/MonoBtlsSsl.cs
+Mono.Btls/MonoBtlsSslCtx.cs
+Mono.Btls/MonoBtlsSslError.cs
+Mono.Btls/MonoBtlsStream.cs
+Mono.Btls/MonoBtlsUtils.cs
+Mono.Btls/MonoBtlsX509.cs
+Mono.Btls/MonoBtlsX509Chain.cs
+Mono.Btls/MonoBtlsX509Crl.cs
+Mono.Btls/MonoBtlsX509Error.cs
+Mono.Btls/MonoBtlsX509Exception.cs
+Mono.Btls/MonoBtlsX509FileType.cs
+Mono.Btls/MonoBtlsX509Format.cs
+Mono.Btls/MonoBtlsX509Lookup.cs
+Mono.Btls/MonoBtlsX509LookupMono.cs
+Mono.Btls/MonoBtlsX509LookupMonoCollection.cs
+Mono.Btls/MonoBtlsX509LookupType.cs
+Mono.Btls/MonoBtlsX509Name.cs
+Mono.Btls/MonoBtlsX509NameList.cs
+Mono.Btls/MonoBtlsX509NameEntryType.cs
+Mono.Btls/MonoBtlsX509Purpose.cs
+Mono.Btls/MonoBtlsX509Revoked.cs
+Mono.Btls/MonoBtlsX509Store.cs
+Mono.Btls/MonoBtlsX509StoreCtx.cs
+Mono.Btls/MonoBtlsX509StoreManager.cs
+Mono.Btls/MonoBtlsX509StoreType.cs
+Mono.Btls/MonoBtlsX509TrustKind.cs
+Mono.Btls/MonoBtlsX509VerifyFlags.cs
+Mono.Btls/MonoBtlsX509VerifyParam.cs
+Mono.Btls/X509CertificateImplBtls.cs
+Mono.Btls/X509ChainImplBtls.cs
+
 Mono.Net.Security/AsyncProtocolRequest.cs
 Mono.Net.Security/CallbackHelpers.cs
 Mono.Net.Security/ChainValidationHelper.cs
@@ -550,7 +589,6 @@ Mono.Net.Security/LegacyTlsProvider.cs
 Mono.Net.Security/MonoSslStreamImpl.cs
 Mono.Net.Security/MonoSslStreamWrapper.cs
 Mono.Net.Security/MonoTlsProviderFactory.cs
-Mono.Net.Security/MonoTlsProviderImpl.cs
 Mono.Net.Security/MonoTlsProviderWrapper.cs
 Mono.Net.Security/MonoTlsStream.cs
 Mono.Net.Security/NoReflectionHelper.cs
index 1f010668d722f454e024aecb54db05e68905f3a6..5d59fa64718a600b4d0cb4d16a0a3ae9a3893ad0 100644 (file)
@@ -33,6 +33,7 @@ using System.Net.Security;
 using System.Security.Cryptography.X509Certificates;
 #if SECURITY_DEP
 using MSX = Mono.Security.X509;
+using Mono.Btls;
 #endif
 
 namespace System {
@@ -43,6 +44,7 @@ namespace System {
                
 #if SECURITY_DEP
                static readonly Converter<List <byte[]>, bool> trustEvaluateSsl;
+               static readonly Func<long, bool, byte[]> certStoreLookup;
 #endif  // SECURITY_DEP
                static readonly Func<IWebProxy> getDefaultProxy;
                static readonly GetInterfaceAddressesDelegate getInterfaceAddresses;
@@ -58,6 +60,12 @@ namespace System {
                                                        "TrustEvaluateSsl",
                                                        ignoreCase:false,
                                                        throwOnBindFailure:true);
+                       certStoreLookup = (Func<long, bool, byte[]>)
+                               Delegate.CreateDelegate (typeof (Func<long, bool, byte[]>),
+                                                       t,
+                                                       "CertStoreLookup",
+                                                       ignoreCase:false,
+                                                       throwOnBindFailure:true);
 #endif  // SECURITY_DEP
                        getDefaultProxy = (Func<IWebProxy>)Delegate.CreateDelegate (
                                typeof (Func<IWebProxy>), t, "GetDefaultProxy",
@@ -83,6 +91,24 @@ namespace System {
                                certsRawData.Add (cert.GetRawCertData ());
                        return trustEvaluateSsl (certsRawData);
                }
+
+               internal static MonoBtlsX509 CertStoreLookup (MonoBtlsX509Name name)
+               {
+                       var hash = name.GetHash ();
+                       var hashOld = name.GetHashOld ();
+                       var result = certStoreLookup (hash, false);
+                       if (result == null)
+                               result = certStoreLookup (hashOld, false);
+                       if (result == null)
+                               result = certStoreLookup (hash, true);
+                       if (result == null)
+                               result = certStoreLookup (hashOld, true);
+
+                       if (result == null)
+                               return null;
+
+                       return MonoBtlsX509.LoadFromData (result, MonoBtlsX509Format.DER);
+               }
 #endif  // SECURITY_DEP
 
                internal static IWebProxy GetDefaultProxy ()
index b0616ac7966c9e8c29deb25b5aa6f7f954ed4a09..14ec2700869c289ee1159851c5402e07138b70a5 100755 (executable)
@@ -2717,6 +2717,9 @@ namespace MonoTests.System.Net.Sockets
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (AggregateException))] // Something catches the PlatformNotSupportedException and re-throws an AggregateException    
+#endif
                public void ConcurrentExceedSocketLimit ()
                {
                        var tasks = new Task[4];
@@ -2727,6 +2730,9 @@ namespace MonoTests.System.Net.Sockets
                }
 
                [Test]
+#if FEATURE_NO_BSD_SOCKETS
+               [ExpectedException (typeof (PlatformNotSupportedException))]
+#endif
                public void SendGenericExceedBuffer ()
                {
                        // Create a buffer larger than the default max.
index 8922c14f00e65e1afe983af6cd8aa7b6d1a0685c..b6808979e4a2d77c8cfce2252e67568d7466a333 100644 (file)
@@ -29,8 +29,10 @@ public class ServicePointManagerTest
        [SetUp]\r
         public void GetReady () \r
        {\r
+#if !FEATURE_NO_BSD_SOCKETS\r
                maxIdle = ServicePointManager.MaxServicePointIdleTime;\r
                ServicePointManager.MaxServicePointIdleTime = 10;\r
+#endif\r
                googleUri = new Uri ("http://www.google.com");\r
                yahooUri = new Uri ("http://www.yahoo.com");\r
                apacheUri = new Uri ("http://www.apache.org");\r
@@ -39,7 +41,9 @@ public class ServicePointManagerTest
        [TearDown]\r
        public void Finish ()\r
        {\r
+#if !FEATURE_NO_BSD_SOCKETS\r
                ServicePointManager.MaxServicePointIdleTime = maxIdle;\r
+#endif\r
        }\r
 \r
         [Test, ExpectedException (typeof (InvalidOperationException))]\r
@@ -82,6 +86,9 @@ public class ServicePointManagerTest
        }\r
        \r
         [Test]\r
+#if FEATURE_NO_BSD_SOCKETS\r
+       [ExpectedException (typeof (PlatformNotSupportedException))]\r
+#endif\r
        public void FindServicePoint ()\r
        {\r
                ServicePointManager.MaxServicePoints = 0;\r
index 1e848148f92c21783688163be5f07e1fcb669a87..6171a2fd25587d85a535b496111aa114628536e0 100644 (file)
@@ -23,6 +23,8 @@ namespace MonoTests.System.Net
 public class ServicePointTest\r
 {\r
        static private int max;\r
+\r
+#if !FEATURE_NO_BSD_SOCKETS\r
        [SetUp]\r
        public void SaveMax () {\r
                max = ServicePointManager.MaxServicePoints;\r
@@ -33,6 +35,7 @@ public class ServicePointTest
        public void RestoreMax () {\r
                ServicePointManager.MaxServicePoints = max;\r
        }\r
+#endif\r
 \r
         [Test]\r
                [Category ("InetAccess")]\r
index 4096f15d09a9f07f802af08cd01d421528571049..8eb0ae99dc15857a48aee48b7ea09ff939e209fd 100644 (file)
@@ -297,12 +297,50 @@ Mono.Net.Security/LegacyTlsProvider.cs
 Mono.Net.Security/MonoSslStreamImpl.cs
 Mono.Net.Security/MonoSslStreamWrapper.cs
 Mono.Net.Security/MonoTlsProviderFactory.cs
-Mono.Net.Security/MonoTlsProviderImpl.cs
 Mono.Net.Security/MonoTlsProviderWrapper.cs
 Mono.Net.Security/MonoTlsStream.cs
 Mono.Net.Security/NoReflectionHelper.cs
 Mono.Net.Security/SystemCertificateValidator.cs
 
+Mono.Btls/MonoBtlsBio.cs
+Mono.Btls/MonoBtlsContext.cs
+Mono.Btls/MonoBtlsError.cs
+Mono.Btls/MonoBtlsException.cs
+Mono.Btls/MonoBtlsKey.cs
+Mono.Btls/MonoBtlsObject.cs
+Mono.Btls/MonoBtlsPkcs12.cs
+Mono.Btls/MonoBtlsProvider.cs
+Mono.Btls/MonoBtlsSsl.cs
+Mono.Btls/MonoBtlsSslCtx.cs
+Mono.Btls/MonoBtlsSslError.cs
+Mono.Btls/MonoBtlsStream.cs
+Mono.Btls/MonoBtlsUtils.cs
+Mono.Btls/MonoBtlsX509.cs
+Mono.Btls/MonoBtlsX509Chain.cs
+Mono.Btls/MonoBtlsX509Crl.cs
+Mono.Btls/MonoBtlsX509Error.cs
+Mono.Btls/MonoBtlsX509Exception.cs
+Mono.Btls/MonoBtlsX509FileType.cs
+Mono.Btls/MonoBtlsX509Format.cs
+Mono.Btls/MonoBtlsX509Lookup.cs
+Mono.Btls/MonoBtlsX509LookupMonoCollection.cs
+Mono.Btls/MonoBtlsX509LookupMono.cs
+Mono.Btls/MonoBtlsX509LookupType.cs
+Mono.Btls/MonoBtlsX509Name.cs
+Mono.Btls/MonoBtlsX509NameList.cs
+Mono.Btls/MonoBtlsX509NameEntryType.cs
+Mono.Btls/MonoBtlsX509Purpose.cs
+Mono.Btls/MonoBtlsX509Revoked.cs
+Mono.Btls/MonoBtlsX509Store.cs
+Mono.Btls/MonoBtlsX509StoreCtx.cs
+Mono.Btls/MonoBtlsX509StoreManager.cs
+Mono.Btls/MonoBtlsX509StoreType.cs
+Mono.Btls/MonoBtlsX509TrustKind.cs
+Mono.Btls/MonoBtlsX509VerifyFlags.cs
+Mono.Btls/MonoBtlsX509VerifyParam.cs
+Mono.Btls/X509CertificateImplBtls.cs
+Mono.Btls/X509ChainImplBtls.cs
+
 ReferenceSources/AutoWebProxyScriptEngine.cs
 ReferenceSources/AssertWrapper.cs
 ReferenceSources/CAPI.cs
@@ -942,7 +980,6 @@ ReferenceSources/Win32Exception.cs
 ../Mono.Security/Mono.Security.Interface/HashAlgorithmType.cs
 ../Mono.Security/Mono.Security.Interface/IBufferOffsetSize.cs
 ../Mono.Security/Mono.Security.Interface/IMonoTlsEventSink.cs
-../Mono.Security/Mono.Security.Interface/IMonoTlsContext.cs
 ../Mono.Security/Mono.Security.Interface/IMonoSslStream.cs
 ../Mono.Security/Mono.Security.Interface/MonoTlsConnectionInfo.cs
 ../Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs
index 686004bd3b16c16676290b8c5bec21daaa5b0827..c2950c536caf33f5d6f337df9463118118f248e8 100644 (file)
@@ -1,3 +1,4 @@
 #include mobile_System.dll.sources
 System/AndroidPlatform.cs
 Mono.Net.Security/MonoTlsProviderFactory.Droid.cs
+Mono.Btls/MonoBtlsX509LookupAndroid.cs
index 0138e11713a9d2305890b72e09a231a581cbf130..384223cfee9079dc93c988eb752e34520ad05dd2 100644 (file)
+../Mono.Security/Mono.Security.Authenticode/PrivateKey.cs
+../Mono.Security/Mono.Security.Cryptography/MD5SHA1.cs
+../Mono.Security/Mono.Security.Cryptography/TlsHMAC.cs
+../Mono.Security/Mono.Security.Interface/Alert.cs
+../Mono.Security/Mono.Security.Interface/CertificateValidationHelper.cs
+../Mono.Security/Mono.Security.Interface/CipherAlgorithmType.cs
+../Mono.Security/Mono.Security.Interface/CipherSuiteCode.cs
+../Mono.Security/Mono.Security.Interface/ExchangeAlgorithmType.cs
+../Mono.Security/Mono.Security.Interface/HashAlgorithmType.cs
+../Mono.Security/Mono.Security.Interface/IBufferOffsetSize.cs
+../Mono.Security/Mono.Security.Interface/IMonoSslStream.cs
+../Mono.Security/Mono.Security.Interface/IMonoTlsContext.cs
+../Mono.Security/Mono.Security.Interface/IMonoTlsEventSink.cs
+../Mono.Security/Mono.Security.Interface/MonoTlsConnectionInfo.cs
+../Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs
+../Mono.Security/Mono.Security.Interface/MonoTlsProviderFactory.Apple.cs
+../Mono.Security/Mono.Security.Interface/MonoTlsProviderFactory.cs
+../Mono.Security/Mono.Security.Interface/MonoTlsSettings.cs
+../Mono.Security/Mono.Security.Interface/TlsException.cs
+../Mono.Security/Mono.Security.Interface/TlsProtocolCode.cs
+../Mono.Security/Mono.Security.Interface/TlsProtocols.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/ChallengeResponse2.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/MessageBase.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/NtlmAuthLevel.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/NtlmFlags.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/NtlmSettings.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/Type1Message.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/Type2Message.cs
+../Mono.Security/Mono.Security.Protocol.Ntlm/Type3Message.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsClientCertificate.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsClientCertificateVerify.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsClientFinished.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsClientHello.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsClientKeyExchange.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerCertificate.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerCertificateRequest.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerFinished.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerHello.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerHelloDone.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Client/TlsServerKeyExchange.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsClientCertificate.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsClientCertificateVerify.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsClientFinished.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsClientHello.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsClientKeyExchange.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerCertificate.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerCertificateRequest.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerFinished.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerHello.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerHelloDone.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake.Server/TlsServerKeyExchange.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake/ClientCertificateType.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake/HandshakeMessage.cs
+../Mono.Security/Mono.Security.Protocol.Tls.Handshake/HandshakeType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/Alert.cs
+../Mono.Security/Mono.Security.Protocol.Tls/CipherAlgorithmType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/CipherSuite.cs
+../Mono.Security/Mono.Security.Protocol.Tls/CipherSuiteCollection.cs
+../Mono.Security/Mono.Security.Protocol.Tls/CipherSuiteFactory.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ClientContext.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ClientRecordProtocol.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ClientSessionCache.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ContentType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/Context.cs
+../Mono.Security/Mono.Security.Protocol.Tls/DebugHelper.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ExchangeAlgorithmType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/HandshakeState.cs
+../Mono.Security/Mono.Security.Protocol.Tls/HashAlgorithmType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/HttpsClientStream.cs
+../Mono.Security/Mono.Security.Protocol.Tls/RecordProtocol.cs
+../Mono.Security/Mono.Security.Protocol.Tls/RSASslSignatureDeformatter.cs
+../Mono.Security/Mono.Security.Protocol.Tls/RSASslSignatureFormatter.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SecurityCompressionType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SecurityParameters.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SecurityProtocolType.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ServerContext.cs
+../Mono.Security/Mono.Security.Protocol.Tls/ServerRecordProtocol.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SslCipherSuite.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SslClientStream.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SslHandshakeHash.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SslServerStream.cs
+../Mono.Security/Mono.Security.Protocol.Tls/SslStreamBase.cs
+../Mono.Security/Mono.Security.Protocol.Tls/TlsCipherSuite.cs
+../Mono.Security/Mono.Security.Protocol.Tls/TlsClientSettings.cs
+../Mono.Security/Mono.Security.Protocol.Tls/TlsException.cs
+../Mono.Security/Mono.Security.Protocol.Tls/TlsServerSettings.cs
+../Mono.Security/Mono.Security.Protocol.Tls/TlsStream.cs
+Mono.Http/NtlmClient.cs
+Mono.Net.Security/AsyncProtocolRequest.cs
+Mono.Net.Security/CallbackHelpers.cs
+Mono.Net.Security/ChainValidationHelper.cs
+Mono.Net.Security/IMonoSslStream.cs
+Mono.Net.Security/IMonoTlsProvider.cs
 Mono.Net.Security/LegacySslStream.cs
+Mono.Net.Security/LegacySslStream.cs
+Mono.Net.Security/LegacyTlsProvider.cs
 Mono.Net.Security/LegacyTlsProvider.cs
+Mono.Net.Security/MobileAuthenticatedStream.cs
+Mono.Net.Security/MobileTlsContext.cs
+Mono.Net.Security/MonoSslStreamImpl.cs
+Mono.Net.Security/MonoSslStreamWrapper.cs
+Mono.Net.Security/MonoTlsProviderFactory.Apple.cs
+Mono.Net.Security/MonoTlsProviderFactory.cs
+Mono.Net.Security/MonoTlsProviderImpl.cs
+Mono.Net.Security/MonoTlsProviderWrapper.cs
+Mono.Net.Security/MonoTlsStream.cs
+Mono.Net.Security/NoReflectionHelper.cs
+Mono.Net.Security/SystemCertificateValidator.cs
 System.Net.Mail/SmtpClient.cs
+System.Net.Security/SslStream.cs
 System.Net.Sockets/TcpClient.cs
 System.Net.Sockets/TcpListener.cs
 System.Net.Sockets/UdpClient.cs
 System.Net.WebSockets/ClientWebSocket.cs
+System.Net/AuthenticationManager.cs
 System.Net/ChunkedInputStream.cs
 System.Net/EndPointListener.cs
 System.Net/EndPointManager.cs
@@ -23,5 +132,51 @@ System.Net/HttpListenerRequest.cs
 System.Net/HttpListenerResponse.cs
 System.Net/HttpWebRequest.cs
 System.Net/HttpWebResponse.cs
+System.Net/IWebConnectionState.cs
 System.Net/ListenerAsyncResult.cs
+System.Net/NtlmClient.cs
 System.Net/ResponseStream.cs
+System.Net/ServicePoint.cs
+System.Net/ServicePointManager.cs
+System.Net/WebConnection.cs
+System.Net/WebConnectionData.cs
+System.Net/WebConnectionGroup.cs
+System.Net/WebConnectionStream.cs
+Mono.Btls/MonoBtlsBio.cs
+Mono.Btls/MonoBtlsContext.cs
+Mono.Btls/MonoBtlsError.cs
+Mono.Btls/MonoBtlsException.cs
+Mono.Btls/MonoBtlsKey.cs
+Mono.Btls/MonoBtlsObject.cs
+Mono.Btls/MonoBtlsPkcs12.cs
+Mono.Btls/MonoBtlsProvider.cs
+Mono.Btls/MonoBtlsSsl.cs
+Mono.Btls/MonoBtlsSslCtx.cs
+Mono.Btls/MonoBtlsSslError.cs
+Mono.Btls/MonoBtlsStream.cs
+Mono.Btls/MonoBtlsUtils.cs
+Mono.Btls/MonoBtlsX509.cs
+Mono.Btls/MonoBtlsX509Chain.cs
+Mono.Btls/MonoBtlsX509Crl.cs
+Mono.Btls/MonoBtlsX509Error.cs
+Mono.Btls/MonoBtlsX509Exception.cs
+Mono.Btls/MonoBtlsX509FileType.cs
+Mono.Btls/MonoBtlsX509Format.cs
+Mono.Btls/MonoBtlsX509Lookup.cs
+Mono.Btls/MonoBtlsX509LookupMonoCollection.cs
+Mono.Btls/MonoBtlsX509LookupMono.cs
+Mono.Btls/MonoBtlsX509LookupType.cs
+Mono.Btls/MonoBtlsX509Name.cs
+Mono.Btls/MonoBtlsX509NameList.cs
+Mono.Btls/MonoBtlsX509NameEntryType.cs
+Mono.Btls/MonoBtlsX509Purpose.cs
+Mono.Btls/MonoBtlsX509Revoked.cs
+Mono.Btls/MonoBtlsX509Store.cs
+Mono.Btls/MonoBtlsX509StoreCtx.cs
+Mono.Btls/MonoBtlsX509StoreManager.cs
+Mono.Btls/MonoBtlsX509StoreType.cs
+Mono.Btls/MonoBtlsX509TrustKind.cs
+Mono.Btls/MonoBtlsX509VerifyFlags.cs
+Mono.Btls/MonoBtlsX509VerifyParam.cs
+Mono.Btls/X509CertificateImplBtls.cs
+Mono.Btls/X509ChainImplBtls.cs
index b606c440802b9f3cb95c43e630fa82760982f681..f7e73d81e36ecfd3775457593b9630c74bd0083d 100644 (file)
@@ -1,9 +1,11 @@
 #include monotouch_System.dll.sources
 System.Net.Mail/SmtpClient.platformnotsupported.cs
+System.Net.Security/SslStream.platformnotsupported.cs
 System.Net.Sockets/TcpClient.platformnotsupported.cs
 System.Net.Sockets/TcpListener.platformnotsupported.cs
 System.Net.Sockets/UdpClient.platformnotsupported.cs
 System.Net.WebSockets/ClientWebSocket.platformnotsupported.cs
+System.Net/AuthenticationManager.platformnotsupported.cs
 System.Net/FtpRequestCreator.platformnotsupported.cs
 System.Net/FtpWebRequest.platformnotsupported.cs
 System.Net/FtpWebResponse.platformnotsupported.cs
@@ -14,3 +16,5 @@ System.Net/HttpListenerRequest.platformnotsupported.cs
 System.Net/HttpListenerResponse.platformnotsupported.cs
 System.Net/HttpWebRequest.platformnotsupported.cs
 System.Net/HttpWebResponse.platformnotsupported.cs
+System.Net/ServicePoint.platformnotsupported.cs
+System.Net/ServicePointManager.platformnotsupported.cs
diff --git a/mcs/class/System/monotouch_watch_runtime_System.dll.exclude.sources b/mcs/class/System/monotouch_watch_runtime_System.dll.exclude.sources
new file mode 100644 (file)
index 0000000..8869410
--- /dev/null
@@ -0,0 +1 @@
+#include monotouch_watch_System.dll.exclude.sources
index 7c0bd5983a519e8499a57c6c30b9be525658c105..c8c328c5ce6605a85a7e34f0db5e1f2c7335d9bb 100644 (file)
@@ -1 +1 @@
-#include monotouch_System.dll.sources
+#include monotouch_watch_System.dll.sources
index d315128745d2cf9d351027e6d2ace24674ff0a7c..6dc94160d19aa713ed172469e82102f8c9396bbd 100644 (file)
@@ -83,6 +83,7 @@ using System.Runtime.InteropServices;
 [assembly: InternalsVisibleTo ("Xamarin.TVOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
 #elif MONOTOUCH_WATCH
 [assembly: InternalsVisibleTo ("Xamarin.WatchOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
+[assembly: InternalsVisibleTo ("System.Security, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
 #else
 [assembly: InternalsVisibleTo ("monotouch, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
 [assembly: InternalsVisibleTo ("Xamarin.iOS, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")]
index efac37b709affdcf88a28ff4184b3d07043f777d..12148ed85d84c200f318fe12be0d087504dfff80 100644 (file)
@@ -31,7 +31,7 @@ using System.Runtime.CompilerServices;
 
 namespace Mono {
 
-#if MOBILE
+#if MOBILE || XAMMAC_4_5
        public
 #endif
        static class Runtime
@@ -40,7 +40,7 @@ namespace Mono {
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private static extern void mono_runtime_install_handlers ();
 
-#if MOBILE
+#if MOBILE || XAMMAC_4_5
                public
 #else
                internal
@@ -50,7 +50,7 @@ namespace Mono {
                        mono_runtime_install_handlers ();
                }
 
-#if MOBILE
+#if MOBILE || XAMMAC_4_5
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                static extern void mono_runtime_cleanup_handlers ();
 
@@ -64,7 +64,7 @@ namespace Mono {
                // Safe to be called using reflection
                // Format is undefined only for use as a string for reporting
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
-#if MOBILE
+#if MOBILE || XAMMAC_4_5
                public
 #else
                internal
index 370beffb237d13dfced0cf1337e278e0f83fee6c..a77d734c36617eaf2c41cc9d6b87cfe5f286118b 100644 (file)
@@ -102,6 +102,12 @@ namespace System
                        return UnderlyingSystemType;
                }
 
+               // Called from the runtime to return the corresponding finished Type object
+               internal virtual Type RuntimeResolve ()
+               {
+                       throw new NotImplementedException ();
+               }
+
                internal virtual bool IsUserType {
                        get {
                                return true;
diff --git a/mcs/class/corlib/ReferenceSources/TypeBuilderInstantiation.cs b/mcs/class/corlib/ReferenceSources/TypeBuilderInstantiation.cs
deleted file mode 100644 (file)
index 9e82664..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-namespace System.Reflection.Emit
-{
-       abstract class TypeBuilderInstantiation : TypeInfo
-       {
-               internal static Type MakeGenericType (Type type, Type[] typeArguments)
-               {
-#if FULL_AOT_RUNTIME
-                       throw new NotSupportedException ("User types are not supported under full aot");
-#else
-                       return new MonoGenericClass (type, typeArguments);
-#endif
-               }
-       }
-}
\ No newline at end of file
index 8397f4c2d2f4db3bcd383e583bf265b06d486137..bb1b719404a992efd5277abda3f6909cdecc3ede 100644 (file)
@@ -151,6 +151,7 @@ namespace System.Diagnostics.Tracing
                {
                }
 
+               [CLSCompliant (false)]
                public void Write<T> (string eventName, ref EventSourceOptions options, ref T data)
                {
                }
index 9c257cb9a80542fc882eb52ddfd9c05c58c0b2ee..ed524bb7c1878e5d63985411be8a9bf3a9dfbe9b 100644 (file)
@@ -1046,7 +1046,7 @@ namespace System.Reflection.Emit
                /*Warning, @typeArguments must be a mscorlib internal array. So make a copy before passing it in*/
                internal Type MakeGenericType (Type gtd, Type[] typeArguments)
                {
-                       return new MonoGenericClass (gtd, typeArguments);
+                       return new TypeBuilderInstantiation (gtd, typeArguments);
                }
 
                void _AssemblyBuilder.GetIDsOfNames([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
index 793e36fd2a01cc033d059b58e1d6d939c34cba2a..55a392d38442814419e937fdb4088f2f3bd8b526 100644 (file)
@@ -145,7 +145,11 @@ namespace System.Reflection.Emit {
                internal override Type GetParameterType (int pos) {
                        return parameters [pos];
                }
-               
+
+               internal MethodBase RuntimeResolve () {
+                       return type.RuntimeResolve ().GetConstructor (this);
+               }
+
                public override Object Invoke (Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
                {
                        throw not_supported ();
@@ -372,6 +376,11 @@ namespace System.Reflection.Emit {
                                        TypeBuilder.ResolveUserTypes (types);
                        }
                }
+
+               internal void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map) {
+                       if (ilgen != null)
+                               ilgen.FixupTokens (token_map, member_map);
+               }
                
                internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
                {
index 149e5dbd6633d1a5d6940d761cfcc18be4a8e37f..643e7272a3a9be6666a2dd3366095b1dd968c8d5 100644 (file)
@@ -42,11 +42,11 @@ namespace System.Reflection.Emit
        internal class ConstructorOnTypeBuilderInst : ConstructorInfo
        {
                #region Keep in sync with object-internals.h
-               MonoGenericClass instantiation;
-               ConstructorInfo cb;
+               internal TypeBuilderInstantiation instantiation;
+               internal ConstructorInfo cb;
                #endregion
 
-               public ConstructorOnTypeBuilderInst (MonoGenericClass instantiation, ConstructorInfo cb)
+               public ConstructorOnTypeBuilderInst (TypeBuilderInstantiation instantiation, ConstructorInfo cb)
                {
                        this.instantiation = instantiation;
                        this.cb = cb;
@@ -134,6 +134,25 @@ namespace System.Reflection.Emit
                        return res;
                }
 
+               internal override Type[] GetParameterTypes () {
+                       if (cb is ConstructorBuilder) {
+                               return (cb as ConstructorBuilder).parameters;
+                       } else {
+                               ParameterInfo[] parms = cb.GetParameters ();
+                               var res = new Type [parms.Length];
+                               for (int i = 0; i < parms.Length; i++) {
+                                       res [i] = parms [i].ParameterType;
+                               }
+                               return res;
+                       }
+               }
+
+               // Called from the runtime to return the corresponding finished ConstructorInfo object
+               internal ConstructorInfo RuntimeResolve () {
+                       var type = instantiation.InternalResolve ();
+                       return type.GetConstructor (cb);
+               }
+
                public override int MetadataToken {
                        get {
                                return base.MetadataToken;
index b7ce6e0410a767355c9db8fcf9c9f0387ffd5f50..0e426991c6ec3392ece4fe91fb7342a7baa5fa61 100644 (file)
@@ -45,9 +45,6 @@ namespace System.Reflection.Emit
        {
                internal Type m_baseType;
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               static extern void create_unmanaged_type (Type type);
-
                internal SymbolType (Type elementType)
                {
                        this.m_baseType = elementType;
@@ -121,7 +118,6 @@ namespace System.Reflection.Emit
        
                public override Type UnderlyingSystemType {
                        get {
-                               create_unmanaged_type (this);
                                return this;
                        }
                }
@@ -131,6 +127,11 @@ namespace System.Reflection.Emit
                                return m_baseType.IsUserType;
                        }
                }
+
+               // Called from the runtime to return the corresponding finished Type object
+               internal override Type RuntimeResolve () {
+                       return InternalResolve ();
+               }
        }
 
        [StructLayout (LayoutKind.Sequential)]
@@ -150,9 +151,17 @@ namespace System.Reflection.Emit
 
                internal override Type InternalResolve ()
                {
-                       Type et = m_baseType.InternalResolve (); 
+                       Type et = m_baseType.InternalResolve ();
+                       if (rank == 0)
+                               return et.MakeArrayType ();
+                       return et.MakeArrayType (rank);
+               }
+
+               internal override Type RuntimeResolve ()
+               {
+                       Type et = m_baseType.RuntimeResolve ();
                        if (rank == 0)
-                               return et.MakeArrayType ();                     
+                               return et.MakeArrayType ();
                        return et.MakeArrayType (rank);
                }
 
index 2e4367ab96573525b9f8da270f134b7d83b8d06a..f54340ebf04df4013daf953c1ee1e3f5e31bc4ec 100644 (file)
@@ -42,17 +42,17 @@ namespace System.Reflection.Emit
        [StructLayout (LayoutKind.Sequential)]
        internal class EventOnTypeBuilderInst : EventInfo
        {
-               MonoGenericClass instantiation;
+               TypeBuilderInstantiation instantiation;
                EventBuilder event_builder;
                EventInfo event_info;
 
-               internal EventOnTypeBuilderInst (MonoGenericClass instantiation, EventBuilder evt)
+               internal EventOnTypeBuilderInst (TypeBuilderInstantiation instantiation, EventBuilder evt)
                {
                        this.instantiation = instantiation;
                        this.event_builder = evt;
                }
 
-               internal EventOnTypeBuilderInst (MonoGenericClass instantiation, EventInfo evt)
+               internal EventOnTypeBuilderInst (TypeBuilderInstantiation instantiation, EventInfo evt)
                {
                        this.instantiation = instantiation;
                        this.event_info = evt;
index f2fff7d7aa1ef9964d99e128965960aa869e2284..f8522ebe862a6dee35fac7668cf2d959260eb50d 100644 (file)
@@ -228,6 +228,10 @@ namespace System.Reflection.Emit {
                                marshal_info.marshaltyperef = TypeBuilder.ResolveUserType (marshal_info.marshaltyperef);
                }
 
+               internal FieldInfo RuntimeResolve () {
+                       return typeb.CreateType ().GetField (this);
+               }
+
                public override Module Module {
                        get {
                                return base.Module;
index ca3d43d85f94e49655d5a260e903cf04fd51b103..9de89b1e2b85d311ea49b1256755585b5f4f9895 100644 (file)
@@ -42,11 +42,11 @@ namespace System.Reflection.Emit
        internal class FieldOnTypeBuilderInst : FieldInfo
        {
                #region Keep in sync with object-internals.h
-               internal MonoGenericClass instantiation;
+               internal TypeBuilderInstantiation instantiation;
                internal FieldInfo fb;
                #endregion
 
-               public FieldOnTypeBuilderInst (MonoGenericClass instantiation, FieldInfo fb) {
+               public FieldOnTypeBuilderInst (TypeBuilderInstantiation instantiation, FieldInfo fb) {
                        this.instantiation = instantiation;
                        this.fb = fb;
                }
@@ -127,6 +127,12 @@ namespace System.Reflection.Emit
                public override void SetValue (object obj, object value, BindingFlags invokeAttr, Binder binder, CultureInfo culture) {
                        throw new NotSupportedException ();
                }
+
+               // Called from the runtime to return the corresponding finished FieldInfo object
+               internal FieldInfo RuntimeResolve () {
+                       var type = instantiation.RuntimeResolve ();
+                       return type.GetField (fb);
+               }
        }
 }
 #endif
index 037d36fdc3ee1fb6c06641a3a8a8ae38a895132d..30b6aac80e572f9402afd9b4403a9cf03e23c95b 100644 (file)
@@ -82,17 +82,21 @@ namespace System.Reflection.Emit
                        this.mbuilder = mbuilder;
                        this.name = name;
                        this.index = index;
-
-                       initialize ();
                }
 
                internal override Type InternalResolve ()
                {
-                       return tbuilder.InternalResolve ().GetGenericArguments () [index]; 
+                       if (mbuilder != null)
+                               return MethodBase.GetMethodFromHandle (mbuilder.MethodHandleInternal).GetGenericArguments () [index];
+                       return tbuilder.InternalResolve ().GetGenericArguments () [index];
                }
 
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void initialize ();
+               internal override Type RuntimeResolve ()
+               {
+                       if (mbuilder != null)
+                               return MethodBase.GetMethodFromHandle (mbuilder.MethodHandleInternal, mbuilder.TypeBuilder.RuntimeResolve ().TypeHandle).GetGenericArguments () [index];
+                       return tbuilder.RuntimeResolve ().GetGenericArguments () [index];
+               }
 
                [ComVisible (true)]
                public override bool IsSubclassOf (Type c)
index ac4fda04472f0572052c8433509685a8e063af93..bf879e8e942f79961b352b37de60b39592e47a5f 100644 (file)
@@ -521,7 +521,7 @@ namespace System.Reflection.Emit {
                        int token = token_gen.GetToken (con, true);
                        make_room (6);
                        ll_emit (opcode);
-                       if (con.DeclaringType.Module == module)
+                       if (con.DeclaringType.Module == module || (con is ConstructorOnTypeBuilderInst) || (con is ConstructorBuilder))
                                add_token_fixup (con);
                        emit_int (token);
                        
@@ -554,7 +554,7 @@ namespace System.Reflection.Emit {
                        int token = token_gen.GetToken (field, true);
                        make_room (6);
                        ll_emit (opcode);
-                       if (field.DeclaringType.Module == module)
+                       if (field.DeclaringType.Module == module || (field is FieldOnTypeBuilderInst) || (field is FieldBuilder))
                                add_token_fixup (field);
                        emit_int (token);
                }
@@ -737,7 +737,7 @@ namespace System.Reflection.Emit {
                        Type declaringType = meth.DeclaringType;
                        // Might be a DynamicMethod with no declaring type
                        if (declaringType != null) {
-                               if (declaringType.Module == module)
+                               if (declaringType.Module == module || meth is MethodOnTypeBuilderInst || meth is MethodBuilder)
                                        add_token_fixup (meth);
                        }
                        emit_int (token);
@@ -755,7 +755,7 @@ namespace System.Reflection.Emit {
                        // Might be a DynamicMethod with no declaring type
                        Type declaringType = method.DeclaringType;
                        if (declaringType != null) {
-                               if (declaringType.Module == module)
+                               if (declaringType.Module == module || method is MethodBuilder)
                                        add_token_fixup (method);
                        }
                        emit_int (token);
@@ -813,7 +813,10 @@ namespace System.Reflection.Emit {
 
                        make_room (6);
                        ll_emit (opcode);
-                       emit_int (token_gen.GetToken (cls, opcode != OpCodes.Ldtoken));
+                       int token = token_gen.GetToken (cls, opcode != OpCodes.Ldtoken);
+                       if (cls is TypeBuilderInstantiation || cls is SymbolType || cls is TypeBuilder || cls is GenericTypeParameterBuilder)
+                               add_token_fixup (cls);
+                       emit_int (token);
                }
 
                [MonoLimitation ("vararg methods are not supported")]
@@ -1007,6 +1010,21 @@ namespace System.Reflection.Emit {
                        }
                }
 
+               internal void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map) {
+                       for (int i = 0; i < num_token_fixups; ++i) {
+                               int pos = token_fixups [i].code_pos;
+                               int old_token = code [pos] | (code [pos + 1] << 8) | (code [pos + 2] << 16) | (code [pos + 3] << 24);
+                               int new_token;
+                               if (token_map.TryGetValue (old_token, out new_token)) {
+                                       token_fixups [i].member = member_map [old_token];
+                                       int old_cl = code_len;
+                                       code_len = pos;
+                                       emit_int (new_token);
+                                       code_len = old_cl;
+                               }
+                       }
+               }
+
                // Used by MethodBuilder.SetMethodBody
                internal void SetExceptionHandlers (ILExceptionInfo[] exHandlers) {
                        this.ex_handlers = exHandlers;
index 5545adca27657930a58d9aed580ece83fe515ea8..8748f20aba2b1e998f751affb651e45a133172e3 100644 (file)
@@ -138,6 +138,12 @@ namespace System.Reflection.Emit
                        }
                }
 
+               internal RuntimeMethodHandle MethodHandleInternal {
+                       get {
+                               return mhandle;
+                       }
+               }
+
                public override Type ReturnType {
                        get { return rtype; }
                }
@@ -248,6 +254,10 @@ namespace System.Reflection.Emit
                        return parameters [pos];
                }
 
+               internal MethodBase RuntimeResolve () {
+                       return type.RuntimeResolve ().GetMethod (this);
+               }
+
                public Module GetModule ()
                {
                        return type.Module;
@@ -380,6 +390,11 @@ namespace System.Reflection.Emit
                        }
                }
 
+               internal void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map) {
+                       if (ilgen != null)
+                               ilgen.FixupTokens (token_map, member_map);
+               }
+
                internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
                {
                        if (ilgen != null && ilgen.HasDebugInfo) {
index 9bc0b8a5994500a625b81919aa59c85cb18192a9..22c89ea9d0bf26717a90afce4b335e13fa97da78 100644 (file)
@@ -50,7 +50,7 @@ namespace System.Reflection.Emit
                #endregion
                MethodInfo generic_method_definition;
 
-               public MethodOnTypeBuilderInst (MonoGenericClass instantiation, MethodInfo base_method)
+               public MethodOnTypeBuilderInst (TypeBuilderInstantiation instantiation, MethodInfo base_method)
                {
                        this.instantiation = instantiation;
                        this.base_method = base_method;
@@ -100,6 +100,19 @@ namespace System.Reflection.Emit
                        return instantiation.GetGenericArguments ();
                }
 
+               // Called from the runtime to return the corresponding finished MethodInfo object
+               internal MethodInfo RuntimeResolve () {
+                       var type = instantiation.InternalResolve ();
+                       var m = type.GetMethod (base_method);
+                       if (method_arguments != null) {
+                               var args = new Type [method_arguments.Length];
+                               for (int i = 0; i < method_arguments.Length; ++i)
+                                       args [i] = method_arguments [i].InternalResolve ();
+                               m = m.MakeGenericMethod (args);
+                       }
+                       return m;
+               }
+
                //
                // MemberInfo members
                //
index 8d485153e38157f892cea66037eb53e78e76057a..b055797bd86763c3e82bc201c6c4d380e9884875 100644 (file)
@@ -681,15 +681,90 @@ namespace System.Reflection.Emit {
                        return result;
                }
 
+               static int typeref_tokengen =  0x01ffffff;
+               static int typedef_tokengen =  0x02ffffff;
+               static int typespec_tokengen =  0x1bffffff;
+               static int memberref_tokengen =  0x0affffff;
+               static int methoddef_tokengen =  0x06ffffff;
+               Dictionary<MemberInfo, int> inst_tokens = new Dictionary<MemberInfo, int> ();
+               Dictionary<MemberInfo, int> inst_tokens_open = new Dictionary<MemberInfo, int> ();
+
+               //
+               // Assign a pseudo token to the various TypeBuilderInst objects, so the runtime
+               // doesn't have to deal with them.
+               // For Save assemblies, the tokens will be fixed up later during Save ().
+               // For Run assemblies, the tokens will not be fixed up, so the runtime will
+               // still encounter these objects, it will resolve them by calling their
+               // RuntimeResolve () methods.
+               //
+               int GetPseudoToken (MemberInfo member, bool create_open_instance) {
+                       int token;
+
+                       if (create_open_instance) {
+                               if (inst_tokens_open.TryGetValue (member, out token))
+                                       return token;
+                       } else {
+                               if (inst_tokens.TryGetValue (member, out token))
+                                       return token;
+                       }
+                       // Count backwards to avoid collisions with the tokens
+                       // allocated by the runtime
+                       if (member is TypeBuilderInstantiation || member is SymbolType)
+                               token = typespec_tokengen --;
+                       else if (member is FieldOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is ConstructorOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is MethodOnTypeBuilderInst)
+                               token = memberref_tokengen --;
+                       else if (member is FieldBuilder)
+                               token = memberref_tokengen --;
+                       else if (member is TypeBuilder) {
+                               if (create_open_instance && (member as TypeBuilder).ContainsGenericParameters)
+                                       token = typespec_tokengen --;
+                               else if (member.Module == this)
+                                       token = typedef_tokengen --;
+                               else
+                                       token = typeref_tokengen --;
+                       } else if (member is ConstructorBuilder) {
+                               if (member.Module == this && !(member as ConstructorBuilder).TypeBuilder.ContainsGenericParameters)
+                                       token = methoddef_tokengen --;
+                               else
+                                       token = memberref_tokengen --;
+                       } else if (member is MethodBuilder) {
+                               var mb = member as MethodBuilder;
+                               if (member.Module == this && !mb.TypeBuilder.ContainsGenericParameters && !mb.IsGenericMethodDefinition)
+                                       token = methoddef_tokengen --;
+                               else
+                                       token = memberref_tokengen --;
+                       } else if (member is GenericTypeParameterBuilder) {
+                               token = typespec_tokengen --;
+                       } else
+                               throw new NotImplementedException ();
+                       if (create_open_instance)
+                               inst_tokens_open [member] = token;
+                       else
+                               inst_tokens [member] = token;
+                       RegisterToken (member, token);
+                       return token;
+               }
+
                internal int GetToken (MemberInfo member) {
+                       if (member is ConstructorBuilder || member is MethodBuilder)
+                               return GetPseudoToken (member, false);
                        return getToken (this, member, true);
                }
 
                internal int GetToken (MemberInfo member, bool create_open_instance) {
+                       if (member is TypeBuilderInstantiation || member is FieldOnTypeBuilderInst || member is ConstructorOnTypeBuilderInst || member is MethodOnTypeBuilderInst || member is SymbolType || member is FieldBuilder || member is TypeBuilder || member is ConstructorBuilder || member is MethodBuilder || member is GenericTypeParameterBuilder)
+                               return GetPseudoToken (member, create_open_instance);
                        return getToken (this, member, create_open_instance);
                }
 
                internal int GetToken (MethodBase method, IEnumerable<Type> opt_param_types) {
+                       if (method is ConstructorBuilder || method is MethodBuilder)
+                               return GetPseudoToken (method, false);
+
                        if (opt_param_types == null)
                                return getToken (this, method, true);
 
@@ -698,6 +773,8 @@ namespace System.Reflection.Emit {
                }
                
                internal int GetToken (MethodBase method, Type[] opt_param_types) {
+                       if (method is ConstructorBuilder || method is MethodBuilder)
+                               return GetPseudoToken (method, false);
                        return getMethodToken (this, method, opt_param_types);
                }
 
@@ -724,12 +801,88 @@ namespace System.Reflection.Emit {
                        return token_gen;
                }
 
+               // Called from the runtime to return the corresponding finished reflection object
+               internal static object RuntimeResolve (object obj) {
+                       if (obj is MethodBuilder)
+                               return (obj as MethodBuilder).RuntimeResolve ();
+                       if (obj is ConstructorBuilder)
+                               return (obj as ConstructorBuilder).RuntimeResolve ();
+                       if (obj is FieldBuilder)
+                               return (obj as FieldBuilder).RuntimeResolve ();
+                       if (obj is GenericTypeParameterBuilder)
+                               return (obj as GenericTypeParameterBuilder).RuntimeResolve ();
+                       if (obj is FieldOnTypeBuilderInst)
+                               return (obj as FieldOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is MethodOnTypeBuilderInst)
+                               return (obj as MethodOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is ConstructorOnTypeBuilderInst)
+                               return (obj as ConstructorOnTypeBuilderInst).RuntimeResolve ();
+                       if (obj is Type)
+                               return (obj as Type).RuntimeResolve ();
+                       throw new NotImplementedException (obj.GetType ().FullName);
+               }
+
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private static extern void build_metadata (ModuleBuilder mb);
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern void WriteToFile (IntPtr handle);
 
+               void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map, Dictionary<MemberInfo, int> inst_tokens,
+                                                 bool open) {
+                       foreach (var v in inst_tokens) {
+                               var member = v.Key;
+                               var old_token = v.Value;
+                               MemberInfo finished = null;
+
+                               // Construct the concrete reflection object corresponding to the
+                               // TypeBuilderInst object, and request a token for it instead.
+                               if (member is TypeBuilderInstantiation || member is SymbolType) {
+                                       finished = (member as Type).RuntimeResolve ();
+                               } else if (member is FieldOnTypeBuilderInst) {
+                                       finished = (member as FieldOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is ConstructorOnTypeBuilderInst) {
+                                       finished = (member as ConstructorOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is MethodOnTypeBuilderInst) {
+                                       finished = (member as MethodOnTypeBuilderInst).RuntimeResolve ();
+                               } else if (member is FieldBuilder) {
+                                       finished = (member as FieldBuilder).RuntimeResolve ();
+                               } else if (member is TypeBuilder) {
+                                       finished = (member as TypeBuilder).RuntimeResolve ();
+                               } else if (member is ConstructorBuilder) {
+                                       finished = (member as ConstructorBuilder).RuntimeResolve ();
+                               } else if (member is MethodBuilder) {
+                                       finished = (member as MethodBuilder).RuntimeResolve ();
+                               } else if (member is GenericTypeParameterBuilder) {
+                                       finished = (member as GenericTypeParameterBuilder).RuntimeResolve ();
+                               } else {
+                                       throw new NotImplementedException ();
+                               }
+
+                               int new_token = GetToken (finished, open);
+                               token_map [old_token] = new_token;
+                               member_map [old_token] = finished;
+                               // Replace the token mapping in the runtime so it points to the new object
+                               RegisterToken (finished, old_token);
+                       }
+               }
+
+               //
+               // Fixup the pseudo tokens assigned to the various SRE objects
+               //
+               void FixupTokens () {
+                       var token_map = new Dictionary<int, int> ();
+                       var member_map = new Dictionary<int, MemberInfo> ();
+                       FixupTokens (token_map, member_map, inst_tokens, false);
+                       FixupTokens (token_map, member_map, inst_tokens_open, true);
+
+                       // Replace the tokens in the IL stream
+                       if (types != null) {
+                               for (int i = 0; i < num_types; ++i)
+                                       types [i].FixupTokens (token_map, member_map);
+                       }
+               }
+
                internal void Save ()
                {
                        if (transient && !is_main)
@@ -741,6 +894,8 @@ namespace System.Reflection.Emit {
                                                throw new NotSupportedException ("Type '" + types [i].FullName + "' was not completed.");
                        }
 
+                       FixupTokens ();
+
                        if ((global_type != null) && (global_type_created == null))
                                global_type_created = global_type.CreateType ();
 
index 1035f494c86223a3bcc547243d9ea635be84dd9c..8b21446c4ef5416f3bd1421a6e59160c001a4cea 100644 (file)
@@ -41,10 +41,10 @@ namespace System.Reflection.Emit
        [StructLayout (LayoutKind.Sequential)]
        internal class PropertyOnTypeBuilderInst : PropertyInfo
        {
-               MonoGenericClass instantiation;
+               TypeBuilderInstantiation instantiation;
                PropertyInfo prop;
 
-               internal PropertyOnTypeBuilderInst (MonoGenericClass instantiation, PropertyInfo prop)
+               internal PropertyOnTypeBuilderInst (TypeBuilderInstantiation instantiation, PropertyInfo prop)
                {
                        this.instantiation = instantiation;
                        this.prop = prop;
index 3972192308d8082a7c6be66c929a8989b4a85dce..e97a1b4c944d0ddd652315adcfec7dc7b8d96656 100644 (file)
@@ -40,6 +40,7 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Globalization;
 using System.Collections;
+using System.Collections.Generic;
 using System.Security;
 using System.Security.Permissions;
 using System.Diagnostics.SymbolStore;
@@ -91,15 +92,6 @@ namespace System.Reflection.Emit
                {
                        return attrs;
                }
-               
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void setup_internal_class ();
-               
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern void create_generic_class ();
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               private extern EventInfo get_event_info (EventBuilder eb);
 
                internal TypeBuilder (ModuleBuilder mb, TypeAttributes attr, int table_idx)
                {
@@ -111,7 +103,6 @@ namespace System.Reflection.Emit
                        this.nspace = String.Empty;
                        this.fullname = TypeIdentifiers.WithoutEscape(this.tname);
                        pmodule = mb;
-                       setup_internal_class ();
                }
 
                internal TypeBuilder (ModuleBuilder mb, string name, TypeAttributes attr, Type parent, Type[] interfaces, PackingSize packing_size, int type_size, Type nesting_type)
@@ -147,7 +138,6 @@ namespace System.Reflection.Emit
 
                        // skip .<Module> ?
                        table_idx = mb.get_next_table_index (this, 0x02, true);
-                       setup_internal_class ();
                        fullname = GetFullName ();
                }
 
@@ -764,8 +754,6 @@ namespace System.Reflection.Emit
                                SetParent (pmodule.assemblyb.corlib_object_type);
                        }
 
-                       create_generic_class ();
-
                        // Fire TypeResolve events for fields whose type is an unfinished
                        // value type.
                        if (fields != null) {
@@ -873,6 +861,17 @@ namespace System.Reflection.Emit
                        }
                }
 
+               internal void FixupTokens (Dictionary<int, int> token_map, Dictionary<int, MemberInfo> member_map) {
+                       if (methods != null) {
+                               for (int i = 0; i < num_methods; ++i)
+                                       methods[i].FixupTokens (token_map, member_map);
+                       }
+                       if (ctors != null) {
+                               foreach (var cb in ctors)
+                                       cb.FixupTokens (token_map, member_map);
+                       }
+               }
+
                internal void GenerateDebugInfo (ISymbolWriter symbolWriter)
                {
                        symbolWriter.OpenNamespace (this.Namespace);
@@ -968,53 +967,6 @@ namespace System.Reflection.Emit
                        throw new NotSupportedException ();
                }
 
-               // This is only used from MonoGenericInst.initialize().
-               internal EventInfo[] GetEvents_internal (BindingFlags bindingAttr)
-               {
-                       if (events == null)
-                               return new EventInfo [0];
-                       ArrayList l = new ArrayList ();
-                       bool match;
-                       MethodAttributes mattrs;
-                       MethodInfo accessor;
-
-                       foreach (EventBuilder eb in events) {
-                               if (eb == null)
-                                       continue;
-                               EventInfo c = get_event_info (eb);
-                               match = false;
-                               accessor = c.GetAddMethod (true);
-                               if (accessor == null)
-                                       accessor = c.GetRemoveMethod (true);
-                               if (accessor == null)
-                                       continue;
-                               mattrs = accessor.Attributes;
-                               if ((mattrs & MethodAttributes.MemberAccessMask) == MethodAttributes.Public) {
-                                       if ((bindingAttr & BindingFlags.Public) != 0)
-                                               match = true;
-                               } else {
-                                       if ((bindingAttr & BindingFlags.NonPublic) != 0)
-                                               match = true;
-                               }
-                               if (!match)
-                                       continue;
-                               match = false;
-                               if ((mattrs & MethodAttributes.Static) != 0) {
-                                       if ((bindingAttr & BindingFlags.Static) != 0)
-                                               match = true;
-                               } else {
-                                       if ((bindingAttr & BindingFlags.Instance) != 0)
-                                               match = true;
-                               }
-                               if (!match)
-                                       continue;
-                               l.Add (c);
-                       }
-                       EventInfo[] result = new EventInfo [l.Count];
-                       l.CopyTo (result);
-                       return result;
-               }
-
                public override FieldInfo GetField (string name, BindingFlags bindingAttr)
                {
                        if (created != null)
@@ -1642,9 +1594,6 @@ namespace System.Reflection.Emit
                                this.parent = parent;
                        }
                        this.parent = ResolveUserType (this.parent);
-
-                       // will just set the parent-related bits if called a second time
-                       setup_internal_class ();
                }
 
                internal int get_next_table_index (object obj, int table, bool inc) {
@@ -1666,6 +1615,12 @@ namespace System.Reflection.Emit
                        return created;
                }
 
+               internal override Type RuntimeResolve ()
+               {
+                       check_created ();
+                       return created;
+               }
+
                internal bool is_created {
                        get {
                                return createTypeCalled;
@@ -1764,9 +1719,10 @@ namespace System.Reflection.Emit
                        }
                }
 
-               public extern override bool IsGenericParameter {
-                       [MethodImplAttribute(MethodImplOptions.InternalCall)]
-                       get;
+               public override bool IsGenericParameter {
+                       get {
+                               return false;
+                       }
                }
 
                public override GenericParameterAttributes GenericParameterAttributes {
@@ -1843,7 +1799,7 @@ namespace System.Reflection.Emit
 
                static bool IsValidGetMethodType (Type type)
                {
-                       if (type is TypeBuilder || type is MonoGenericClass)
+                       if (type is TypeBuilder || type is TypeBuilderInstantiation)
                                return true;
                        /*GetMethod() must work with TypeBuilders after CreateType() was called.*/
                        if (type.Module is ModuleBuilder)
diff --git a/mcs/class/corlib/System.Reflection.Emit/TypeBuilderInstantiation.cs b/mcs/class/corlib/System.Reflection.Emit/TypeBuilderInstantiation.cs
new file mode 100644 (file)
index 0000000..c6870f9
--- /dev/null
@@ -0,0 +1,506 @@
+//
+// System.Reflection.Emit.TypeBuilderInstantiation
+//
+// Sean MacIsaac (macisaac@ximian.com)
+// Paolo Molaro (lupus@ximian.com)
+// Patrik Torstensson (patrik.torstensson@labs2.com)
+//
+// (C) 2001 Ximian, Inc.
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if !FULL_AOT_RUNTIME
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections;
+using System.Runtime.CompilerServices;
+using System.Globalization;
+using System.Runtime.Serialization;
+using System.Text;
+using System.Runtime.InteropServices;
+
+namespace System.Reflection.Emit
+{
+       /*
+        * TypeBuilderInstantiation represents an instantiation of a generic TypeBuilder.
+        */
+       [StructLayout (LayoutKind.Sequential)]
+       sealed class TypeBuilderInstantiation :
+               TypeInfo
+       {
+               #region Keep in sync with object-internals.h
+#pragma warning disable 649
+               internal Type generic_type;
+               Type[] type_arguments;
+#pragma warning restore 649
+               #endregion
+
+               Hashtable fields, ctors, methods;
+
+               internal TypeBuilderInstantiation ()
+               {
+                       // this should not be used
+                       throw new InvalidOperationException ();
+               }
+
+               internal TypeBuilderInstantiation (Type tb, Type[] args)
+               {
+                       this.generic_type = tb;
+                       this.type_arguments = args;
+               }
+
+               internal override Type InternalResolve ()
+               {
+                       Type gtd = generic_type.InternalResolve ();
+                       Type[] args = new Type [type_arguments.Length];
+                       for (int i = 0; i < type_arguments.Length; ++i)
+                               args [i] = type_arguments [i].InternalResolve ();
+                       return gtd.MakeGenericType (args);
+               }
+
+               // Called from the runtime to return the corresponding finished Type object
+               internal override Type RuntimeResolve ()
+               {
+                       if (generic_type is TypeBuilder && !(generic_type as TypeBuilder).IsCreated ())
+                               AppDomain.CurrentDomain.DoTypeResolve (generic_type);
+                       for (int i = 0; i < type_arguments.Length; ++i) {
+                               var t = type_arguments [i];
+                               if (t is TypeBuilder && !(t as TypeBuilder).IsCreated ())
+                                       AppDomain.CurrentDomain.DoTypeResolve (t);
+                       }
+                       return InternalResolve ();
+               }
+
+               internal bool IsCreated {
+                       get {
+                               TypeBuilder tb = generic_type as TypeBuilder;
+                               return tb != null ? tb.is_created : true;
+                       }
+               }
+
+               private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
+               BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+               Type GetParentType ()
+               {
+                       return InflateType (generic_type.BaseType);             
+               }
+
+               internal Type InflateType (Type type)
+               {
+                       return InflateType (type, type_arguments, null);
+               }
+
+               internal Type InflateType (Type type, Type[] method_args)
+               {
+                       return InflateType (type, type_arguments, method_args);
+               }
+
+               internal static Type InflateType (Type type, Type[] type_args, Type[] method_args)
+               {
+                       if (type == null)
+                               return null;
+                       if (!type.IsGenericParameter && !type.ContainsGenericParameters)
+                               return type;
+                       if (type.IsGenericParameter) {
+                               if (type.DeclaringMethod == null)
+                                       return type_args == null ? type : type_args [type.GenericParameterPosition];
+                               return method_args == null ? type : method_args [type.GenericParameterPosition];
+                       }
+                       if (type.IsPointer)
+                               return InflateType (type.GetElementType (), type_args, method_args).MakePointerType ();
+                       if (type.IsByRef)
+                               return InflateType (type.GetElementType (), type_args, method_args).MakeByRefType ();
+                       if (type.IsArray) {
+                               if (type.GetArrayRank () > 1)
+                                       return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType (type.GetArrayRank ());
+                               
+                               if (type.ToString ().EndsWith ("[*]", StringComparison.Ordinal)) /*FIXME, the reflection API doesn't offer a way around this*/
+                                       return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType (1);
+                               return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType ();
+                       }
+
+                       Type[] args = type.GetGenericArguments ();
+                       for (int i = 0; i < args.Length; ++i)
+                               args [i] = InflateType (args [i], type_args, method_args);
+
+                       Type gtd = type.IsGenericTypeDefinition ? type : type.GetGenericTypeDefinition ();
+                       return gtd.MakeGenericType (args);
+               }
+               
+               public override Type BaseType {
+                       get { return generic_type.BaseType; }
+               }
+
+               public override Type[] GetInterfaces ()
+               {
+                       throw new NotSupportedException ();
+               }
+
+               protected override bool IsValueTypeImpl ()
+               {
+                       return generic_type.IsValueType;
+               }
+
+               internal override MethodInfo GetMethod (MethodInfo fromNoninstanciated)
+               {
+                       if (methods == null)
+                               methods = new Hashtable ();
+                       if (!methods.ContainsKey (fromNoninstanciated))
+                               methods [fromNoninstanciated] = new MethodOnTypeBuilderInst (this, fromNoninstanciated);
+                       return (MethodInfo)methods [fromNoninstanciated];
+               }
+
+               internal override ConstructorInfo GetConstructor (ConstructorInfo fromNoninstanciated)
+               {
+                       if (ctors == null)
+                               ctors = new Hashtable ();
+                       if (!ctors.ContainsKey (fromNoninstanciated))
+                               ctors [fromNoninstanciated] = new ConstructorOnTypeBuilderInst (this, fromNoninstanciated);
+                       return (ConstructorInfo)ctors [fromNoninstanciated];
+               }
+
+               internal override FieldInfo GetField (FieldInfo fromNoninstanciated)
+               {
+                       if (fields == null)
+                               fields = new Hashtable ();
+                       if (!fields.ContainsKey (fromNoninstanciated))
+                               fields [fromNoninstanciated] = new FieldOnTypeBuilderInst (this, fromNoninstanciated);
+                       return (FieldInfo)fields [fromNoninstanciated];
+               }
+               
+               public override MethodInfo[] GetMethods (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override ConstructorInfo[] GetConstructors (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override FieldInfo[] GetFields (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override PropertyInfo[] GetProperties (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override EventInfo[] GetEvents (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override Type[] GetNestedTypes (BindingFlags bf)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override bool IsAssignableFrom (Type c)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override Type UnderlyingSystemType {
+                       get { return this; }
+               }
+
+               public override Assembly Assembly {
+                       get { return generic_type.Assembly; }
+               }
+
+               public override Module Module {
+                       get { return generic_type.Module; }
+               }
+
+               public override string Name {
+                       get { return generic_type.Name; }
+               }
+
+               public override string Namespace {
+                       get { return generic_type.Namespace; }
+               }
+
+               public override string FullName {
+                       get { return format_name (true, false); }
+               }
+
+               public override string AssemblyQualifiedName {
+                       get { return format_name (true, true); }
+               }
+
+               public override Guid GUID {
+                       get { throw new NotSupportedException (); }
+               }
+
+               string format_name (bool full_name, bool assembly_qualified)
+               {
+                       StringBuilder sb = new StringBuilder (generic_type.FullName);
+
+                       sb.Append ("[");
+                       for (int i = 0; i < type_arguments.Length; ++i) {
+                               if (i > 0)
+                                       sb.Append (",");
+                               
+                               string name;
+                               if (full_name) {
+                                       string assemblyName = type_arguments [i].Assembly.FullName;
+                                       name = type_arguments [i].FullName;
+                                       if (name != null && assemblyName != null)
+                                               name = name + ", " + assemblyName;
+                               } else {
+                                       name = type_arguments [i].ToString ();
+                               }
+                               if (name == null) {
+                                       return null;
+                               }
+                               if (full_name)
+                                       sb.Append ("[");
+                               sb.Append (name);
+                               if (full_name)
+                                       sb.Append ("]");
+                       }
+                       sb.Append ("]");
+                       if (assembly_qualified) {
+                               sb.Append (", ");
+                               sb.Append (generic_type.Assembly.FullName);
+                       }
+                       return sb.ToString ();
+               }
+
+               public override string ToString ()
+               {
+                       return format_name (false, false);
+               }
+
+               public override Type GetGenericTypeDefinition ()
+               {
+                       return generic_type;
+               }
+
+               public override Type[] GetGenericArguments ()
+               {
+                       Type[] ret = new Type [type_arguments.Length];
+                       type_arguments.CopyTo (ret, 0);
+                       return ret;
+               }
+
+               public override bool ContainsGenericParameters {
+                       get {
+                               foreach (Type t in type_arguments) {
+                                       if (t.ContainsGenericParameters)
+                                               return true;
+                               }
+                               return false;
+                       }
+               }
+
+               public override bool IsGenericTypeDefinition {
+                       get { return false; }
+               }
+
+               public override bool IsGenericType {
+                       get { return true; }
+               }
+
+               public override Type DeclaringType {
+                       get { return generic_type.DeclaringType; }
+               }
+
+               public override RuntimeTypeHandle TypeHandle {
+                       get {
+                               throw new NotSupportedException ();
+                       }
+               }
+
+               public override Type MakeArrayType ()
+               {
+                       return new ArrayType (this, 0);
+               }
+
+               public override Type MakeArrayType (int rank)
+               {
+                       if (rank < 1)
+                               throw new IndexOutOfRangeException ();
+                       return new ArrayType (this, rank);
+               }
+
+               public override Type MakeByRefType ()
+               {
+                       return new ByRefType (this);
+               }
+
+               public override Type MakePointerType ()
+               {
+                       return new PointerType (this);
+               }
+
+               public override Type GetElementType ()
+               {
+                       throw new NotSupportedException ();
+               }
+
+               protected override bool HasElementTypeImpl ()
+               {
+                       return false;
+               }
+
+               protected override bool IsCOMObjectImpl ()
+               {
+                       return false;
+               }
+
+               protected override bool IsPrimitiveImpl ()
+               {
+                       return false;
+               }
+
+               protected override bool IsArrayImpl ()
+               {
+                       return false;
+               }
+
+               protected override bool IsByRefImpl ()
+               {
+                       return false;
+               }
+
+               protected override bool IsPointerImpl ()
+               {
+                       return false;
+               }
+
+               protected override TypeAttributes GetAttributeFlagsImpl ()
+               {
+                       return generic_type.Attributes; 
+               }
+
+               //stuff that throws
+               public override Type GetInterface (string name, bool ignoreCase)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override EventInfo GetEvent (string name, BindingFlags bindingAttr)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override FieldInfo GetField( string name, BindingFlags bindingAttr)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override MemberInfo[] GetMembers (BindingFlags bindingAttr)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override Type GetNestedType (string name, BindingFlags bindingAttr)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override object InvokeMember (string name, BindingFlags invokeAttr,
+                                                    Binder binder, object target, object[] args,
+                                                    ParameterModifier[] modifiers,
+                                                    CultureInfo culture, string[] namedParameters)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               protected override MethodInfo GetMethodImpl (string name, BindingFlags bindingAttr, Binder binder,
+                                                            CallingConventions callConvention, Type[] types,
+                                                            ParameterModifier[] modifiers)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               protected override PropertyInfo GetPropertyImpl (string name, BindingFlags bindingAttr, Binder binder,
+                                                                Type returnType, Type[] types, ParameterModifier[] modifiers)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               protected override ConstructorInfo GetConstructorImpl (BindingFlags bindingAttr,
+                                                                      Binder binder,
+                                                                      CallingConventions callConvention,
+                                                                      Type[] types,
+                                                                      ParameterModifier[] modifiers)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               //MemberInfo
+               public override bool IsDefined (Type attributeType, bool inherit)
+               {
+                       throw new NotSupportedException ();
+               }
+
+               public override object [] GetCustomAttributes (bool inherit)
+               {
+                       if (IsCreated)
+                               return generic_type.GetCustomAttributes (inherit);
+                       throw new NotSupportedException ();
+               }
+
+               public override object [] GetCustomAttributes (Type attributeType, bool inherit)
+               {
+                       if (IsCreated)
+                               return generic_type.GetCustomAttributes (attributeType, inherit);
+                       throw new NotSupportedException ();
+               }
+
+               internal override bool IsUserType {
+                       get {
+                               foreach (var t in type_arguments) {
+                                       if (t.IsUserType)
+                                               return true;
+                               }
+                               return false;
+                       }
+               }
+
+               internal static Type MakeGenericType (Type type, Type[] typeArguments)
+               {
+                       return new TypeBuilderInstantiation (type, typeArguments);
+               }
+       }
+}
+#else
+namespace System.Reflection.Emit
+{
+       abstract class TypeBuilderInstantiation : TypeInfo
+       {
+               internal static Type MakeGenericType (Type type, Type[] typeArguments)
+               {
+                       throw new NotSupportedException ("User types are not supported under full aot");
+               }
+       }
+}
+#endif
diff --git a/mcs/class/corlib/System.Reflection/MonoGenericClass.cs b/mcs/class/corlib/System.Reflection/MonoGenericClass.cs
deleted file mode 100644 (file)
index 51a1a50..0000000
+++ /dev/null
@@ -1,519 +0,0 @@
-//
-// System.Reflection.MonoGenericClass
-//
-// Sean MacIsaac (macisaac@ximian.com)
-// Paolo Molaro (lupus@ximian.com)
-// Patrik Torstensson (patrik.torstensson@labs2.com)
-//
-// (C) 2001 Ximian, Inc.
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-#if !FULL_AOT_RUNTIME
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Collections;
-using System.Runtime.CompilerServices;
-using System.Globalization;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Runtime.InteropServices;
-
-namespace System.Reflection
-{
-       /*
-        * MonoGenericClass represents an instantiation of a generic TypeBuilder. MS
-        * calls this class TypeBuilderInstantiation (a much better name). MS returns 
-        * NotImplementedException for many of the methods but we can't do that as gmcs
-        * depends on them.
-        */
-       [StructLayout (LayoutKind.Sequential)]
-       sealed class MonoGenericClass :
-               TypeInfo
-       {
-               #region Keep in sync with object-internals.h
-#pragma warning disable 649
-               internal Type generic_type;
-               Type[] type_arguments;
-               bool initialized;
-#pragma warning restore 649
-               #endregion
-
-               Hashtable fields, ctors, methods;
-
-               internal MonoGenericClass ()
-               {
-                       // this should not be used
-                       throw new InvalidOperationException ();
-               }
-
-               internal MonoGenericClass (Type tb, Type[] args)
-               {
-                       this.generic_type = tb;
-                       this.type_arguments = args;
-                       /*
-                       This is a temporary hack until we can fix the rest of the runtime
-                       to properly handle this class to be a complete UT.
-
-                       We must not regisrer this with the runtime after the type is created
-                       otherwise created_type.MakeGenericType will return an instance of MonoGenericClass,
-                       which is very very broken.
-                       */
-                       if (tb is TypeBuilder && !(tb as TypeBuilder).is_created)
-                               register_with_runtime (this);
-                       
-               }
-
-               internal override Type InternalResolve ()
-               {
-                       Type gtd = generic_type.InternalResolve ();
-                       Type[] args = new Type [type_arguments.Length];
-                       for (int i = 0; i < type_arguments.Length; ++i)
-                               args [i] = type_arguments [i].InternalResolve ();
-                       return gtd.MakeGenericType (args);
-               }
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               extern void initialize (FieldInfo[] fields);
-
-               [MethodImplAttribute(MethodImplOptions.InternalCall)]
-               internal static extern void register_with_runtime (Type type);
-
-               internal bool IsCreated {
-                       get {
-                               TypeBuilder tb = generic_type as TypeBuilder;
-                               return tb != null ? tb.is_created : true;
-                       }
-               }
-
-               private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
-               BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
-
-               void initialize ()
-               {
-                       if (initialized)
-                               return;
-
-                       MonoGenericClass parent = GetParentType () as MonoGenericClass;
-                       if (parent != null)
-                               parent.initialize ();
-                               
-                       initialize (generic_type.GetFields (flags));
-
-                       initialized = true;
-               }
-
-               Type GetParentType ()
-               {
-                       return InflateType (generic_type.BaseType);             
-               }
-
-               internal Type InflateType (Type type)
-               {
-                       return InflateType (type, type_arguments, null);
-               }
-
-               internal Type InflateType (Type type, Type[] method_args)
-               {
-                       return InflateType (type, type_arguments, method_args);
-               }
-
-               internal static Type InflateType (Type type, Type[] type_args, Type[] method_args)
-               {
-                       if (type == null)
-                               return null;
-                       if (!type.IsGenericParameter && !type.ContainsGenericParameters)
-                               return type;
-                       if (type.IsGenericParameter) {
-                               if (type.DeclaringMethod == null)
-                                       return type_args == null ? type : type_args [type.GenericParameterPosition];
-                               return method_args == null ? type : method_args [type.GenericParameterPosition];
-                       }
-                       if (type.IsPointer)
-                               return InflateType (type.GetElementType (), type_args, method_args).MakePointerType ();
-                       if (type.IsByRef)
-                               return InflateType (type.GetElementType (), type_args, method_args).MakeByRefType ();
-                       if (type.IsArray) {
-                               if (type.GetArrayRank () > 1)
-                                       return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType (type.GetArrayRank ());
-                               
-                               if (type.ToString ().EndsWith ("[*]", StringComparison.Ordinal)) /*FIXME, the reflection API doesn't offer a way around this*/
-                                       return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType (1);
-                               return InflateType (type.GetElementType (), type_args, method_args).MakeArrayType ();
-                       }
-
-                       Type[] args = type.GetGenericArguments ();
-                       for (int i = 0; i < args.Length; ++i)
-                               args [i] = InflateType (args [i], type_args, method_args);
-
-                       Type gtd = type.IsGenericTypeDefinition ? type : type.GetGenericTypeDefinition ();
-                       return gtd.MakeGenericType (args);
-               }
-               
-               public override Type BaseType {
-                       get { return generic_type.BaseType; }
-               }
-
-               public override Type[] GetInterfaces ()
-               {
-                       throw new NotSupportedException ();
-               }
-
-               protected override bool IsValueTypeImpl ()
-               {
-                       return generic_type.IsValueType;
-               }
-
-               internal override MethodInfo GetMethod (MethodInfo fromNoninstanciated)
-               {
-                       initialize ();
-
-                       if (methods == null)
-                               methods = new Hashtable ();
-                       if (!methods.ContainsKey (fromNoninstanciated))
-                               methods [fromNoninstanciated] = new MethodOnTypeBuilderInst (this, fromNoninstanciated);
-                       return (MethodInfo)methods [fromNoninstanciated];
-               }
-
-               internal override ConstructorInfo GetConstructor (ConstructorInfo fromNoninstanciated)
-               {
-                       initialize ();
-
-                       if (ctors == null)
-                               ctors = new Hashtable ();
-                       if (!ctors.ContainsKey (fromNoninstanciated))
-                               ctors [fromNoninstanciated] = new ConstructorOnTypeBuilderInst (this, fromNoninstanciated);
-                       return (ConstructorInfo)ctors [fromNoninstanciated];
-               }
-
-               internal override FieldInfo GetField (FieldInfo fromNoninstanciated)
-               {
-                       initialize ();
-                       if (fields == null)
-                               fields = new Hashtable ();
-                       if (!fields.ContainsKey (fromNoninstanciated))
-                               fields [fromNoninstanciated] = new FieldOnTypeBuilderInst (this, fromNoninstanciated);
-                       return (FieldInfo)fields [fromNoninstanciated];
-               }
-               
-               public override MethodInfo[] GetMethods (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override ConstructorInfo[] GetConstructors (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override FieldInfo[] GetFields (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override PropertyInfo[] GetProperties (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override EventInfo[] GetEvents (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override Type[] GetNestedTypes (BindingFlags bf)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override bool IsAssignableFrom (Type c)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override Type UnderlyingSystemType {
-                       get { return this; }
-               }
-
-               public override Assembly Assembly {
-                       get { return generic_type.Assembly; }
-               }
-
-               public override Module Module {
-                       get { return generic_type.Module; }
-               }
-
-               public override string Name {
-                       get { return generic_type.Name; }
-               }
-
-               public override string Namespace {
-                       get { return generic_type.Namespace; }
-               }
-
-               public override string FullName {
-                       get { return format_name (true, false); }
-               }
-
-               public override string AssemblyQualifiedName {
-                       get { return format_name (true, true); }
-               }
-
-               public override Guid GUID {
-                       get { throw new NotSupportedException (); }
-               }
-
-               string format_name (bool full_name, bool assembly_qualified)
-               {
-                       StringBuilder sb = new StringBuilder (generic_type.FullName);
-
-                       sb.Append ("[");
-                       for (int i = 0; i < type_arguments.Length; ++i) {
-                               if (i > 0)
-                                       sb.Append (",");
-                               
-                               string name;
-                               if (full_name) {
-                                       string assemblyName = type_arguments [i].Assembly.FullName;
-                                       name = type_arguments [i].FullName;
-                                       if (name != null && assemblyName != null)
-                                               name = name + ", " + assemblyName;
-                               } else {
-                                       name = type_arguments [i].ToString ();
-                               }
-                               if (name == null) {
-                                       return null;
-                               }
-                               if (full_name)
-                                       sb.Append ("[");
-                               sb.Append (name);
-                               if (full_name)
-                                       sb.Append ("]");
-                       }
-                       sb.Append ("]");
-                       if (assembly_qualified) {
-                               sb.Append (", ");
-                               sb.Append (generic_type.Assembly.FullName);
-                       }
-                       return sb.ToString ();
-               }
-
-               public override string ToString ()
-               {
-                       return format_name (false, false);
-               }
-
-               public override Type GetGenericTypeDefinition ()
-               {
-                       return generic_type;
-               }
-
-               public override Type[] GetGenericArguments ()
-               {
-                       Type[] ret = new Type [type_arguments.Length];
-                       type_arguments.CopyTo (ret, 0);
-                       return ret;
-               }
-
-               public override bool ContainsGenericParameters {
-                       get {
-                               foreach (Type t in type_arguments) {
-                                       if (t.ContainsGenericParameters)
-                                               return true;
-                               }
-                               return false;
-                       }
-               }
-
-               public override bool IsGenericTypeDefinition {
-                       get { return false; }
-               }
-
-               public override bool IsGenericType {
-                       get { return true; }
-               }
-
-               public override Type DeclaringType {
-                       get { return generic_type.DeclaringType; }
-               }
-
-               public override RuntimeTypeHandle TypeHandle {
-                       get {
-                               throw new NotSupportedException ();
-                       }
-               }
-
-               public override Type MakeArrayType ()
-               {
-                       return new ArrayType (this, 0);
-               }
-
-               public override Type MakeArrayType (int rank)
-               {
-                       if (rank < 1)
-                               throw new IndexOutOfRangeException ();
-                       return new ArrayType (this, rank);
-               }
-
-               public override Type MakeByRefType ()
-               {
-                       return new ByRefType (this);
-               }
-
-               public override Type MakePointerType ()
-               {
-                       return new PointerType (this);
-               }
-
-               public override Type GetElementType ()
-               {
-                       throw new NotSupportedException ();
-               }
-
-               protected override bool HasElementTypeImpl ()
-               {
-                       return false;
-               }
-
-               protected override bool IsCOMObjectImpl ()
-               {
-                       return false;
-               }
-
-               protected override bool IsPrimitiveImpl ()
-               {
-                       return false;
-               }
-
-               protected override bool IsArrayImpl ()
-               {
-                       return false;
-               }
-
-               protected override bool IsByRefImpl ()
-               {
-                       return false;
-               }
-
-               protected override bool IsPointerImpl ()
-               {
-                       return false;
-               }
-
-               protected override TypeAttributes GetAttributeFlagsImpl ()
-               {
-                       return generic_type.Attributes; 
-               }
-
-               //stuff that throws
-               public override Type GetInterface (string name, bool ignoreCase)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override EventInfo GetEvent (string name, BindingFlags bindingAttr)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override FieldInfo GetField( string name, BindingFlags bindingAttr)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override MemberInfo[] GetMembers (BindingFlags bindingAttr)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override Type GetNestedType (string name, BindingFlags bindingAttr)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override object InvokeMember (string name, BindingFlags invokeAttr,
-                                                    Binder binder, object target, object[] args,
-                                                    ParameterModifier[] modifiers,
-                                                    CultureInfo culture, string[] namedParameters)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               protected override MethodInfo GetMethodImpl (string name, BindingFlags bindingAttr, Binder binder,
-                                                            CallingConventions callConvention, Type[] types,
-                                                            ParameterModifier[] modifiers)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               protected override PropertyInfo GetPropertyImpl (string name, BindingFlags bindingAttr, Binder binder,
-                                                                Type returnType, Type[] types, ParameterModifier[] modifiers)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               protected override ConstructorInfo GetConstructorImpl (BindingFlags bindingAttr,
-                                                                      Binder binder,
-                                                                      CallingConventions callConvention,
-                                                                      Type[] types,
-                                                                      ParameterModifier[] modifiers)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               //MemberInfo
-               public override bool IsDefined (Type attributeType, bool inherit)
-               {
-                       throw new NotSupportedException ();
-               }
-
-               public override object [] GetCustomAttributes (bool inherit)
-               {
-                       if (IsCreated)
-                               return generic_type.GetCustomAttributes (inherit);
-                       throw new NotSupportedException ();
-               }
-
-               public override object [] GetCustomAttributes (Type attributeType, bool inherit)
-               {
-                       if (IsCreated)
-                               return generic_type.GetCustomAttributes (attributeType, inherit);
-                       throw new NotSupportedException ();
-               }
-
-               internal override bool IsUserType {
-                       get {
-                               foreach (var t in type_arguments) {
-                                       if (t.IsUserType)
-                                               return true;
-                               }
-                               return false;
-                       }
-               }
-
-       }
-}
-
-#endif
diff --git a/mcs/class/corlib/System.Reflection/MonoGenericMethod.cs b/mcs/class/corlib/System.Reflection/MonoGenericMethod.cs
deleted file mode 100644 (file)
index 48ef423..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// System.Reflection.MonoGenericMethod
-//
-// Martin Baulig (martin@ximian.com)
-//
-// (C) 2004 Novell, Inc.
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System.Reflection
-{
-       [Serializable]
-       [StructLayout (LayoutKind.Sequential)]
-       internal class MonoGenericMethod : MonoMethod
-       {
-               internal MonoGenericMethod ()
-               {
-                       // this should not be used
-                       throw new InvalidOperationException ();
-               }
-
-       }
-
-       [Serializable]
-       [StructLayout (LayoutKind.Sequential)]
-       internal class MonoGenericCMethod : MonoCMethod
-       {
-               internal MonoGenericCMethod ()
-               {
-                       // this should not be used
-                       throw new InvalidOperationException ();
-               }
-       }
-}
index 5e854cbe3e439f01312ecdf1ffe3b075c188a676..22b4ef6748ccc18659e36beff266127d8ce5c58f 100644 (file)
@@ -57,7 +57,7 @@ namespace System {
                 * of icalls, do not require an increment.
                 */
 #pragma warning disable 169
-               private const int mono_corlib_version = 157;
+               private const int mono_corlib_version = 158;
 #pragma warning restore 169
 
                [ComVisible (true)]
index 88ae954687a88ce11d5f10cb3545a875e77c0d35..7f5e1ee5000932c728fd8a48396d04bb37744518 100644 (file)
@@ -506,6 +506,8 @@ namespace MonoTests.System.Reflection.Emit
                }
 
                [Test]
+               // The token is not guaranteed to be 0x0a000001
+               [Category ("NotWorking")]
                public void ResolveFieldMemberRefWithGenericArguments ()
                {
                        var assembly = genAssembly ();
@@ -533,6 +535,8 @@ namespace MonoTests.System.Reflection.Emit
                }
 
                [Test]
+               // The token is not guaranteed to be 0x0a000002
+               [Category ("NotWorking")]
                public void ResolveMethodMemberRefWithGenericArguments ()
                {
                        var assembly = genAssembly ();
@@ -566,6 +570,8 @@ namespace MonoTests.System.Reflection.Emit
                }
 
                [Test]
+               // The token is not guaranteed to be 0x2b000001
+               [Category("NotWorking")]
                public void ResolveMethodSpecWithGenericArguments ()
                {
                        var assembly = genAssembly ();
index 43f32cfa5959467d35da5011b26986550ffe0368..be5f2168b83308df42b73a06d546194e128a8ead 100644 (file)
@@ -9748,6 +9748,33 @@ namespace MonoTests.System.Reflection.Emit
                        //Console.WriteLine (res[0]);
                }
 
+               [Test]
+               public void FieldWithInitializedDataWorksWithCompilerRuntimeHelpers2 ()
+               {
+                       TypeBuilder tb = module.DefineType ("Type1", TypeAttributes.Public);
+                       var garg = tb.DefineGenericParameters ("T") [0];
+                       FieldBuilder fb = tb.DefineInitializedData ("Foo", new byte [] {1,2,3,4}, FieldAttributes.Static|FieldAttributes.Public);
+                       tb.CreateType ();
+
+                       assembly = Thread.GetDomain ().DefineDynamicAssembly (new AssemblyName (ASSEMBLY_NAME+"2"), AssemblyBuilderAccess.RunAndSave, Path.GetTempPath ());
+                       module = assembly.DefineDynamicModule ("Instance.exe");
+
+                       TypeBuilder tb2 = module.DefineType ("Type2", TypeAttributes.Public);
+                       MethodBuilder mb = tb2.DefineMethod ("Test", MethodAttributes.Public | MethodAttributes.Static, typeof (object), new Type [0]);
+                       ILGenerator il = mb.GetILGenerator ();
+
+                       il.Emit (OpCodes.Ldc_I4_1);
+                       il.Emit (OpCodes.Newarr, typeof (int));
+                       il.Emit (OpCodes.Dup);
+                       il.Emit (OpCodes.Ldtoken, fb);
+                       il.Emit (OpCodes.Call, typeof (RuntimeHelpers).GetMethod ("InitializeArray"));
+                       il.Emit (OpCodes.Ret);
+
+                       Type t = tb2.CreateType ();
+                       int[] res = (int[])t.GetMethod ("Test").Invoke (null, new object[0]);
+                       //Console.WriteLine (res[0]);
+               }
+
                public interface IDelegateFactory
                {
                        Delegate Create (Delegate del);
index 95f0db7329cb36a446b037c41d2f4f6a1347bf06..80bce2dd720b884d1511d97509a096df15a917d6 100644 (file)
     <Compile Include="System.Reflection\MonoEvent.cs" />\r
     <Compile Include="System.Reflection\MonoField.cs" />\r
     <Compile Include="System.Reflection\MonoGenericClass.cs" />\r
-    <Compile Include="System.Reflection\MonoGenericMethod.cs" />\r
     <Compile Include="System.Reflection\MonoMethod.cs" />\r
     <Compile Include="System.Reflection\MonoModule.cs" />\r
     <Compile Include="System.Reflection\MonoParameterInfo.cs" />\r
index 3716291a2686d256f3466d4aa50d8b7ff0025a72..63f78fbf85b693364b17a468631e549b44abcd1c 100644 (file)
@@ -245,8 +245,6 @@ System.Reflection/MethodBody.cs
 System.Reflection/Module.cs
 System.Reflection/ModuleResolveEventHandler.cs
 System.Reflection/MonoAssembly.cs
-System.Reflection/MonoGenericClass.cs
-System.Reflection/MonoGenericMethod.cs
 System.Reflection/MonoEvent.cs
 System.Reflection/MonoField.cs
 System.Reflection/MonoMethod.cs
@@ -301,6 +299,7 @@ System.Reflection.Emit/SignatureToken.cs
 System.Reflection.Emit/StackBehaviour.cs
 System.Reflection.Emit/StringToken.cs
 System.Reflection.Emit/TypeBuilder.cs
+System.Reflection.Emit/TypeBuilderInstantiation.cs
 System.Reflection.Emit/TypeToken.cs
 System.Reflection.Emit/UnmanagedMarshal.cs
 System.Reflection.Emit/AssemblyBuilder.pns.cs
@@ -900,7 +899,6 @@ ReferenceSources/MethodBase.cs
 ReferenceSources/NativeMethods.cs
 ReferenceSources/RuntimeHandles.cs
 ReferenceSources/CompareInfo.cs
-ReferenceSources/TypeBuilderInstantiation.cs
 ReferenceSources/Buffer.cs
 ReferenceSources/TextInfo.cs
 ReferenceSources/win32native.cs
index a2e5ca0a4c157c1d6e97c17d340b90375fbbaef3..3489ee15514ca283e2c358fbbfa84cdeaf144b88 100644 (file)
@@ -29,7 +29,9 @@ namespace System.Linq.Expressions.Compiler {
         private const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public;
         private const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed;
         private const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual;
+#if FEATURE_REFEMIT
         private static readonly Type[] _DelegateCtorSignature = new Type[] { typeof(object), typeof(IntPtr) };
+#endif
 
         private static Type MakeNewCustomDelegate(Type[] types) {
 #if FEATURE_REFEMIT
index d603b38fdcb1197ccaefe0df9449a6646e0e5779..a86c03ff01e8cfc78fb5c08150c498456faf873f 100644 (file)
@@ -40,6 +40,7 @@ namespace System.Data.Sql {
 
         override public DataTable GetDataSources() {
 #if MONO
+            timeoutTime = 0;
             throw new NotImplementedException ();
 #else
             (new NamedPermissionSet("FullTrust")).Demand(); // SQLBUDT 244304
diff --git a/mcs/errors/cs0177-15.cs b/mcs/errors/cs0177-15.cs
new file mode 100644 (file)
index 0000000..310f405
--- /dev/null
@@ -0,0 +1,21 @@
+// CS0177: The out parameter `x' must be assigned to before control leaves the current method
+// Line: 6
+
+public class GotoWithOut
+{
+       public static void Test (bool cond, out int x)
+       {
+               if (cond)
+               {
+                       goto Label2;
+               }
+               else
+               {
+                       goto Label;
+               }
+               Label:
+               x = 0;
+               Label2:
+               return;
+       }
+}
\ No newline at end of file
index b2399c8bd89d45c71aee3882c56bb09c8fddd2e1..33b05ff809b320ddcb69813f7fbc448007e81153 100644 (file)
@@ -526,6 +526,19 @@ namespace Mono.CSharp
                        return da;
                }
 
+               public Dictionary<Statement, List<DefiniteAssignmentBitSet>> CopyLabelStack ()
+               {
+                       if (LabelStack == null)
+                               return null;
+
+                       var dest = new Dictionary<Statement, List<DefiniteAssignmentBitSet>> ();
+                       foreach (var entry in LabelStack) {
+                               dest.Add (entry.Key, new List<DefiniteAssignmentBitSet> (entry.Value));
+                       }
+
+                       return dest;
+               }
+
                public bool IsDefinitelyAssigned (VariableInfo variable)
                {
                        return variable.IsAssigned (DefiniteAssignment);
@@ -536,6 +549,11 @@ namespace Mono.CSharp
                        return variable.IsStructFieldAssigned (DefiniteAssignment, name);
                }
 
+               public void SetLabelStack (Dictionary<Statement, List<DefiniteAssignmentBitSet>> labelStack)
+               {
+                       LabelStack = labelStack;
+               }
+
                public void SetVariableAssigned (VariableInfo variable, bool generatedAssignment = false)
                {
                        variable.SetAssigned (DefiniteAssignment, generatedAssignment);
index b644e126dc1cecfab235cb03d5bac052d7c0b74e..eab87d16a17871ef5789fd98503ec70a99708f86 100644 (file)
@@ -270,10 +270,14 @@ namespace Mono.CSharp {
                        var da_false = new DefiniteAssignmentBitSet (fc.DefiniteAssignmentOnFalse);
 
                        fc.DefiniteAssignment = fc.DefiniteAssignmentOnTrue;
+                       var labels = fc.CopyLabelStack ();
 
                        var res = TrueStatement.FlowAnalysis (fc);
 
+                       fc.SetLabelStack (labels);
+
                        if (FalseStatement == null) {
+
                                var c = expr as Constant;
                                if (c != null && !c.IsDefaultValue)
                                        return true_returns;
@@ -288,14 +292,20 @@ namespace Mono.CSharp {
 
                        if (true_returns) {
                                fc.DefiniteAssignment = da_false;
-                               return FalseStatement.FlowAnalysis (fc);
+
+                               res = FalseStatement.FlowAnalysis (fc);
+                               fc.SetLabelStack (labels);
+                               return res;
                        }
 
                        var da_true = fc.DefiniteAssignment;
 
                        fc.DefiniteAssignment = da_false;
+
                        res &= FalseStatement.FlowAnalysis (fc);
 
+                       fc.SetLabelStack (labels);
+
                        if (!TrueStatement.IsUnreachable) {
                                if (false_returns || FalseStatement.IsUnreachable)
                                        fc.DefiniteAssignment = da_true;
diff --git a/mcs/tests/test-941.cs b/mcs/tests/test-941.cs
new file mode 100644 (file)
index 0000000..f5d90c0
--- /dev/null
@@ -0,0 +1,30 @@
+public class GotoCodeFlowBug
+{
+       public static void Test (bool cond, out int x)
+       {
+               if (cond)
+               {
+                       goto Label;
+               }
+               Label:
+               x = 0;
+       }
+
+       public static void Test2 (bool cond, out int x)
+       {
+               if (cond)
+               {
+                       goto Label;
+               }
+               else
+               {
+                       goto Label;
+               }
+               Label:
+               x = 0;
+       }
+
+       public static void Main ()
+       {
+       }
+}
\ No newline at end of file
index df5884f7fe914d2177021945f3f5aebe91ca4cc1..0ac3d56b53db124bf9f98bfae87da7b2ecf8f4cc 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-941.cs">
+    <type name="GotoCodeFlowBug">
+      <method name="Void Test(Boolean, Int32 ByRef)" attrs="150">
+        <size>17</size>
+      </method>
+      <method name="Void Test2(Boolean, Int32 ByRef)" attrs="150">
+        <size>23</size>
+      </method>
+      <method name="Void Main()" attrs="150">
+        <size>2</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-95.cs">
     <type name="X">
       <method name="Int32 Main()" attrs="150">
index 693318cbea7e07fdb27df8413379a15d159e7ac0..af120d403ed56646c67d8ad8299c5779f5a6cb12 100644 (file)
@@ -47,7 +47,8 @@ net_4_5_dirs := \
        mdbrebase       \
        ikdasm          \
        mono-symbolicate        \
-       linker-analyzer
+       linker-analyzer \
+       btls
 
 build_SUBDIRS = gacutil security culevel cil-stringreplacer commoncryptogenerator
 net_4_5_SUBDIRS = gacutil
diff --git a/mcs/tools/btls/AssemblyInfo.cs b/mcs/tools/btls/AssemblyInfo.cs
new file mode 100644 (file)
index 0000000..06f8d61
--- /dev/null
@@ -0,0 +1,26 @@
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle ("btls-cert-sync")]
+[assembly: AssemblyDescription ("btls-cert-sync")]
+[assembly: AssemblyDefaultAlias ("btls-cert-sync")]
+
+[assembly: AssemblyCompany (Consts.MonoCompany)]
+[assembly: AssemblyProduct (Consts.MonoProduct)]
+[assembly: AssemblyCopyright (Consts.MonoCopyright)]
+[assembly: AssemblyVersion (Consts.FxVersion)]
+[assembly: AssemblyFileVersion (Consts.FxFileVersion)]
+[assembly: SatelliteContractVersion (Consts.FxVersion)]
+[assembly: AssemblyInformationalVersion (Consts.FxFileVersion)]
+
+[assembly: CLSCompliant (true)]
+[assembly: NeutralResourcesLanguage ("en-US")]
+
+[assembly: ComVisible (false)]
+
+[assembly: AssemblyDelaySign (true)]
+[assembly: AssemblyKeyFile ("../../class/mono.pub")]
diff --git a/mcs/tools/btls/Makefile b/mcs/tools/btls/Makefile
new file mode 100644 (file)
index 0000000..b871a0f
--- /dev/null
@@ -0,0 +1,9 @@
+thisdir = tools/btls
+SUBDIRS = 
+include ../../build/rules.make
+
+LOCAL_MCS_FLAGS =
+LIB_REFS = System Mono.Security Mono.Btls.Interface
+PROGRAM = btls-cert-sync.exe
+
+include ../../build/executable.make
diff --git a/mcs/tools/btls/btls-cert-sync.cs b/mcs/tools/btls/btls-cert-sync.cs
new file mode 100644 (file)
index 0000000..0ef071f
--- /dev/null
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Security.Cryptography.X509Certificates;
+using Mono.Btls;
+
+namespace Mono.Btls
+{
+       static class BtlsCertSync
+       {
+               static void Main (string[] args)
+               {
+                       if (!MonoBtlsProvider.IsSupported ()) {
+                               Console.Error.WriteLine ("BTLS is not supported in this runtime!");
+                               Environment.Exit (255);
+                       }
+
+                       var configPath = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
+                       configPath = Path.Combine (configPath, ".mono");
+
+                       var oldStorePath = Path.Combine (configPath, "certs", "Trust");
+                       var newStorePath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.UserTrustedRoots);
+
+                       if (!Directory.Exists (oldStorePath)) {
+                               Console.WriteLine ("Old trust store {0} does not exist.");
+                               Environment.Exit (255);
+                       }
+
+                       if (Directory.Exists (newStorePath))
+                               Directory.Delete (newStorePath, true);
+                       Directory.CreateDirectory (newStorePath);
+
+                       var oldfiles = Directory.GetFiles (oldStorePath, "*.cer");
+                       Console.WriteLine ("Found {0} files in the old store.", oldfiles.Length);
+
+                       foreach (var file in oldfiles) {
+                               Console.WriteLine ("Converting {0}.", file);
+                               var data = File.ReadAllBytes (file);
+                               using (var x509 = MonoBtlsX509.LoadFromData (data, MonoBtlsX509Format.DER)) {
+                                       ConvertToNewFormat (newStorePath, x509);
+                               }
+                       }
+               }
+
+               static void ConvertToNewFormat (string root, MonoBtlsX509 x509)
+               {
+                       long hash = x509.GetSubjectNameHash ();
+
+                       string newName;
+                       int index = 0;
+                       do {
+                               newName = Path.Combine (root, string.Format ("{0:x8}.{1}", hash, index++));
+                       } while (File.Exists (newName));
+                       Console.WriteLine ("  new name: {0}", newName);
+
+                       using (var stream = new FileStream (newName, FileMode.Create))
+                       using (var bio = MonoBtlsBio.CreateMonoStream (stream))
+                                x509.ExportAsPEM (bio, true);
+               }
+       }
+}
diff --git a/mcs/tools/btls/btls-cert-sync.exe.sources b/mcs/tools/btls/btls-cert-sync.exe.sources
new file mode 100644 (file)
index 0000000..706d78f
--- /dev/null
@@ -0,0 +1,4 @@
+../../build/common/SR.cs
+../../build/common/Consts.cs
+AssemblyInfo.cs
+btls-cert-sync.cs
index 396acc5a69eb9d4b15cbab8a7e160fe041adcd2a..31764d0efac7e6113a3689c233918c2aed052786 100644 (file)
                <type fullname="System.Reflection.MonoEventInfo" preserve="fields" />
                <type fullname="System.Reflection.MonoField" preserve="fields" />
                <type fullname="System.Reflection.MonoGenericClass" preserve="fields" />
-               <type fullname="System.Reflection.MonoGenericMethod" preserve="fields" />
-               <type fullname="System.Reflection.MonoGenericCMethod" preserve="fields" />
                <type fullname="System.Reflection.MonoMethod" preserve="fields" />
                <type fullname="System.Reflection.MonoMethodInfo" preserve="fields" />
                <type fullname="System.Reflection.MonoPropertyInfo" preserve="fields" />
                <type fullname="System.Reflection.Emit.MethodBuilder" preserve="fields" />
                <type fullname="System.Reflection.Emit.ModuleBuilder" preserve="fields">
                        <method name="Mono_GetGuid" />
+                       <method name="RuntimeResolve" />
                </type>
                <type fullname="System.Reflection.Emit.MonoResource" preserve="fields" />
                <type fullname="System.Reflection.Emit.MonoWin32Resource" preserve="fields" />
index cc891536b8af26f751fb8fa1aebc08c5a5a42487..447540860f50024ec14df5685b4cf49d5fc3218d 100755 (executable)
@@ -386,11 +386,11 @@ class MakeBundle {
                                        }
                                }
                                
-                               Console.WriteLine ("Using runtime {0} for {1}", runtime, output);
                        }
                        GeneratePackage (files);
                }
-               
+               Console.WriteLine ("Generated {0}", output);
+
                return 0;
        }
 
@@ -608,6 +608,7 @@ class MakeBundle {
                }
                
                var maker = new PackageMaker (output);
+               Console.WriteLine ("Using runtime: " + runtime);
                maker.AddFile (runtime);
                
                foreach (var url in files){
@@ -615,9 +616,13 @@ class MakeBundle {
                        string aname = MakeBundle.GetAssemblyName (fname);
 
                        maker.Add ("assembly:" + aname, fname);
-                       if (File.Exists (fname + ".config"))
+                       Console.WriteLine ("     Assembly: " + fname);
+                       if (File.Exists (fname + ".config")){
                                maker.Add ("config:" + aname, fname + ".config");
+                               Console.WriteLine ("       Config: " + runtime);
+                       }
                }
+               
                if (!MaybeAddFile (maker, "systemconfig:", config_file) || !MaybeAddFile (maker, "machineconfig:", machine_config_file))
                        return false;
 
@@ -631,6 +636,7 @@ class MakeBundle {
                }
                if (libraries.Count > 0){
                        foreach (var alias_and_path in libraries){
+                               Console.WriteLine ("     Library:  " + alias_and_path.Value);
                                maker.Add ("library:" + alias_and_path.Key, alias_and_path.Value);
                        }
                }
index ac2c2ef82c72d87c20a4c9a4a86869f290bd53b1..f253194bd75a8d28d5ca08cf0ffc4f682db7e10f 100644 (file)
@@ -50,6 +50,7 @@ namespace Mono.Tools
                static string inputFile;
                static bool quiet;
                static bool userStore;
+               static bool btlsStore = true;
 
                static X509Certificate DecodeCertificate (string s)
                {
@@ -116,14 +117,19 @@ namespace Mono.Tools
                                return 0;
                        }
                                
-                       X509Stores stores = userStore ? X509StoreManager.CurrentUser : X509StoreManager.LocalMachine;
-                       X509CertificateCollection trusted = stores.TrustedRoot.Certificates;
+                       X509Stores stores;
+                       if (userStore)
+                               stores = btlsStore ? X509StoreManager.NewCurrentUser : X509StoreManager.CurrentUser;
+                       else
+                               stores = btlsStore ? X509StoreManager.NewLocalMachine : X509StoreManager.LocalMachine;
+                       X509Store store = stores.TrustedRoot;
+                       X509CertificateCollection trusted = store.Certificates;
                        int additions = 0;
                        WriteLine ("I already trust {0}, your new list has {1}", trusted.Count, roots.Count);
                        foreach (X509Certificate root in roots) {
                                if (!trusted.Contains (root)) {
                                        try {
-                                               stores.TrustedRoot.Import (root);
+                                               store.Import (root);
                                                WriteLine ("Certificate added: {0}", root.SubjectName);
                                                additions++;
                                        } catch (Exception e) {
@@ -145,7 +151,7 @@ namespace Mono.Tools
                                WriteLine ("{0} previously trusted certificates were removed.", removed.Count);
 
                                foreach (X509Certificate old in removed) {
-                                       stores.TrustedRoot.Remove (old);
+                                       store.Remove (old);
                                        WriteLine ("Certificate removed: {0}", old.SubjectName);
                                }
                        }
@@ -173,6 +179,9 @@ namespace Mono.Tools
                                case "--user":
                                        userStore = true;
                                        break;
+                               case "--legacy":
+                                       btlsStore = false;
+                                       break;
                                default:
                                        WriteLine ("Unknown option '{0}'.", args[i]);
                                        return false;
@@ -228,4 +237,4 @@ namespace Mono.Tools
                        }
                }
        }
-}
\ No newline at end of file
+}
index 7bf7b5c3dedfa0122abb5dba36dd6120370cb231..651271c25f895fe4a332287feba54f1eed76833f 100644 (file)
@@ -2,11 +2,15 @@ if SUPPORT_SGEN
 sgen_dirs = sgen
 endif
 
+if BTLS
+btls_dirs = btls
+endif
+
 if CROSS_COMPILING
-SUBDIRS = arch utils io-layer cil metadata $(sgen_dirs) mini dis profiler
+SUBDIRS = $(btls_dirs) arch utils io-layer cil metadata $(sgen_dirs) mini dis profiler
 else
 if INSTALL_MONOTOUCH
-SUBDIRS = arch utils io-layer metadata $(sgen_dirs) mini profiler
+SUBDIRS = $(btls_dirs) arch utils io-layer metadata $(sgen_dirs) mini profiler
 
 monotouch-do-build:
        @list='$(SUBDIRS)'; for subdir in $$list; do \
@@ -30,7 +34,7 @@ monotouch-do-clean:
          (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$target); \
     done;
 else
-SUBDIRS = arch utils io-layer cil metadata $(sgen_dirs) mini dis tests unit-tests benchmark profiler
+SUBDIRS = $(btls_dirs) arch utils io-layer cil metadata $(sgen_dirs) mini dis tests unit-tests benchmark profiler
 endif
 endif
-DIST_SUBDIRS = arch utils io-layer cil metadata $(sgen_dirs) mini dis tests unit-tests benchmark profiler
+DIST_SUBDIRS = btls arch utils io-layer cil metadata $(sgen_dirs) mini dis tests unit-tests benchmark profiler
diff --git a/mono/btls/.gitignore b/mono/btls/.gitignore
new file mode 100644 (file)
index 0000000..545f630
--- /dev/null
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+build/
+martin-test
+build-shared/
+build-static/
diff --git a/mono/btls/CMakeLists.txt b/mono/btls/CMakeLists.txt
new file mode 100644 (file)
index 0000000..aba7440
--- /dev/null
@@ -0,0 +1,93 @@
+cmake_minimum_required (VERSION 2.8.10)
+
+project (mono-btls)
+
+if(POLICY CMP0026)
+cmake_policy(SET CMP0026 NEW)
+endif()
+if(POLICY CMP0042)
+cmake_policy(SET CMP0042 NEW)
+endif()
+
+enable_language(C)
+enable_language(CXX)
+
+# FIXME: cmake's asm detection is broken when using xcrun.
+set (CMAKE_ASM_COMPILER "${CMAKE_C_COMPILER}")
+set (CMAKE_ASM_COMPILER_ARG1 "${CMAKE_C_COMPILER_ARG1}")
+set (CMAKE_ASM_COMPILER_ID "${CMAKE_C_COMPILER_ID}")
+enable_language(ASM)
+
+if (NOT "${BTLS_ARCH}" STREQUAL "")
+       message (WARNING "SET ARCH: ${BTLS_ARCH}")
+       set (CMAKE_SYSTEM_PROCESSOR "${BTLS_ARCH}")
+endif ()
+set (C_CXX_FLAGS "-Wall -Wsign-compare -Wmissing-field-initializers -ggdb -fvisibility=hidden")
+set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_CXX_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_CXX_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${BTLS_CFLAGS}")
+set (CMAKE_MACOSX_RPATH 1)
+set (MONO_BTLS 1)
+
+add_subdirectory (${BTLS_ROOT} boringssl)
+
+include_directories (
+       ${SRC_DIR}
+       ${BTLS_ROOT}/include
+)
+
+set (
+       MONO_BTLS_SOURCES
+
+       btls-bio.c
+       btls-bio.h
+       btls-error.c
+       btls-error.h
+       btls-key.c
+       btls-key.h
+       btls-pkcs12.c
+       btls-pkcs12.h
+       btls-ssl-ctx.c
+       btls-ssl-ctx.h
+       btls-ssl.c
+       btls-ssl.h
+       btls-util.c
+       btls-util.h
+       btls-x509-chain.c
+       btls-x509-chain.h
+       btls-x509-crl.c
+       btls-x509-crl.h
+       btls-x509-lookup.c
+       btls-x509-lookup.h
+       btls-x509-lookup-mono.c
+       btls-x509-lookup-mono.h
+       btls-x509-name.c
+       btls-x509-name.h
+       btls-x509-revoked.c
+       btls-x509-revoked.h
+       btls-x509-store-ctx.c
+       btls-x509-store-ctx.h
+       btls-x509-store.c
+       btls-x509-store.h
+       btls-x509-verify-param.c
+       btls-x509-verify-param.h
+       btls-x509.c
+       btls-x509.h
+
+       btls-android-utils.c
+
+       ${BORINGSSL_OBJECTS}
+)
+
+if (BUILD_SHARED_LIBS)
+       add_library (mono-btls-shared SHARED ${MONO_BTLS_SOURCES})
+       set_target_properties (mono-btls-shared PROPERTIES RULE_LAUNCH_LINK
+               "${PROJECT_SOURCE_DIR}/create-object-library.sh ${CMAKE_BINARY_DIR} mono-btls-shared.txt mono-btls-shared-lo.txt libmono-btls-shared.a shared ${CMAKE_AR} ${CMAKE_RANLIB} <OBJECTS> --"
+       )
+else ()
+       add_library (mono-btls-static STATIC ${MONO_BTLS_SOURCES})
+       set_target_properties (mono-btls-static PROPERTIES RULE_LAUNCH_LINK
+               "${PROJECT_SOURCE_DIR}/create-object-library.sh ${CMAKE_BINARY_DIR} mono-btls-static.txt mono-btls-static-lo.txt libmono-btls-static.a static ${CMAKE_AR} ${CMAKE_RANLIB} <OBJECTS> --"
+       )
+endif ()
+
diff --git a/mono/btls/Makefile.am b/mono/btls/Makefile.am
new file mode 100644 (file)
index 0000000..064a05d
--- /dev/null
@@ -0,0 +1,30 @@
+BTLS_STATIC_LIST = build-static/mono-btls-static-lo.txt
+BTLS_SHARED_LIST = build-shared/mono-btls-shared-lo.txt
+
+BTLS_DEPS = $(BTLS_LIBS) build-shared/Makefile build-static/Makefile
+
+CMAKE_VERBOSE=$(if $(V),VERBOSE=1,)
+
+CMAKE_ARGS = -D CMAKE_INSTALL_PREFIX:PATH=$(prefix) -D BTLS_ROOT:PATH=$(BTLS_ROOT) \
+       -D SRC_DIR:PATH=$(abs_top_srcdir)/mono/btls -D BTLS_CFLAGS:STRING="$(BTLS_CFLAGS)"
+
+all-local: $(BTLS_STATIC_LIST) $(BTLS_SHARED_LIST)
+
+build-shared/Makefile:
+       -mkdir -p build-shared
+       (cd build-shared && $(CMAKE) $(CMAKE_ARGS) $(BTLS_CMAKE_ARGS) -DBUILD_SHARED_LIBS=1 $(abs_top_srcdir)/mono/btls)
+
+build-static/Makefile:
+       -mkdir -p build-static
+       (cd build-static && $(CMAKE) $(CMAKE_ARGS) $(BTLS_CMAKE_ARGS) $(abs_top_srcdir)/mono/btls)
+
+$(BTLS_STATIC_LIST): build-static/Makefile
+       $(MAKE) -C build-static $(CMAKE_VERBOSE)
+
+$(BTLS_SHARED_LIST): build-shared/Makefile
+       $(MAKE) -C build-shared $(CMAKE_VERBOSE)
+
+clean-local:
+       -rm -rf build-static
+       -rm -rf build-shared
+
diff --git a/mono/btls/btls-android-utils.c b/mono/btls/btls-android-utils.c
new file mode 100644 (file)
index 0000000..df30f85
--- /dev/null
@@ -0,0 +1,33 @@
+// Copied from Chromium: https://src.chromium.org/svn/trunk/src/base/os_compat_android.cc
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(__ANDROID__)
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#if !defined(__LP64__)
+#include <time64.h>
+#endif
+
+#if !defined(__LP64__)
+// 32-bit Android has only timegm64() and not timegm().
+// We replicate the behaviour of timegm() when the result overflows time_t.
+time_t timegm(struct tm* const t) {
+  // time_t is signed on Android.
+  static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
+  static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
+  time64_t result = timegm64(t);
+  if (result < kTimeMin || result > kTimeMax)
+    return -1;
+  return result;
+}
+#endif
+
+#endif
diff --git a/mono/btls/btls-bio.c b/mono/btls/btls-bio.c
new file mode 100644 (file)
index 0000000..5af2d86
--- /dev/null
@@ -0,0 +1,206 @@
+//
+//  btls-bio.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include <btls-ssl.h>
+#include <btls-bio.h>
+#include <errno.h>
+
+struct MonoBtlsBio {
+       const void *instance;
+       MonoBtlsReadFunc read_func;
+       MonoBtlsWriteFunc write_func;
+       MonoBtlsControlFunc control_func;
+};
+
+#if 0
+static void
+mono_debug (const char *message)
+{
+       BIO *bio_err;
+       bio_err = BIO_new_fp (stderr, BIO_NOCLOSE);
+       fprintf (stderr, "DEBUG: %s\n", message);
+       ERR_print_errors (bio_err);
+}
+#endif
+
+static int
+mono_read (BIO *bio, char *out, int outl)
+{
+       MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+       int ret, wantMore;
+
+       if (!mono)
+               return -1;
+
+       ret = mono->read_func (mono->instance, out, outl, &wantMore);
+
+       if (ret < 0)
+               return -1;
+       if (ret > 0)
+               return ret;
+
+       if (wantMore) {
+               errno = EAGAIN;
+               BIO_set_retry_read (bio);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+mono_write (BIO *bio, const char *in, int inl)
+{
+       MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+       if (!mono)
+               return -1;
+
+       return mono->write_func (mono->instance, in, inl);
+}
+
+static long
+mono_ctrl (BIO *bio, int cmd, long num, void *ptr)
+{
+       MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+       if (!mono)
+               return -1;
+
+       // fprintf (stderr, "mono_ctrl: %x - %lx - %p\n", cmd, num, ptr);
+       switch (cmd) {
+               case BIO_CTRL_FLUSH:
+                       return mono->control_func (mono->instance, MONO_BTLS_CONTROL_COMMAND_FLUSH, 0);
+               default:
+                       return -1;
+       }
+       return -1;
+}
+
+static int
+mono_new (BIO *bio)
+{
+       // mono_debug("mono_new!\n");
+       bio->init = 0;
+       bio->num = -1;
+       bio->flags = 0;
+       return 1;
+}
+
+static int
+mono_free (BIO *bio)
+{
+       // mono_debug ("mono_free!\n");
+       if (bio->ptr) {
+               MonoBtlsBio *mono = (MonoBtlsBio *)bio->ptr;
+
+               bio->ptr = NULL;
+               mono->instance = NULL;
+               mono->read_func = NULL;
+               mono->write_func = NULL;
+               mono->control_func = NULL;
+               free (mono);
+       }
+       return 1;
+}
+
+static const BIO_METHOD mono_method = {
+       BIO_TYPE_NONE, "mono", mono_write, mono_read,
+       NULL, NULL, mono_ctrl, mono_new, mono_free, NULL
+};
+
+BIO *
+mono_btls_bio_mono_new (void)
+{
+       BIO *bio;
+       MonoBtlsBio *monoBio;
+
+       bio = BIO_new (&mono_method);
+       if (!bio)
+               return NULL;
+
+       monoBio = calloc (1, sizeof (MonoBtlsBio));
+       if (!monoBio) {
+               BIO_free (bio);
+               return NULL;
+       }
+
+       bio->ptr = monoBio;
+       bio->init = 0;
+
+       return bio;
+}
+
+void
+mono_btls_bio_mono_initialize (BIO *bio, const void *instance,
+                             MonoBtlsReadFunc read_func, MonoBtlsWriteFunc write_func,
+                             MonoBtlsControlFunc control_func)
+{
+       MonoBtlsBio *monoBio = bio->ptr;
+
+       monoBio->instance = instance;
+       monoBio->read_func = read_func;
+       monoBio->write_func = write_func;
+       monoBio->control_func = control_func;
+
+       bio->init = 1;
+}
+
+int
+mono_btls_bio_read (BIO *bio, void *data, int len)
+{
+       return BIO_read (bio, data, len);
+}
+
+int
+mono_btls_bio_write (BIO *bio, const void *data, int len)
+{
+       return BIO_write (bio, data, len);
+}
+
+int
+mono_btls_bio_flush (BIO *bio)
+{
+       return BIO_flush (bio);
+}
+
+int
+mono_btls_bio_indent (BIO *bio, unsigned indent, unsigned max_indent)
+{
+       return BIO_indent (bio, indent, max_indent);
+}
+
+int
+mono_btls_bio_hexdump (BIO *bio, const uint8_t *data, int len, unsigned indent)
+{
+       return BIO_hexdump (bio, data, len, indent);
+}
+
+void
+mono_btls_bio_print_errors (BIO *bio)
+{
+       BIO_print_errors (bio);
+}
+
+void
+mono_btls_bio_free (BIO *bio)
+{
+       BIO_free (bio);
+}
+
+BIO *
+mono_btls_bio_mem_new (void)
+{
+       return BIO_new (BIO_s_mem ());
+}
+
+int
+mono_btls_bio_mem_get_data (BIO *bio, void **data)
+{
+       return (int)BIO_get_mem_data (bio, (char**)data);
+}
diff --git a/mono/btls/btls-bio.h b/mono/btls/btls-bio.h
new file mode 100644 (file)
index 0000000..d4429f6
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  btls-bio.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_bio__
+#define __btls__btls_bio__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+
+typedef enum {
+       MONO_BTLS_CONTROL_COMMAND_FLUSH = 1
+} MonoBtlsControlCommand;
+
+typedef int (* MonoBtlsReadFunc) (const void *instance, const void *buf, int size, int *wantMore);
+typedef int (* MonoBtlsWriteFunc) (const void *instance, const void *buf, int size);
+typedef long (* MonoBtlsControlFunc) (const void *instance, MonoBtlsControlCommand command, long arg);
+
+BIO *
+mono_btls_bio_mono_new (void);
+
+void
+mono_btls_bio_mono_initialize (BIO *bio, const void *instance,
+                             MonoBtlsReadFunc read_func, MonoBtlsWriteFunc write_func,
+                             MonoBtlsControlFunc control_func);
+
+int
+mono_btls_bio_read (BIO *bio, void *data, int len);
+
+int
+mono_btls_bio_write (BIO *bio, const void *data, int len);
+
+int
+mono_btls_bio_flush (BIO *bio);
+
+int
+mono_btls_bio_indent (BIO *bio, unsigned indent, unsigned max_indent);
+
+int
+mono_btls_bio_hexdump (BIO *bio, const uint8_t *data, int len, unsigned indent);
+
+void
+mono_btls_bio_print_errors (BIO *bio);
+
+void
+mono_btls_bio_free (BIO *bio);
+
+BIO *
+mono_btls_bio_mem_new (void);
+
+int
+mono_btls_bio_mem_get_data (BIO *bio, void **data);
+
+#endif /* defined(__btls__btls_bio__) */
diff --git a/mono/btls/btls-error.c b/mono/btls/btls-error.c
new file mode 100644 (file)
index 0000000..8ed950c
--- /dev/null
@@ -0,0 +1,35 @@
+//
+//  btls-error.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 6/19/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-error.h>
+#include <assert.h>
+
+int
+mono_btls_error_peek_error (void)
+{
+       return ERR_peek_error ();
+}
+
+int
+mono_btls_error_get_error (void)
+{
+       return ERR_get_error ();
+}
+
+void
+mono_btls_error_clear_error (void)
+{
+       ERR_clear_error ();
+}
+
+void
+mono_btls_error_get_error_string_n (int error, char *buf, int len)
+{
+       ERR_error_string_n (error, buf, len);
+}
+
diff --git a/mono/btls/btls-error.h b/mono/btls/btls-error.h
new file mode 100644 (file)
index 0000000..6f791c3
--- /dev/null
@@ -0,0 +1,29 @@
+//
+//  btls-util.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_error__
+#define __btls__btls_error__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/ssl.h>
+
+int
+mono_btls_error_peek_error (void);
+
+int
+mono_btls_error_get_error (void);
+
+void
+mono_btls_error_clear_error (void);
+
+void
+mono_btls_error_get_error_string_n (int error, char *buf, int len);
+
+#endif /* __btls__btls_error__ */
diff --git a/mono/btls/btls-key.c b/mono/btls/btls-key.c
new file mode 100644 (file)
index 0000000..756f9c7
--- /dev/null
@@ -0,0 +1,62 @@
+//
+//  btls-key.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/7/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-key.h>
+
+void
+mono_btls_key_free (EVP_PKEY *pkey)
+{
+       EVP_PKEY_free (pkey);
+}
+
+EVP_PKEY *
+mono_btls_key_up_ref (EVP_PKEY *pkey)
+{
+       return EVP_PKEY_up_ref (pkey);
+}
+
+int
+mono_btls_key_get_bits (EVP_PKEY *pkey)
+{
+       return EVP_PKEY_bits (pkey);
+}
+
+int
+mono_btls_key_is_rsa (EVP_PKEY *pkey)
+{
+       return pkey->type == EVP_PKEY_RSA;
+}
+
+int
+mono_btls_key_get_bytes (EVP_PKEY *pkey, uint8_t **buffer, int *size, int include_private_bits)
+{
+       size_t len;
+       RSA *rsa;
+       int ret;
+
+       *size = 0;
+       *buffer = NULL;
+
+       if (pkey->type != EVP_PKEY_RSA)
+               return 0;
+
+       rsa = EVP_PKEY_get1_RSA (pkey);
+       if (!rsa)
+               return 0;
+
+       if (include_private_bits)
+               ret = RSA_private_key_to_bytes (buffer, &len, rsa);
+       else
+               ret = RSA_public_key_to_bytes (buffer, &len, rsa);
+
+       if (ret != 1)
+               return 0;
+
+       *size = (int)len;
+       return 1;
+}
diff --git a/mono/btls/btls-key.h b/mono/btls/btls-key.h
new file mode 100644 (file)
index 0000000..85ee5b2
--- /dev/null
@@ -0,0 +1,32 @@
+//
+//  btls-key.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/7/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_key__
+#define __btls__btls_key__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+
+void
+mono_btls_key_free (EVP_PKEY *pkey);
+
+EVP_PKEY *
+mono_btls_key_up_ref (EVP_PKEY *pkey);
+
+int
+mono_btls_key_get_bits (EVP_PKEY *pkey);
+
+int
+mono_btls_key_is_rsa (EVP_PKEY *pkey);
+
+int
+mono_btls_key_get_bytes (EVP_PKEY *pkey, uint8_t **buffer, int *size, int include_private_bits);
+
+#endif /* __btls__btls_key__ */
+
diff --git a/mono/btls/btls-pkcs12.c b/mono/btls/btls-pkcs12.c
new file mode 100644 (file)
index 0000000..d037ddb
--- /dev/null
@@ -0,0 +1,101 @@
+//
+//  btls-pkcs12.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/8/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-pkcs12.h>
+#include <openssl/pkcs12.h>
+
+struct MonoBtlsPkcs12 {
+       STACK_OF(X509) *certs;
+       EVP_PKEY *private_key;
+       CRYPTO_refcount_t references;
+};
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_new (void)
+{
+       MonoBtlsPkcs12 *pkcs12 = (MonoBtlsPkcs12 *)OPENSSL_malloc (sizeof (MonoBtlsPkcs12));
+       if (pkcs12 == NULL)
+               return NULL;
+
+       memset (pkcs12, 0, sizeof(MonoBtlsPkcs12));
+       pkcs12->certs = sk_X509_new_null ();
+       pkcs12->references = 1;
+       return pkcs12;
+}
+
+int
+mono_btls_pkcs12_get_count (MonoBtlsPkcs12 *pkcs12)
+{
+       return (int)sk_X509_num (pkcs12->certs);
+}
+
+X509 *
+mono_btls_pkcs12_get_cert (MonoBtlsPkcs12 *pkcs12, int index)
+{
+       X509 *cert;
+
+       if ((size_t)index >= sk_X509_num (pkcs12->certs))
+               return NULL;
+       cert = sk_X509_value (pkcs12->certs, index);
+       if (cert)
+               X509_up_ref (cert);
+       return cert;
+}
+
+STACK_OF(X509) *
+mono_btls_pkcs12_get_certs (MonoBtlsPkcs12 *pkcs12)
+{
+       return pkcs12->certs;
+}
+
+int
+mono_btls_pkcs12_free (MonoBtlsPkcs12 *pkcs12)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero (&pkcs12->references))
+               return 0;
+
+       sk_X509_pop_free (pkcs12->certs, X509_free);
+       OPENSSL_free (pkcs12);
+       return 1;
+}
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_up_ref (MonoBtlsPkcs12 *pkcs12)
+{
+       CRYPTO_refcount_inc (&pkcs12->references);
+       return pkcs12;
+}
+
+void
+mono_btls_pkcs12_add_cert (MonoBtlsPkcs12 *pkcs12, X509 *x509)
+{
+       X509_up_ref (x509);
+       sk_X509_push (pkcs12->certs, x509);
+}
+
+int
+mono_btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const void *password)
+{
+       CBS cbs;
+       CBS_init (&cbs, data, len);
+       return PKCS12_get_key_and_certs (&pkcs12->private_key, pkcs12->certs, &cbs, password);
+}
+
+int
+mono_btls_pkcs12_has_private_key (MonoBtlsPkcs12 *pkcs12)
+{
+       return pkcs12->private_key != NULL;
+}
+
+EVP_PKEY *
+mono_btls_pkcs12_get_private_key (MonoBtlsPkcs12 *pkcs12)
+{
+       if (!pkcs12->private_key)
+               return NULL;
+       return EVP_PKEY_up_ref (pkcs12->private_key);
+}
diff --git a/mono/btls/btls-pkcs12.h b/mono/btls/btls-pkcs12.h
new file mode 100644 (file)
index 0000000..20c4fd9
--- /dev/null
@@ -0,0 +1,46 @@
+//
+//  btls-pkcs12.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/8/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_pkcs12__
+#define __btls__btls_pkcs12__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_new (void);
+
+int
+mono_btls_pkcs12_get_count (MonoBtlsPkcs12 *pkcs12);
+
+X509 *
+mono_btls_pkcs12_get_cert (MonoBtlsPkcs12 *pkcs12, int index);
+
+STACK_OF(X509) *
+mono_btls_pkcs12_get_certs (MonoBtlsPkcs12 *pkcs12);
+
+int
+mono_btls_pkcs12_free (MonoBtlsPkcs12 *pkcs12);
+
+MonoBtlsPkcs12 *
+mono_btls_pkcs12_up_ref (MonoBtlsPkcs12 *pkcs12);
+
+void
+mono_btls_pkcs12_add_cert (MonoBtlsPkcs12 *pkcs12, X509 *x509);
+
+int
+mono_btls_pkcs12_import (MonoBtlsPkcs12 *pkcs12, const void *data, int len, const void *password);
+
+int
+mono_btls_pkcs12_has_private_key (MonoBtlsPkcs12 *pkcs12);
+
+EVP_PKEY *
+mono_btls_pkcs12_get_private_key (MonoBtlsPkcs12 *pkcs12);
+
+#endif /* __btls__btls_pkcs12__ */
diff --git a/mono/btls/btls-ssl-ctx.c b/mono/btls/btls-ssl-ctx.c
new file mode 100644 (file)
index 0000000..ddbb02f
--- /dev/null
@@ -0,0 +1,255 @@
+//
+//  btls-ssl-ctx.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 4/11/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-ssl-ctx.h>
+#include <btls-x509-verify-param.h>
+
+struct MonoBtlsSslCtx {
+       CRYPTO_refcount_t references;
+       SSL_CTX *ctx;
+       BIO *bio;
+       BIO *debug_bio;
+       void *instance;
+       MonoBtlsVerifyFunc verify_func;
+       MonoBtlsSelectFunc select_func;
+};
+
+#define debug_print(ptr,message) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
+mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " message, __FILE__, __LINE__, \
+       __func__); } while (0)
+
+#define debug_printf(ptr,fmt, ...) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
+mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
+       __func__, __VA_ARGS__); } while (0)
+
+void ssl_cipher_preference_list_free (struct ssl_cipher_preference_list_st *cipher_list);
+
+int
+mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx)
+{
+       return ctx->debug_bio != NULL;
+}
+
+int
+mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...)
+{
+       va_list args;
+       int ret;
+
+       if (!ctx->debug_bio)
+               return 0;
+
+       va_start (args, format);
+       ret = mono_btls_debug_printf (ctx->debug_bio, format, args);
+       va_end (args);
+       return ret;
+}
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_new (void)
+{
+       MonoBtlsSslCtx *ctx;
+
+       ctx = OPENSSL_malloc (sizeof (MonoBtlsSslCtx));
+       if (!ctx)
+               return NULL;
+
+       memset (ctx, 0, sizeof (MonoBtlsSslCtx));
+       ctx->references = 1;
+       ctx->ctx = SSL_CTX_new (TLS_method ());
+       return ctx;
+}
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx)
+{
+       CRYPTO_refcount_inc (&ctx->references);
+       return ctx;
+}
+
+int
+mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
+               return 0;
+       SSL_CTX_free (ctx->ctx);
+       ctx->instance = NULL;
+       OPENSSL_free (ctx);
+       return 1;
+}
+
+SSL_CTX *
+mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx)
+{
+       return ctx->ctx;
+}
+
+void
+mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio)
+{
+       if (debug_bio)
+               ctx->debug_bio = BIO_up_ref(debug_bio);
+       else
+               ctx->debug_bio = NULL;
+}
+
+void
+mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance)
+{
+       ctx->instance = instance;
+}
+
+static int
+cert_verify_callback (X509_STORE_CTX *storeCtx, void *arg)
+{
+       MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
+       int ret;
+
+       debug_printf (ptr, "cert_verify_callback(): %p\n", ptr->verify_func);
+       ret = X509_verify_cert (storeCtx);
+       debug_printf (ptr, "cert_verify_callback() #1: %d\n", ret);
+
+       if (ptr->verify_func)
+               ret = ptr->verify_func (ptr->instance, ret, storeCtx);
+
+       return ret;
+}
+
+void
+mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required)
+{
+       int mode;
+
+       ptr->verify_func = func;
+       SSL_CTX_set_cert_verify_callback (ptr->ctx, cert_verify_callback, ptr);
+
+       mode = SSL_VERIFY_PEER;
+       if (cert_required)
+               mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+
+       SSL_CTX_set_verify (ptr->ctx, mode, NULL);
+}
+
+static int
+cert_select_callback (SSL *ssl, void *arg)
+{
+       MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
+       int ret = 1;
+
+       debug_printf (ptr, "cert_select_callback(): %p\n", ptr->select_func);
+       if (ptr->select_func)
+               ret = ptr->select_func (ptr->instance);
+       debug_printf (ptr, "cert_select_callback() #1: %d\n", ret);
+
+       return ret;
+}
+
+void
+mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func)
+{
+       ptr->select_func = func;
+       SSL_CTX_set_cert_cb (ptr->ctx, cert_select_callback, ptr);
+}
+
+X509_STORE *
+mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx)
+{
+       return SSL_CTX_get_cert_store (ctx->ctx);
+}
+
+void
+mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version)
+{
+       SSL_CTX_set_min_version (ctx->ctx, version);
+}
+
+void
+mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version)
+{
+       SSL_CTX_set_max_version (ctx->ctx, version);
+}
+
+int
+mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value)
+{
+       const SSL_CIPHER *cipher;
+
+       cipher = SSL_get_cipher_by_value (value);
+       return cipher != NULL;
+}
+
+int
+mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
+                                  int allow_unsupported)
+{
+       STACK_OF(SSL_CIPHER) *ciphers = NULL;
+       struct ssl_cipher_preference_list_st *pref_list = NULL;
+       uint8_t *in_group_flags = NULL;
+       int i;
+
+       ciphers = sk_SSL_CIPHER_new_null ();
+       if (!ciphers)
+               goto err;
+
+       for (i = 0; i < count; i++) {
+               const SSL_CIPHER *cipher = SSL_get_cipher_by_value (data [i]);
+               if (!cipher) {
+                       debug_printf (ctx, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data [i]);
+                       if (!allow_unsupported)
+                               goto err;
+                       continue;
+               }
+               if (!sk_SSL_CIPHER_push (ciphers, cipher))
+                        goto err;
+       }
+
+       pref_list = OPENSSL_malloc (sizeof (struct ssl_cipher_preference_list_st));
+       if (!pref_list)
+               goto err;
+
+       memset (pref_list, 0, sizeof (struct ssl_cipher_preference_list_st));
+       pref_list->ciphers = sk_SSL_CIPHER_dup (ciphers);
+       if (!pref_list->ciphers)
+               goto err;
+       pref_list->in_group_flags = OPENSSL_malloc (sk_SSL_CIPHER_num (ciphers));
+       if (!pref_list->in_group_flags)
+               goto err;
+
+       if (ctx->ctx->cipher_list)
+               ssl_cipher_preference_list_free (ctx->ctx->cipher_list);
+       if (ctx->ctx->cipher_list_by_id)
+               sk_SSL_CIPHER_free (ctx->ctx->cipher_list_by_id);
+       if (ctx->ctx->cipher_list_tls10) {
+               ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls10);
+               ctx->ctx->cipher_list_tls10 = NULL;
+       }
+       if (ctx->ctx->cipher_list_tls11) {
+               ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls11);
+               ctx->ctx->cipher_list_tls11 = NULL;
+       }
+
+       ctx->ctx->cipher_list = pref_list;
+       ctx->ctx->cipher_list_by_id = ciphers;
+
+       return (int)sk_SSL_CIPHER_num (ciphers);
+
+err:
+       sk_SSL_CIPHER_free (ciphers);
+       OPENSSL_free (pref_list);
+       OPENSSL_free (in_group_flags);
+       return 0;
+}
+
+int
+mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param)
+{
+       return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param));
+}
+
diff --git a/mono/btls/btls-ssl-ctx.h b/mono/btls/btls-ssl-ctx.h
new file mode 100644 (file)
index 0000000..0954192
--- /dev/null
@@ -0,0 +1,84 @@
+//
+//  btls-ssl-ctx.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 4/11/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls_ssl_ctx__btls_ssl_ctx__
+#define __btls_ssl_ctx__btls_ssl_ctx__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/ssl.h>
+#include <btls-util.h>
+
+typedef struct MonoBtlsBio MonoBtlsBio;
+typedef struct MonoBtlsX509Chain MonoBtlsX509Chain;
+typedef struct MonoBtlsX509Crl MonoBtlsX509Crl;
+typedef struct MonoBtlsX509Lookup MonoBtlsX509Lookup;
+typedef struct MonoBtlsX509LookupMono MonoBtlsX509LookupMono;
+typedef struct MonoBtlsX509Name MonoBtlsX509Name;
+typedef struct MonoBtlsX509Store MonoBtlsX509Store;
+typedef struct MonoBtlsX509StoreCtx MonoBtlsX509StoreCtx;
+typedef struct MonoBtlsX509Revoked MonoBtlsX509Revoked;
+typedef struct MonoBtlsX509VerifyParam MonoBtlsX509VerifyParam;
+typedef struct MonoBtlsPkcs12 MonoBtlsPkcs12;
+typedef struct MonoBtlsSsl MonoBtlsSsl;
+typedef struct MonoBtlsSslCtx MonoBtlsSslCtx;
+
+typedef int (* MonoBtlsVerifyFunc) (void *instance, int preverify_ok, X509_STORE_CTX *ctx);
+typedef int (* MonoBtlsSelectFunc) (void *instance);
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_new (void);
+
+MonoBtlsSslCtx *
+mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance);
+
+SSL_CTX *
+mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...);
+
+int
+mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required);
+
+void
+mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func);
+
+void
+mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio);
+
+X509_STORE *
+mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx);
+
+void
+mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version);
+
+void
+mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version);
+
+int
+mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value);
+
+int
+mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
+                                  int allow_unsupported);
+
+int
+mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param);
+
+#endif /* __btls_ssl_ctx__btls_ssl_ctx__ */
diff --git a/mono/btls/btls-ssl.c b/mono/btls/btls-ssl.c
new file mode 100644 (file)
index 0000000..fa3e53d
--- /dev/null
@@ -0,0 +1,209 @@
+//
+//  btls-ssl.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include <btls-ssl.h>
+#include <btls-x509-verify-param.h>
+
+struct MonoBtlsSsl {
+       MonoBtlsSslCtx *ctx;
+       SSL *ssl;
+};
+
+#define debug_print(ptr,message) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr->ctx)) \
+mono_btls_ssl_ctx_debug_printf (ptr->ctx, "%s:%d:%s(): " message, __FILE__, __LINE__, \
+__func__); } while (0)
+
+#define debug_printf(ptr,fmt, ...) \
+do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr->ctx)) \
+mono_btls_ssl_ctx_debug_printf (ptr->ctx, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
+__func__, __VA_ARGS__); } while (0)
+
+STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list (SSL *s, const CBS *cbs);
+
+MonoBtlsSsl *
+mono_btls_ssl_new (MonoBtlsSslCtx *ctx)
+{
+       MonoBtlsSsl *ptr;
+
+       ptr = calloc (1, sizeof (MonoBtlsSsl));
+
+       ptr->ctx = mono_btls_ssl_ctx_up_ref (ctx);
+       ptr->ssl = SSL_new (mono_btls_ssl_ctx_get_ctx (ptr->ctx));
+
+       SSL_set_options (ptr->ssl, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
+
+       return ptr;
+}
+
+void
+mono_btls_ssl_destroy (MonoBtlsSsl *ptr)
+{
+       mono_btls_ssl_close (ptr);
+       if (ptr->ssl) {
+               SSL_free (ptr->ssl);
+               ptr->ssl = NULL;
+       }
+       if (ptr->ctx) {
+               mono_btls_ssl_ctx_free (ptr->ctx);
+               ptr->ctx = NULL;
+       }
+       free (ptr);
+}
+
+void
+mono_btls_ssl_close (MonoBtlsSsl *ptr)
+{
+       ;
+}
+
+void
+mono_btls_ssl_set_bio (MonoBtlsSsl *ptr, BIO *bio)
+{
+       BIO_up_ref (bio);
+       SSL_set_bio (ptr->ssl, bio, bio);
+}
+
+void
+mono_btls_ssl_print_errors_cb (ERR_print_errors_callback_t callback, void *ctx)
+{
+       ERR_print_errors_cb (callback, ctx);
+}
+
+int
+mono_btls_ssl_use_certificate (MonoBtlsSsl *ptr, X509 *x509)
+{
+       return SSL_use_certificate (ptr->ssl, x509);
+}
+
+int
+mono_btls_ssl_use_private_key (MonoBtlsSsl *ptr, EVP_PKEY *key)
+{
+       return SSL_use_PrivateKey (ptr->ssl, key);
+}
+
+int
+mono_btls_ssl_add_chain_certificate (MonoBtlsSsl *ptr, X509 *x509)
+{
+       return SSL_add1_chain_cert (ptr->ssl, x509);
+}
+
+int
+mono_btls_ssl_accept (MonoBtlsSsl *ptr)
+{
+       return SSL_accept (ptr->ssl);
+}
+
+int
+mono_btls_ssl_connect (MonoBtlsSsl *ptr)
+{
+       return SSL_connect (ptr->ssl);
+}
+
+int
+mono_btls_ssl_handshake (MonoBtlsSsl *ptr)
+{
+       return SSL_do_handshake (ptr->ssl);
+}
+
+int
+mono_btls_ssl_read (MonoBtlsSsl *ptr, void *buf, int count)
+{
+       return SSL_read (ptr->ssl, buf, count);
+}
+
+int
+mono_btls_ssl_write (MonoBtlsSsl *ptr, void *buf, int count)
+{
+       return SSL_write (ptr->ssl, buf, count);
+}
+
+int
+mono_btls_ssl_get_version (MonoBtlsSsl *ptr)
+{
+       return SSL_version (ptr->ssl);
+}
+
+void
+mono_btls_ssl_set_min_version (MonoBtlsSsl *ptr, int version)
+{
+       SSL_set_min_version (ptr->ssl, version);
+}
+
+void
+mono_btls_ssl_set_max_version (MonoBtlsSsl *ptr, int version)
+{
+       SSL_set_max_version (ptr->ssl, version);
+}
+
+int
+mono_btls_ssl_get_cipher (MonoBtlsSsl *ptr)
+{
+       const SSL_CIPHER *cipher;
+
+       cipher = SSL_get_current_cipher (ptr->ssl);
+       if (!cipher)
+               return 0;
+       return (uint16_t)SSL_CIPHER_get_id (cipher);
+}
+
+int
+mono_btls_ssl_set_cipher_list (MonoBtlsSsl *ptr, const char *str)
+{
+       return SSL_set_cipher_list(ptr->ssl, str);
+}
+
+int
+mono_btls_ssl_get_ciphers (MonoBtlsSsl *ptr, uint16_t **data)
+{
+       STACK_OF(SSL_CIPHER) *ciphers;
+       int count, i;
+
+       *data = NULL;
+
+       ciphers = SSL_get_ciphers (ptr->ssl);
+       if (!ciphers)
+               return 0;
+
+       count = (int)sk_SSL_CIPHER_num (ciphers);
+
+       *data = OPENSSL_malloc (2 * count);
+       if (!*data)
+               return 0;
+
+       for (i = 0; i < count; i++) {
+               const SSL_CIPHER *cipher = sk_SSL_CIPHER_value (ciphers, i);
+               (*data) [i] = (uint16_t) SSL_CIPHER_get_id (cipher);
+       }
+
+       return count;
+}
+
+X509 *
+mono_btls_ssl_get_peer_certificate (MonoBtlsSsl *ptr)
+{
+       return SSL_get_peer_certificate (ptr->ssl);
+}
+
+int
+mono_btls_ssl_get_error (MonoBtlsSsl *ptr, int ret_code)
+{
+       return SSL_get_error (ptr->ssl, ret_code);
+}
+
+int
+mono_btls_ssl_set_verify_param (MonoBtlsSsl *ptr, const MonoBtlsX509VerifyParam *param)
+{
+       return SSL_set1_param (ptr->ssl, mono_btls_x509_verify_param_peek_param (param));
+}
+
+int
+mono_btls_ssl_set_server_name (MonoBtlsSsl *ptr, const char *name)
+{
+       return SSL_set_tlsext_host_name (ptr->ssl, name);
+}
diff --git a/mono/btls/btls-ssl.h b/mono/btls/btls-ssl.h
new file mode 100644 (file)
index 0000000..10da436
--- /dev/null
@@ -0,0 +1,83 @@
+//
+//  btls-ssl.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_ssl__
+#define __btls__btls_ssl__
+
+#include <btls-ssl-ctx.h>
+
+MonoBtlsSsl *
+mono_btls_ssl_new (MonoBtlsSslCtx *ctx);
+
+int
+mono_btls_ssl_use_certificate (MonoBtlsSsl *ptr, X509 *x509);
+
+int
+mono_btls_ssl_use_private_key (MonoBtlsSsl *ptr, EVP_PKEY *key);
+
+int
+mono_btls_ssl_add_chain_certificate (MonoBtlsSsl *ptr, X509 *x509);
+
+int
+mono_btls_ssl_accept (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_connect (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_handshake (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_print_errors_cb (ERR_print_errors_callback_t callback, void *ctx);
+
+void
+mono_btls_ssl_set_bio (MonoBtlsSsl *ptr, BIO *bio);
+
+int
+mono_btls_ssl_read (MonoBtlsSsl *ptr, void *buf, int count);
+
+int
+mono_btls_ssl_write (MonoBtlsSsl *ptr, void *buf, int count);
+
+int
+mono_btls_ssl_get_version (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_set_min_version (MonoBtlsSsl *ptr, int version);
+
+void
+mono_btls_ssl_set_max_version (MonoBtlsSsl *ptr, int version);
+
+int
+mono_btls_ssl_get_cipher (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_set_cipher_list (MonoBtlsSsl *ptr, const char *str);
+
+int
+mono_btls_ssl_get_ciphers (MonoBtlsSsl *ptr, uint16_t **data);
+
+X509 *
+mono_btls_ssl_get_peer_certificate (MonoBtlsSsl *ptr);
+
+void
+mono_btls_ssl_close (MonoBtlsSsl *ptr);
+
+int
+mono_btls_ssl_get_error (MonoBtlsSsl *ptr, int ret_code);
+
+int
+mono_btls_ssl_set_verify_param (MonoBtlsSsl *ptr, const MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_ssl_set_server_name (MonoBtlsSsl *ptr, const char *name);
+
+void
+mono_btls_ssl_destroy (MonoBtlsSsl *ptr);
+
+#endif /* defined(__btls__btls_ssl__) */
diff --git a/mono/btls/btls-util.c b/mono/btls/btls-util.c
new file mode 100644 (file)
index 0000000..d28763a
--- /dev/null
@@ -0,0 +1,76 @@
+//
+//  btls-util.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-util.h>
+#include <assert.h>
+#include <time.h>
+
+#if defined(__ANDROID__) && !defined(__LP64__)
+#include <time64.h>
+extern time_t timegm (struct tm* const t);
+#endif
+
+extern int asn1_generalizedtime_to_tm (struct tm *tm, const ASN1_GENERALIZEDTIME *d);
+
+void
+mono_btls_free (void *data)
+{
+       OPENSSL_free (data);
+}
+
+long
+mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time)
+{
+       ASN1_GENERALIZEDTIME *gtime;
+       struct tm tm;
+       time_t epoch;
+
+       gtime = ASN1_TIME_to_generalizedtime (time, NULL);
+       asn1_generalizedtime_to_tm (&tm, gtime);
+       ASN1_GENERALIZEDTIME_free (gtime);
+       epoch = timegm(&tm);
+
+       return epoch;
+}
+
+// Copied from crypto/bio/printf.c, takes va_list
+int
+mono_btls_debug_printf (BIO *bio, const char *format, va_list args)
+{
+       char buf[256], *out, out_malloced = 0;
+       int out_len, ret;
+
+       out_len = vsnprintf (buf, sizeof(buf), format, args);
+       if (out_len < 0) {
+               return -1;
+       }
+
+       if ((size_t) out_len >= sizeof(buf)) {
+               const int requested_len = out_len;
+               /* The output was truncated. Note that vsnprintf's return value
+                * does not include a trailing NUL, but the buffer must be sized
+                * for it. */
+               out = OPENSSL_malloc (requested_len + 1);
+               out_malloced = 1;
+               if (out == NULL) {
+                       OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE);
+                       return -1;
+               }
+               out_len = vsnprintf (out, requested_len + 1, format, args);
+               assert(out_len == requested_len);
+       } else {
+               out = buf;
+       }
+
+       ret = BIO_write(bio, out, out_len);
+       if (out_malloced) {
+               OPENSSL_free(out);
+       }
+
+       return ret;
+}
diff --git a/mono/btls/btls-util.h b/mono/btls/btls-util.h
new file mode 100644 (file)
index 0000000..a77bfcd
--- /dev/null
@@ -0,0 +1,29 @@
+//
+//  btls-util.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_util__
+#define __btls__btls_util__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <openssl/ssl.h>
+
+void
+mono_btls_free (void *data);
+
+long
+mono_btls_util_asn1_time_to_ticks (ASN1_TIME *time);
+
+int
+mono_btls_debug_printf (BIO *bio, const char *format, va_list args);
+
+OPENSSL_EXPORT void CRYPTO_refcount_inc(CRYPTO_refcount_t *count);
+OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count);
+
+#endif /* __btls__btls_util__ */
diff --git a/mono/btls/btls-x509-chain.c b/mono/btls/btls-x509-chain.c
new file mode 100644 (file)
index 0000000..0584791
--- /dev/null
@@ -0,0 +1,96 @@
+//
+//  btls-x509-chain.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-chain.h>
+
+struct MonoBtlsX509Chain {
+       STACK_OF(X509) *certs;
+       CRYPTO_refcount_t references;
+};
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_new (void)
+{
+       MonoBtlsX509Chain *chain = (MonoBtlsX509Chain *)OPENSSL_malloc (sizeof (MonoBtlsX509Chain));
+       if (chain == NULL)
+               return NULL;
+
+       memset(chain, 0, sizeof(MonoBtlsX509Chain));
+       chain->certs = sk_X509_new_null ();
+       chain->references = 1;
+       return chain;
+}
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_from_certs (STACK_OF(X509) *certs)
+{
+       MonoBtlsX509Chain *chain = (MonoBtlsX509Chain *)OPENSSL_malloc (sizeof (MonoBtlsX509Chain));
+       if (chain == NULL)
+               return NULL;
+
+       memset(chain, 0, sizeof(MonoBtlsX509Chain));
+       chain->certs = X509_chain_up_ref(certs);
+       chain->references = 1;
+       return chain;
+}
+
+STACK_OF(X509) *
+mono_btls_x509_chain_peek_certs (MonoBtlsX509Chain *chain)
+{
+       return chain->certs;
+}
+
+int
+mono_btls_x509_chain_get_count (MonoBtlsX509Chain *chain)
+{
+       return (int)sk_X509_num(chain->certs);
+}
+
+X509 *
+mono_btls_x509_chain_get_cert (MonoBtlsX509Chain *chain, int index)
+{
+       X509 *cert;
+
+       if ((size_t)index >= sk_X509_num(chain->certs))
+               return NULL;
+       cert = sk_X509_value(chain->certs, index);
+       if (cert)
+               X509_up_ref(cert);
+       return cert;
+}
+
+STACK_OF(X509) *
+mono_btls_x509_chain_get_certs (MonoBtlsX509Chain *chain)
+{
+       return chain->certs;
+}
+
+int
+mono_btls_x509_chain_free (MonoBtlsX509Chain *chain)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero(&chain->references))
+               return 0;
+
+       sk_X509_pop_free(chain->certs, X509_free);
+       OPENSSL_free (chain);
+       return 1;
+}
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_up_ref (MonoBtlsX509Chain *chain)
+{
+       CRYPTO_refcount_inc(&chain->references);
+       return chain;
+}
+
+void
+mono_btls_x509_chain_add_cert (MonoBtlsX509Chain *chain, X509 *x509)
+{
+       X509_up_ref(x509);
+       sk_X509_push(chain->certs, x509);
+}
diff --git a/mono/btls/btls-x509-chain.h b/mono/btls/btls-x509-chain.h
new file mode 100644 (file)
index 0000000..68ef577
--- /dev/null
@@ -0,0 +1,41 @@
+//
+//  btls-x509-chain.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_chain__
+#define __btls__btls_x509_chain__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_new (void);
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_from_certs (STACK_OF(X509) *certs);
+
+STACK_OF(X509) *
+mono_btls_x509_chain_peek_certs (MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_chain_get_count (MonoBtlsX509Chain *chain);
+
+X509 *
+mono_btls_x509_chain_get_cert (MonoBtlsX509Chain *chain, int index);
+
+MonoBtlsX509Chain *
+mono_btls_x509_chain_up_ref (MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_chain_free (MonoBtlsX509Chain *chain);
+
+void
+mono_btls_x509_chain_add_cert (MonoBtlsX509Chain *chain, X509 *x509);
+
+#endif /* defined(__btls__btls_x509_chain__) */
+
diff --git a/mono/btls/btls-x509-crl.c b/mono/btls/btls-x509-crl.c
new file mode 100644 (file)
index 0000000..ccd3e28
--- /dev/null
@@ -0,0 +1,150 @@
+//
+//  btls-x509-crl.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-crl.h>
+#include <btls-x509-revoked.h>
+
+struct MonoBtlsX509Crl {
+       X509_CRL *crl;
+       CRYPTO_refcount_t references;
+};
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_from_data (const void *buf, int len, MonoBtlsX509Format format)
+{
+       MonoBtlsX509Crl *crl;
+       BIO *bio;
+
+       crl = OPENSSL_malloc (sizeof (MonoBtlsX509Crl));
+       memset (crl, 0, sizeof(MonoBtlsX509Crl));
+       crl->references = 1;
+
+       bio = BIO_new_mem_buf ((void *)buf, len);
+       switch (format) {
+               case MONO_BTLS_X509_FORMAT_DER:
+                       crl->crl = d2i_X509_CRL_bio (bio, NULL);
+                       break;
+               case MONO_BTLS_X509_FORMAT_PEM:
+                       crl->crl = PEM_read_bio_X509_CRL (bio, NULL, NULL, NULL);
+                       break;
+       }
+       BIO_free (bio);
+
+       if (!crl->crl) {
+               OPENSSL_free (crl);
+               return NULL;
+       }
+
+       return crl;
+}
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_ref (MonoBtlsX509Crl *crl)
+{
+       CRYPTO_refcount_inc (&crl->references);
+       return crl;
+}
+
+int
+mono_btls_x509_crl_free (MonoBtlsX509Crl *crl)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero (&crl->references))
+               return 0;
+
+       X509_CRL_free (crl->crl);
+       OPENSSL_free (crl);
+       return 1;
+}
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_cert (MonoBtlsX509Crl *crl, X509 *x509)
+{
+       X509_REVOKED *revoked;
+       int ret;
+
+       revoked = NULL;
+       ret = X509_CRL_get0_by_cert (crl->crl, &revoked, x509);
+       fprintf (stderr, "mono_btls_x509_crl_get_by_cert: %d - %p\n", ret, revoked);
+
+       if (!ret || !revoked)
+               return NULL;
+
+       return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_serial (MonoBtlsX509Crl *crl, void *serial, int len)
+{
+       ASN1_INTEGER si;
+       X509_REVOKED *revoked;
+       int ret;
+
+       si.type = V_ASN1_INTEGER;
+       si.length = len;
+       si.data = serial;
+
+       revoked = NULL;
+       ret = X509_CRL_get0_by_serial (crl->crl, &revoked, &si);
+       fprintf (stderr, "mono_btls_x509_crl_get_by_serial: %d - %p\n", ret, revoked);
+
+       if (!ret || !revoked)
+               return NULL;
+
+       return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+int
+mono_btls_x509_crl_get_revoked_count (MonoBtlsX509Crl *crl)
+{
+       STACK_OF(X509_REVOKED) *stack;
+
+       stack = X509_CRL_get_REVOKED (crl->crl);
+       return (int)sk_X509_REVOKED_num (stack);
+}
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index)
+{
+       STACK_OF(X509_REVOKED) *stack;
+       X509_REVOKED *revoked;
+
+       stack = X509_CRL_get_REVOKED (crl->crl);
+       if ((size_t)index >= sk_X509_REVOKED_num (stack))
+               return NULL;
+
+       revoked = sk_X509_REVOKED_value (stack, index);
+       if (!revoked)
+               return NULL;
+
+       return mono_btls_x509_revoked_new (crl, revoked);
+}
+
+long
+mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl)
+{
+       return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_lastUpdate (crl->crl));
+}
+
+long
+mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl)
+{
+       return mono_btls_util_asn1_time_to_ticks (X509_CRL_get_nextUpdate (crl->crl));
+}
+
+long
+mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl)
+{
+       return X509_CRL_get_version (crl->crl);
+}
+
+MonoBtlsX509Name *
+mono_btls_x509_crl_get_issuer (MonoBtlsX509Crl *crl)
+{
+       return mono_btls_x509_name_copy (X509_CRL_get_issuer (crl->crl));
+}
+
diff --git a/mono/btls/btls-x509-crl.h b/mono/btls/btls-x509-crl.h
new file mode 100644 (file)
index 0000000..0813fe5
--- /dev/null
@@ -0,0 +1,49 @@
+//
+//  btls-x509-crl.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_crl__
+#define __btls__btls_x509_crl__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_from_data (const void *buf, int len, MonoBtlsX509Format format);
+
+MonoBtlsX509Crl *
+mono_btls_x509_crl_ref (MonoBtlsX509Crl *crl);
+
+int
+mono_btls_x509_crl_free (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_cert (MonoBtlsX509Crl *crl, X509 *x509);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_by_serial (MonoBtlsX509Crl *crl, void *serial, int len);
+
+int
+mono_btls_x509_crl_get_revoked_count (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Revoked *
+mono_btls_x509_crl_get_revoked (MonoBtlsX509Crl *crl, int index);
+
+long
+mono_btls_x509_crl_get_last_update (MonoBtlsX509Crl *crl);
+
+long
+mono_btls_x509_crl_get_next_update (MonoBtlsX509Crl *crl);
+
+long
+mono_btls_x509_crl_get_version (MonoBtlsX509Crl *crl);
+
+MonoBtlsX509Name *
+mono_btls_x509_crl_get_issuer (MonoBtlsX509Crl *crl);
+
+#endif /* __btls__btls_x509_crl__ */
diff --git a/mono/btls/btls-x509-lookup-mono.c b/mono/btls/btls-x509-lookup-mono.c
new file mode 100644 (file)
index 0000000..cce7368
--- /dev/null
@@ -0,0 +1,228 @@
+//
+//  btls-x509-lookup-mono.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/6/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-lookup.h>
+#include <btls-x509-lookup-mono.h>
+#include <openssl/stack.h>
+
+// random high number
+#define MONO_BTLS_X509_L_MONO_ADD      36292
+
+typedef struct MonoLookupNode MonoLookupNode;
+struct MonoLookupNode {
+       MonoBtlsX509LookupMono *mono;
+       MonoLookupNode *next;
+};
+
+typedef struct {
+       MonoLookupNode *nodes;
+} MonoLookup;
+
+struct MonoBtlsX509LookupMono {
+       const void *instance;
+       MonoBtlsX509LookupMono_BySubject by_subject_func;
+       MonoLookup *lookup;
+};
+
+MonoBtlsX509LookupMono *
+mono_btls_x509_lookup_mono_new (void)
+{
+       MonoBtlsX509LookupMono *mono;
+
+       mono = OPENSSL_malloc (sizeof (MonoBtlsX509LookupMono));
+       if (!mono)
+               return NULL;
+
+       memset (mono, 0, sizeof (MonoBtlsX509LookupMono));
+       return mono;
+}
+
+void
+mono_btls_x509_lookup_mono_init (MonoBtlsX509LookupMono *mono, const void *instance,
+                                MonoBtlsX509LookupMono_BySubject by_subject_func)
+{
+       mono->instance = instance;
+       mono->by_subject_func = by_subject_func;
+}
+
+static int
+mono_lookup_install (MonoLookup *lookup, MonoBtlsX509LookupMono *mono)
+{
+       MonoLookupNode *node;
+
+       node = OPENSSL_malloc (sizeof (MonoLookupNode));
+       if (!node)
+               return 0;
+
+       memset (node, 0, sizeof (MonoLookupNode));
+       mono->lookup = lookup;
+       node->mono = mono;
+       node->next = lookup->nodes;
+       lookup->nodes = node;
+       return 1;
+}
+
+static int
+mono_lookup_uninstall (MonoBtlsX509LookupMono *mono)
+{
+       MonoLookupNode **ptr;
+
+       if (!mono->lookup)
+               return 0;
+
+       for (ptr = &mono->lookup->nodes; *ptr; ptr = &(*ptr)->next) {
+               if ((*ptr)->mono == mono) {
+                       *ptr = (*ptr)->next;
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+int
+mono_btls_x509_lookup_mono_free (MonoBtlsX509LookupMono *mono)
+{
+       mono->instance = NULL;
+       mono->by_subject_func = NULL;
+
+       if (mono->lookup) {
+               if (!mono_lookup_uninstall (mono))
+                       return 0;
+       }
+
+       mono->lookup = NULL;
+
+       OPENSSL_free (mono);
+       return 1;
+}
+
+static int
+mono_lookup_ctrl (X509_LOOKUP *ctx, int cmd, const char *argp, long argl, char **ret)
+{
+       MonoLookup *lookup = (MonoLookup*)ctx->method_data;
+       MonoBtlsX509LookupMono *mono = (MonoBtlsX509LookupMono*)argp;
+
+       if (!lookup || cmd != MONO_BTLS_X509_L_MONO_ADD)
+               return 0;
+       if (!mono || mono->lookup)
+               return 0;
+
+       return mono_lookup_install (lookup, mono);
+}
+
+static int
+mono_lookup_new (X509_LOOKUP *ctx)
+{
+       MonoLookup *data;
+
+       data = OPENSSL_malloc (sizeof (MonoLookup));
+       if (!data)
+               return 0;
+
+       memset (data, 0, sizeof (MonoLookup));
+       ctx->method_data = (void *)data;
+       return 1;
+}
+
+static void
+mono_lookup_free (X509_LOOKUP *ctx)
+{
+       MonoLookup *lookup;
+       MonoLookupNode *ptr;
+
+       lookup = (MonoLookup *)ctx->method_data;
+       ctx->method_data = NULL;
+       if (!lookup)
+               return;
+
+       ptr = lookup->nodes;
+       lookup->nodes = NULL;
+
+       while (ptr) {
+               MonoLookupNode *node = ptr;
+               ptr = ptr->next;
+
+               if (node->mono)
+                       node->mono->lookup = NULL;
+               node->mono = NULL;
+               node->next = NULL;
+               OPENSSL_free (node);
+       }
+
+       OPENSSL_free (lookup);
+}
+
+static int
+mono_lookup_get_by_subject (X509_LOOKUP *ctx, int type, X509_NAME *name, X509_OBJECT *obj_ret)
+{
+       MonoLookup *lookup;
+       MonoBtlsX509Name *name_obj;
+       MonoLookupNode *node;
+       X509 *x509 = NULL;
+       int ret = 0;
+
+       lookup = (MonoLookup *)ctx->method_data;
+
+       if (!lookup || !lookup->nodes)
+               return 0;
+       if (type != X509_LU_X509)
+               return 0;
+
+       name_obj = mono_btls_x509_name_from_name (name);
+       x509 = NULL;
+
+       for (node = lookup->nodes; node; node = node->next) {
+               if (!node->mono || !node->mono->by_subject_func)
+                       continue;
+               ret = (* node->mono->by_subject_func) (node->mono->instance, name_obj, &x509);
+               if (ret)
+                       break;
+       }
+
+       mono_btls_x509_name_free (name_obj);
+
+       if (!ret) {
+               if (x509)
+                       X509_free(x509);
+               return 0;
+       }
+
+       obj_ret->type = X509_LU_X509;
+       obj_ret->data.x509 = x509;
+       return 1;
+}
+
+static X509_LOOKUP_METHOD mono_lookup_method = {
+       "Mono lookup method",
+       mono_lookup_new,                /* new */
+       mono_lookup_free,               /* free */
+       NULL,                           /* init */
+       NULL,                           /* shutdown */
+       mono_lookup_ctrl,               /* ctrl */
+       mono_lookup_get_by_subject,     /* get_by_subject */
+       NULL,                           /* get_by_issuer_serial */
+       NULL,                           /* get_by_fingerprint */
+       NULL,                           /* get_by_alias */
+};
+
+X509_LOOKUP_METHOD *
+mono_btls_x509_lookup_mono_method (void)
+{
+       return &mono_lookup_method;
+}
+
+int
+mono_btls_x509_lookup_add_mono (MonoBtlsX509Lookup *lookup, MonoBtlsX509LookupMono *mono)
+{
+       if (mono_btls_x509_lookup_get_type (lookup) != MONO_BTLS_X509_LOOKUP_TYPE_MONO)
+               return 0;
+       return X509_LOOKUP_ctrl (mono_btls_x509_lookup_peek_lookup (lookup),
+                                MONO_BTLS_X509_L_MONO_ADD,
+                                (void*)mono, 0, NULL);
+}
diff --git a/mono/btls/btls-x509-lookup-mono.h b/mono/btls/btls-x509-lookup-mono.h
new file mode 100644 (file)
index 0000000..06df552
--- /dev/null
@@ -0,0 +1,36 @@
+//
+//  btls-x509-lookup-mono.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_lookup_mono__
+#define __btls__btls_x509_lookup_mono__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+#include <btls-x509-store.h>
+
+typedef int (* MonoBtlsX509LookupMono_BySubject) (const void *instance, MonoBtlsX509Name *name, X509 **ret);
+
+MonoBtlsX509LookupMono *
+mono_btls_x509_lookup_mono_new (void);
+
+int
+mono_btls_x509_lookup_mono_free (MonoBtlsX509LookupMono *mono);
+
+void
+mono_btls_x509_lookup_mono_init (MonoBtlsX509LookupMono *mono, const void *instance,
+                                MonoBtlsX509LookupMono_BySubject by_subject_func);
+
+int
+mono_btls_x509_lookup_add_mono (MonoBtlsX509Lookup *lookup, MonoBtlsX509LookupMono *mono);
+
+X509_LOOKUP_METHOD *
+mono_btls_x509_lookup_mono_method (void);
+
+#endif /* defined(__btls__btls_x509_lookup_mono__) */
+
diff --git a/mono/btls/btls-x509-lookup.c b/mono/btls/btls-x509-lookup.c
new file mode 100644 (file)
index 0000000..1cfc174
--- /dev/null
@@ -0,0 +1,160 @@
+//
+//  btls-x509-lookup.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/6/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-lookup.h>
+#include <btls-x509-lookup-mono.h>
+
+struct MonoBtlsX509Lookup {
+       MonoBtlsX509LookupType type;
+       X509_LOOKUP *lookup;
+       int owns_lookup;
+       MonoBtlsX509Store *store;
+       CRYPTO_refcount_t references;
+};
+
+static X509_LOOKUP_METHOD *
+get_lookup_method (MonoBtlsX509LookupType type)
+{
+       switch (type) {
+       case MONO_BTLS_X509_LOOKUP_TYPE_FILE:
+               return X509_LOOKUP_file ();
+       case MONO_BTLS_X509_LOOKUP_TYPE_HASH_DIR:
+               return X509_LOOKUP_hash_dir ();
+       case MONO_BTLS_X509_LOOKUP_TYPE_MONO:
+               return mono_btls_x509_lookup_mono_method ();
+       default:
+               return NULL;
+       }
+}
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_new (MonoBtlsX509Store *store, MonoBtlsX509LookupType type)
+{
+       MonoBtlsX509Lookup *lookup;
+       X509_LOOKUP *store_lookup;
+       X509_LOOKUP_METHOD *method;
+
+       method = get_lookup_method (type);
+       if (!method)
+               return NULL;
+
+       lookup = OPENSSL_malloc (sizeof(MonoBtlsX509Lookup));
+       if (!lookup)
+               return NULL;
+
+       store_lookup = X509_STORE_add_lookup (mono_btls_x509_store_peek_store (store), method);
+       if (!store_lookup)
+               return NULL;
+
+       memset (lookup, 0, sizeof(MonoBtlsX509Lookup));
+       // The X509_STORE owns the X509_LOOKUP.
+       lookup->store = mono_btls_x509_store_up_ref (store);
+       lookup->lookup = store_lookup;
+       lookup->owns_lookup = 0;
+       lookup->references = 1;
+       lookup->type = type;
+       return lookup;
+}
+
+int
+mono_btls_x509_lookup_load_file (MonoBtlsX509Lookup *lookup, const char *file, MonoBtlsX509FileType type)
+{
+       return X509_LOOKUP_load_file (lookup->lookup, file, type);
+}
+
+int
+mono_btls_x509_lookup_add_dir (MonoBtlsX509Lookup *lookup, const char *dir, MonoBtlsX509FileType type)
+{
+       return X509_LOOKUP_add_dir (lookup->lookup, dir, type);
+}
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_up_ref (MonoBtlsX509Lookup *lookup)
+{
+       CRYPTO_refcount_inc (&lookup->references);
+       return lookup;
+}
+
+int
+mono_btls_x509_lookup_free (MonoBtlsX509Lookup *lookup)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero (&lookup->references))
+               return 0;
+
+       if (lookup->store) {
+               mono_btls_x509_store_free (lookup->store);
+               lookup->store = NULL;
+       }
+
+       if (lookup->lookup) {
+               if (lookup->owns_lookup)
+                       X509_LOOKUP_free (lookup->lookup);
+               lookup->lookup = NULL;
+       }
+
+       OPENSSL_free (lookup);
+       return 1;
+}
+
+int
+mono_btls_x509_lookup_init (MonoBtlsX509Lookup *lookup)
+{
+       return X509_LOOKUP_init (lookup->lookup);
+}
+
+int
+mono_btls_x509_lookup_shutdown (MonoBtlsX509Lookup *lookup)
+{
+       return X509_LOOKUP_shutdown (lookup->lookup);
+}
+
+MonoBtlsX509LookupType
+mono_btls_x509_lookup_get_type (MonoBtlsX509Lookup *lookup)
+{
+       return lookup->type;
+}
+
+X509_LOOKUP *
+mono_btls_x509_lookup_peek_lookup (MonoBtlsX509Lookup *lookup)
+{
+       return lookup->lookup;
+}
+
+X509 *
+mono_btls_x509_lookup_by_subject (MonoBtlsX509Lookup *lookup, MonoBtlsX509Name *name)
+{
+       X509_OBJECT obj;
+       X509 *x509;
+       int ret;
+
+       ret = X509_LOOKUP_by_subject (lookup->lookup, X509_LU_X509, mono_btls_x509_name_peek_name (name), &obj);
+       if (ret != X509_LU_X509) {
+               X509_OBJECT_free_contents (&obj);
+               return NULL;
+       }
+
+       x509 = X509_up_ref (obj.data.x509);
+       return x509;
+}
+
+X509 *
+mono_btls_x509_lookup_by_fingerprint (MonoBtlsX509Lookup *lookup, unsigned char *bytes, int len)
+{
+       X509_OBJECT obj;
+       X509 *x509;
+       int ret;
+
+       ret = X509_LOOKUP_by_fingerprint (lookup->lookup, X509_LU_X509, bytes, len, &obj);
+       if (ret != X509_LU_X509) {
+               X509_OBJECT_free_contents (&obj);
+               return NULL;
+       }
+
+       x509 = X509_up_ref (obj.data.x509);
+       return x509;
+}
diff --git a/mono/btls/btls-x509-lookup.h b/mono/btls/btls-x509-lookup.h
new file mode 100644 (file)
index 0000000..df3d37f
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  btls-x509-lookup.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_lookup__
+#define __btls__btls_x509_lookup__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+#include <btls-x509-store.h>
+
+typedef enum {
+       MONO_BTLS_X509_LOOKUP_TYPE_UNKNOWN = 0,
+       MONO_BTLS_X509_LOOKUP_TYPE_FILE,
+       MONO_BTLS_X509_LOOKUP_TYPE_HASH_DIR,
+       MONO_BTLS_X509_LOOKUP_TYPE_MONO
+} MonoBtlsX509LookupType;
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_new (MonoBtlsX509Store *store, MonoBtlsX509LookupType type);
+
+int
+mono_btls_x509_lookup_load_file (MonoBtlsX509Lookup *lookup, const char *file, MonoBtlsX509FileType type);
+
+int
+mono_btls_x509_lookup_add_dir (MonoBtlsX509Lookup *lookup, const char *dir, MonoBtlsX509FileType type);
+
+MonoBtlsX509Lookup *
+mono_btls_x509_lookup_up_ref (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_free (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_init (MonoBtlsX509Lookup *lookup);
+
+MonoBtlsX509LookupType
+mono_btls_x509_lookup_get_type (MonoBtlsX509Lookup *lookup);
+
+X509_LOOKUP *
+mono_btls_x509_lookup_peek_lookup (MonoBtlsX509Lookup *lookup);
+
+int
+mono_btls_x509_lookup_shutdown (MonoBtlsX509Lookup *lookup);
+
+X509 *
+mono_btls_x509_lookup_by_subject (MonoBtlsX509Lookup *lookup, MonoBtlsX509Name *name);
+
+X509 *
+mono_btls_x509_lookup_by_fingerprint (MonoBtlsX509Lookup *lookup, unsigned char *bytes, int len);
+
+#endif /* defined(__btls__btls_x509_lookup__) */
+
diff --git a/mono/btls/btls-x509-name.c b/mono/btls/btls-x509-name.c
new file mode 100644 (file)
index 0000000..d76d885
--- /dev/null
@@ -0,0 +1,294 @@
+//
+//  btls-x509-name.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/5/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-name.h>
+
+struct MonoBtlsX509Name {
+       int owns;
+       X509_NAME *name;
+};
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_name (X509_NAME *xn)
+{
+       MonoBtlsX509Name *name;
+
+       name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+       if (!name)
+               return NULL;
+
+       memset(name, 0, sizeof(MonoBtlsX509Name));
+       name->name = xn;
+       return name;
+}
+
+MonoBtlsX509Name *
+mono_btls_x509_name_copy (X509_NAME *xn)
+{
+       MonoBtlsX509Name *name;
+
+       name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+       if (!name)
+               return NULL;
+
+       memset(name, 0, sizeof(MonoBtlsX509Name));
+       name->name = X509_NAME_dup(xn);
+       name->owns = 1;
+       return name;
+}
+
+void
+mono_btls_x509_name_free (MonoBtlsX509Name *name)
+{
+       if (name->owns) {
+               if (name->name) {
+                       X509_NAME_free(name->name);
+                       name->name = NULL;
+               }
+       }
+       OPENSSL_free(name);
+}
+
+X509_NAME *
+mono_btls_x509_name_peek_name (MonoBtlsX509Name *name)
+{
+       return name->name;
+}
+
+int
+mono_btls_x509_name_print_bio (MonoBtlsX509Name *name, BIO *bio)
+{
+       return X509_NAME_print_ex (bio, name->name, 0, ASN1_STRFLGS_RFC2253 | XN_FLAG_FN_SN | XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_DN_REV);
+}
+
+int
+mono_btls_x509_name_get_raw_data (MonoBtlsX509Name *name, void **buffer, int use_canon_enc)
+{
+       int len;
+       void *ptr;
+
+       if (use_canon_enc) {
+               // make sure canon_enc is initialized.
+               i2d_X509_NAME (name->name, NULL);
+
+               len = name->name->canon_enclen;
+               ptr = name->name->canon_enc;
+       } else {
+               len = (int)name->name->bytes->length;
+               ptr = name->name->bytes->data;
+       }
+
+       *buffer = OPENSSL_malloc (len);
+       if (!*buffer)
+               return 0;
+
+       memcpy (*buffer, ptr, len);
+       return len;
+}
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_data (const void *data, int len, int use_canon_enc)
+{
+       MonoBtlsX509Name *name;
+       uint8_t *buf;
+       const unsigned char *ptr;
+       X509_NAME *ret;
+
+       name = OPENSSL_malloc (sizeof (MonoBtlsX509Name));
+       if (!name)
+               return NULL;
+
+       memset (name, 0, sizeof(MonoBtlsX509Name));
+       name->owns = 1;
+
+       name->name = X509_NAME_new ();
+       if (!name->name) {
+               OPENSSL_free (name);
+               return NULL;
+       }
+
+       if (use_canon_enc) {
+               CBB cbb, contents;
+               size_t buf_len;
+
+               // re-add ASN1 SEQUENCE header.
+               CBB_init(&cbb, 0);
+               if (!CBB_add_asn1(&cbb, &contents, 0x30) ||
+                   !CBB_add_bytes(&contents, data, len) ||
+                   !CBB_finish(&cbb, &buf, &buf_len)) {
+                       CBB_cleanup (&cbb);
+                       mono_btls_x509_name_free (name);
+                       return NULL;
+               }
+
+               ptr = buf;
+               len = (int)buf_len;
+       } else {
+               ptr = data;
+               buf = NULL;
+       }
+
+       ret = d2i_X509_NAME (&name->name, &ptr, len);
+
+       if (buf)
+               OPENSSL_free (buf);
+
+       if (ret != name->name) {
+               mono_btls_x509_name_free (name);
+               return NULL;
+       }
+
+       return name;
+}
+
+int
+mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size)
+{
+       *buffer = 0;
+       return X509_NAME_oneline (name->name, buffer, size) != NULL;
+}
+
+long
+mono_btls_x509_name_hash (MonoBtlsX509Name *name)
+{
+       return X509_NAME_hash (name->name);
+}
+
+long
+mono_btls_x509_name_hash_old (MonoBtlsX509Name *name)
+{
+       return X509_NAME_hash_old (name->name);
+}
+
+int
+mono_btls_x509_name_get_entry_count (MonoBtlsX509Name *name)
+{
+       return X509_NAME_entry_count (name->name);
+}
+
+static MonoBtlsX509NameEntryType
+nid2mono (int nid)
+{
+       switch (nid) {
+       case NID_countryName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_COUNTRY_NAME;
+       case NID_organizationName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATION_NAME;
+       case NID_organizationalUnitName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATIONAL_UNIT_NAME;
+       case NID_commonName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_COMMON_NAME;
+       case NID_localityName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_LOCALITY_NAME;
+       case NID_stateOrProvinceName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_STATE_OR_PROVINCE_NAME;
+       case NID_streetAddress:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_STREET_ADDRESS;
+       case NID_serialNumber:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_SERIAL_NUMBER;
+       case NID_domainComponent:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_DOMAIN_COMPONENT;
+       case NID_userId:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_USER_ID;
+       case NID_dnQualifier:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_DN_QUALIFIER;
+       case NID_title:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_TITLE;
+       case NID_surname:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_SURNAME;
+       case NID_givenName:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_GIVEN_NAME;
+       case NID_initials:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_INITIAL;
+       default:
+               return MONO_BTLS_X509_NAME_ENTRY_TYPE_UNKNOWN;
+       }
+}
+
+MonoBtlsX509NameEntryType
+mono_btls_x509_name_get_entry_type (MonoBtlsX509Name *name, int index)
+{
+       X509_NAME_ENTRY *entry;
+       ASN1_OBJECT *obj;
+
+       if (index >= X509_NAME_entry_count (name->name))
+               return -1;
+
+       entry = X509_NAME_get_entry (name->name, index);
+       if (!entry)
+               return -1;
+
+       obj = X509_NAME_ENTRY_get_object (entry);
+       if (!obj)
+               return -1;
+
+       return nid2mono (OBJ_obj2nid (obj));
+}
+
+int
+mono_btls_x509_name_get_entry_oid (MonoBtlsX509Name *name, int index, char *buffer, int size)
+{
+       X509_NAME_ENTRY *entry;
+       ASN1_OBJECT *obj;
+
+       if (index >= X509_NAME_entry_count (name->name))
+               return 0;
+
+       entry = X509_NAME_get_entry (name->name, index);
+       if (!entry)
+               return 0;
+
+       obj = X509_NAME_ENTRY_get_object (entry);
+       if (!obj)
+               return 0;
+
+       return OBJ_obj2txt (buffer, size, obj, 1);
+}
+
+int
+mono_btls_x509_name_get_entry_oid_data (MonoBtlsX509Name *name, int index, const void **data)
+{
+       X509_NAME_ENTRY *entry;
+       ASN1_OBJECT *obj;
+
+       if (index >= X509_NAME_entry_count (name->name))
+               return -1;
+
+       entry = X509_NAME_get_entry (name->name, index);
+       if (!entry)
+               return -1;
+
+       obj = X509_NAME_ENTRY_get_object (entry);
+       if (!obj)
+               return -1;
+
+       *data = obj->data;
+       return obj->length;
+}
+
+int
+mono_btls_x509_name_get_entry_value (MonoBtlsX509Name *name, int index, unsigned char **str)
+{
+       X509_NAME_ENTRY *entry;
+       ASN1_STRING *data;
+
+       *str = NULL;
+
+       if (index >= X509_NAME_entry_count (name->name))
+               return 0;
+
+       entry = X509_NAME_get_entry (name->name, index);
+       if (!entry)
+               return 0;
+
+       data = X509_NAME_ENTRY_get_data (entry);
+       if (!data)
+               return 0;
+
+       return ASN1_STRING_to_UTF8 (str, data);
+}
diff --git a/mono/btls/btls-x509-name.h b/mono/btls/btls-x509-name.h
new file mode 100644 (file)
index 0000000..20c6a68
--- /dev/null
@@ -0,0 +1,80 @@
+//
+//  btls-x509-name.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/5/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_name__
+#define __btls__btls_x509_name__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+
+typedef enum {
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_UNKNOWN = 0,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_COUNTRY_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATION_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_ORGANIZATIONAL_UNIT_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_COMMON_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_LOCALITY_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_STATE_OR_PROVINCE_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_STREET_ADDRESS,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_SERIAL_NUMBER,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_DOMAIN_COMPONENT,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_USER_ID,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_EMAIL,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_DN_QUALIFIER,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_TITLE,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_SURNAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_GIVEN_NAME,
+       MONO_BTLS_X509_NAME_ENTRY_TYPE_INITIAL
+} MonoBtlsX509NameEntryType;
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_name (X509_NAME *name);
+
+MonoBtlsX509Name *
+mono_btls_x509_name_copy (X509_NAME *xn);
+
+void
+mono_btls_x509_name_free (MonoBtlsX509Name *name);
+
+X509_NAME *
+mono_btls_x509_name_peek_name (MonoBtlsX509Name *name);
+
+MonoBtlsX509Name *
+mono_btls_x509_name_from_data (const void *data, int len, int use_canon_enc);
+
+int
+mono_btls_x509_name_print_bio (MonoBtlsX509Name *name, BIO *bio);
+
+int
+mono_btls_x509_name_print_string (MonoBtlsX509Name *name, char *buffer, int size);
+
+int
+mono_btls_x509_name_get_raw_data (MonoBtlsX509Name *name, void **buffer, int use_canon_enc);
+
+long
+mono_btls_x509_name_hash (MonoBtlsX509Name *name);
+
+long
+mono_btls_x509_name_hash_old (MonoBtlsX509Name *name);
+
+int
+mono_btls_x509_name_get_entry_count (MonoBtlsX509Name *name);
+
+MonoBtlsX509NameEntryType
+mono_btls_x509_name_get_entry_type (MonoBtlsX509Name *name, int index);
+
+int
+mono_btls_x509_name_get_entry_oid (MonoBtlsX509Name *name, int index, char *buffer, int size);
+
+int
+mono_btls_x509_name_get_entry_oid_data (MonoBtlsX509Name *name, int index, const void **data);
+
+int
+mono_btls_x509_name_get_entry_value (MonoBtlsX509Name *name, int index, unsigned char **str);
+
+#endif /* __btls__btls_x509_name__ */
diff --git a/mono/btls/btls-x509-revoked.c b/mono/btls/btls-x509-revoked.c
new file mode 100644 (file)
index 0000000..e6fb4b0
--- /dev/null
@@ -0,0 +1,72 @@
+//
+//  btls-x509-revoked.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-revoked.h>
+
+struct MonoBtlsX509Revoked {
+       MonoBtlsX509Crl *owner;
+       X509_REVOKED *revoked;
+};
+
+MonoBtlsX509Revoked *
+mono_btls_x509_revoked_new (MonoBtlsX509Crl *owner, X509_REVOKED *revoked)
+{
+       MonoBtlsX509Revoked *instance;
+
+       instance = OPENSSL_malloc (sizeof (MonoBtlsX509Revoked));
+       memset (instance, 0, sizeof (MonoBtlsX509Revoked));
+
+       instance->owner = mono_btls_x509_crl_ref (owner);
+       instance->revoked = revoked;
+       return instance;
+}
+
+void
+mono_btls_x509_revoked_free (MonoBtlsX509Revoked *revoked)
+{
+       mono_btls_x509_crl_free (revoked->owner);
+       OPENSSL_free (revoked);
+}
+
+int
+mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *buffer, int size)
+{
+       ASN1_INTEGER *serial;
+
+       serial = revoked->revoked->serialNumber;
+       if (serial->length == 0 || serial->length+1 > size)
+               return 0;
+
+       memcpy (buffer, serial->data, serial->length);
+       return serial->length;
+}
+
+long
+mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked)
+{
+       ASN1_TIME *date;
+
+       date = revoked->revoked->revocationDate;
+       if (!date)
+               return 0;
+
+       return mono_btls_util_asn1_time_to_ticks (date);
+}
+
+int
+mono_btls_x509_revoked_get_reason (MonoBtlsX509Revoked *revoked)
+{
+       return revoked->revoked->reason;
+}
+
+int
+mono_btls_x509_revoked_get_sequence (MonoBtlsX509Revoked *revoked)
+{
+       return revoked->revoked->sequence;
+}
+
diff --git a/mono/btls/btls-x509-revoked.h b/mono/btls/btls-x509-revoked.h
new file mode 100644 (file)
index 0000000..e1229c6
--- /dev/null
@@ -0,0 +1,34 @@
+//
+//  btls-x509-revoked.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/23/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_revoked__
+#define __btls__btls_x509_revoked__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509-crl.h>
+
+MonoBtlsX509Revoked *
+mono_btls_x509_revoked_new (MonoBtlsX509Crl *owner, X509_REVOKED *revoked);
+
+void
+mono_btls_x509_revoked_free (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_serial_number (MonoBtlsX509Revoked *revoked, char *buffer, int size);
+
+long
+mono_btls_x509_revoked_get_revocation_date (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_reason (MonoBtlsX509Revoked *revoked);
+
+int
+mono_btls_x509_revoked_get_sequence (MonoBtlsX509Revoked *revoked);
+
+#endif /* __btls__btls_x509_revoked__ */
diff --git a/mono/btls/btls-x509-store-ctx.c b/mono/btls/btls-x509-store-ctx.c
new file mode 100644 (file)
index 0000000..f023e31
--- /dev/null
@@ -0,0 +1,217 @@
+//
+//  btls-x509-store-ctx.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/5/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-store-ctx.h>
+
+struct MonoBtlsX509StoreCtx {
+       int owns;
+       X509_STORE_CTX *ctx;
+       CRYPTO_refcount_t references;
+       MonoBtlsX509Store *store;
+       MonoBtlsX509Chain *chain;
+};
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_from_ptr (X509_STORE_CTX *ptr)
+{
+       MonoBtlsX509StoreCtx *ctx;
+
+       ctx = OPENSSL_malloc (sizeof(MonoBtlsX509StoreCtx));
+       if (!ctx)
+               return NULL;
+
+       memset (ctx, 0, sizeof (MonoBtlsX509StoreCtx));
+       ctx->ctx = ptr;
+       ctx->references = 1;
+       return ctx;
+}
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_new (void)
+{
+       MonoBtlsX509StoreCtx *ctx;
+
+       ctx = OPENSSL_malloc (sizeof(MonoBtlsX509StoreCtx));
+       if (!ctx)
+               return NULL;
+
+       memset (ctx, 0, sizeof (MonoBtlsX509StoreCtx));
+       ctx->ctx = X509_STORE_CTX_new ();
+       ctx->references = 1;
+       ctx->owns = 1;
+       return ctx;
+}
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_up_ref (MonoBtlsX509StoreCtx *ctx)
+{
+       CRYPTO_refcount_inc (&ctx->references);
+       return ctx;
+}
+
+int
+mono_btls_x509_store_ctx_free (MonoBtlsX509StoreCtx *ctx)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
+               return 0;
+
+       if (ctx->owns) {
+               X509_STORE_CTX_cleanup (ctx->ctx);
+               X509_STORE_CTX_free (ctx->ctx);
+               ctx->owns = 0;
+       }
+       if (ctx->store) {
+               mono_btls_x509_store_free (ctx->store);
+               ctx->store = NULL;
+       }
+       if (ctx->chain) {
+               mono_btls_x509_chain_free (ctx->chain);
+               ctx->chain = NULL;
+       }
+       OPENSSL_free (ctx);
+       return 1;
+}
+
+int
+mono_btls_x509_store_ctx_get_error (MonoBtlsX509StoreCtx *ctx, const char **error_string)
+{
+       int error;
+
+       error = X509_STORE_CTX_get_error (ctx->ctx);
+       if (error_string)
+               *error_string = X509_verify_cert_error_string (error);
+       return error;
+}
+
+int
+mono_btls_x509_store_ctx_get_error_depth (MonoBtlsX509StoreCtx *ctx)
+{
+       return X509_STORE_CTX_get_error_depth (ctx->ctx);
+}
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_chain (MonoBtlsX509StoreCtx *ctx)
+{
+       STACK_OF(X509) *certs;
+
+       certs = X509_STORE_CTX_get_chain (ctx->ctx);
+       if (!certs)
+               return NULL;
+
+       return mono_btls_x509_chain_from_certs (certs);
+}
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_untrusted (MonoBtlsX509StoreCtx *ctx)
+{
+       STACK_OF(X509) *untrusted;
+
+       /*
+        * Unfortunately, there is no accessor function for this.
+        *
+        * This is the set of certificate that's passed in by
+        * X509_STORE_CTX_init() and X509_STORE_CTX_set_chain().
+        */
+       untrusted = ctx->ctx->untrusted;
+       if (!untrusted)
+               return NULL;
+
+       return mono_btls_x509_chain_from_certs (untrusted);
+}
+
+int
+mono_btls_x509_store_ctx_init (MonoBtlsX509StoreCtx *ctx,
+                                  MonoBtlsX509Store *store, MonoBtlsX509Chain *chain)
+{
+       STACK_OF(X509) *certs;
+       X509 *leaf;
+       int ret;
+
+       if (ctx->store)
+               return 0;
+
+       certs = mono_btls_x509_chain_peek_certs (chain);
+       if (!certs || !sk_X509_num (certs))
+               return 0;
+
+       ctx->store = mono_btls_x509_store_up_ref(store);
+       ctx->chain = mono_btls_x509_chain_up_ref(chain);
+
+       leaf = sk_X509_value (certs, 0);
+       ret = X509_STORE_CTX_init (ctx->ctx, mono_btls_x509_store_peek_store (store), leaf, certs);
+       if (ret != 1)
+               return ret;
+
+       X509_STORE_CTX_set_app_data (ctx->ctx, ctx);
+       return 1;
+}
+
+int
+mono_btls_x509_store_ctx_set_param (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509VerifyParam *param)
+{
+       return X509_VERIFY_PARAM_set1 (X509_STORE_CTX_get0_param (ctx->ctx), mono_btls_x509_verify_param_peek_param (param));
+}
+
+int
+mono_btls_x509_store_ctx_verify_cert (MonoBtlsX509StoreCtx *ctx)
+{
+       return X509_verify_cert (ctx->ctx);
+}
+
+X509 *
+mono_btls_x509_store_ctx_get_by_subject (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509Name *name)
+{
+       X509_OBJECT obj;
+       X509 *x509;
+       int ret;
+
+       ret = X509_STORE_get_by_subject (ctx->ctx, X509_LU_X509, mono_btls_x509_name_peek_name (name), &obj);
+       if (ret != X509_LU_X509) {
+               X509_OBJECT_free_contents (&obj);
+               return NULL;
+       }
+
+       x509 = X509_up_ref (obj.data.x509);
+       return x509;
+}
+
+X509 *
+mono_btls_x509_store_ctx_get_current_cert (MonoBtlsX509StoreCtx *ctx)
+{
+       X509 *x509 = X509_STORE_CTX_get_current_cert (ctx->ctx);
+       if (!x509)
+               return NULL;
+       return X509_up_ref (x509);
+}
+
+X509 *
+mono_btls_x509_store_ctx_get_current_issuer (MonoBtlsX509StoreCtx *ctx)
+{
+       X509 *x509 = X509_STORE_CTX_get0_current_issuer (ctx->ctx);
+       if (!x509)
+               return NULL;
+       return X509_up_ref (x509);
+}
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_store_ctx_get_verify_param (MonoBtlsX509StoreCtx *ctx)
+{
+       X509_VERIFY_PARAM *param;
+
+       param = X509_STORE_CTX_get0_param (ctx->ctx);
+       if (!param)
+               return NULL;
+
+       return mono_btls_x509_verify_param_from_store_ctx (ctx, param);
+}
+
+int
+mono_btls_x509_store_ctx_get_foo (MonoBtlsX509StoreCtx *ctx)
+{
+       return 0;
+}
\ No newline at end of file
diff --git a/mono/btls/btls-x509-store-ctx.h b/mono/btls/btls-x509-store-ctx.h
new file mode 100644 (file)
index 0000000..188092e
--- /dev/null
@@ -0,0 +1,66 @@
+//
+//  btls-x509-store-ctx.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_store_ctx__
+#define __btls__btls_x509_store_ctx__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509-chain.h>
+#include <btls-x509-name.h>
+#include <btls-x509-store.h>
+#include <btls-x509-verify-param.h>
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_from_ptr (X509_STORE_CTX *ptr);
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_new (void);
+
+MonoBtlsX509StoreCtx *
+mono_btls_x509_store_ctx_up_ref (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_free (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_get_error (MonoBtlsX509StoreCtx *ctx, const char **error_string);
+
+int
+mono_btls_x509_store_ctx_get_error_depth (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_chain (MonoBtlsX509StoreCtx *ctx);
+
+X509 *
+mono_btls_x509_store_ctx_get_current_cert (MonoBtlsX509StoreCtx *ctx);
+
+X509 *
+mono_btls_x509_store_ctx_get_current_issuer (MonoBtlsX509StoreCtx *ctx);
+
+int
+mono_btls_x509_store_ctx_init (MonoBtlsX509StoreCtx *ctx,
+                                  MonoBtlsX509Store *store, MonoBtlsX509Chain *chain);
+
+int
+mono_btls_x509_store_ctx_set_param (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509VerifyParam *param);
+
+X509 *
+mono_btls_x509_store_ctx_get_by_subject (MonoBtlsX509StoreCtx *ctx, MonoBtlsX509Name *name);
+
+int
+mono_btls_x509_store_ctx_verify_cert (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_store_ctx_get_verify_param (MonoBtlsX509StoreCtx *ctx);
+
+MonoBtlsX509Chain *
+mono_btls_x509_store_ctx_get_untrusted (MonoBtlsX509StoreCtx *ctx);
+
+#endif /* defined(__btls__btls_x509_store_ctx__) */
+
diff --git a/mono/btls/btls-x509-store.c b/mono/btls/btls-x509-store.c
new file mode 100644 (file)
index 0000000..f2c826e
--- /dev/null
@@ -0,0 +1,110 @@
+//
+//  btls-x509-store.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-store.h>
+
+struct MonoBtlsX509Store {
+       X509_STORE *store;
+       CRYPTO_refcount_t references;
+};
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_store (X509_STORE *ctx)
+{
+       MonoBtlsX509Store *store;
+
+       store = OPENSSL_malloc (sizeof(MonoBtlsX509Store));
+       if (!store)
+               return NULL;
+
+       memset (store, 0, sizeof(MonoBtlsX509Store));
+       store->store = ctx;
+       CRYPTO_refcount_inc (&store->store->references);
+       store->references = 1;
+       return store;
+}
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ctx (X509_STORE_CTX *ctx)
+{
+       return mono_btls_x509_store_from_store (ctx->ctx);
+}
+
+MonoBtlsX509Store *
+mono_btls_x509_store_new (void)
+{
+       MonoBtlsX509Store *store;
+
+       store = OPENSSL_malloc (sizeof(MonoBtlsX509Store));
+       if (!store)
+               return NULL;
+
+       memset (store, 0, sizeof(MonoBtlsX509Store));
+       store->store = X509_STORE_new ();
+       store->references = 1;
+       return store;
+}
+
+X509_STORE *
+mono_btls_x509_store_peek_store (MonoBtlsX509Store *store)
+{
+       return store->store;
+}
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ssl_ctx (MonoBtlsSslCtx *ctx)
+{
+       X509_STORE *store = mono_btls_ssl_ctx_peek_store (ctx);
+       return mono_btls_x509_store_from_store (store);
+}
+
+int
+mono_btls_x509_store_free (MonoBtlsX509Store *store)
+{
+       if (!CRYPTO_refcount_dec_and_test_zero(&store->references))
+               return 0;
+
+       if (store->store) {
+               X509_STORE_free (store->store);
+               store->store = NULL;
+       }
+       OPENSSL_free (store);
+       return 1;
+}
+
+MonoBtlsX509Store *
+mono_btls_x509_store_up_ref (MonoBtlsX509Store *store)
+{
+       CRYPTO_refcount_inc (&store->references);
+       return store;
+}
+
+int
+mono_btls_x509_store_add_cert (MonoBtlsX509Store *store, X509 *cert)
+{
+       return X509_STORE_add_cert (store->store, cert);
+}
+
+int
+mono_btls_x509_store_load_locations (MonoBtlsX509Store *store, const char *file, const char *path)
+{
+       return X509_STORE_load_locations (store->store, file, path);
+}
+
+int
+mono_btls_x509_store_set_default_paths (MonoBtlsX509Store *store)
+{
+       return X509_STORE_set_default_paths (store->store);
+}
+
+int
+mono_btls_x509_store_get_count (MonoBtlsX509Store *store)
+{
+       return (int)sk_X509_OBJECT_num (store->store->objs);
+}
+
diff --git a/mono/btls/btls-x509-store.h b/mono/btls/btls-x509-store.h
new file mode 100644 (file)
index 0000000..67ffe00
--- /dev/null
@@ -0,0 +1,46 @@
+//
+//  btls-x509-store.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_store__
+#define __btls__btls_x509_store__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+
+MonoBtlsX509Store *
+mono_btls_x509_store_new (void);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ctx (X509_STORE_CTX *ctx);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_from_ssl_ctx (MonoBtlsSslCtx *ctx);
+
+MonoBtlsX509Store *
+mono_btls_x509_store_up_ref (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_free (MonoBtlsX509Store *store);
+
+X509_STORE *
+mono_btls_x509_store_peek_store (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_add_cert (MonoBtlsX509Store *store, X509 *cert);
+
+int
+mono_btls_x509_store_load_locations (MonoBtlsX509Store *store, const char *file, const char *path);
+
+int
+mono_btls_x509_store_set_default_paths (MonoBtlsX509Store *store);
+
+int
+mono_btls_x509_store_get_count (MonoBtlsX509Store *store);
+
+#endif /* defined(__btls__btls_x509_store__) */
+
diff --git a/mono/btls/btls-x509-verify-param.c b/mono/btls/btls-x509-verify-param.c
new file mode 100644 (file)
index 0000000..643fdcd
--- /dev/null
@@ -0,0 +1,221 @@
+//
+//  btls-x509-verify-param.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/5/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#include <btls-x509-verify-param.h>
+#include <btls-x509-store-ctx.h>
+
+struct MonoBtlsX509VerifyParam {
+       int owns;
+       MonoBtlsX509StoreCtx *owner;
+       X509_VERIFY_PARAM *param;
+};
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_new (void)
+{
+       MonoBtlsX509VerifyParam *param;
+
+       param = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+       if (!param)
+               return NULL;
+       memset (param, 0, sizeof (MonoBtlsX509VerifyParam));
+       param->param = X509_VERIFY_PARAM_new();
+       param->owns = 1;
+       return param;
+}
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_from_store_ctx (MonoBtlsX509StoreCtx *ctx, X509_VERIFY_PARAM *param)
+{
+       MonoBtlsX509VerifyParam *instance;
+
+       instance = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+       if (!instance)
+               return NULL;
+       memset (instance, 0, sizeof (MonoBtlsX509VerifyParam));
+       instance->param = param;
+       instance->owner = mono_btls_x509_store_ctx_up_ref (ctx);
+       return instance;
+}
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_copy (const MonoBtlsX509VerifyParam *from)
+{
+       MonoBtlsX509VerifyParam *param;
+
+       param = mono_btls_x509_verify_param_new ();
+       if (!param)
+               return NULL;
+
+       X509_VERIFY_PARAM_set1 (param->param, from->param);
+       return param;
+}
+
+const X509_VERIFY_PARAM *
+mono_btls_x509_verify_param_peek_param (const MonoBtlsX509VerifyParam *param)
+{
+       return param->param;
+}
+
+int
+mono_btls_x509_verify_param_can_modify (MonoBtlsX509VerifyParam *param)
+{
+       return param->owns;
+}
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_lookup (const char *name)
+{
+       MonoBtlsX509VerifyParam *param;
+       const X509_VERIFY_PARAM *p;
+
+       p = X509_VERIFY_PARAM_lookup(name);
+       if (!p)
+               return NULL;
+
+       param = OPENSSL_malloc (sizeof(MonoBtlsX509VerifyParam));
+       if (!param)
+               return NULL;
+       memset (param, 0, sizeof (MonoBtlsX509VerifyParam));
+       param->param = (X509_VERIFY_PARAM *)p;
+       return param;
+}
+
+void
+mono_btls_x509_verify_param_free (MonoBtlsX509VerifyParam *param)
+{
+       if (param->owns) {
+               if (param->param) {
+                       X509_VERIFY_PARAM_free (param->param);
+                       param->param = NULL;
+               }
+       }
+       if (param->owner) {
+               mono_btls_x509_store_ctx_free (param->owner);
+               param->owner = NULL;
+       }
+       OPENSSL_free (param);
+}
+
+int
+mono_btls_x509_verify_param_set_name (MonoBtlsX509VerifyParam *param, const char *name)
+{
+       if (!param->owns)
+               return -1;
+       return X509_VERIFY_PARAM_set1_name (param->param, name);
+}
+
+int
+mono_btls_x509_verify_param_set_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen)
+{
+       if (!param->owns)
+               return -1;
+       return X509_VERIFY_PARAM_set1_host (param->param, host, namelen);
+}
+
+int
+mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen)
+{
+       if (!param->owns)
+               return -1;
+       return X509_VERIFY_PARAM_set1_host (param->param, host, namelen);
+}
+
+unsigned long
+mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param)
+{
+       return X509_VERIFY_PARAM_get_flags (param->param);
+}
+
+int
+mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, unsigned long flags)
+{
+       if (!param->owns)
+               return -1;
+       return X509_VERIFY_PARAM_set_flags (param->param, flags);
+}
+
+MonoBtlsX509VerifyFlags
+mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param)
+{
+       MonoBtlsX509VerifyFlags current;
+       unsigned long flags;
+
+       if (!param->owns)
+               return -1;
+
+       current = 0;
+       flags = X509_VERIFY_PARAM_get_flags (param->param);
+
+       if (flags & X509_V_FLAG_CRL_CHECK)
+               current |= MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK;
+       if (flags & X509_V_FLAG_CRL_CHECK_ALL)
+               current |= MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL;
+       if (flags & X509_V_FLAG_X509_STRICT)
+               current |= MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT;
+
+       return current;
+}
+
+int
+mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags)
+{
+       unsigned long current;
+
+       if (!param->owns)
+               return -1;
+
+       current = X509_VERIFY_PARAM_get_flags (param->param);
+       if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK)
+               current |= X509_V_FLAG_CRL_CHECK;
+       if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL)
+               current |= X509_V_FLAG_CRL_CHECK_ALL;
+       if (flags & MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT)
+               current |= X509_V_FLAG_X509_STRICT;
+
+       return X509_VERIFY_PARAM_set_flags (param->param, current);
+}
+
+int
+mono_btls_x509_verify_param_set_purpose (MonoBtlsX509VerifyParam *param, MonoBtlsX509Purpose purpose)
+{
+       if (!param->owns)
+               return -1;
+       return X509_VERIFY_PARAM_set_purpose (param->param, purpose);
+}
+
+int
+mono_btls_x509_verify_param_get_depth (MonoBtlsX509VerifyParam *param)
+{
+       return X509_VERIFY_PARAM_get_depth (param->param);
+}
+
+int
+mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth)
+{
+       if (!param->owns)
+               return -1;
+       X509_VERIFY_PARAM_set_depth (param->param, depth);
+       return 1;
+}
+
+int
+mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, long time)
+{
+       if (!param->owns)
+               return -1;
+       X509_VERIFY_PARAM_set_time (param->param, time);
+       return 1;
+}
+
+char *
+mono_btls_x509_verify_param_get_peername (MonoBtlsX509VerifyParam *param)
+{
+       char *peer = X509_VERIFY_PARAM_get0_peername (param->param);
+       return peer;
+}
diff --git a/mono/btls/btls-x509-verify-param.h b/mono/btls/btls-x509-verify-param.h
new file mode 100644 (file)
index 0000000..6f4f1b5
--- /dev/null
@@ -0,0 +1,81 @@
+//
+//  btls-x509-verify-param.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 3/3/16.
+//  Copyright © 2016 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509_verify_param__
+#define __btls__btls_x509_verify_param__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509.h>
+
+typedef enum {
+       MONO_BTLS_X509_VERIFY_FLAGS_DEFAULT             = 0,
+       MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK   = 1,
+       MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL       = 2,
+       MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT = 4
+} MonoBtlsX509VerifyFlags;
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_new (void);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_from_store_ctx (MonoBtlsX509StoreCtx *ctx, X509_VERIFY_PARAM *param);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_copy (const MonoBtlsX509VerifyParam *from);
+
+void
+mono_btls_x509_verify_param_free (MonoBtlsX509VerifyParam *param);
+
+const X509_VERIFY_PARAM *
+mono_btls_x509_verify_param_peek_param (const MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_can_modify (MonoBtlsX509VerifyParam *param);
+
+MonoBtlsX509VerifyParam *
+mono_btls_x509_verify_param_lookup (const char *name);
+
+int
+mono_btls_x509_verify_param_set_name (MonoBtlsX509VerifyParam *param, const char *name);
+
+int
+mono_btls_x509_verify_param_set_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen);
+
+int
+mono_btls_x509_verify_param_add_host (MonoBtlsX509VerifyParam *param, const char *host, int namelen);
+
+unsigned long
+mono_btls_x509_verify_param_get_flags (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, unsigned long flags);
+
+MonoBtlsX509VerifyFlags
+mono_btls_x509_verify_param_get_mono_flags (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags);
+
+int
+mono_btls_x509_verify_param_set_purpose (MonoBtlsX509VerifyParam *param, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_verify_param_get_depth (MonoBtlsX509VerifyParam *param);
+
+int
+mono_btls_x509_verify_param_set_depth (MonoBtlsX509VerifyParam *param, int depth);
+
+int
+mono_btls_x509_verify_param_set_time (MonoBtlsX509VerifyParam *param, long time);
+
+char *
+mono_btls_x509_verify_param_get_peername (MonoBtlsX509VerifyParam *param);
+
+#endif /* defined(__btls__btls_x509_verify_param__) */
+
diff --git a/mono/btls/btls-x509.c b/mono/btls/btls-x509.c
new file mode 100644 (file)
index 0000000..5417422
--- /dev/null
@@ -0,0 +1,436 @@
+//
+//  btls-x509.c
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#include <btls-x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/pkcs12.h>
+
+X509 *
+mono_btls_x509_from_data (const void *buf, int len, MonoBtlsX509Format format)
+{
+       BIO *bio;
+       X509 *cert = NULL;
+
+       bio = BIO_new_mem_buf ((void *)buf, len);
+       switch (format) {
+               case MONO_BTLS_X509_FORMAT_DER:
+                       cert = d2i_X509_bio (bio, NULL);
+                       break;
+               case MONO_BTLS_X509_FORMAT_PEM:
+                       cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
+                       break;
+       }
+       BIO_free (bio);
+       return cert;
+}
+
+X509 *
+mono_btls_x509_up_ref (X509 *x509)
+{
+       X509_up_ref (x509);
+       return x509;
+}
+
+void
+mono_btls_x509_free (X509 *x509)
+{
+       X509_free (x509);
+}
+
+X509 *
+mono_btls_x509_dup (X509 *x509)
+{
+       return X509_dup (x509);
+}
+
+MonoBtlsX509Name *
+mono_btls_x509_get_subject_name (X509 *x509)
+{
+       return mono_btls_x509_name_copy (X509_get_subject_name (x509));
+}
+
+MonoBtlsX509Name *
+mono_btls_x509_get_issuer_name (X509 *x509)
+{
+       return mono_btls_x509_name_copy (X509_get_issuer_name (x509));
+}
+
+int
+mono_btls_x509_get_subject_name_string (X509 *name, char *buffer, int size)
+{
+       *buffer = 0;
+       return X509_NAME_oneline (X509_get_subject_name (name), buffer, size) != NULL;
+}
+
+int
+mono_btls_x509_get_issuer_name_string (X509 *name, char *buffer, int size)
+{
+       *buffer = 0;
+       return X509_NAME_oneline (X509_get_issuer_name (name), buffer, size) != NULL;
+}
+
+int
+mono_btls_x509_get_raw_data (X509 *x509, BIO *bio, MonoBtlsX509Format format)
+{
+       switch (format) {
+               case MONO_BTLS_X509_FORMAT_DER:
+                       return i2d_X509_bio (bio, x509);
+               case MONO_BTLS_X509_FORMAT_PEM:
+                       return PEM_write_bio_X509 (bio, x509);
+               default:
+                       return 0;
+       }
+}
+
+int
+mono_btls_x509_cmp (const X509 *a, const X509 *b)
+{
+       return X509_cmp (a, b);
+}
+
+int
+mono_btls_x509_get_hash (X509 *x509, const void **data)
+{
+       X509_check_purpose (x509, -1, 0);
+       *data = x509->sha1_hash;
+       return SHA_DIGEST_LENGTH;
+}
+
+long
+mono_btls_x509_get_not_before (X509 *x509)
+{
+       return mono_btls_util_asn1_time_to_ticks (X509_get_notBefore (x509));
+}
+
+long
+mono_btls_x509_get_not_after (X509 *x509)
+{
+       return mono_btls_util_asn1_time_to_ticks (X509_get_notAfter (x509));
+}
+
+int
+mono_btls_x509_get_public_key (X509 *x509, BIO *bio)
+{
+       EVP_PKEY *pkey;
+       uint8_t *data = NULL;
+       int ret;
+
+       pkey = X509_get_pubkey (x509);
+       if (!pkey)
+               return -1;
+
+       ret = i2d_PublicKey (pkey, &data);
+
+       if (ret > 0 && data) {
+               ret = BIO_write (bio, data, ret);
+               OPENSSL_free (data);
+       }
+
+       EVP_PKEY_free (pkey);
+       return ret;
+}
+
+int
+mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_style)
+{
+       ASN1_INTEGER *serial;
+       char *pos;
+       int len, idx;
+
+       serial = X509_get_serialNumber (x509);
+       if (serial->length == 0 || serial->length+1 > size)
+               return 0;
+
+       if (!mono_style) {
+               memcpy (buffer, serial->data, serial->length);
+               return serial->length;
+       }
+
+       pos = buffer;
+       len = 0;
+
+       for (idx = serial->length - 1; idx >= 0; idx--) {
+               *pos++ = serial->data [idx];
+               len++;
+       }
+
+       if (serial->data [0] >= 0x80) {
+               *pos++ = 0;
+               len++;
+       }
+
+       return len;
+}
+
+int
+mono_btls_x509_get_public_key_algorithm (X509 *x509, char *buffer, int size)
+{
+       X509_PUBKEY *pkey;
+       ASN1_OBJECT *ppkalg;
+       int ret;
+
+       *buffer = 0;
+       pkey = X509_get_X509_PUBKEY (x509);
+       if (!pkey)
+               return 0;
+
+       ret = X509_PUBKEY_get0_param (&ppkalg, NULL, NULL, NULL, pkey);
+       if (!ret || !ppkalg)
+               return ret;
+
+       return OBJ_obj2txt (buffer, size, ppkalg, 1);
+}
+
+int
+mono_btls_x509_get_version (X509 *x509)
+{
+       return (int)X509_get_version (x509) + 1;
+}
+
+int
+mono_btls_x509_get_signature_algorithm (X509 *x509, char *buffer, int size)
+{
+       const ASN1_OBJECT *obj;
+       int nid;
+
+       *buffer = 0;
+
+       nid = X509_get_signature_nid (x509);
+
+       obj = OBJ_nid2obj (nid);
+       if (!obj)
+               return 0;
+
+       return OBJ_obj2txt (buffer, size, obj, 1);
+}
+
+int
+mono_btls_x509_get_public_key_asn1 (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
+{
+       X509_PUBKEY *pkey;
+       ASN1_OBJECT *ppkalg;
+       const unsigned char *pk;
+       int pk_len;
+       int ret;
+
+       if (out_oid)
+               *out_oid = 0;
+
+       pkey = X509_get_X509_PUBKEY (x509);
+       if (!pkey || !pkey->public_key)
+               return 0;
+
+       ret = X509_PUBKEY_get0_param (&ppkalg, &pk, &pk_len, NULL, pkey);
+       if (ret != 1 || !ppkalg || !pk)
+               return 0;
+
+       if (out_oid) {
+               OBJ_obj2txt (out_oid, oid_len, ppkalg, 1);
+       }
+
+       if (buffer) {
+               *size = pk_len;
+               *buffer = OPENSSL_malloc (pk_len);
+               if (!*buffer)
+                       return 0;
+
+               memcpy (*buffer, pk, pk_len);
+       }
+
+       return 1;
+
+}
+
+int
+mono_btls_x509_get_public_key_parameters (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size)
+{
+       X509_PUBKEY *pkey;
+       X509_ALGOR *algor;
+       ASN1_OBJECT *paobj;
+       int ptype;
+       void *pval;
+       int ret;
+
+       if (out_oid)
+               *out_oid = 0;
+
+       pkey = X509_get_X509_PUBKEY (x509);
+
+       ret = X509_PUBKEY_get0_param (NULL, NULL, NULL, &algor, pkey);
+       if (ret != 1 || !algor)
+               return 0;
+
+       X509_ALGOR_get0 (&paobj, &ptype, &pval, algor);
+
+       if (ptype != V_ASN1_NULL && ptype != V_ASN1_SEQUENCE)
+               return 0;
+
+       if (ptype == V_ASN1_NULL) {
+               uint8_t *ptr;
+
+               *size = 2;
+               *buffer = OPENSSL_malloc (2);
+               if (!*buffer)
+                       return 0;
+
+               ptr = *buffer;
+               *ptr++ = 0x05;
+               *ptr++ = 0x00;
+
+               if (out_oid)
+                       OBJ_obj2txt (out_oid, oid_len, paobj, 1);
+
+               return 1;
+       } else if (ptype == V_ASN1_SEQUENCE) {
+               ASN1_STRING *pstr = pval;
+
+               *size = pstr->length;
+               *buffer = OPENSSL_malloc (pstr->length);
+               if (!*buffer)
+                       return 0;
+
+               memcpy (*buffer, pstr->data, pstr->length);
+
+               if (out_oid)
+                       OBJ_obj2txt (out_oid, oid_len, paobj, 1);
+
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+EVP_PKEY *
+mono_btls_x509_get_pubkey (X509 *x509)
+{
+       return X509_get_pubkey (x509);
+}
+
+int
+mono_btls_x509_get_subject_key_identifier (X509 *x509, uint8_t **buffer, int *size)
+{
+       ASN1_OCTET_STRING *skid;
+
+       *size = 0;
+       *buffer = NULL;
+
+       if (X509_get_version (x509) != 2)
+               return 0;
+
+       skid = X509_get_ext_d2i (x509, NID_subject_key_identifier, NULL, NULL);
+       if (!skid)
+               return 0;
+
+       *size = skid->length;
+       *buffer = OPENSSL_malloc (*size);
+       if (!*buffer)
+               return 0;
+
+       memcpy (*buffer, skid->data, *size);
+       return 1;
+}
+
+int
+mono_btls_x509_print (X509 *x509, BIO *bio)
+{
+       return X509_print_ex (bio, x509, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
+}
+
+static int
+get_trust_nid (MonoBtlsX509Purpose purpose)
+{
+       switch (purpose) {
+               case MONO_BTLS_X509_PURPOSE_SSL_CLIENT:
+                       return NID_client_auth;
+               case MONO_BTLS_X509_PURPOSE_SSL_SERVER:
+                       return NID_server_auth;
+               default:
+                       return 0;
+       }
+}
+
+int
+mono_btls_x509_add_trust_object (X509 *x509, MonoBtlsX509Purpose purpose)
+{
+       ASN1_OBJECT *trust;
+       int nid;
+
+       nid = get_trust_nid (purpose);
+       if (!nid)
+               return 0;
+
+       trust = ASN1_OBJECT_new ();
+       if (!trust)
+               return 0;
+
+       trust->nid = nid;
+       return X509_add1_trust_object (x509, trust);
+}
+
+int
+mono_btls_x509_add_reject_object (X509 *x509, MonoBtlsX509Purpose purpose)
+{
+       ASN1_OBJECT *reject;
+       int nid;
+
+       nid = get_trust_nid (purpose);
+       if (!nid)
+               return 0;
+
+       reject = ASN1_OBJECT_new ();
+       if (!reject)
+               return 0;
+
+       reject->nid = nid;
+       return X509_add1_reject_object (x509, reject);
+}
+
+int
+mono_btls_x509_add_explicit_trust (X509 *x509, MonoBtlsX509TrustKind kind)
+{
+       int ret = 0;
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_ALL) != 0)
+               kind |= MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT | MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER;
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_ALL) != 0)
+               kind |= MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT | MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER;
+
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT) != 0) {
+               ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
+               if (!ret)
+                       return ret;
+       }
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER) != 0) {
+               ret = mono_btls_x509_add_reject_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
+               if (!ret)
+                       return ret;
+       }
+
+       if (ret) {
+               // Ignore any MONO_BTLS_X509_TRUST_KIND_TRUST_* settings if we added
+               // any kind of MONO_BTLS_X509_TRUST_KIND_REJECT_* before.
+               return ret;
+       }
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT) != 0) {
+               ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_CLIENT);
+               if (!ret)
+                       return ret;
+       }
+
+       if ((kind & MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER) != 0) {
+               ret = mono_btls_x509_add_trust_object (x509, MONO_BTLS_X509_PURPOSE_SSL_SERVER);
+               if (!ret)
+                       return ret;
+       }
+
+       return ret;
+}
diff --git a/mono/btls/btls-x509.h b/mono/btls/btls-x509.h
new file mode 100644 (file)
index 0000000..a9a9200
--- /dev/null
@@ -0,0 +1,127 @@
+//
+//  btls-x509.h
+//  MonoBtls
+//
+//  Created by Martin Baulig on 14/11/15.
+//  Copyright (c) 2015 Xamarin. All rights reserved.
+//
+
+#ifndef __btls__btls_x509__
+#define __btls__btls_x509__
+
+#include <stdio.h>
+#include <btls-ssl.h>
+#include <btls-x509-name.h>
+
+typedef enum {
+       MONO_BTLS_X509_FORMAT_DER = 1,
+       MONO_BTLS_X509_FORMAT_PEM = 2
+} MonoBtlsX509Format;
+
+typedef enum {
+       MONO_BTLS_x509_FILE_TYPE_PEM = 1,               // X509_FILETYPE_PEM
+       MONO_BTLS_x509_FILE_TYPE_ASN1 = 2,              // X509_FILETYPE_ASN1
+       MONO_BTLS_x509_FILE_TYPE_DEFAULT = 3,   // X509_FILETYPE_DEFAULT
+} MonoBtlsX509FileType;
+
+typedef enum {
+       MONO_BTLS_X509_PURPOSE_SSL_CLIENT               = 1,
+       MONO_BTLS_X509_PURPOSE_SSL_SERVER               = 2,
+       MONO_BTLS_X509_PURPOSE_NS_SSL_SERVER    = 3,
+       MONO_BTLS_X509_PURPOSE_SMIME_SIGN               = 4,
+       MONO_BTLS_X509_PURPOSE_SMIME_ENCRYPT    = 5,
+       MONO_BTLS_X509_PURPOSE_CRL_SIGN         = 6,
+       MONO_BTLS_X509_PURPOSE_ANY                      = 7,
+       MONO_BTLS_X509_PURPOSE_OCSP_HELPER              = 8,
+       MONO_BTLS_X509_PURPOSE_TIMESTAMP_SIGN   = 9,
+} MonoBtlsX509Purpose;
+
+typedef enum {
+       MONO_BTLS_X509_TRUST_KIND_DEFAULT               = 0,
+       MONO_BTLS_X509_TRUST_KIND_TRUST_CLIENT  = 1,
+       MONO_BTLS_X509_TRUST_KIND_TRUST_SERVER  = 2,
+       MONO_BTLS_X509_TRUST_KIND_TRUST_ALL             = 4,
+       MONO_BTLS_X509_TRUST_KIND_REJECT_CLIENT = 32,
+       MONO_BTLS_X509_TRUST_KIND_REJECT_SERVER = 64,
+       MONO_BTLS_X509_TRUST_KIND_REJECT_ALL    = 128
+} MonoBtlsX509TrustKind;
+
+X509 *
+mono_btls_x509_from_data (const void *buf, int len, MonoBtlsX509Format format);
+
+X509 *
+mono_btls_x509_up_ref (X509 *x509);
+
+void
+mono_btls_x509_free (X509 *x509);
+
+X509 *
+mono_btls_x509_dup (X509 *x509);
+
+MonoBtlsX509Name *
+mono_btls_x509_get_subject_name (X509 *x509);
+
+MonoBtlsX509Name *
+mono_btls_x509_get_issuer_name (X509 *x509);
+
+int
+mono_btls_x509_get_subject_name_string (X509 *name, char *buffer, int size);
+
+int
+mono_btls_x509_get_issuer_name_string (X509 *name, char *buffer, int size);
+
+int
+mono_btls_x509_get_raw_data (X509 *x509, BIO *bio, MonoBtlsX509Format format);
+
+int
+mono_btls_x509_cmp (const X509 *a, const X509 *b);
+
+int
+mono_btls_x509_get_hash (X509 *x509, const void **data);
+
+long
+mono_btls_x509_get_not_before (X509 *x509);
+
+long
+mono_btls_x509_get_not_after (X509 *x509);
+
+int
+mono_btls_x509_get_public_key (X509 *x509, BIO *bio);
+
+int
+mono_btls_x509_get_public_key_parameters (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size);
+
+int
+mono_btls_x509_get_serial_number (X509 *x509, char *buffer, int size, int mono_style);
+
+int
+mono_btls_x509_get_public_key_algorithm (X509 *x509, char *buffer, int size);
+
+int
+mono_btls_x509_get_version (X509 *x509);
+
+int
+mono_btls_x509_get_signature_algorithm (X509 *x509, char *buffer, int size);
+
+int
+mono_btls_x509_get_public_key_asn1 (X509 *x509, char *out_oid, int oid_len, uint8_t **buffer, int *size);
+
+EVP_PKEY *
+mono_btls_x509_get_pubkey (X509 *x509);
+
+int
+mono_btls_x509_get_subject_key_identifier (X509 *x509, uint8_t **buffer, int *size);
+
+int
+mono_btls_x509_print (X509 *x509, BIO *bio);
+
+int
+mono_btls_x509_add_trust_object (X509 *x509, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_add_reject_object (X509 *x509, MonoBtlsX509Purpose purpose);
+
+int
+mono_btls_x509_add_explicit_trust (X509 *x509, MonoBtlsX509TrustKind kind);
+
+#endif /* defined(__btls__btls_x509__) */
diff --git a/mono/btls/create-object-library.sh b/mono/btls/create-object-library.sh
new file mode 100755 (executable)
index 0000000..8ceda08
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+DIR=$1; shift
+FILELIST=$1; shift
+LOFILELIST=$1 ; shift
+TARGET=$1; shift
+STATIC=$1; shift
+AR=$1; shift
+RANLIB=$1; shift
+
+HEADER="# Generated by Martin's tool $0, not libtool"
+
+test -f $TARGET && exit 0
+
+rm -f $FILELIST
+rm -f $LOFILELIST
+
+while [ "$1" != "--" ]; do
+       file=$1; shift
+       filename=`basename $file`
+       LOFILE=$file.lo
+       echo "$HEADER" > $LOFILE
+       if [ "$STATIC" = "static" ]; then
+               echo "non_pic_object='$filename'" >> $LOFILE
+       else
+               echo "pic_object='$filename'" >> $LOFILE
+       fi
+       echo "$DIR/$file " >> $FILELIST
+       echo "$DIR/$LOFILE " >> $LOFILELIST
+done
+
+(cd $DIR && $AR cr $TARGET `cat $FILELIST` && $RANLIB $TARGET)
+
index a3cbe2abfee3419be56e504891aa2e749f9ed3cf..e9096e25580ee216938e36854d2668b6325b4a45 100755 (executable)
@@ -11,6 +11,9 @@
 #ifndef _MONO_IOLAYER_IOLAYER_H_
 #define _MONO_IOLAYER_IOLAYER_H_
 
+#include <config.h>
+#include <glib.h>
+
 #if defined(__WIN32__) || defined(_WIN32)
 /* Native win32 */
 #define __USE_W32_SOCKETS
@@ -25,8 +28,8 @@
 #include <ws2tcpip.h>
 #endif
 #include <psapi.h>
-#include <shlobj.h>
-/*
+
+ /*
  * Workaround for missing WSAPOLLFD typedef in mingw's winsock2.h that is required for mswsock.h below.
  * Remove once http://sourceforge.net/p/mingw/bugs/1980/ is fixed.
  */
@@ -37,7 +40,11 @@ typedef struct pollfd {
   short  revents;
 } WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
 #endif
+
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
 #include <mswsock.h>
+#endif
+
 #else  /* EVERYONE ELSE */
 #include "mono/io-layer/wapi.h"
 #include "mono/io-layer/uglify.h"
index d541472ada7a675f588cbd457f4b44b5887ed3ee..60d6b47a321a2c0de23a36b3034e2f82f2c8962c 100644 (file)
@@ -38,6 +38,14 @@ if PLATFORM_ANDROID
 platform_sources += ../../support/libm/complex.c
 endif
 
+if BTLS
+btls_file_list := $(shell cat ../btls/build-shared/mono-btls-shared-lo.txt)
+btls_static_file_list := $(shell cat ../btls/build-static/mono-btls-static-lo.txt)
+btls_libs = $(btls_file_list)
+btls_static_libs = $(btls_static_file_list)
+btls_cflags = -I$(top_srcdir)/external/boringssl/include -I$(top_srcdir)/mono/btls
+endif
+
 #
 # libtool is not capable of creating static/shared versions of the same
 # convenience lib, so we have to do it ourselves
@@ -70,7 +78,7 @@ else
 noinst_LTLIBRARIES = libmonoruntime-config.la $(boehm_libraries) $(sgen_libraries)
 endif
 
-AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CPPFLAGS) $(GLIB_CFLAGS) $(SHARED_CFLAGS)
+AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(LIBGC_CPPFLAGS) $(GLIB_CFLAGS) $(SHARED_CFLAGS) $(btls_cflags)
 
 #
 # Make sure any prefix changes are updated in the binaries too.
@@ -270,21 +278,21 @@ sgen_sources = \
 
 libmonoruntime_la_SOURCES = $(common_sources) $(gc_dependent_sources) $(null_gc_sources) $(boehm_sources)
 libmonoruntime_la_CFLAGS = $(BOEHM_DEFINES)
-libmonoruntime_la_LIBADD = libmonoruntime-config.la
+libmonoruntime_la_LIBADD = libmonoruntime-config.la $(btls_libs)
 
 libmonoruntimesgen_la_SOURCES = $(common_sources) $(gc_dependent_sources) $(sgen_sources)
 libmonoruntimesgen_la_CFLAGS = $(SGEN_DEFINES)
-libmonoruntimesgen_la_LIBADD = libmonoruntime-config.la
+libmonoruntimesgen_la_LIBADD = libmonoruntime-config.la $(btls_libs)
 
 libmonoruntime_static_la_SOURCES = $(libmonoruntime_la_SOURCES)
 libmonoruntime_static_la_LDFLAGS = -static
 libmonoruntime_static_la_CFLAGS = $(BOEHM_DEFINES)
-libmonoruntime_static_la_LIBADD = $(bundle_obj) $(libmonoruntime_la_LIBADD)
+libmonoruntime_static_la_LIBADD = $(bundle_obj) libmonoruntime-config.la $(btls_static_libs)
 
 libmonoruntimesgen_static_la_SOURCES = $(libmonoruntimesgen_la_SOURCES)
 libmonoruntimesgen_static_la_LDFLAGS = -static
 libmonoruntimesgen_static_la_CFLAGS = $(SGEN_DEFINES)
-libmonoruntimesgen_static_la_LIBADD = $(libmonoruntimesgen_la_LIBADD)
+libmonoruntimesgen_static_la_LIBADD = libmonoruntime-config.la $(btls_static_libs)
 
 libmonoruntimeincludedir = $(includedir)/mono-$(API_VER)/mono/metadata
 
index 0608394ff10b1db34d66b3aefc98aee657cf0cb1..58fa379e5bb57a2c73580b74fc83680d022126eb 100644 (file)
@@ -84,7 +84,7 @@
  * Changes which are already detected at runtime, like the addition
  * of icalls, do not require an increment.
  */
-#define MONO_CORLIB_VERSION 157
+#define MONO_CORLIB_VERSION 158
 
 typedef struct
 {
index e7ee0517dd22bc28555975281b8c4820f4dd7f8d..d084501c929424aa8dc14ccb01150eb818cee407 100644 (file)
@@ -99,6 +99,9 @@ mono_gc_warning (char *msg, GC_word arg)
        mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg);
 }
 
+static void on_gc_notification (GC_EventType event);
+static void on_gc_heap_resize (size_t new_size);
+
 void
 mono_gc_base_init (void)
 {
@@ -251,7 +254,8 @@ mono_gc_base_init (void)
 
        mono_thread_info_attach (&dummy);
 
-       mono_gc_enable_events ();
+       GC_set_on_collection_event (on_gc_notification);
+       GC_on_heap_resize = on_gc_heap_resize;
 
        MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
        MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table");
@@ -523,21 +527,6 @@ on_gc_heap_resize (size_t new_size)
        mono_profiler_gc_heap_resize (new_size);
 }
 
-void
-mono_gc_enable_events (void)
-{
-       GC_set_on_collection_event (on_gc_notification);
-       GC_on_heap_resize = on_gc_heap_resize;
-}
-
-static gboolean alloc_events = FALSE;
-
-void
-mono_gc_enable_alloc_events (void)
-{
-       alloc_events = TRUE;
-}
-
 int
 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
 {
@@ -679,7 +668,7 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
                obj->vtable = vtable;
        }
 
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (obj);
 
        return obj;
@@ -713,7 +702,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
 
        obj->max_length = max_length;
 
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&obj->obj);
 
        return obj;
@@ -750,7 +739,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint
        if (bounds_size)
                obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size);
 
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&obj->obj);
 
        return obj;
@@ -768,7 +757,7 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
        obj->length = len;
        obj->chars [len] = 0;
 
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&obj->object);
 
        return obj;
index bedd740079bfdc160e07c76ae65b67134f7af777..5f7d15560aa1c3c83d20b8664b7ae7cfe4517e34 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#if defined(HOST_WIN32)
+#include <oleauto.h>
+#endif
+
 /*
 Code shared between the DISABLE_COM and !DISABLE_COM
 */
index a1d48eb3d4431fdb2792d47eae84c5644cd9489f..d76c0376adc8620dd1a35a940bf35eb631b93f80 100644 (file)
@@ -1545,10 +1545,6 @@ mono_reflection_get_custom_attrs_info_checked (MonoObject *obj, MonoError *error
                MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
                cinfo = mono_custom_attrs_from_method_checked (rmethod->method, error);
                return_val_if_nok (error, NULL);
-       } else if ((strcmp ("MonoGenericMethod", klass->name) == 0) || (strcmp ("MonoGenericCMethod", klass->name) == 0)) {
-               MonoReflectionMethod *rmethod = (MonoReflectionMethod*)obj;
-               cinfo = mono_custom_attrs_from_method_checked (rmethod->method, error);
-               return_val_if_nok (error, NULL);
        } else if (strcmp ("ParameterInfo", klass->name) == 0 || strcmp ("MonoParameterInfo", klass->name) == 0) {
                MonoReflectionParameter *param = (MonoReflectionParameter*)obj;
                MonoClass *member_class = mono_object_class (param->MemberImpl);
@@ -1568,22 +1564,11 @@ mono_reflection_get_custom_attrs_info_checked (MonoObject *obj, MonoError *error
                } 
 #ifndef DISABLE_REFLECTION_EMIT
                else if (mono_is_sre_method_on_tb_inst (member_class)) {/*XXX This is a workaround for Compiler Context*/
-                       MonoMethod *method = mono_reflection_method_on_tb_inst_get_handle ((MonoReflectionMethodOnTypeBuilderInst*)param->MemberImpl, error);
-                       return_val_if_nok (error, NULL);
-                       cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
-                       return_val_if_nok (error, NULL);
+                       // FIXME: Is this still needed ?
+                       g_assert_not_reached ();
                } else if (mono_is_sre_ctor_on_tb_inst (member_class)) { /*XX This is a workaround for Compiler Context*/
-                       MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)param->MemberImpl;
-                       MonoMethod *method = NULL;
-                       if (mono_is_sre_ctor_builder (mono_object_class (c->cb)))
-                               method = ((MonoReflectionCtorBuilder *)c->cb)->mhandle;
-                       else if (mono_is_sr_mono_cmethod (mono_object_class (c->cb)))
-                               method = ((MonoReflectionMethod *)c->cb)->method;
-                       else
-                               g_error ("mono_reflection_get_custom_attrs_info:: can't handle a CTBI with base_method of type %s", mono_type_get_full_name (member_class));
-
-                       cinfo = mono_custom_attrs_from_param_checked (method, param->PositionImpl + 1, error);
-                       return_val_if_nok (error, NULL);
+                       // FIXME: Is this still needed ?
+                       g_assert_not_reached ();
                } 
 #endif
                else {
index f418b2078cee4af6f2da49eb191d887c99d458bb..b7e48f95d44aebf774a53df0f23ca8fc3521e7e7 100644 (file)
@@ -649,11 +649,6 @@ mono_debug_symfile_get_seq_points (MonoDebugMethodInfo *minfo, char **source_fil
                        if (source_files)
                                (*source_files) [i] = (*source_file_list)->len - 1;
                }
-               if ((*source_file_list)->len == 0 && stm.file) {
-                       MonoDebugSourceInfo *info = get_source_info (symfile, stm.file);
-
-                       g_ptr_array_add (*source_file_list, info);
-               }
        }                               
 
        if (n_seq_points) {
index bb40725ac1f401e085deccb0dc901a0b083a6ecd..d280e30982144af7f8bd20328d420f38e742ad9b 100644 (file)
@@ -1175,6 +1175,12 @@ mono_domain_free (MonoDomain *domain, gboolean force)
        g_slist_free (domain->domain_assemblies);
        domain->domain_assemblies = NULL;
 
+       /* 
+        * Send this after the assemblies have been unloaded and the domain is still in a 
+        * usable state.
+        */
+       mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
+
        if (free_domain_hook)
                free_domain_hook (domain);
 
index 17f0f8e82fba2642e8296010cd2c33d41c5d4284..9906f43b31838ec448675aeab80c281ee262d8c1 100644 (file)
@@ -347,7 +347,6 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c
        image->handleref_managed = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module reference-to-token table");
        image->tokens = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module tokens table");
        image->generic_def_objects = mono_g_hash_table_new_type (NULL, NULL, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module generic definitions table");
-       image->methodspec = mono_g_hash_table_new_type ((GHashFunc)mono_object_hash, NULL, MONO_HASH_KEY_GC, MONO_ROOT_SOURCE_REFLECTION, "dynamic module method specifications table");
        image->typespec = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
        image->typeref = g_hash_table_new ((GHashFunc)mono_metadata_type_hash, (GCompareFunc)mono_metadata_type_equal);
        image->blob_cache = g_hash_table_new ((GHashFunc)mono_blob_entry_hash, (GCompareFunc)mono_blob_entry_equal);
@@ -469,7 +468,6 @@ mono_dynamic_image_release_gc_roots (MonoDynamicImage *image)
        release_hashtable (&image->tokens);
        release_hashtable (&image->remapped_tokens);
        release_hashtable (&image->generic_def_objects);
-       release_hashtable (&image->methodspec);
 }
 
 // Free dynamic image pass one: Free resources but not image itself
@@ -480,8 +478,6 @@ mono_dynamic_image_free (MonoDynamicImage *image)
        GList *list;
        int i;
 
-       if (di->methodspec)
-               mono_g_hash_table_destroy (di->methodspec);
        if (di->typespec)
                g_hash_table_destroy (di->typespec);
        if (di->typeref)
index cd9408df98bbd073b054eeff706deb64b7a9765f..d3d81f272a8820b14d5710c4bee0a7b532548485 100644 (file)
@@ -103,8 +103,6 @@ extern void mono_gc_set_stack_end (void *stack_end);
 gboolean mono_object_is_alive (MonoObject* obj);
 gboolean mono_gc_is_finalizer_thread (MonoThread *thread);
 gpointer mono_gc_out_of_memory (size_t size);
-void     mono_gc_enable_events (void);
-void     mono_gc_enable_alloc_events (void);
 
 void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj);
 
index 46eaf5e224af7ad3bd1ac05a365d4415ad0d910b..ae4329be666865957ba53ad41f60586c4c2cc065 100644 (file)
@@ -560,8 +560,6 @@ mono_domain_finalize (MonoDomain *domain, guint32 timeout)
                mono_gc_finalize_threadpool_threads ();
        }
 
-       mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD);
-
 done:
        if (InterlockedDecrement (&req->ref) == 0) {
                mono_coop_sem_destroy (&req->done);
index 507c67244a750418461cd8a74f4660d0e10c4cdc..703ad861363ca259bc48ebf4e7a298d0595d9fc5 100644 (file)
@@ -78,6 +78,247 @@ ICALL(NATIVEMETHODS_10, "TerminateProcess", ves_icall_Microsoft_Win32_NativeMeth
 ICALL(NATIVEMETHODS_11, "WaitForInputIdle", ves_icall_Microsoft_Win32_NativeMethods_WaitForInputIdle)
 #endif /* !DISABLE_PROCESS_HANDLING */
 
+#if HAVE_BTLS
+ICALL_TYPE(BTLS_BIO, "Mono.Btls.MonoBtlsBio", BTLS_BIO_1)
+ICALL(BTLS_BIO_1, "mono_btls_bio_flush", mono_btls_bio_flush)
+ICALL(BTLS_BIO_2, "mono_btls_bio_free", mono_btls_bio_free)
+ICALL(BTLS_BIO_3, "mono_btls_bio_hexdump", mono_btls_bio_hexdump)
+ICALL(BTLS_BIO_4, "mono_btls_bio_indent", mono_btls_bio_indent)
+ICALL(BTLS_BIO_5, "mono_btls_bio_print_errors", mono_btls_bio_print_errors)
+ICALL(BTLS_BIO_6, "mono_btls_bio_read", mono_btls_bio_read)
+ICALL(BTLS_BIO_7, "mono_btls_bio_write", mono_btls_bio_write)
+
+ICALL_TYPE(BTLS_BIO_MEM, "Mono.Btls.MonoBtlsBioMemory", BTLS_BIO_MEM_1)
+ICALL(BTLS_BIO_MEM_1, "mono_btls_bio_mem_get_data", mono_btls_bio_mem_get_data)
+ICALL(BTLS_BIO_MEM_2, "mono_btls_bio_mem_new", mono_btls_bio_mem_new)
+
+ICALL_TYPE(BTLS_BIO_MONO, "Mono.Btls.MonoBtlsBioMono", BTLS_BIO_MONO_1)
+ICALL(BTLS_BIO_MONO_1, "mono_btls_bio_mono_initialize", mono_btls_bio_mono_initialize)
+ICALL(BTLS_BIO_MONO_2, "mono_btls_bio_mono_new", mono_btls_bio_mono_new)
+
+ICALL_TYPE(BTLS_ERROR, "Mono.Btls.MonoBtlsError", BTLS_ERROR_1)
+ICALL(BTLS_ERROR_1, "mono_btls_error_clear_error", mono_btls_error_clear_error)
+ICALL(BTLS_ERROR_2, "mono_btls_error_get_error", mono_btls_error_get_error)
+ICALL(BTLS_ERROR_3, "mono_btls_error_get_error_string_n", mono_btls_error_get_error_string_n)
+ICALL(BTLS_ERROR_4, "mono_btls_error_peek_error", mono_btls_error_peek_error)
+
+ICALL_TYPE(BTLS_KEY, "Mono.Btls.MonoBtlsKey", BTLS_KEY_1)
+ICALL(BTLS_KEY_1, "mono_btls_key_free", mono_btls_key_free)
+ICALL(BTLS_KEY_2, "mono_btls_key_get_bits", mono_btls_key_get_bits)
+ICALL(BTLS_KEY_3, "mono_btls_key_get_bytes", mono_btls_key_get_bytes)
+ICALL(BTLS_KEY_4, "mono_btls_key_is_rsa", mono_btls_key_is_rsa)
+ICALL(BTLS_KEY_5, "mono_btls_key_up_ref", mono_btls_key_up_ref)
+
+ICALL_TYPE(BTLS_OBJECT, "Mono.Btls.MonoBtlsObject", BTLS_OBJECT_1)
+ICALL(BTLS_OBJECT_1, "mono_btls_free", mono_btls_free)
+
+ICALL_TYPE(BTLS_PKCS12, "Mono.Btls.MonoBtlsPkcs12", BTLS_PKCS12_1)
+ICALL(BTLS_PKCS12_1, "mono_btls_pkcs12_add_cert", mono_btls_pkcs12_add_cert)
+ICALL(BTLS_PKCS12_2, "mono_btls_pkcs12_free", mono_btls_pkcs12_free)
+ICALL(BTLS_PKCS12_3, "mono_btls_pkcs12_get_cert", mono_btls_pkcs12_get_cert)
+ICALL(BTLS_PKCS12_4, "mono_btls_pkcs12_get_certs", mono_btls_pkcs12_get_certs)
+ICALL(BTLS_PKCS12_5, "mono_btls_pkcs12_get_count", mono_btls_pkcs12_get_count)
+ICALL(BTLS_PKCS12_6, "mono_btls_pkcs12_get_private_key", mono_btls_pkcs12_get_private_key)
+ICALL(BTLS_PKCS12_7, "mono_btls_pkcs12_has_private_key", mono_btls_pkcs12_has_private_key)
+ICALL(BTLS_PKCS12_8, "mono_btls_pkcs12_import", mono_btls_pkcs12_import)
+ICALL(BTLS_PKCS12_9, "mono_btls_pkcs12_new", mono_btls_pkcs12_new)
+ICALL(BTLS_PKCS12_10, "mono_btls_pkcs12_up_ref", mono_btls_pkcs12_up_ref)
+
+ICALL_TYPE(BTLS_PROVIDER, "Mono.Btls.MonoBtlsProvider", BTLS_PROVIDER_1)
+ICALL(BTLS_PROVIDER_1, "IsSupported", ves_icall_Mono_Btls_Provider_IsSupported)
+
+ICALL_TYPE(BTLS_SSL, "Mono.Btls.MonoBtlsSsl", BTLS_SSL_1)
+ICALL(BTLS_SSL_1, "mono_btls_ssl_accept", mono_btls_ssl_accept)
+ICALL(BTLS_SSL_2, "mono_btls_ssl_add_chain_certificate", mono_btls_ssl_add_chain_certificate)
+ICALL(BTLS_SSL_3, "mono_btls_ssl_close", mono_btls_ssl_close)
+ICALL(BTLS_SSL_4, "mono_btls_ssl_connect", mono_btls_ssl_connect)
+ICALL(BTLS_SSL_5, "mono_btls_ssl_destroy", mono_btls_ssl_destroy)
+ICALL(BTLS_SSL_6, "mono_btls_ssl_get_cipher", mono_btls_ssl_get_cipher)
+ICALL(BTLS_SSL_7, "mono_btls_ssl_get_ciphers", mono_btls_ssl_get_ciphers)
+ICALL(BTLS_SSL_8, "mono_btls_ssl_get_error", mono_btls_ssl_get_error)
+ICALL(BTLS_SSL_9, "mono_btls_ssl_get_peer_certificate", mono_btls_ssl_get_peer_certificate)
+ICALL(BTLS_SSL_10, "mono_btls_ssl_get_version", mono_btls_ssl_get_version)
+ICALL(BTLS_SSL_11, "mono_btls_ssl_handshake", mono_btls_ssl_handshake)
+ICALL(BTLS_SSL_12, "mono_btls_ssl_new", mono_btls_ssl_new)
+ICALL(BTLS_SSL_13, "mono_btls_ssl_print_errors_cb", mono_btls_ssl_print_errors_cb)
+ICALL(BTLS_SSL_14, "mono_btls_ssl_read", mono_btls_ssl_read)
+ICALL(BTLS_SSL_15, "mono_btls_ssl_set_bio", mono_btls_ssl_set_bio)
+ICALL(BTLS_SSL_16, "mono_btls_ssl_set_cipher_list", mono_btls_ssl_set_cipher_list)
+ICALL(BTLS_SSL_17, "mono_btls_ssl_set_max_version", mono_btls_ssl_set_max_version)
+ICALL(BTLS_SSL_18, "mono_btls_ssl_set_min_version", mono_btls_ssl_set_min_version)
+ICALL(BTLS_SSL_19, "mono_btls_ssl_set_server_name", mono_btls_ssl_set_server_name)
+ICALL(BTLS_SSL_20, "mono_btls_ssl_set_verify_param", mono_btls_ssl_set_verify_param)
+ICALL(BTLS_SSL_21, "mono_btls_ssl_use_certificate", mono_btls_ssl_use_certificate)
+ICALL(BTLS_SSL_22, "mono_btls_ssl_use_private_key", mono_btls_ssl_use_private_key)
+ICALL(BTLS_SSL_23, "mono_btls_ssl_write", mono_btls_ssl_write)
+
+ICALL_TYPE(BTLS_SSL_CTX, "Mono.Btls.MonoBtlsSslCtx", BTLS_SSL_CTX_1)
+ICALL(BTLS_SSL_CTX_1, "mono_btls_ssl_ctx_debug_printf", mono_btls_ssl_ctx_debug_printf)
+ICALL(BTLS_SSL_CTX_2, "mono_btls_ssl_ctx_free", mono_btls_ssl_ctx_free)
+ICALL(BTLS_SSL_CTX_3, "mono_btls_ssl_ctx_get_ctx", mono_btls_ssl_ctx_get_ctx)
+ICALL(BTLS_SSL_CTX_4, "mono_btls_ssl_ctx_initialize", mono_btls_ssl_ctx_initialize)
+ICALL(BTLS_SSL_CTX_5, "mono_btls_ssl_ctx_is_cipher_supported", mono_btls_ssl_ctx_is_cipher_supported)
+ICALL(BTLS_SSL_CTX_6, "mono_btls_ssl_ctx_is_debug_enabled", mono_btls_ssl_ctx_is_debug_enabled)
+ICALL(BTLS_SSL_CTX_7, "mono_btls_ssl_ctx_new", mono_btls_ssl_ctx_new)
+ICALL(BTLS_SSL_CTX_8, "mono_btls_ssl_ctx_peek_store", mono_btls_ssl_ctx_peek_store)
+ICALL(BTLS_SSL_CTX_9, "mono_btls_ssl_ctx_set_cert_select_callback", mono_btls_ssl_ctx_set_cert_select_callback)
+ICALL(BTLS_SSL_CTX_10, "mono_btls_ssl_ctx_set_cert_verify_callback", mono_btls_ssl_ctx_set_cert_verify_callback)
+ICALL(BTLS_SSL_CTX_11, "mono_btls_ssl_ctx_set_ciphers", mono_btls_ssl_ctx_set_ciphers)
+ICALL(BTLS_SSL_CTX_12, "mono_btls_ssl_ctx_set_debug_bio", mono_btls_ssl_ctx_set_debug_bio)
+ICALL(BTLS_SSL_CTX_13, "mono_btls_ssl_ctx_set_max_version", mono_btls_ssl_ctx_set_max_version)
+ICALL(BTLS_SSL_CTX_14, "mono_btls_ssl_ctx_set_min_version", mono_btls_ssl_ctx_set_min_version)
+ICALL(BTLS_SSL_CTX_15, "mono_btls_ssl_ctx_set_verify_param", mono_btls_ssl_ctx_set_verify_param)
+ICALL(BTLS_SSL_CTX_16, "mono_btls_ssl_ctx_up_ref", mono_btls_ssl_ctx_up_ref)
+
+ICALL_TYPE(BTLS_X509, "Mono.Btls.MonoBtlsX509", BTLS_X509_1)
+ICALL(BTLS_X509_1, "mono_btls_x509_add_explicit_trust", mono_btls_x509_add_explicit_trust)
+ICALL(BTLS_X509_2, "mono_btls_x509_add_reject_object", mono_btls_x509_add_reject_object)
+ICALL(BTLS_X509_3, "mono_btls_x509_add_trust_object", mono_btls_x509_add_trust_object)
+ICALL(BTLS_X509_4, "mono_btls_x509_cmp", mono_btls_x509_cmp)
+ICALL(BTLS_X509_5, "mono_btls_x509_dup", mono_btls_x509_dup)
+ICALL(BTLS_X509_6, "mono_btls_x509_free", mono_btls_x509_free)
+ICALL(BTLS_X509_7, "mono_btls_x509_from_data", mono_btls_x509_from_data)
+ICALL(BTLS_X509_8, "mono_btls_x509_get_hash", mono_btls_x509_get_hash)
+ICALL(BTLS_X509_9, "mono_btls_x509_get_issuer_name", mono_btls_x509_get_issuer_name)
+ICALL(BTLS_X509_10, "mono_btls_x509_get_issuer_name_string", mono_btls_x509_get_issuer_name_string)
+ICALL(BTLS_X509_11, "mono_btls_x509_get_not_after", mono_btls_x509_get_not_after)
+ICALL(BTLS_X509_12, "mono_btls_x509_get_not_before", mono_btls_x509_get_not_before)
+ICALL(BTLS_X509_13, "mono_btls_x509_get_pubkey", mono_btls_x509_get_pubkey)
+ICALL(BTLS_X509_14, "mono_btls_x509_get_public_key", mono_btls_x509_get_public_key)
+ICALL(BTLS_X509_15, "mono_btls_x509_get_public_key_algorithm", mono_btls_x509_get_public_key_algorithm)
+ICALL(BTLS_X509_16, "mono_btls_x509_get_public_key_asn1", mono_btls_x509_get_public_key_asn1)
+ICALL(BTLS_X509_17, "mono_btls_x509_get_public_key_parameters", mono_btls_x509_get_public_key_parameters)
+ICALL(BTLS_X509_18, "mono_btls_x509_get_raw_data", mono_btls_x509_get_raw_data)
+ICALL(BTLS_X509_19, "mono_btls_x509_get_serial_number", mono_btls_x509_get_serial_number)
+ICALL(BTLS_X509_20, "mono_btls_x509_get_signature_algorithm", mono_btls_x509_get_signature_algorithm)
+ICALL(BTLS_X509_21, "mono_btls_x509_get_subject_key_identifier", mono_btls_x509_get_subject_key_identifier)
+ICALL(BTLS_X509_22, "mono_btls_x509_get_subject_name", mono_btls_x509_get_subject_name)
+ICALL(BTLS_X509_23, "mono_btls_x509_get_subject_name_string", mono_btls_x509_get_subject_name_string)
+ICALL(BTLS_X509_24, "mono_btls_x509_get_version", mono_btls_x509_get_version)
+ICALL(BTLS_X509_25, "mono_btls_x509_print", mono_btls_x509_print)
+ICALL(BTLS_X509_26, "mono_btls_x509_up_ref", mono_btls_x509_up_ref)
+
+ICALL_TYPE(BTLS_X509_CHAIN, "Mono.Btls.MonoBtlsX509Chain", BTLS_X509_CHAIN_1)
+ICALL(BTLS_X509_CHAIN_1, "mono_btls_x509_chain_add_cert", mono_btls_x509_chain_add_cert)
+ICALL(BTLS_X509_CHAIN_2, "mono_btls_x509_chain_free", mono_btls_x509_chain_free)
+ICALL(BTLS_X509_CHAIN_3, "mono_btls_x509_chain_from_certs", mono_btls_x509_chain_from_certs)
+ICALL(BTLS_X509_CHAIN_4, "mono_btls_x509_chain_get_cert", mono_btls_x509_chain_get_cert)
+ICALL(BTLS_X509_CHAIN_5, "mono_btls_x509_chain_get_count", mono_btls_x509_chain_get_count)
+ICALL(BTLS_X509_CHAIN_6, "mono_btls_x509_chain_new", mono_btls_x509_chain_new)
+ICALL(BTLS_X509_CHAIN_7, "mono_btls_x509_chain_peek_certs", mono_btls_x509_chain_peek_certs)
+ICALL(BTLS_X509_CHAIN_8, "mono_btls_x509_chain_up_ref", mono_btls_x509_chain_up_ref)
+
+ICALL_TYPE(BTLS_X509_CRL, "Mono.Btls.MonoBtlsX509Crl", BTLS_X509_CRL_1)
+ICALL(BTLS_X509_CRL_1, "mono_btls_x509_crl_free", mono_btls_x509_crl_free)
+ICALL(BTLS_X509_CRL_2, "mono_btls_x509_crl_from_data", mono_btls_x509_crl_from_data)
+ICALL(BTLS_X509_CRL_3, "mono_btls_x509_crl_get_by_cert", mono_btls_x509_crl_get_by_cert)
+ICALL(BTLS_X509_CRL_4, "mono_btls_x509_crl_get_by_serial", mono_btls_x509_crl_get_by_serial)
+ICALL(BTLS_X509_CRL_5, "mono_btls_x509_crl_get_issuer", mono_btls_x509_crl_get_issuer)
+ICALL(BTLS_X509_CRL_6, "mono_btls_x509_crl_get_last_update", mono_btls_x509_crl_get_last_update)
+ICALL(BTLS_X509_CRL_7, "mono_btls_x509_crl_get_next_update", mono_btls_x509_crl_get_next_update)
+ICALL(BTLS_X509_CRL_8, "mono_btls_x509_crl_get_revoked", mono_btls_x509_crl_get_revoked)
+ICALL(BTLS_X509_CRL_9, "mono_btls_x509_crl_get_revoked_count", mono_btls_x509_crl_get_revoked_count)
+ICALL(BTLS_X509_CRL_10, "mono_btls_x509_crl_get_version", mono_btls_x509_crl_get_version)
+ICALL(BTLS_X509_CRL_11, "mono_btls_x509_crl_ref", mono_btls_x509_crl_ref)
+
+ICALL_TYPE(BTLS_X509_LOOKUP, "Mono.Btls.MonoBtlsX509Lookup", BTLS_X509_LOOKUP_1)
+ICALL(BTLS_X509_LOOKUP_1, "mono_btls_x509_lookup_add_dir", mono_btls_x509_lookup_add_dir)
+ICALL(BTLS_X509_LOOKUP_2, "mono_btls_x509_lookup_add_mono", mono_btls_x509_lookup_add_mono)
+ICALL(BTLS_X509_LOOKUP_3, "mono_btls_x509_lookup_by_fingerprint", mono_btls_x509_lookup_by_fingerprint)
+ICALL(BTLS_X509_LOOKUP_4, "mono_btls_x509_lookup_by_subject", mono_btls_x509_lookup_by_subject)
+ICALL(BTLS_X509_LOOKUP_5, "mono_btls_x509_lookup_free", mono_btls_x509_lookup_free)
+ICALL(BTLS_X509_LOOKUP_6, "mono_btls_x509_lookup_init", mono_btls_x509_lookup_init)
+ICALL(BTLS_X509_LOOKUP_7, "mono_btls_x509_lookup_load_file", mono_btls_x509_lookup_load_file)
+ICALL(BTLS_X509_LOOKUP_8, "mono_btls_x509_lookup_mono_init", mono_btls_x509_lookup_mono_init)
+ICALL(BTLS_X509_LOOKUP_9, "mono_btls_x509_lookup_new", mono_btls_x509_lookup_new)
+ICALL(BTLS_X509_LOOKUP_10, "mono_btls_x509_lookup_peek_lookup", mono_btls_x509_lookup_peek_lookup)
+ICALL(BTLS_X509_LOOKUP_11, "mono_btls_x509_lookup_shutdown", mono_btls_x509_lookup_shutdown)
+ICALL(BTLS_X509_LOOKUP_12, "mono_btls_x509_lookup_up_ref", mono_btls_x509_lookup_up_ref)
+
+ICALL_TYPE(BTLS_X509_LOOKUP_MONO, "Mono.Btls.MonoBtlsX509LookupMono", BTLS_X509_LOOKUP_MONO_1)
+ICALL(BTLS_X509_LOOKUP_MONO_1, "mono_btls_x509_lookup_mono_free", mono_btls_x509_lookup_mono_free)
+ICALL(BTLS_X509_LOOKUP_MONO_2, "mono_btls_x509_lookup_mono_init", mono_btls_x509_lookup_mono_init)
+ICALL(BTLS_X509_LOOKUP_MONO_3, "mono_btls_x509_lookup_mono_new", mono_btls_x509_lookup_mono_new)
+
+ICALL_TYPE(BTLS_X509_NAME, "Mono.Btls.MonoBtlsX509Name", BTLS_X509_NAME_1)
+ICALL(BTLS_X509_NAME_1, "mono_btls_x509_name_copy", mono_btls_x509_name_copy)
+ICALL(BTLS_X509_NAME_2, "mono_btls_x509_name_free", mono_btls_x509_name_free)
+ICALL(BTLS_X509_NAME_3, "mono_btls_x509_name_from_data", mono_btls_x509_name_from_data)
+ICALL(BTLS_X509_NAME_4, "mono_btls_x509_name_from_name", mono_btls_x509_name_from_name)
+ICALL(BTLS_X509_NAME_5, "mono_btls_x509_name_get_entry_count", mono_btls_x509_name_get_entry_count)
+ICALL(BTLS_X509_NAME_6, "mono_btls_x509_name_get_entry_oid", mono_btls_x509_name_get_entry_oid)
+ICALL(BTLS_X509_NAME_7, "mono_btls_x509_name_get_entry_oid_data", mono_btls_x509_name_get_entry_oid_data)
+ICALL(BTLS_X509_NAME_8, "mono_btls_x509_name_get_entry_type", mono_btls_x509_name_get_entry_type)
+ICALL(BTLS_X509_NAME_9, "mono_btls_x509_name_get_entry_value", mono_btls_x509_name_get_entry_value)
+ICALL(BTLS_X509_NAME_10, "mono_btls_x509_name_get_raw_data", mono_btls_x509_name_get_raw_data)
+ICALL(BTLS_X509_NAME_11, "mono_btls_x509_name_hash", mono_btls_x509_name_hash)
+ICALL(BTLS_X509_NAME_12, "mono_btls_x509_name_hash_old", mono_btls_x509_name_hash_old)
+ICALL(BTLS_X509_NAME_13, "mono_btls_x509_name_peek_name", mono_btls_x509_name_peek_name)
+ICALL(BTLS_X509_NAME_14, "mono_btls_x509_name_print_bio", mono_btls_x509_name_print_bio)
+ICALL(BTLS_X509_NAME_15, "mono_btls_x509_name_print_string", mono_btls_x509_name_print_string)
+
+ICALL_TYPE(BTLS_X509_REVOKED, "Mono.Btls.MonoBtlsX509Revoked", BTLS_X509_REVOKED_1)
+ICALL(BTLS_X509_REVOKED_1, "mono_btls_x509_revoked_free", mono_btls_x509_revoked_free)
+ICALL(BTLS_X509_REVOKED_2, "mono_btls_x509_revoked_get_reason", mono_btls_x509_revoked_get_reason)
+ICALL(BTLS_X509_REVOKED_2a, "mono_btls_x509_revoked_get_revocation_date", mono_btls_x509_revoked_get_revocation_date)
+ICALL(BTLS_X509_REVOKED_3, "mono_btls_x509_revoked_get_sequence", mono_btls_x509_revoked_get_sequence)
+ICALL(BTLS_X509_REVOKED_4, "mono_btls_x509_revoked_get_serial_number", mono_btls_x509_revoked_get_serial_number)
+ICALL(BTLS_X509_REVOKED_5, "mono_btls_x509_revoked_new", mono_btls_x509_revoked_new)
+
+ICALL_TYPE(BTLS_X509_STORE, "Mono.Btls.MonoBtlsX509Store", BTLS_X509_STORE_1)
+ICALL(BTLS_X509_STORE_1, "mono_btls_x509_store_add_cert", mono_btls_x509_store_add_cert)
+ICALL(BTLS_X509_STORE_2, "mono_btls_x509_store_free", mono_btls_x509_store_free)
+ICALL(BTLS_X509_STORE_3, "mono_btls_x509_store_from_ctx", mono_btls_x509_store_from_ctx)
+ICALL(BTLS_X509_STORE_4, "mono_btls_x509_store_from_ssl_ctx", mono_btls_x509_store_from_ssl_ctx)
+ICALL(BTLS_X509_STORE_5, "mono_btls_x509_store_get_count", mono_btls_x509_store_get_count)
+ICALL(BTLS_X509_STORE_6, "mono_btls_x509_store_load_locations", mono_btls_x509_store_load_locations)
+ICALL(BTLS_X509_STORE_7, "mono_btls_x509_store_new", mono_btls_x509_store_new)
+ICALL(BTLS_X509_STORE_8, "mono_btls_x509_store_peek_store", mono_btls_x509_store_peek_store)
+ICALL(BTLS_X509_STORE_9, "mono_btls_x509_store_set_default_paths", mono_btls_x509_store_set_default_paths)
+ICALL(BTLS_X509_STORE_10, "mono_btls_x509_store_up_ref", mono_btls_x509_store_up_ref)
+
+ICALL_TYPE(BTLS_X509_STORE_CTX, "Mono.Btls.MonoBtlsX509StoreCtx", BTLS_X509_STORE_CTX_1)
+ICALL(BTLS_X509_STORE_CTX_1, "mono_btls_x509_store_ctx_free", mono_btls_x509_store_ctx_free)
+ICALL(BTLS_X509_STORE_CTX_2, "mono_btls_x509_store_ctx_from_ptr", mono_btls_x509_store_ctx_from_ptr)
+ICALL(BTLS_X509_STORE_CTX_3, "mono_btls_x509_store_ctx_get_by_subject", mono_btls_x509_store_ctx_get_by_subject)
+ICALL(BTLS_X509_STORE_CTX_4, "mono_btls_x509_store_ctx_get_chain", mono_btls_x509_store_ctx_get_chain)
+ICALL(BTLS_X509_STORE_CTX_5, "mono_btls_x509_store_ctx_get_current_cert", mono_btls_x509_store_ctx_get_current_cert)
+ICALL(BTLS_X509_STORE_CTX_6, "mono_btls_x509_store_ctx_get_current_issuer", mono_btls_x509_store_ctx_get_current_issuer)
+ICALL(BTLS_X509_STORE_CTX_7, "mono_btls_x509_store_ctx_get_error", mono_btls_x509_store_ctx_get_error)
+ICALL(BTLS_X509_STORE_CTX_8, "mono_btls_x509_store_ctx_get_error_depth", mono_btls_x509_store_ctx_get_error_depth)
+ICALL(BTLS_X509_STORE_CTX_9, "mono_btls_x509_store_ctx_get_untrusted", mono_btls_x509_store_ctx_get_untrusted)
+ICALL(BTLS_X509_STORE_CTX_10, "mono_btls_x509_store_ctx_get_verify_param", mono_btls_x509_store_ctx_get_verify_param)
+ICALL(BTLS_X509_STORE_CTX_11, "mono_btls_x509_store_ctx_init", mono_btls_x509_store_ctx_init)
+ICALL(BTLS_X509_STORE_CTX_12, "mono_btls_x509_store_ctx_new", mono_btls_x509_store_ctx_new)
+ICALL(BTLS_X509_STORE_CTX_13, "mono_btls_x509_store_ctx_set_param", mono_btls_x509_store_ctx_set_param)
+ICALL(BTLS_X509_STORE_CTX_15, "mono_btls_x509_store_ctx_up_ref", mono_btls_x509_store_ctx_up_ref)
+ICALL(BTLS_X509_STORE_CTX_16, "mono_btls_x509_store_ctx_verify_cert", mono_btls_x509_store_ctx_verify_cert)
+
+ICALL_TYPE(BTLS_X509_VERIFY_PARAM, "Mono.Btls.MonoBtlsX509VerifyParam", BTLS_X509_VERIFY_PARAM_1)
+ICALL(BTLS_X509_VERIFY_PARAM_1, "mono_btls_x509_verify_param_add_host", mono_btls_x509_verify_param_add_host)
+ICALL(BTLS_X509_VERIFY_PARAM_2, "mono_btls_x509_verify_param_can_modify", mono_btls_x509_verify_param_can_modify)
+ICALL(BTLS_X509_VERIFY_PARAM_3, "mono_btls_x509_verify_param_copy", mono_btls_x509_verify_param_copy)
+ICALL(BTLS_X509_VERIFY_PARAM_4, "mono_btls_x509_verify_param_free", mono_btls_x509_verify_param_free)
+ICALL(BTLS_X509_VERIFY_PARAM_5, "mono_btls_x509_verify_param_from_store_ctx", mono_btls_x509_verify_param_from_store_ctx)
+ICALL(BTLS_X509_VERIFY_PARAM_6, "mono_btls_x509_verify_param_get_depth", mono_btls_x509_verify_param_get_depth)
+ICALL(BTLS_X509_VERIFY_PARAM_7, "mono_btls_x509_verify_param_get_flags", mono_btls_x509_verify_param_get_flags)
+ICALL(BTLS_X509_VERIFY_PARAM_8, "mono_btls_x509_verify_param_get_mono_flags", mono_btls_x509_verify_param_get_mono_flags)
+ICALL(BTLS_X509_VERIFY_PARAM_9, "mono_btls_x509_verify_param_get_peername", mono_btls_x509_verify_param_get_peername)
+ICALL(BTLS_X509_VERIFY_PARAM_10, "mono_btls_x509_verify_param_lookup", mono_btls_x509_verify_param_lookup)
+ICALL(BTLS_X509_VERIFY_PARAM_11, "mono_btls_x509_verify_param_new", mono_btls_x509_verify_param_new)
+ICALL(BTLS_X509_VERIFY_PARAM_12, "mono_btls_x509_verify_param_peek_param", mono_btls_x509_verify_param_peek_param)
+ICALL(BTLS_X509_VERIFY_PARAM_13, "mono_btls_x509_verify_param_set_depth", mono_btls_x509_verify_param_set_depth)
+ICALL(BTLS_X509_VERIFY_PARAM_14, "mono_btls_x509_verify_param_set_flags", mono_btls_x509_verify_param_set_flags)
+ICALL(BTLS_X509_VERIFY_PARAM_15, "mono_btls_x509_verify_param_set_host", mono_btls_x509_verify_param_set_host)
+ICALL(BTLS_X509_VERIFY_PARAM_16, "mono_btls_x509_verify_param_set_mono_flags", mono_btls_x509_verify_param_set_mono_flags)
+ICALL(BTLS_X509_VERIFY_PARAM_17, "mono_btls_x509_verify_param_set_name", mono_btls_x509_verify_param_set_name)
+ICALL(BTLS_X509_VERIFY_PARAM_18, "mono_btls_x509_verify_param_set_purpose", mono_btls_x509_verify_param_set_purpose)
+ICALL(BTLS_X509_VERIFY_PARAM_19, "mono_btls_x509_verify_param_set_time", mono_btls_x509_verify_param_set_time)
+#else
+ICALL_TYPE(BTLS_PROVIDER, "Mono.Btls.MonoBtlsProvider", BTLS_PROVIDER_1)
+ICALL(BTLS_PROVIDER_1, "IsSupported", ves_icall_Mono_Btls_Provider_IsSupported)
+#endif
+
 #ifndef DISABLE_COM
 ICALL_TYPE(COMPROX, "Mono.Interop.ComInteropProxy", COMPROX_1)
 ICALL(COMPROX_1, "AddProxy", ves_icall_Mono_Interop_ComInteropProxy_AddProxy)
@@ -544,12 +785,6 @@ ICALL(DYNM_1, "create_dynamic_method", ves_icall_DynamicMethod_create_dynamic_me
 ICALL_TYPE(ENUMB, "System.Reflection.Emit.EnumBuilder", ENUMB_1)
 ICALL(ENUMB_1, "setup_enum_type", ves_icall_EnumBuilder_setup_enum_type)
 
-ICALL_TYPE(GPARB, "System.Reflection.Emit.GenericTypeParameterBuilder", GPARB_1)
-ICALL(GPARB_1, "initialize", ves_icall_GenericTypeParameterBuilder_initialize_generic_parameter)
-
-ICALL_TYPE(METHODB, "System.Reflection.Emit.MethodBuilder", METHODB_1)
-ICALL(METHODB_1, "MakeGenericMethod", ves_icall_MethodBuilder_MakeGenericMethod)
-
 ICALL_TYPE(MODULEB, "System.Reflection.Emit.ModuleBuilder", MODULEB_10)
 ICALL(MODULEB_10, "GetRegisteredToken", ves_icall_ModuleBuilder_GetRegisteredToken)
 ICALL(MODULEB_8, "RegisterToken", ves_icall_ModuleBuilder_RegisterToken)
@@ -565,17 +800,8 @@ ICALL_TYPE(SIGH, "System.Reflection.Emit.SignatureHelper", SIGH_1)
 ICALL(SIGH_1, "get_signature_field", ves_icall_SignatureHelper_get_signature_field)
 ICALL(SIGH_2, "get_signature_local", ves_icall_SignatureHelper_get_signature_local)
 
-#ifndef DISABLE_REFLECTION_EMIT
-ICALL_TYPE(SYMBOLTYPE, "System.Reflection.Emit.SymbolType", SYMBOLTYPE_1)
-ICALL(SYMBOLTYPE_1, "create_unmanaged_type", ves_icall_SymbolType_create_unmanaged_type)
-#endif
-
 ICALL_TYPE(TYPEB, "System.Reflection.Emit.TypeBuilder", TYPEB_1)
-ICALL(TYPEB_1, "create_generic_class", ves_icall_TypeBuilder_create_generic_class)
-ICALL(TYPEB_3, "create_runtime_class", ves_icall_TypeBuilder_create_runtime_class)
-ICALL(TYPEB_4, "get_IsGenericParameter", ves_icall_TypeBuilder_get_IsGenericParameter)
-ICALL(TYPEB_5, "get_event_info", ves_icall_TypeBuilder_get_event_info)
-ICALL(TYPEB_7, "setup_internal_class", ves_icall_TypeBuilder_setup_internal_class)
+ICALL(TYPEB_1, "create_runtime_class", ves_icall_TypeBuilder_create_runtime_class)
 
 ICALL_TYPE(EVENTI, "System.Reflection.EventInfo", EVENTI_1)
 ICALL(EVENTI_1, "internal_from_handle_type", ves_icall_System_Reflection_EventInfo_internal_from_handle_type)
@@ -626,10 +852,6 @@ ICALL(MFIELD_6, "ResolveType", ves_icall_MonoField_ResolveType)
 ICALL(MFIELD_4, "SetValueInternal", ves_icall_MonoField_SetValueInternal)
 ICALL(MFIELD_7, "get_core_clr_security_level", ves_icall_MonoField_get_core_clr_security_level)
 
-ICALL_TYPE(MGENCL, "System.Reflection.MonoGenericClass", MGENCL_5)
-ICALL(MGENCL_5, "initialize", mono_reflection_generic_class_initialize)
-ICALL(MGENCL_6, "register_with_runtime", mono_reflection_register_with_runtime)
-
 ICALL_TYPE(MMETH, "System.Reflection.MonoMethod", MMETH_2)
 ICALL(MMETH_2, "GetGenericArguments", ves_icall_MonoMethod_GetGenericArguments)
 ICALL(MMETH_3, "GetGenericMethodDefinition_impl", ves_icall_MonoMethod_GetGenericMethodDefinition)
index 4e5d773cb73447db0fb8e0f8cc4e80689d21b15b..27bafb33291f7151a889412b11f11102bf7f4883 100644 (file)
 #include <sys/utsname.h>
 #endif
 
+#if HAVE_BTLS
+#include <btls/btls-ssl.h>
+#include <btls/btls-bio.h>
+#include <btls/btls-error.h>
+#include <btls/btls-key.h>
+#include <btls/btls-pkcs12.h>
+#include <btls/btls-x509-crl.h>
+#include <btls/btls-x509-chain.h>
+#include <btls/btls-x509-lookup.h>
+#include <btls/btls-x509-lookup-mono.h>
+#include <btls/btls-x509-name.h>
+#include <btls/btls-x509-revoked.h>
+#include <btls/btls-x509-store-ctx.h>
+#include <btls/btls-x509-verify-param.h>
+#endif
+
 extern MonoString* ves_icall_System_Environment_GetOSVersionString (void);
 
 ICALL_EXPORT MonoReflectionAssembly* ves_icall_System_Reflection_Assembly_GetCallingAssembly (void);
@@ -8077,6 +8093,16 @@ ves_icall_Microsoft_Win32_NativeMethods_SetPriorityClass (gpointer handle, gint3
        return SetPriorityClass (handle, priorityClass);
 }
 
+ICALL_EXPORT MonoBoolean
+ves_icall_Mono_Btls_Provider_IsSupported (void)
+{
+#if HAVE_BTLS
+       return TRUE;
+#else
+       return FALSE;
+#endif
+}
+
 #ifndef DISABLE_ICALL_TABLES
 
 #define ICALL_TYPE(id,name,first)
index fd20aea402f3651fcaa22801629447222f2de0ce..f5cfadbb8faf929ec49a9295ab0f955476660643 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#if defined(HOST_WIN32)
+#include <objbase.h>
+#endif
+
 /* #define DEBUG_RUNTIME_CODE */
 
 #define OPDEF(a,b,c,d,e,f,g,h,i,j) \
index 9d2e569dfd7d4ceb58dfd0ab61019c2faa393d6b..a68897538aec5f910d666a786c38532051f87d5d 100644 (file)
@@ -499,7 +499,6 @@ struct _MonoDynamicImage {
        GHashTable *method_aux_hash;
        GHashTable *vararg_aux_hash;
        MonoGHashTable *generic_def_objects;
-       MonoGHashTable *methodspec;
        /*
         * Maps final token values to the object they describe.
         */
index 0f47c00fa62f299a3e11d4016c37da9c420d1222..aa8bc0259bb91a23d08f559f83d96b51d352aabf 100644 (file)
@@ -111,16 +111,6 @@ mono_object_is_alive (MonoObject* o)
        return TRUE;
 }
 
-void
-mono_gc_enable_events (void)
-{
-}
-
-void
-mono_gc_enable_alloc_events (void)
-{
-}
-
 int
 mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg)
 {
index d643b57206a9edc4194b127fd6496da2e74ec508..b2cdf6a9fe9cb65c3665ab51b725630c161e7d7c 100644 (file)
@@ -1180,12 +1180,16 @@ typedef struct {
        guint32 attrs;
 } MonoReflectionGenericParam;
 
+typedef struct {
+       MonoReflectionType type;
+       MonoReflectionTypeBuilder *tb;
+} MonoReflectionEnumBuilder;
+
 typedef struct _MonoReflectionGenericClass MonoReflectionGenericClass;
 struct _MonoReflectionGenericClass {
        MonoReflectionType type;
        MonoReflectionType *generic_type; /*Can be either a MonoType or a TypeBuilder*/
        MonoArray *type_arguments;
-       guint32 initialized;
 };
 
 typedef struct {
@@ -1282,26 +1286,6 @@ typedef struct {
        MonoArray *modopts;
 } MonoReflectionSigHelper;
 
-typedef struct {
-       MonoObject object;
-       MonoReflectionGenericClass *inst;
-       MonoObject *fb; /*can be either a MonoField or a FieldBuilder*/
-} MonoReflectionFieldOnTypeBuilderInst;
-
-typedef struct {
-       MonoObject object;
-       MonoReflectionGenericClass *inst;
-       MonoObject *cb; /*can be either a MonoCMethod or ConstructorBuilder*/
-} MonoReflectionCtorOnTypeBuilderInst;
-
-typedef struct {
-       MonoObject object;
-       MonoReflectionType *inst;
-       MonoObject *mb; /*can be either a MonoMethod or MethodBuilder*/
-       MonoArray *method_args;
-       MonoReflectionMethodBuilder *generic_method_definition;
-} MonoReflectionMethodOnTypeBuilderInst;
-
 typedef struct {
        MonoObject object;
        MonoBoolean visible;
@@ -1357,12 +1341,6 @@ void          mono_dynamic_image_release_gc_roots (MonoDynamicImage *image);
 
 void        mono_reflection_setup_internal_class  (MonoReflectionTypeBuilder *tb);
 
-MonoReflectionType*
-ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb);
-
-void
-ves_icall_TypeBuilder_setup_internal_class (MonoReflectionTypeBuilder *tb);
-
 void        mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error);
 
 void mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb);
@@ -1785,17 +1763,14 @@ ves_icall_AssemblyBuilder_basic_init (MonoReflectionAssemblyBuilder *assemblyb);
 MonoReflectionModule*
 ves_icall_AssemblyBuilder_InternalAddModule (MonoReflectionAssemblyBuilder *ab, MonoString *fileName);
 
-void
-ves_icall_TypeBuilder_create_generic_class (MonoReflectionTypeBuilder *tb);
-
 MonoArray*
 ves_icall_CustomAttributeBuilder_GetBlob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues);
 
 void
 ves_icall_DynamicMethod_create_dynamic_method (MonoReflectionDynamicMethod *mb);
 
-MonoBoolean
-ves_icall_TypeBuilder_get_IsGenericParameter (MonoReflectionTypeBuilder *tb);
+MonoReflectionType*
+ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb);
 
 void
 ves_icall_EnumBuilder_setup_enum_type (MonoReflectionType *enumtype,
@@ -1810,10 +1785,4 @@ ves_icall_ModuleBuilder_getUSIndex (MonoReflectionModuleBuilder *module, MonoStr
 void
 ves_icall_ModuleBuilder_set_wrappers_type (MonoReflectionModuleBuilder *moduleb, MonoReflectionType *type);
 
-void
-ves_icall_GenericTypeParameterBuilder_initialize_generic_parameter (MonoReflectionGenericParam *gparam);
-
-MonoReflectionMethod*
-ves_icall_MethodBuilder_MakeGenericMethod (MonoReflectionMethod *rmethod, MonoArray *types);
-
 #endif /* __MONO_OBJECT_INTERNALS_H__ */
index 057e858b882fe4d2e135185473d69afa2e795eb1..3ab92326b1b388bfdf002a7bc1074694047887c4 100644 (file)
@@ -5457,7 +5457,7 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *p
 
        *pass_size_in_words = FALSE;
 
-       if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS))
+       if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass))
                return ves_icall_object_new_specific;
 
        if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) {
index fb4cdeca08b8632bf1f746c8ea5bda5b26a1517a..0fd162dd98a86884d77a104587973a79cd5549a0 100644 (file)
@@ -273,7 +273,6 @@ mono_profiler_install_transition (MonoProfileMethodResult callback)
 void 
 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
 {
-       mono_gc_enable_alloc_events ();
        if (!prof_list)
                return;
        prof_list->allocation_cb = callback;
@@ -876,7 +875,6 @@ mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *ext
 void
 mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
 {
-       mono_gc_enable_events ();
        if (!prof_list)
                return;
        prof_list->gc_event = callback;
@@ -970,7 +968,7 @@ mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileG
 
        prof_list->gc_finalize_begin = begin;
        prof_list->gc_finalize_object_begin = begin_obj;
-       prof_list->gc_finalize_object_begin = end_obj;
+       prof_list->gc_finalize_object_end = end_obj;
        prof_list->gc_finalize_end = end;
 }
 
index 0a5ea615a03f73a95bfc4822f98dd4307a265158..b8b5e08da499becfb47ed64e24eba3c2916dfa33 100644 (file)
@@ -53,8 +53,6 @@ static MonoType* mono_reflection_get_type_with_rootimage (MonoImage *rootimage,
 /* Class lazy loading functions */
 static GENERATE_GET_CLASS_WITH_CACHE (mono_assembly, System.Reflection, MonoAssembly)
 static GENERATE_GET_CLASS_WITH_CACHE (mono_module, System.Reflection, MonoModule)
-static GENERATE_GET_CLASS_WITH_CACHE (mono_generic_method, System.Reflection, MonoGenericMethod);
-static GENERATE_GET_CLASS_WITH_CACHE (mono_generic_cmethod, System.Reflection, MonoGenericCMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_method, System.Reflection, MonoMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_cmethod, System.Reflection, MonoCMethod);
 static GENERATE_GET_CLASS_WITH_CACHE (mono_field, System.Reflection, MonoField);
@@ -499,7 +497,7 @@ mono_type_get_object_checked (MonoDomain *domain, MonoType *type, MonoError *err
                if (klass->byval_arg.type == MONO_TYPE_MVAR || klass->byval_arg.type == MONO_TYPE_VAR) {
                        MonoGenericParam *gparam = klass->byval_arg.data.generic_param;
 
-                       if (gparam->owner && gparam->owner->is_method) {
+                       if (gparam->owner && gparam->owner->is_method && !gparam->owner->is_anonymous) {
                                MonoMethod *method = gparam->owner->owner.method;
                                if (method && mono_class_get_generic_type_definition (method->klass)->wastypebuilder)
                                        is_type_done = FALSE;
@@ -575,33 +573,6 @@ mono_method_get_object_checked (MonoDomain *domain, MonoMethod *method, MonoClas
 
        mono_error_init (error);
 
-       if (method->is_inflated) {
-               MonoReflectionGenericMethod *gret;
-
-               if (!refclass)
-                       refclass = method->klass;
-               CHECK_OBJECT (MonoReflectionMethod *, method, refclass);
-               if ((*method->name == '.') && (!strcmp (method->name, ".ctor") || !strcmp (method->name, ".cctor"))) {
-                       klass = mono_class_get_mono_generic_cmethod_class ();
-               } else {
-                       klass = mono_class_get_mono_generic_method_class ();
-               }
-               gret = (MonoReflectionGenericMethod*)mono_object_new_checked (domain, klass, error);
-               if (!mono_error_ok (error))
-                       goto leave;
-               gret->method.method = method;
-
-               MONO_OBJECT_SETREF (gret, method.name, mono_string_new (domain, method->name));
-
-               rt = mono_type_get_object_checked (domain, &refclass->byval_arg, error);
-               if (!mono_error_ok (error))
-                   goto leave;
-
-               MONO_OBJECT_SETREF (gret, method.reftype, rt);
-
-               CACHE_OBJECT (MonoReflectionMethod *, method, (MonoReflectionMethod*)gret, refclass);
-       }
-
        if (!refclass)
                refclass = method->klass;
 
@@ -2149,9 +2120,7 @@ mono_reflection_get_token_checked (MonoObject *obj, MonoError *error)
 
                token = mc->type_token;
        } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
-                  strcmp (klass->name, "MonoMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericCMethod") == 0) {
+                          strcmp (klass->name, "MonoMethod") == 0) {
                MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
                if (m->method->is_inflated) {
                        MonoMethodInflated *inflated = (MonoMethodInflated *) m->method;
@@ -2214,7 +2183,6 @@ MonoType*
 mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error)
 {
        MonoClass *klass;
-       MonoReflectionTypeBuilder *tb = NULL;
        gboolean is_dynamic = FALSE;
        MonoClass *geninst;
 
@@ -2223,25 +2191,13 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
        mono_loader_lock ();
 
        if (mono_is_sre_type_builder (mono_object_class (type))) {
-               tb = (MonoReflectionTypeBuilder *) type;
-
                is_dynamic = TRUE;
        } else if (mono_is_sre_generic_instance (mono_object_class (type))) {
                MonoReflectionGenericClass *rgi = (MonoReflectionGenericClass *) type;
                MonoReflectionType *gtd = rgi->generic_type;
 
-               if (mono_is_sre_type_builder (mono_object_class (gtd))) {
-                       tb = (MonoReflectionTypeBuilder *)gtd;
+               if (mono_is_sre_type_builder (mono_object_class (gtd)))
                        is_dynamic = TRUE;
-               }
-       }
-
-       /* FIXME: fix the CreateGenericParameters protocol to avoid the two stage setup of TypeBuilders */
-       if (tb && tb->generic_container) {
-               if (!mono_reflection_create_generic_class (tb, error)) {
-                       mono_loader_unlock ();
-                       return NULL;
-               }
        }
 
        MonoType *t = mono_reflection_type_get_handle (type, error);
@@ -2257,11 +2213,8 @@ mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc
                return NULL;
        }
 
-       if (klass->wastypebuilder) {
-               tb = (MonoReflectionTypeBuilder *) mono_class_get_ref_info (klass);
-
+       if (klass->wastypebuilder)
                is_dynamic = TRUE;
-       }
 
        mono_loader_unlock ();
 
@@ -2297,13 +2250,9 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr
 
        mono_error_init (error);
 
-       /*FIXME but this no longer should happen*/
-       if (!strcmp (rmethod->object.vtable->klass->name, "MethodBuilder")) {
-               method = mono_reflection_method_builder_to_mono_method ((MonoReflectionMethodBuilder*)rmethod, error);
-               return_val_if_nok (error, NULL);
-       } else {
-               method = rmethod->method;
-       }
+       g_assert (strcmp (rmethod->object.vtable->klass->name, "MethodBuilder"));
+
+       method = rmethod->method;
 
        klass = method->klass;
 
@@ -2350,17 +2299,7 @@ reflection_bind_generic_method_parameters (MonoReflectionMethod *rmethod, MonoAr
                return NULL;
        }
        
-       MonoReflectionMethod *ret = mono_method_get_object_checked (mono_object_domain (rmethod), inflated, NULL, error);
-       return ret;
-}
-
-MonoReflectionMethod*
-ves_icall_MethodBuilder_MakeGenericMethod (MonoReflectionMethod *rmethod, MonoArray *types)
-{
-       MonoError error;
-       MonoReflectionMethod *result = reflection_bind_generic_method_parameters (rmethod, types, &error);
-       mono_error_set_pending_exception (&error);
-       return result;
+       return mono_method_get_object_checked (mono_object_domain (rmethod), inflated, NULL, error);
 }
 
 MonoReflectionMethod*
index 332ed1df8f69815856f3e4af7d43b2167692664b..eee26b706018d4efcd05204190364373da3d096f 100644 (file)
@@ -84,6 +84,7 @@ extern void mono_sgen_init_stw (void);
 
 enum {
        INTERNAL_MEM_EPHEMERON_LINK = INTERNAL_MEM_FIRST_CLIENT,
+       INTERNAL_MEM_MOVED_OBJECT,
        INTERNAL_MEM_MAX
 };
 
index 4b6a5d355ef9e4aeb19226ec6b2ff0d687195017..725a7eccc638d2b2bf8b0c30b57f9f9e27f8d73e 100644 (file)
@@ -16,6 +16,7 @@
 #include "sgen/sgen-client.h"
 #include "sgen/sgen-cardtable.h"
 #include "sgen/sgen-pinning.h"
+#include "sgen/sgen-thread-pool.h"
 #include "metadata/marshal.h"
 #include "metadata/method-builder.h"
 #include "metadata/abi-details.h"
@@ -917,20 +918,12 @@ mono_gc_clear_domain (MonoDomain * domain)
  * Allocation
  */
 
-static gboolean alloc_events = FALSE;
-
-void
-mono_gc_enable_alloc_events (void)
-{
-       alloc_events = TRUE;
-}
-
 void*
 mono_gc_alloc_obj (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -943,7 +936,7 @@ mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj_pinned (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -956,7 +949,7 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size)
 {
        MonoObject *obj = sgen_alloc_obj_mature (vtable, size);
 
-       if (G_UNLIKELY (alloc_events)) {
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) {
                if (obj)
                        mono_profiler_allocation (obj);
        }
@@ -1753,7 +1746,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length)
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&arr->obj);
 
        SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Vector has incorrect size.");
@@ -1801,7 +1794,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&arr->obj);
 
        SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Array has incorrect size.");
@@ -1842,7 +1835,7 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len)
        UNLOCK_GC;
 
  done:
-       if (G_UNLIKELY (alloc_events))
+       if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS))
                mono_profiler_allocation (&str->object);
 
        return str;
@@ -2061,22 +2054,45 @@ sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQu
 static void *moved_objects [MOVED_OBJECTS_NUM];
 static int moved_objects_idx = 0;
 
+static SgenPointerQueue moved_objects_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT);
+
 void
 mono_sgen_register_moved_object (void *obj, void *destination)
 {
-       g_assert (mono_profiler_events & MONO_PROFILE_GC_MOVES);
+       /*
+        * This function can be called from SGen's worker threads. We want to try
+        * and avoid exposing those threads to the profiler API, so queue up move
+        * events and send them later when the main GC thread calls
+        * mono_sgen_gc_event_moves ().
+        *
+        * TODO: Once SGen has multiple worker threads, we need to switch to a
+        * lock-free data structure for the queue as multiple threads will be
+        * adding to it at the same time.
+        */
+       if (sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ())) {
+               sgen_pointer_queue_add (&moved_objects_queue, obj);
+               sgen_pointer_queue_add (&moved_objects_queue, destination);
+       } else {
+               if (moved_objects_idx == MOVED_OBJECTS_NUM) {
+                       mono_profiler_gc_moves (moved_objects, moved_objects_idx);
+                       moved_objects_idx = 0;
+               }
 
-       if (moved_objects_idx == MOVED_OBJECTS_NUM) {
-               mono_profiler_gc_moves (moved_objects, moved_objects_idx);
-               moved_objects_idx = 0;
+               moved_objects [moved_objects_idx++] = obj;
+               moved_objects [moved_objects_idx++] = destination;
        }
-       moved_objects [moved_objects_idx++] = obj;
-       moved_objects [moved_objects_idx++] = destination;
 }
 
 void
 mono_sgen_gc_event_moves (void)
 {
+       while (!sgen_pointer_queue_is_empty (&moved_objects_queue)) {
+               void *dst = sgen_pointer_queue_pop (&moved_objects_queue);
+               void *src = sgen_pointer_queue_pop (&moved_objects_queue);
+
+               mono_sgen_register_moved_object (src, dst);
+       }
+
        if (moved_objects_idx) {
                mono_profiler_gc_moves (moved_objects, moved_objects_idx);
                moved_objects_idx = 0;
@@ -2512,11 +2528,6 @@ mono_gc_get_generation (MonoObject *obj)
        return 1;
 }
 
-void
-mono_gc_enable_events (void)
-{
-}
-
 const char *
 mono_gc_get_gc_name (void)
 {
@@ -2788,6 +2799,7 @@ sgen_client_description_for_internal_mem_type (int type)
 {
        switch (type) {
        case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link";
+       case INTERNAL_MEM_MOVED_OBJECT: return "moved-object";
        default:
                return NULL;
        }
@@ -3002,6 +3014,9 @@ void
 mono_gc_base_cleanup (void)
 {
        sgen_thread_pool_shutdown ();
+
+       // We should have consumed any outstanding moves.
+       g_assert (sgen_pointer_queue_is_empty (&moved_objects_queue));
 }
 
 gboolean
index ef91c85b0ace8172ccd7a7aa23727f40a6fe643d..1d9e50ba93ce86dd692da0586f8e951df4c590de 100644 (file)
@@ -591,7 +591,6 @@ handle_enum:
        return idx;
 }
 
-
 guint32
 mono_dynimage_encode_field_signature (MonoDynamicImage *assembly, MonoReflectionFieldBuilder *fb, MonoError *error)
 {
@@ -605,9 +604,6 @@ mono_dynimage_encode_field_signature (MonoDynamicImage *assembly, MonoReflection
        MonoType *type;
        MonoClass *klass;
 
-       mono_reflection_init_type_builder_generics (fb->type, error);
-       return_val_if_nok (error, 0);
-
        type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
        return_val_if_nok (error, 0);
        klass = mono_class_from_mono_type (type);
@@ -806,32 +802,6 @@ mono_image_typedef_or_ref (MonoDynamicImage *assembly, MonoType *type)
        return mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
 }
 
-guint32
-mono_dynimage_encode_generic_method_definition_sig (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb)
-{
-       SigBuffer buf;
-       int i;
-       guint32 nparams = mono_array_length (mb->generic_params);
-       guint32 idx;
-
-       if (!assembly->save)
-               return 0;
-
-       sigbuffer_init (&buf, 32);
-
-       sigbuffer_add_value (&buf, 0xa);
-       sigbuffer_add_value (&buf, nparams);
-
-       for (i = 0; i < nparams; i++) {
-               sigbuffer_add_value (&buf, MONO_TYPE_MVAR);
-               sigbuffer_add_value (&buf, i);
-       }
-
-       idx = sigbuffer_add_to_blob_cached (assembly, &buf);
-       sigbuffer_free (&buf);
-       return idx;
-}
-
 guint32
 mono_dynimage_encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context)
 {
@@ -858,84 +828,6 @@ mono_dynimage_encode_generic_method_sig (MonoDynamicImage *assembly, MonoGeneric
        return idx;
 }
 
-#ifndef DISABLE_REFLECTION_EMIT
-guint32
-mono_dynimage_encode_generic_typespec (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error)
-{
-       MonoDynamicTable *table;
-       MonoClass *klass;
-       MonoType *type;
-       guint32 *values;
-       guint32 token;
-       SigBuffer buf;
-       int count, i;
-
-       /*
-        * We're creating a TypeSpec for the TypeBuilder of a generic type declaration,
-        * ie. what we'd normally use as the generic type in a TypeSpec signature.
-        * Because of this, we must not insert it into the `typeref' hash table.
-        */
-       type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
-       return_val_if_nok (error, 0);
-       token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->typespec, type));
-       if (token)
-               return token;
-
-       sigbuffer_init (&buf, 32);
-
-       g_assert (tb->generic_params);
-       klass = mono_class_from_mono_type (type);
-
-       if (tb->generic_container) {
-               if (!mono_reflection_create_generic_class (tb, error))
-                       goto fail;
-       }
-
-       sigbuffer_add_value (&buf, MONO_TYPE_GENERICINST);
-       g_assert (klass->generic_container);
-       sigbuffer_add_value (&buf, klass->byval_arg.type);
-       sigbuffer_add_value (&buf, mono_dynimage_encode_typedef_or_ref_full (assembly, &klass->byval_arg, FALSE));
-
-       count = mono_array_length (tb->generic_params);
-       sigbuffer_add_value (&buf, count);
-       for (i = 0; i < count; i++) {
-               MonoReflectionGenericParam *gparam;
-
-               gparam = mono_array_get (tb->generic_params, MonoReflectionGenericParam *, i);
-               MonoType *gparam_type = mono_reflection_type_get_handle ((MonoReflectionType*)gparam, error);
-               if (!is_ok (error))
-                       goto fail;
-
-               encode_type (assembly, gparam_type, &buf);
-       }
-
-       table = &assembly->tables [MONO_TABLE_TYPESPEC];
-
-       if (assembly->save) {
-               token = sigbuffer_add_to_blob_cached (assembly, &buf);
-               alloc_table (table, table->rows + 1);
-               values = table->values + table->next_idx * MONO_TYPESPEC_SIZE;
-               values [MONO_TYPESPEC_SIGNATURE] = token;
-       }
-       sigbuffer_free (&buf);
-
-       token = MONO_TYPEDEFORREF_TYPESPEC | (table->next_idx << MONO_TYPEDEFORREF_BITS);
-       g_hash_table_insert (assembly->typespec, type, GUINT_TO_POINTER(token));
-       table->next_idx ++;
-       return token;
-fail:
-       sigbuffer_free (&buf);
-       return 0;
-}
-#else /*DISABLE_REFLECTION_EMIT*/
-guint32
-mono_dynimage_encode_generic_typespec (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error)
-{
-       g_assert_not_reached ();
-       return 0;
-}
-#endif /*DISABLE_REFLECTION_EMIT*/
-
 #ifndef DISABLE_REFLECTION_EMIT
 guint32
 mono_dynimage_encode_reflection_sighelper (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper, MonoError *error)
index 87d823a22e0f48b55626f6627714f3e55410063a..5f902cd7cc086bf64cd4957f526171ee6ac29aab 100644 (file)
@@ -74,15 +74,6 @@ mono_is_sr_mono_cmethod (MonoClass *klass);
 gboolean
 mono_is_sr_mono_property (MonoClass *klass);
 
-gboolean
-mono_reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error);
-
-MonoMethod*
-mono_reflection_method_builder_to_mono_method (MonoReflectionMethodBuilder *mb, MonoError *error);
-
-MonoMethod*
-mono_reflection_method_on_tb_inst_get_handle (MonoReflectionMethodOnTypeBuilderInst *m, MonoError *error);
-
 gpointer
 mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
 
@@ -98,9 +89,6 @@ mono_reflection_methodbuilder_from_method_builder (ReflectionMethodBuilder *rmb,
 gboolean
 mono_reflection_methodbuilder_from_ctor_builder (ReflectionMethodBuilder *rmb, MonoReflectionCtorBuilder *mb,
                                                 MonoError *error);
-
-void
-mono_reflection_init_type_builder_generics (MonoObject *type, MonoError *error);
                                                            
 guint32
 mono_reflection_resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image);
@@ -129,15 +117,9 @@ guint32
 mono_dynimage_encode_method_builder_signature (MonoDynamicImage *assembly, ReflectionMethodBuilder *mb,
                                               MonoError *error);
 
-guint32
-mono_dynimage_encode_generic_method_definition_sig (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb);
-
 guint32
 mono_dynimage_encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context);
 
-guint32
-mono_dynimage_encode_generic_typespec (MonoDynamicImage *assembly, MonoReflectionTypeBuilder *tb, MonoError *error);
-
 guint32
 mono_dynimage_encode_typedef_or_ref_full (MonoDynamicImage *assembly, MonoType *type, gboolean try_typespec);
 
index ff2f93a767be1a8ef630b34a058a2fa076a48db5..3256f8cb1990d4e3b18a5d2e8e92d668ada6fa08 100644 (file)
@@ -705,7 +705,6 @@ mono_image_get_field_info (MonoReflectionFieldBuilder *fb, MonoDynamicImage *ass
        values [MONO_FIELD_SIGNATURE] = mono_dynimage_encode_field_signature (assembly, fb, error);
        return_if_nok (error);
 
-
        if (fb->offset != -1) {
                table = &assembly->tables [MONO_TABLE_FIELDLAYOUT];
                table->rows ++;
@@ -1691,9 +1690,6 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse
 {
        guint32 code_idx = GPOINTER_TO_UINT (value);
        MonoReflectionILTokenInfo *iltoken;
-       MonoReflectionFieldBuilder *field;
-       MonoReflectionCtorBuilder *ctor;
-       MonoReflectionMethodBuilder *method;
        MonoReflectionTypeBuilder *tb;
        MonoReflectionArrayMethod *am;
        guint32 i, idx = 0;
@@ -1705,8 +1701,7 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse
                switch (target [3]) {
                case MONO_TABLE_FIELD:
                        if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
-                               field = (MonoReflectionFieldBuilder *)iltoken->member;
-                               idx = field->table_idx;
+                               g_assert_not_reached ();
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
                                MonoClassField *f = ((MonoReflectionField*)iltoken->member)->field;
                                idx = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->field_to_table_idx, f));
@@ -1716,11 +1711,9 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse
                        break;
                case MONO_TABLE_METHOD:
                        if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
-                               method = (MonoReflectionMethodBuilder *)iltoken->member;
-                               idx = method->table_idx;
+                               g_assert_not_reached ();
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
-                               ctor = (MonoReflectionCtorBuilder *)iltoken->member;
-                               idx = ctor->table_idx;
+                               g_assert_not_reached ();
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") || 
                                           !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
                                MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
@@ -1730,47 +1723,67 @@ fixup_method (MonoReflectionILGen *ilgen, gpointer value, MonoDynamicImage *asse
                        }
                        break;
                case MONO_TABLE_TYPEDEF:
-                       if (strcmp (iltoken->member->vtable->klass->name, "TypeBuilder"))
+                       if (!strcmp (iltoken->member->vtable->klass->name, "TypeBuilder")) {
+                               g_assert_not_reached ();
+                       } else if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
+                               MonoClass *k = mono_class_from_mono_type (((MonoReflectionType*)iltoken->member)->type);
+                               MonoObject *obj = mono_class_get_ref_info (k);
+                               g_assert (obj);
+                               g_assert (!strcmp (obj->vtable->klass->name, "TypeBuilder"));
+                               tb = (MonoReflectionTypeBuilder*)obj;
+                               idx = tb->table_idx;
+                       } else {
                                g_assert_not_reached ();
-                       tb = (MonoReflectionTypeBuilder *)iltoken->member;
-                       idx = tb->table_idx;
+                       }
                        break;
                case MONO_TABLE_MEMBERREF:
                        if (!strcmp (iltoken->member->vtable->klass->name, "MonoArrayMethod")) {
                                am = (MonoReflectionArrayMethod*)iltoken->member;
                                idx = am->table_idx;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod") ||
-                                  !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod") ||
-                                  !strcmp (iltoken->member->vtable->klass->name, "MonoGenericMethod") ||
-                                  !strcmp (iltoken->member->vtable->klass->name, "MonoGenericCMethod")) {
+                                          !strcmp (iltoken->member->vtable->klass->name, "MonoCMethod")) {
                                MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
                                g_assert (m->klass->generic_class || m->klass->generic_container);
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldBuilder")) {
+                               g_assert_not_reached ();
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MonoField")) {
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder") ||
                                        !strcmp (iltoken->member->vtable->klass->name, "ConstructorBuilder")) {
+                               g_assert_not_reached ();
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "FieldOnTypeBuilderInst")) {
+                               g_assert_not_reached ();
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
+                               g_assert_not_reached ();
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "ConstructorOnTypeBuilderInst")) {
+                               g_assert_not_reached ();
                                continue;
                        } else {
                                g_assert_not_reached ();
                        }
                        break;
                case MONO_TABLE_METHODSPEC:
-                       if (!strcmp (iltoken->member->vtable->klass->name, "MonoGenericMethod")) {
+                       if (!strcmp (iltoken->member->vtable->klass->name, "MonoMethod")) {
                                MonoMethod *m = ((MonoReflectionMethod*)iltoken->member)->method;
                                g_assert (mono_method_signature (m)->generic_param_count);
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodBuilder")) {
+                               g_assert_not_reached ();
                                continue;
                        } else if (!strcmp (iltoken->member->vtable->klass->name, "MethodOnTypeBuilderInst")) {
+                               g_assert_not_reached ();
+                               continue;
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       break;
+               case MONO_TABLE_TYPESPEC:
+                       if (!strcmp (iltoken->member->vtable->klass->name, "RuntimeType")) {
                                continue;
                        } else {
                                g_assert_not_reached ();
index 6e800f3913908264254951d21e1db7c5b7a59402..2bd9121b9ebf7b54489782ddab54ddcd98f01b5d 100644 (file)
 #include "mono/utils/checked-build.h"
 #include "mono/utils/mono-digest.h"
 
-void
-mono_sre_generic_param_table_entry_free (GenericParamTableEntry *entry)
-{
-       mono_gc_deregister_root ((char*) &entry->gparam);
-       g_free (entry);
-}
-
 static GENERATE_GET_CLASS_WITH_CACHE (marshal_as_attribute, System.Runtime.InteropServices, MarshalAsAttribute);
+static GENERATE_GET_CLASS_WITH_CACHE (module_builder, System.Reflection.Emit, ModuleBuilder);
 
 #ifndef DISABLE_REFLECTION_EMIT
 static guint32 mono_image_get_methodref_token (MonoDynamicImage *assembly, MonoMethod *method, gboolean create_typespec);
-static guint32 mono_image_get_methodbuilder_token (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, gboolean create_open_instance, MonoError *error);
-static guint32 mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *cb, MonoError *error);
 static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper, MonoError *error);
 static gboolean ensure_runtime_vtable (MonoClass *klass, MonoError  *error);
-static guint32 mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method, MonoError *error);
 static void reflection_methodbuilder_from_dynamic_method (ReflectionMethodBuilder *rmb, MonoReflectionDynamicMethod *mb);
+static gboolean reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error);
 
 static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
 #endif
@@ -61,17 +53,17 @@ static MonoReflectionType *mono_reflection_type_get_underlying_system_type (Mono
 static gboolean is_sre_array (MonoClass *klass);
 static gboolean is_sre_byref (MonoClass *klass);
 static gboolean is_sre_pointer (MonoClass *klass);
+static gboolean is_sre_generic_instance (MonoClass *klass);
 static gboolean is_sre_type_builder (MonoClass *klass);
 static gboolean is_sre_method_builder (MonoClass *klass);
 static gboolean is_sre_field_builder (MonoClass *klass);
+static gboolean is_sre_gparam_builder (MonoClass *klass);
+static gboolean is_sre_enum_builder (MonoClass *klass);
 static gboolean is_sr_mono_method (MonoClass *klass);
-static gboolean is_sr_mono_generic_method (MonoClass *klass);
-static gboolean is_sr_mono_generic_cmethod (MonoClass *klass);
 static gboolean is_sr_mono_field (MonoClass *klass);
 
 static guint32 mono_image_get_methodspec_token (MonoDynamicImage *assembly, MonoMethod *method);
 static guint32 mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m);
-static MonoMethod * inflate_method (MonoReflectionType *type, MonoObject *obj, MonoError *error);
 
 #define mono_type_array_get_and_resolve(array, index, error) mono_reflection_type_get_handle ((MonoReflectionType*)mono_array_get (array, gpointer, index), error)
 
@@ -363,7 +355,6 @@ mono_save_custom_attrs (MonoImage *image, void *obj, MonoArray *cattrs)
 }
 #endif
 
-
 guint32
 mono_reflection_resolution_scope_from_image (MonoDynamicImage *assembly, MonoImage *image)
 {
@@ -684,52 +675,6 @@ mono_image_get_methodref_token (MonoDynamicImage *assembly, MonoMethod *method,
        return token;
 }
 
-static guint32
-mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method, MonoError *error)
-{
-       guint32 token, parent, sig;
-       ReflectionMethodBuilder rmb;
-       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)method->type;
-       
-       mono_error_init (error);
-       token = GPOINTER_TO_UINT (g_hash_table_lookup (assembly->handleref, method));
-       if (token)
-               return token;
-
-       if (!mono_reflection_methodbuilder_from_method_builder (&rmb, method, error))
-               return 0;
-
-       /*
-        * A methodref signature can't contain an unmanaged calling convention.
-        * Since some flags are encoded as part of call_conv, we need to check against it.
-       */
-       if ((rmb.call_conv & ~0x60) != MONO_CALL_DEFAULT && (rmb.call_conv & ~0x60) != MONO_CALL_VARARG)
-               rmb.call_conv = (rmb.call_conv & 0x60) | MONO_CALL_DEFAULT;
-
-       sig = mono_dynimage_encode_method_builder_signature (assembly, &rmb, error);
-       return_val_if_nok (error, 0);
-
-       if (tb->generic_params) {
-               parent = mono_dynimage_encode_generic_typespec (assembly, tb, error);
-               return_val_if_nok (error, 0);
-       } else {
-               MonoType *t = mono_reflection_type_get_handle ((MonoReflectionType*)rmb.type, error);
-               return_val_if_nok (error, 0);
-
-               parent = mono_image_typedef_or_ref (assembly, t);
-       }
-
-       char *name = mono_string_to_utf8_checked (method->name, error);
-       return_val_if_nok (error, 0);
-
-       token = mono_image_add_memberef_row (assembly, parent, name, sig);
-       g_free (name);
-
-       g_hash_table_insert (assembly->handleref, method, GUINT_TO_POINTER(token));
-
-       return token;
-}
-
 static guint32
 mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 original,
                                     const gchar *name, guint32 sig)
@@ -754,107 +699,6 @@ mono_image_get_varargs_method_token (MonoDynamicImage *assembly, guint32 origina
        return token;
 }
 
-static guint32
-mono_image_get_methodspec_token_for_generic_method_definition (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, MonoError *error)
-{
-       MonoDynamicTable *table;
-       guint32 *values;
-       guint32 token, mtoken = 0;
-
-       mono_error_init (error);
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->methodspec, mb));
-       if (token)
-               return token;
-
-       table = &assembly->tables [MONO_TABLE_METHODSPEC];
-
-       mtoken = mono_image_get_methodref_token_for_methodbuilder (assembly, mb, error);
-       if (!mono_error_ok (error))
-               return 0;
-
-       switch (mono_metadata_token_table (mtoken)) {
-       case MONO_TABLE_MEMBERREF:
-               mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODREF;
-               break;
-       case MONO_TABLE_METHOD:
-               mtoken = (mono_metadata_token_index (mtoken) << MONO_METHODDEFORREF_BITS) | MONO_METHODDEFORREF_METHODDEF;
-               break;
-       default:
-               g_assert_not_reached ();
-       }
-
-       if (assembly->save) {
-               alloc_table (table, table->rows + 1);
-               values = table->values + table->next_idx * MONO_METHODSPEC_SIZE;
-               values [MONO_METHODSPEC_METHOD] = mtoken;
-               values [MONO_METHODSPEC_SIGNATURE] = mono_dynimage_encode_generic_method_definition_sig (assembly, mb);
-       }
-
-       token = MONO_TOKEN_METHOD_SPEC | table->next_idx;
-       table->next_idx ++;
-
-       mono_g_hash_table_insert (assembly->methodspec, mb, GUINT_TO_POINTER(token));
-       return token;
-}
-
-static guint32
-mono_image_get_methodbuilder_token (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *mb, gboolean create_methodspec, MonoError *error)
-{
-       guint32 token;
-
-       mono_error_init (error);
-
-       if (mb->generic_params && create_methodspec) 
-               return mono_image_get_methodspec_token_for_generic_method_definition (assembly, mb, error);
-
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, mb));
-       if (token)
-               return token;
-
-       token = mono_image_get_methodref_token_for_methodbuilder (assembly, mb, error);
-       if (!mono_error_ok (error))
-               return 0;
-       mono_g_hash_table_insert (assembly->handleref_managed, mb, GUINT_TO_POINTER(token));
-       return token;
-}
-
-static guint32
-mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *mb, MonoError *error)
-{
-       guint32 token, parent, sig;
-       ReflectionMethodBuilder rmb;
-       char *name;
-       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mb->type;
-       
-       mono_error_init (error);
-       
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, mb));
-       if (token)
-               return token;
-
-       if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
-               return 0;
-
-       if (tb->generic_params) {
-               parent = mono_dynimage_encode_generic_typespec (assembly, tb, error);
-               return_val_if_nok (error, 0);
-       } else {
-               MonoType * type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
-               return_val_if_nok (error, 0);
-               parent = mono_image_typedef_or_ref (assembly, type);
-       }
-       
-       name = mono_string_to_utf8_checked (rmb.name, error);
-       return_val_if_nok (error, 0);
-       sig = mono_dynimage_encode_method_builder_signature (assembly, &rmb, error);
-       return_val_if_nok (error, 0);
-
-       token = mono_image_add_memberef_row (assembly, parent, name, sig);
-
-       g_free (name);
-       mono_g_hash_table_insert (assembly->handleref_managed, mb, GUINT_TO_POINTER(token));
-       return token;
-}
 #endif
 
 static gboolean
@@ -890,221 +734,6 @@ mono_image_get_fieldref_token (MonoDynamicImage *assembly, MonoObject *f, MonoCl
        return token;
 }
 
-static guint32
-mono_image_get_field_on_inst_token (MonoDynamicImage *assembly, MonoReflectionFieldOnTypeBuilderInst *f, MonoError *error)
-{
-       guint32 token;
-       MonoClass *klass;
-       MonoGenericClass *gclass;
-       MonoType *type;
-       char *name;
-
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, f));
-       if (token)
-               return token;
-       if (is_sre_field_builder (mono_object_class (f->fb))) {
-               MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)f->fb;
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-               gclass = type->data.generic_class;
-               g_assert (gclass->is_dynamic);
-
-               guint32 sig_token = mono_dynimage_encode_field_signature (assembly, fb, error);
-               return_val_if_nok (error, 0);
-               name = mono_string_to_utf8_checked (fb->name, error);
-               return_val_if_nok (error, 0);
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name, sig_token);
-               g_free (name);          
-       } else if (is_sr_mono_field (mono_object_class (f->fb))) {
-               guint32 sig;
-               MonoClassField *field = ((MonoReflectionField *)f->fb)->field;
-
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-
-               sig = mono_dynimage_encode_fieldref_signature (assembly, field->parent->image, field->type);
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, field->name, sig);
-       } else {
-               char *name = mono_type_get_full_name (mono_object_class (f->fb));
-               g_error ("mono_image_get_field_on_inst_token: don't know how to handle %s", name);
-       }
-
-       mono_g_hash_table_insert (assembly->handleref_managed, f, GUINT_TO_POINTER (token));
-       return token;
-}
-
-static guint32
-mono_image_get_ctor_on_inst_token (MonoDynamicImage *assembly, MonoReflectionCtorOnTypeBuilderInst *c, gboolean create_methodspec, MonoError *error)
-{
-       guint32 sig, token;
-       MonoClass *klass;
-       MonoGenericClass *gclass;
-       MonoType *type;
-
-       mono_error_init (error);
-
-       /* A ctor cannot be a generic method, so we can ignore create_methodspec */
-
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, c));
-       if (token)
-               return token;
-
-       if (mono_is_sre_ctor_builder (mono_object_class (c->cb))) {
-               MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder *)c->cb;
-               ReflectionMethodBuilder rmb;
-               char *name;
-
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-
-               gclass = type->data.generic_class;
-               g_assert (gclass->is_dynamic);
-
-               if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, cb, error))
-                       return 0;
-
-               sig = mono_dynimage_encode_method_builder_signature (assembly, &rmb, error);
-               return_val_if_nok (error, 0);
-
-               name = mono_string_to_utf8_checked (rmb.name, error);
-               return_val_if_nok (error, 0);
-
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name, sig);
-               g_free (name);
-       } else if (mono_is_sr_mono_cmethod (mono_object_class (c->cb))) {
-               MonoMethod *mm = ((MonoReflectionMethod *)c->cb)->method;
-
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-
-               sig = mono_dynimage_encode_method_signature (assembly, mono_method_signature (mm));
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, mm->name, sig);
-       } else {
-               char *name = mono_type_get_full_name (mono_object_class (c->cb));
-               g_error ("mono_image_get_method_on_inst_token: don't know how to handle %s", name);
-       }
-
-
-       mono_g_hash_table_insert (assembly->handleref_managed, c, GUINT_TO_POINTER (token));
-       return token;
-}
-
-MonoMethod*
-mono_reflection_method_on_tb_inst_get_handle (MonoReflectionMethodOnTypeBuilderInst *m, MonoError *error)
-{
-       MonoClass *klass;
-       MonoGenericContext tmp_context;
-       MonoType **type_argv;
-       MonoGenericInst *ginst;
-       MonoMethod *method, *inflated;
-       int count, i;
-
-       mono_error_init (error);
-
-       mono_reflection_init_type_builder_generics ((MonoObject*)m->inst, error);
-       return_val_if_nok (error, NULL);
-
-       method = inflate_method (m->inst, (MonoObject*)m->mb, error);
-       return_val_if_nok (error, NULL);
-
-       klass = method->klass;
-
-       if (m->method_args == NULL)
-               return method;
-
-       if (method->is_inflated)
-               method = ((MonoMethodInflated *) method)->declaring;
-
-       count = mono_array_length (m->method_args);
-
-       type_argv = g_new0 (MonoType *, count);
-       for (i = 0; i < count; i++) {
-               MonoReflectionType *garg = (MonoReflectionType *)mono_array_get (m->method_args, gpointer, i);
-               type_argv [i] = mono_reflection_type_get_handle (garg, error);
-               return_val_if_nok (error, NULL);
-       }
-       ginst = mono_metadata_get_generic_inst (count, type_argv);
-       g_free (type_argv);
-
-       tmp_context.class_inst = klass->generic_class ? klass->generic_class->context.class_inst : NULL;
-       tmp_context.method_inst = ginst;
-
-       inflated = mono_class_inflate_generic_method_checked (method, &tmp_context, error);
-       mono_error_assert_ok (error);
-       return inflated;
-}
-
-static guint32
-mono_image_get_method_on_inst_token (MonoDynamicImage *assembly, MonoReflectionMethodOnTypeBuilderInst *m, gboolean create_methodspec, MonoError *error)
-{
-       guint32 sig, token = 0;
-       MonoType *type;
-       MonoClass *klass;
-
-       mono_error_init (error);
-
-       if (m->method_args) {
-               MonoMethod *inflated;
-
-               inflated = mono_reflection_method_on_tb_inst_get_handle (m, error);
-               return_val_if_nok (error, 0);
-
-               if (create_methodspec)
-                       token = mono_image_get_methodspec_token (assembly, inflated);
-               else
-                       token = mono_image_get_inflated_method_token (assembly, inflated);
-               return token;
-       }
-
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, m));
-       if (token)
-               return token;
-
-       if (is_sre_method_builder (mono_object_class (m->mb))) {
-               MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)m->mb;
-               MonoGenericClass *gclass;
-               ReflectionMethodBuilder rmb;
-               char *name;
-
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-               gclass = type->data.generic_class;
-               g_assert (gclass->is_dynamic);
-
-               if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error))
-                       return 0;
-
-               sig = mono_dynimage_encode_method_builder_signature (assembly, &rmb, error);
-               return_val_if_nok (error, 0);
-
-               name = mono_string_to_utf8_checked (rmb.name, error);
-               return_val_if_nok (error, 0);
-
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, name, sig);
-               g_free (name);          
-       } else if (is_sr_mono_method (mono_object_class (m->mb))) {
-               MonoMethod *mm = ((MonoReflectionMethod *)m->mb)->method;
-
-               type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
-               return_val_if_nok (error, 0);
-               klass = mono_class_from_mono_type (type);
-
-               sig = mono_dynimage_encode_method_signature (assembly, mono_method_signature (mm));
-               token = mono_image_get_memberref_token (assembly, &klass->byval_arg, mm->name, sig);
-       } else {
-               char *name = mono_type_get_full_name (mono_object_class (m->mb));
-               g_error ("mono_image_get_method_on_inst_token: don't know how to handle %s", name);
-       }
-
-       mono_g_hash_table_insert (assembly->handleref_managed, m, GUINT_TO_POINTER (token));
-       return token;
-}
-
 static guint32
 method_encode_methodspec (MonoDynamicImage *assembly, MonoMethod *method)
 {
@@ -1191,138 +820,6 @@ mono_image_get_inflated_method_token (MonoDynamicImage *assembly, MonoMethod *m)
        return token;
 }
 
-/*
- * Return a copy of TYPE, adding the custom modifiers in MODREQ and MODOPT.
- */
-static MonoType*
-add_custom_modifiers (MonoDynamicImage *assembly, MonoType *type, MonoArray *modreq, MonoArray *modopt, MonoError *error)
-{
-       int i, count, len, pos;
-       MonoType *t;
-
-       mono_error_init (error);
-
-       count = 0;
-       if (modreq)
-               count += mono_array_length (modreq);
-       if (modopt)
-               count += mono_array_length (modopt);
-
-       if (count == 0)
-               return mono_metadata_type_dup (NULL, type);
-
-       len = MONO_SIZEOF_TYPE + ((gint32)count) * sizeof (MonoCustomMod);
-       t = (MonoType *)g_malloc (len);
-       memcpy (t, type, MONO_SIZEOF_TYPE);
-
-       t->num_mods = count;
-       pos = 0;
-       if (modreq) {
-               for (i = 0; i < mono_array_length (modreq); ++i) {
-                       MonoType *mod = mono_type_array_get_and_resolve (modreq, i, error);
-                       if (!is_ok (error))
-                               goto fail;
-                       t->modifiers [pos].required = 1;
-                       t->modifiers [pos].token = mono_image_typedef_or_ref (assembly, mod);
-                       pos ++;
-               }
-       }
-       if (modopt) {
-               for (i = 0; i < mono_array_length (modopt); ++i) {
-                       MonoType *mod = mono_type_array_get_and_resolve (modopt, i, error);
-                       if (!is_ok (error))
-                               goto fail;
-                       t->modifiers [pos].required = 0;
-                       t->modifiers [pos].token = mono_image_typedef_or_ref (assembly, mod);
-                       pos ++;
-               }
-       }
-
-       return t;
-fail:
-       g_free (t);
-       return NULL;
-}
-
-void
-mono_reflection_init_type_builder_generics (MonoObject *type, MonoError *error)
-{
-       MonoReflectionTypeBuilder *tb;
-
-       mono_error_init (error);
-
-       if (!is_sre_type_builder(mono_object_class (type)))
-               return;
-       tb = (MonoReflectionTypeBuilder *)type;
-
-       if (tb && tb->generic_container)
-               mono_reflection_create_generic_class (tb, error);
-}
-
-static guint32
-mono_image_get_generic_field_token (MonoDynamicImage *assembly, MonoReflectionFieldBuilder *fb, MonoError *error)
-{
-       MonoDynamicTable *table;
-       MonoType *custom = NULL, *type;
-       guint32 *values;
-       guint32 token, pclass, parent, sig;
-       gchar *name;
-
-       mono_error_init (error);
-
-       token = GPOINTER_TO_UINT (mono_g_hash_table_lookup (assembly->handleref_managed, fb));
-       if (token)
-               return token;
-
-       MonoType *typeb = mono_reflection_type_get_handle (fb->typeb, error);
-       return_val_if_nok (error, 0);
-       /* FIXME: is this call necessary? */
-       mono_class_from_mono_type (typeb);
-
-       /*FIXME this is one more layer of ugliness due how types are created.*/
-       mono_reflection_init_type_builder_generics (fb->type, error);
-       return_val_if_nok (error, 0);
-
-       /* fb->type does not include the custom modifiers */
-       /* FIXME: We should do this in one place when a fieldbuilder is created */
-       type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
-       return_val_if_nok (error, 0);
-
-       if (fb->modreq || fb->modopt) {
-               type = custom = add_custom_modifiers (assembly, type, fb->modreq, fb->modopt, error);
-               return_val_if_nok (error, 0);
-       }
-
-       sig = mono_dynimage_encode_fieldref_signature (assembly, NULL, type);
-       g_free (custom);
-
-       parent = mono_dynimage_encode_generic_typespec (assembly, (MonoReflectionTypeBuilder *) fb->typeb, error);
-       return_val_if_nok (error, 0);
-       g_assert ((parent & MONO_TYPEDEFORREF_MASK) == MONO_TYPEDEFORREF_TYPESPEC);
-       
-       pclass = MONO_MEMBERREF_PARENT_TYPESPEC;
-       parent >>= MONO_TYPEDEFORREF_BITS;
-
-       table = &assembly->tables [MONO_TABLE_MEMBERREF];
-
-       name = mono_string_to_utf8_checked (fb->name, error);
-       return_val_if_nok (error, 0);
-
-       if (assembly->save) {
-               alloc_table (table, table->rows + 1);
-               values = table->values + table->next_idx * MONO_MEMBERREF_SIZE;
-               values [MONO_MEMBERREF_CLASS] = pclass | (parent << MONO_MEMBERREF_PARENT_BITS);
-               values [MONO_MEMBERREF_NAME] = string_heap_insert (&assembly->sheap, name);
-               values [MONO_MEMBERREF_SIGNATURE] = sig;
-       }
-
-       token = MONO_TOKEN_MEMBER_REF | table->next_idx;
-       table->next_idx ++;
-       mono_g_hash_table_insert (assembly->handleref_managed, fb, GUINT_TO_POINTER(token));
-       g_free (name);
-       return token;
-}
-
 static guint32 
 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper, MonoError *error)
 {
@@ -1573,6 +1070,10 @@ mono_image_create_method_token (MonoDynamicImage *assembly, MonoObject *obj, Mon
                        if (!is_ok (error)) goto fail;
                }
 
+               // FIXME: This doesn't work, we don't use 'sig' for anything
+               // The token fixup doesn't work either
+               g_assert_not_reached ();
+
                sig_token = mono_dynimage_encode_method_builder_signature (assembly, &rmb, error);
                if (!is_ok (error))
                        goto fail;
@@ -1632,81 +1133,14 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
                return 0;
        }
 
-       if (strcmp (klass->name, "MethodBuilder") == 0) {
-               MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)obj;
-               MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
-
-               if (tb->module->dynamic_image == assembly && !tb->generic_params && !mb->generic_params)
-                       token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
-               else {
-                       token = mono_image_get_methodbuilder_token (assembly, mb, create_open_instance, error);
-                       if (!mono_error_ok (error))
-                               return 0;
-               }
-               /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
-       } else if (strcmp (klass->name, "ConstructorBuilder") == 0) {
-               MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)obj;
-               MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
-
-               if (tb->module->dynamic_image == assembly && !tb->generic_params)
-                       token = mb->table_idx | MONO_TOKEN_METHOD_DEF;
-               else {
-                       token = mono_image_get_ctorbuilder_token (assembly, mb, error);
-                       if (!mono_error_ok (error))
-                               return 0;
-               }
-               /*g_print ("got token 0x%08x for %s\n", token, mono_string_to_utf8 (mb->name));*/
-       } else if (strcmp (klass->name, "FieldBuilder") == 0) {
-               MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)obj;
-               MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)fb->typeb;
-               if (tb->generic_params) {
-                       token = mono_image_get_generic_field_token (assembly, fb, error);
-                       return_val_if_nok (error, 0);
-               } else {
-                       if (tb->module->dynamic_image == assembly) {
-                               token = fb->table_idx | MONO_TOKEN_FIELD_DEF;
-                       } else {
-                               token = mono_image_get_fieldref_token (assembly, (MonoObject*)fb, fb->handle);
-                       }
-               }
-       } else if (strcmp (klass->name, "TypeBuilder") == 0) {
-               MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)obj;
-               if (create_open_instance && tb->generic_params) {
-                       MonoType *type;
-                       mono_reflection_init_type_builder_generics (obj, error);
-                       return_val_if_nok (error, 0);
-                       type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
-                       return_val_if_nok (error, 0);
-                       token = mono_dynimage_encode_typedef_or_ref_full (assembly, type, TRUE);
-                       token = mono_metadata_token_from_dor (token);
-               } else if (tb->module->dynamic_image == assembly) {
-                       token = tb->table_idx | MONO_TOKEN_TYPE_DEF;
-               } else {
-                       MonoType *type;
-                       type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
-                       return_val_if_nok (error, 0);
-                       token = mono_metadata_token_from_dor (mono_image_typedef_or_ref (assembly, type));
-               }
-       } else if (strcmp (klass->name, "RuntimeType") == 0) {
+       if (strcmp (klass->name, "RuntimeType") == 0) {
                MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
                return_val_if_nok (error, 0);
                MonoClass *mc = mono_class_from_mono_type (type);
                token = mono_metadata_token_from_dor (
                        mono_dynimage_encode_typedef_or_ref_full (assembly, type, mc->generic_container == NULL || create_open_instance));
-       } else if (strcmp (klass->name, "GenericTypeParameterBuilder") == 0) {
-               MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
-               return_val_if_nok (error, 0);
-               token = mono_metadata_token_from_dor (
-                       mono_image_typedef_or_ref (assembly, type));
-       } else if (strcmp (klass->name, "MonoGenericClass") == 0) {
-               MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
-               return_val_if_nok (error, 0);
-               token = mono_metadata_token_from_dor (
-                       mono_image_typedef_or_ref (assembly, type));
        } else if (strcmp (klass->name, "MonoCMethod") == 0 ||
-                  strcmp (klass->name, "MonoMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericMethod") == 0 ||
-                  strcmp (klass->name, "MonoGenericCMethod") == 0) {
+                          strcmp (klass->name, "MonoMethod") == 0) {
                MonoReflectionMethod *m = (MonoReflectionMethod *)obj;
                if (m->method->is_inflated) {
                        if (create_open_instance)
@@ -1758,25 +1192,6 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
                return_val_if_nok (error, 0);
                token = mono_metadata_token_from_dor (
                        mono_image_typedef_or_ref (assembly, type));
-       } else if (strcmp (klass->name, "FieldOnTypeBuilderInst") == 0) {
-               MonoReflectionFieldOnTypeBuilderInst *f = (MonoReflectionFieldOnTypeBuilderInst*)obj;
-               token = mono_image_get_field_on_inst_token (assembly, f, error);
-               return_val_if_nok (error, 0);
-       } else if (strcmp (klass->name, "ConstructorOnTypeBuilderInst") == 0) {
-               MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
-               token = mono_image_get_ctor_on_inst_token (assembly, c, create_open_instance, error);
-               if (!mono_error_ok (error))
-                       return 0;
-       } else if (strcmp (klass->name, "MethodOnTypeBuilderInst") == 0) {
-               MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
-               token = mono_image_get_method_on_inst_token (assembly, m, create_open_instance, error);
-               if (!mono_error_ok (error))
-                       return 0;
-       } else if (is_sre_array (klass) || is_sre_byref (klass) || is_sre_pointer (klass)) {
-               MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType *)obj, error);
-               return_val_if_nok (error, 0);
-               token = mono_metadata_token_from_dor (
-                               mono_image_typedef_or_ref (assembly, type));
        } else {
                g_error ("requested token for %s\n", klass->name);
        }
@@ -1996,7 +1411,7 @@ is_sre_pointer (MonoClass *klass)
 static gboolean
 is_sre_generic_instance (MonoClass *klass)
 {
-       check_corlib_type_cached (klass, "System.Reflection", "MonoGenericClass");
+       check_corlib_type_cached (klass, "System.Reflection.Emit", "TypeBuilderInstantiation");
 }
 
 static gboolean
@@ -2023,6 +1438,18 @@ is_sre_field_builder (MonoClass *klass)
        check_corlib_type_cached (klass, "System.Reflection.Emit", "FieldBuilder");
 }
 
+static gboolean
+is_sre_gparam_builder (MonoClass *klass)
+{
+       check_corlib_type_cached (klass, "System.Reflection.Emit", "GenericTypeParameterBuilder");
+}
+
+static gboolean
+is_sre_enum_builder (MonoClass *klass)
+{
+       check_corlib_type_cached (klass, "System.Reflection.Emit", "EnumBuilder");
+}
+
 gboolean
 mono_is_sre_method_on_tb_inst (MonoClass *klass)
 {
@@ -2126,60 +1553,64 @@ mono_reflection_type_get_handle (MonoReflectionType* ref, MonoError *error)
                g_assert (res);
                gclass->type.type = res;
                return res;
-       }
+       } else if (is_sre_gparam_builder (klass)) {
+               MonoReflectionGenericParam *gparam = (MonoReflectionGenericParam *)ref;
+               MonoGenericParamFull *param;
+               MonoImage *image;
+               MonoClass *pklass;
 
-       g_error ("Cannot handle corlib user type %s", mono_type_full_name (&mono_object_class(ref)->byval_arg));
-       return NULL;
-}
+               image = &gparam->tbuilder->module->dynamic_image->image;
 
-void
-ves_icall_SymbolType_create_unmanaged_type (MonoReflectionType *type)
-{
-       MonoError error;
-       mono_reflection_type_get_handle (type, &error);
-       mono_error_set_pending_exception (&error);
-}
+               param = mono_image_new0 (image, MonoGenericParamFull, 1);
 
-static gboolean
-reflection_register_with_runtime (MonoReflectionType *type, MonoError *error)
-{
-       MonoDomain *domain = mono_object_domain ((MonoObject*)type);
-       MonoClass *klass;
+               param->info.name = mono_string_to_utf8_image (image, gparam->name, error);
+               mono_error_assert_ok (error);
+               param->param.num = gparam->index;
 
-       mono_error_init (error);
+               if (gparam->mbuilder) {
+                       if (!gparam->mbuilder->generic_container) {
+                               gparam->mbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (image, sizeof (MonoGenericContainer));
+                               gparam->mbuilder->generic_container->is_method = TRUE;
+                               /*
+                                * Cannot set owner.method, since the MonoMethod is not created yet.
+                                * Set the image field instead, so type_in_image () works.
+                                */
+                               gparam->mbuilder->generic_container->is_anonymous = TRUE;
+                               gparam->mbuilder->generic_container->owner.image = image;
+                       }
+                       param->param.owner = gparam->mbuilder->generic_container;
+               } else if (gparam->tbuilder) {
+                       MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)(gparam->tbuilder), error);
+                       mono_error_assert_ok (error);
+                       MonoClass *owner = mono_class_from_mono_type (type);
+                       g_assert (owner->generic_container);
+                       param->param.owner = owner->generic_container;
+               }
 
-       MonoType *res = mono_reflection_type_get_handle (type, error);
+               pklass = mono_class_from_generic_parameter_internal ((MonoGenericParam *) param);
 
-       if (!res && is_ok (error)) {
-               mono_error_set_argument (error, NULL, "Invalid generic instantiation, one or more arguments are not proper user types");
-       }
-       return_val_if_nok (error, FALSE);
+               gparam->type.type = &pklass->byval_arg;
 
-       klass = mono_class_from_mono_type (res);
+               mono_class_set_ref_info (pklass, gparam);
+               mono_image_append_class_to_reflection_info_set (pklass);
 
-       mono_loader_lock (); /*same locking as mono_type_get_object_checked */
-       mono_domain_lock (domain);
+               return &pklass->byval_arg;
+       } else if (is_sre_enum_builder (klass)) {
+               MonoReflectionEnumBuilder *ebuilder = (MonoReflectionEnumBuilder *)ref;
 
-       if (!image_is_dynamic (klass->image)) {
-               mono_class_setup_supertypes (klass);
-       } else {
-               if (!domain->type_hash)
-                       domain->type_hash = mono_g_hash_table_new_type ((GHashFunc)mono_metadata_type_hash, 
-                                       (GCompareFunc)mono_metadata_type_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection types table");
-               mono_g_hash_table_insert (domain->type_hash, res, type);
-       }
-       mono_domain_unlock (domain);
-       mono_loader_unlock ();
+               return mono_reflection_type_get_handle ((MonoReflectionType*)ebuilder->tb, error);
+       } else if (is_sre_type_builder (klass)) {
+               MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)ref;
 
-       return TRUE;
-}
+               /* This happens when a finished type references an unfinished one. Have to create the minimal type */
+               reflection_setup_internal_class (tb, error);
+               mono_error_assert_ok (error);
+               g_assert (ref->type);
+               return ref->type;
+       }
 
-void
-mono_reflection_register_with_runtime (MonoReflectionType *type)
-{
-       MonoError error;
-       (void) reflection_register_with_runtime (type, &error);
-       mono_error_set_pending_exception (&error);
+       g_error ("Cannot handle corlib user type %s", mono_type_full_name (&mono_object_class(ref)->byval_arg));
+       return NULL;
 }
 
 /**
@@ -2309,12 +1740,6 @@ get_field_name_and_type (MonoObject *field, char **name, MonoType **type, MonoEr
 
 #else /* DISABLE_REFLECTION_EMIT */
 
-void
-mono_reflection_register_with_runtime (MonoReflectionType *type)
-{
-       /* This is empty */
-}
-
 static gboolean
 is_sre_type_builder (MonoClass *klass)
 {
@@ -2345,12 +1770,6 @@ mono_is_sre_ctor_on_tb_inst (MonoClass *klass)
        return FALSE;
 }
 
-void
-mono_reflection_init_type_builder_generics (MonoObject *type, MonoError *error)
-{
-       mono_error_init (error);
-}
-
 #endif /* !DISABLE_REFLECTION_EMIT */
 
 
@@ -2378,22 +1797,10 @@ mono_is_sr_mono_cmethod (MonoClass *klass)
        check_corlib_type_cached (klass, "System.Reflection", "MonoCMethod");
 }
 
-static gboolean
-is_sr_mono_generic_method (MonoClass *klass)
-{
-       check_corlib_type_cached (klass, "System.Reflection", "MonoGenericMethod");
-}
-
-static gboolean
-is_sr_mono_generic_cmethod (MonoClass *klass)
-{
-       check_corlib_type_cached (klass, "System.Reflection", "MonoGenericCMethod");
-}
-
 gboolean
 mono_class_is_reflection_method_or_constructor (MonoClass *klass)
 {
-       return is_sr_mono_method (klass) || mono_is_sr_mono_cmethod (klass) || is_sr_mono_generic_method (klass) || is_sr_mono_generic_cmethod (klass);
+       return is_sr_mono_method (klass) || mono_is_sr_mono_cmethod (klass);
 }
 
 gboolean
@@ -2959,6 +2366,7 @@ reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error
        tb->type.type = &klass->byval_arg;
 
        if (tb->nesting_type) {
+               reflection_setup_internal_class ((MonoReflectionTypeBuilder*)tb->nesting_type, error);
                g_assert (tb->nesting_type->type);
                MonoType *nesting_type = mono_reflection_type_get_handle (tb->nesting_type, error);
                if (!is_ok (error)) goto failure;
@@ -2978,50 +2386,30 @@ failure:
 }
 
 /**
- * ves_icall_TypeBuilder_setup_internal_class:
- * @tb: a TypeBuilder object
- *
- * (icall)
- * Creates a MonoClass that represents the TypeBuilder.
- * This is a trick that lets us simplify a lot of reflection code
- * (and will allow us to support Build and Run assemblies easier).
- *
- */
-void
-ves_icall_TypeBuilder_setup_internal_class (MonoReflectionTypeBuilder *tb)
-{
-       MonoError error;
-       (void) reflection_setup_internal_class (tb, &error);
-       mono_error_set_pending_exception (&error);
-}
-
-/**
- * mono_reflection_create_generic_class:
+ * reflection_create_generic_class:
  * @tb: a TypeBuilder object
  * @error: set on error
  *
  * Creates the generic class after all generic parameters have been added.
  * On success returns TRUE, on failure returns FALSE and sets @error.
- * 
  */
-gboolean
-mono_reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error)
+static gboolean
+reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error)
 {
-
        MonoClass *klass;
        int count, i;
 
        mono_error_init (error);
 
+       reflection_setup_internal_class (tb, error);
+
        klass = mono_class_from_mono_type (tb->type.type);
 
        count = tb->generic_params ? mono_array_length (tb->generic_params) : 0;
 
-       if (klass->generic_container || (count == 0))
+       if (count == 0)
                return TRUE;
 
-       g_assert (tb->generic_container && (tb->generic_container->owner.klass == klass));
-
        klass->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
 
        klass->generic_container->owner.klass = klass;
@@ -3292,14 +2680,14 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass,
 
        if (rmb->generic_params) {
                int count = mono_array_length (rmb->generic_params);
-               MonoGenericContainer *container = rmb->generic_container;
-
-               g_assert (container);
+               MonoGenericContainer *container;
 
+               container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
+               container->is_method = TRUE;
+               container->is_anonymous = FALSE;
                container->type_argc = count;
                container->type_params = image_g_new0 (image, MonoGenericParamFull, count);
                container->owner.method = m;
-               container->is_anonymous = FALSE; // Method is now known, container is no longer anonymous
 
                m->is_generic = TRUE;
                mono_method_set_generic_container (m, container);
@@ -3311,6 +2699,9 @@ reflection_methodbuilder_to_mono_method (MonoClass *klass,
                        mono_error_assert_ok (error);
                        MonoGenericParamFull *param = (MonoGenericParamFull *) gp_type->data.generic_param;
                        container->type_params [i] = *param;
+                       container->type_params [i].param.owner = container;
+
+                       gp->type.type->data.generic_param = (MonoGenericParam*)&container->type_params [i];
                }
 
                /*
@@ -3442,183 +2833,57 @@ ctorbuilder_to_mono_method (MonoClass *klass, MonoReflectionCtorBuilder* mb, Mon
        MonoMethodSignature *sig;
 
        mono_loader_lock ();
-       g_assert (klass->image != NULL);
-       sig = ctor_builder_to_signature (klass->image, mb, error);
-       mono_loader_unlock ();
-       return_val_if_nok (error, NULL);
 
        if (!mono_reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
                return NULL;
 
-       mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig, error);
-       return_val_if_nok (error, NULL);
-       mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);
-
-       /* If we are in a generic class, we might be called multiple times from inflate_method */
-       if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save && !klass->generic_container) {
-               /* ilgen is no longer needed */
-               mb->ilgen = NULL;
-       }
-
-       return mb->mhandle;
-}
-
-static MonoMethod*
-methodbuilder_to_mono_method (MonoClass *klass, MonoReflectionMethodBuilder* mb, MonoError *error)
-{
-       ReflectionMethodBuilder rmb;
-       MonoMethodSignature *sig;
-
-       mono_error_init (error);
-
-       mono_loader_lock ();
        g_assert (klass->image != NULL);
-       sig = method_builder_to_signature (klass->image, mb, error);
+       sig = ctor_builder_to_signature (klass->image, mb, error);
        mono_loader_unlock ();
        return_val_if_nok (error, NULL);
 
-       if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error))
-               return NULL;
-
        mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig, error);
        return_val_if_nok (error, NULL);
        mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);
 
-       /* If we are in a generic class, we might be called multiple times from inflate_method */
-       if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save && !klass->generic_container) {
+       if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save) {
                /* ilgen is no longer needed */
-               mb->ilgen = NULL;
-       }
-       return mb->mhandle;
-}
-#endif
-
-#ifndef DISABLE_REFLECTION_EMIT
-
-static MonoMethod *
-inflate_mono_method (MonoClass *klass, MonoMethod *method, MonoObject *obj)
-{
-       MonoMethodInflated *imethod;
-       MonoGenericContext *context;
-       int i;
-
-       /*
-        * With generic code sharing the klass might not be inflated.
-        * This can happen because classes inflated with their own
-        * type arguments are "normalized" to the uninflated class.
-        */
-       if (!klass->generic_class)
-               return method;
-
-       context = mono_class_get_context (klass);
-
-       if (klass->method.count && klass->methods) {
-               /* Find the already created inflated method */
-               for (i = 0; i < klass->method.count; ++i) {
-                       g_assert (klass->methods [i]->is_inflated);
-                       if (((MonoMethodInflated*)klass->methods [i])->declaring == method)
-                               break;
-               }
-               g_assert (i < klass->method.count);
-               imethod = (MonoMethodInflated*)klass->methods [i];
-       } else {
-               MonoError error;
-               imethod = (MonoMethodInflated *) mono_class_inflate_generic_method_full_checked (method, klass, context, &error);
-               mono_error_assert_ok (&error);
-       }
-
-       if (method->is_generic && image_is_dynamic (method->klass->image)) {
-               MonoDynamicImage *image = (MonoDynamicImage*)method->klass->image;
-
-               mono_image_lock ((MonoImage*)image);
-               mono_g_hash_table_insert (image->generic_def_objects, imethod, obj);
-               mono_image_unlock ((MonoImage*)image);
-       }
-       return (MonoMethod *) imethod;
-}
-
-static MonoMethod *
-inflate_method (MonoReflectionType *type, MonoObject *obj, MonoError *error)
-{
-       MonoMethod *method;
-       MonoClass *gklass;
-
-       mono_error_init (error);
-
-       MonoClass *type_class = mono_object_class (type);
-
-       if (is_sre_generic_instance (type_class)) {
-               MonoReflectionGenericClass *mgc = (MonoReflectionGenericClass*)type;
-               MonoType *generic_type = mono_reflection_type_get_handle ((MonoReflectionType*)mgc->generic_type, error);
-               return_val_if_nok (error, NULL);
-               gklass = mono_class_from_mono_type (generic_type);
-       } else if (is_sre_type_builder (type_class)) {
-               MonoType *t = mono_reflection_type_get_handle (type, error);
-               return_val_if_nok (error, NULL);
-               gklass = mono_class_from_mono_type (t);
-       } else if (type->type) {
-               gklass = mono_class_from_mono_type (type->type);
-               gklass = mono_class_get_generic_type_definition (gklass);
-       } else {
-               g_error ("Can't handle type %s", mono_type_get_full_name (mono_object_class (type)));
-       }
-
-       if (!strcmp (obj->vtable->klass->name, "MethodBuilder"))
-               if (((MonoReflectionMethodBuilder*)obj)->mhandle)
-                       method = ((MonoReflectionMethodBuilder*)obj)->mhandle;
-               else {
-                       method = methodbuilder_to_mono_method (gklass, (MonoReflectionMethodBuilder *) obj, error);
-                       if (!method)
-                               return NULL;
-               }
-       else if (!strcmp (obj->vtable->klass->name, "ConstructorBuilder")) {
-               method = ctorbuilder_to_mono_method (gklass, (MonoReflectionCtorBuilder *) obj, error);
-               if (!method)
-                       return NULL;
-       } else if (!strcmp (obj->vtable->klass->name, "MonoMethod") || !strcmp (obj->vtable->klass->name, "MonoCMethod"))
-               method = ((MonoReflectionMethod *) obj)->method;
-       else {
-               method = NULL; /* prevent compiler warning */
-               g_error ("can't handle type %s", obj->vtable->klass->name);
+               mb->ilgen = NULL;
        }
 
-       MonoType *t = mono_reflection_type_get_handle (type, error);
-       return_val_if_nok (error, NULL);
-       return inflate_mono_method (mono_class_from_mono_type (t), method, obj);
+       return mb->mhandle;
 }
 
-static void
-reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoError *error)
+static MonoMethod*
+methodbuilder_to_mono_method (MonoClass *klass, MonoReflectionMethodBuilder* mb, MonoError *error)
 {
-       MonoGenericClass *gclass;
-       MonoClass *klass, *gklass;
-       MonoType *gtype;
+       ReflectionMethodBuilder rmb;
+       MonoMethodSignature *sig;
 
        mono_error_init (error);
 
-       gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type, error);
-       return_if_nok (error);
-       klass = mono_class_from_mono_type (gtype);
-       g_assert (gtype->type == MONO_TYPE_GENERICINST);
-       gclass = gtype->data.generic_class;
+       mono_loader_lock ();
 
-       if (!gclass->is_dynamic)
-               return;
+       if (!mono_reflection_methodbuilder_from_method_builder (&rmb, mb, error))
+               return NULL;
+
+       g_assert (klass->image != NULL);
+       sig = method_builder_to_signature (klass->image, mb, error);
+       mono_loader_unlock ();
+       return_val_if_nok (error, NULL);
 
-       gklass = gclass->container_class;
-       mono_class_init (gklass);
+       mb->mhandle = reflection_methodbuilder_to_mono_method (klass, &rmb, sig, error);
+       return_val_if_nok (error, NULL);
+       mono_save_custom_attrs (klass->image, mb->mhandle, mb->cattrs);
 
-       /* Mark this as needing synchronization with its generic container */
-       gclass->need_sync = TRUE;
+       if (!((MonoDynamicImage*)(MonoDynamicImage*)klass->image)->save)
+               /* ilgen is no longer needed */
+               mb->ilgen = NULL;
+       return mb->mhandle;
 }
+#endif
 
-void
-mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
-{
-       MonoError error;
-       reflection_generic_class_initialize (type, &error);
-       mono_error_set_pending_exception (&error);
-}
+#ifndef DISABLE_REFLECTION_EMIT
 
 /**
  * fix_partial_generic_class:
@@ -3825,7 +3090,7 @@ mono_reflection_method_get_handle (MonoObject *method, MonoError *error)
 {
        mono_error_init (error);
        MonoClass *klass = mono_object_class (method);
-       if (is_sr_mono_method (klass) || is_sr_mono_generic_method (klass)) {
+       if (is_sr_mono_method (klass)) {
                MonoReflectionMethod *sr_method = (MonoReflectionMethod*)method;
                return sr_method->method;
        }
@@ -3834,26 +3099,11 @@ mono_reflection_method_get_handle (MonoObject *method, MonoError *error)
                return mb->mhandle;
        }
        if (mono_is_sre_method_on_tb_inst (klass)) {
-               MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)method;
-               MonoMethod *result;
-               /*FIXME move this to a proper method and unify with resolve_object*/
-               if (m->method_args) {
-                       result = mono_reflection_method_on_tb_inst_get_handle (m, error);
-               } else {
-                       MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
-                       return_val_if_nok (error, NULL);
-                       MonoClass *inflated_klass = mono_class_from_mono_type (type);
-                       MonoMethod *mono_method;
+               MonoClass *handle_class;
 
-                       if (is_sre_method_builder (mono_object_class (m->mb)))
-                               mono_method = ((MonoReflectionMethodBuilder *)m->mb)->mhandle;
-                       else if (is_sr_mono_method (mono_object_class (m->mb)))
-                               mono_method = ((MonoReflectionMethod *)m->mb)->method;
-                       else
-                               g_error ("resolve_object:: can't handle a MTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (m->mb)));
+               MonoMethod *result =  mono_reflection_resolve_object (NULL, method, &handle_class, NULL, error);
+               return_val_if_nok (error, NULL);
 
-                       result = inflate_mono_method (inflated_klass, mono_method, (MonoObject*)m->mb);
-               }
                return result;
        }
 
@@ -4060,68 +3310,6 @@ typebuilder_setup_properties (MonoClass *klass, MonoError *error)
        }
 }
 
-static MonoReflectionEvent *
-reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb, MonoError *error)
-{
-       mono_error_init (error);
-
-       MonoEvent *event = g_new0 (MonoEvent, 1);
-       MonoClass *klass;
-
-       MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
-       if (!is_ok (error)) {
-               g_free (event);
-               return NULL;
-       }
-       klass = mono_class_from_mono_type (type);
-
-       event->parent = klass;
-       event->attrs = eb->attrs;
-       event->name = mono_string_to_utf8_checked (eb->name, error);
-       if (!is_ok (error)) {
-               g_free (event);
-               return NULL;
-       }
-       if (eb->add_method)
-               event->add = eb->add_method->mhandle;
-       if (eb->remove_method)
-               event->remove = eb->remove_method->mhandle;
-       if (eb->raise_method)
-               event->raise = eb->raise_method->mhandle;
-
-#ifndef MONO_SMALL_CONFIG
-       if (eb->other_methods) {
-               int j;
-               event->other = g_new0 (MonoMethod*, mono_array_length (eb->other_methods) + 1);
-               for (j = 0; j < mono_array_length (eb->other_methods); ++j) {
-                       MonoReflectionMethodBuilder *mb = 
-                               mono_array_get (eb->other_methods,
-                                               MonoReflectionMethodBuilder*, j);
-                       event->other [j] = mb->mhandle;
-               }
-       }
-#endif
-
-       MonoReflectionEvent *ev_obj = mono_event_get_object_checked (mono_object_domain (tb), klass, event, error);
-       if (!is_ok (error)) {
-#ifndef MONO_SMALL_CONFIG
-               g_free (event->other);
-#endif
-               g_free (event);
-               return NULL;
-       }
-       return ev_obj;
-}
-
-MonoReflectionEvent *
-ves_icall_TypeBuilder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
-{
-       MonoError error;
-       MonoReflectionEvent *result = reflection_event_builder_get_event_info (tb, eb, &error);
-       mono_error_set_pending_exception (&error);
-       return result;
-}
-
 static void
 typebuilder_setup_events (MonoClass *klass, MonoError *error)
 {
@@ -4215,6 +3403,9 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb)
 
        mono_error_init (&error);
 
+       reflection_create_generic_class (tb, &error);
+       mono_error_assert_ok (&error);
+
        domain = mono_object_domain (tb);
        klass = mono_class_from_mono_type (tb->type.type);
 
@@ -4248,22 +3439,6 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb)
        mono_class_setup_supertypes (klass);
        mono_class_setup_mono_type (klass);
 
-#if 0
-       if (!((MonoDynamicImage*)klass->image)->run) {
-               if (klass->generic_container) {
-                       /* FIXME: The code below can't handle generic classes */
-                       klass->wastypebuilder = TRUE;
-                       mono_loader_unlock ();
-                       mono_domain_unlock (domain);
-
-                       res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
-                       mono_error_set_pending_exception (&error);
-
-                       return res;
-               }
-       }
-#endif
-
        /* enums are done right away */
        if (!klass->enumtype)
                if (!ensure_runtime_vtable (klass, &error))
@@ -4273,6 +3448,12 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb)
                for (i = 0; i < mono_array_length (tb->subtypes); ++i) {
                        MonoReflectionTypeBuilder *subtb = mono_array_get (tb->subtypes, MonoReflectionTypeBuilder*, i);
                        mono_class_alloc_ext (klass);
+
+                       if (!subtb->type.type) {
+                               reflection_setup_internal_class (subtb, &error);
+                               mono_error_assert_ok (&error);
+                       }
+
                        MonoType *subtype = mono_reflection_type_get_handle ((MonoReflectionType*)subtb, &error);
                        if (!is_ok (&error)) goto failure;
                        klass->ext->nested_classes = g_list_prepend_image (klass->image, klass->ext->nested_classes, mono_class_from_mono_type (subtype));
@@ -4355,69 +3536,6 @@ failure_unlocked:
        return NULL;
 }
 
-static gboolean
-reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam, MonoError *error)
-{
-       MonoGenericParamFull *param;
-       MonoImage *image;
-       MonoClass *pklass;
-
-       mono_error_init (error);
-
-       image = &gparam->tbuilder->module->dynamic_image->image;
-
-       param = mono_image_new0 (image, MonoGenericParamFull, 1);
-
-       param->info.name = mono_string_to_utf8_image (image, gparam->name, error);
-       mono_error_assert_ok (error);
-       param->param.num = gparam->index;
-
-       if (gparam->mbuilder) {
-               if (!gparam->mbuilder->generic_container) {
-                       MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->mbuilder->type, error);
-                       return_val_if_nok (error, FALSE);
-
-                       MonoClass *klass = mono_class_from_mono_type (tb);
-                       gparam->mbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
-                       gparam->mbuilder->generic_container->is_method = TRUE;
-                       /* 
-                        * Cannot set owner.method, since the MonoMethod is not created yet.
-                        * Set the image field instead, so type_in_image () works.
-                        */
-                       gparam->mbuilder->generic_container->is_anonymous = TRUE;
-                       gparam->mbuilder->generic_container->owner.image = klass->image;
-               }
-               param->param.owner = gparam->mbuilder->generic_container;
-       } else if (gparam->tbuilder) {
-               if (!gparam->tbuilder->generic_container) {
-                       MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder, error);
-                       return_val_if_nok (error, FALSE);
-                       MonoClass *klass = mono_class_from_mono_type (tb);
-                       gparam->tbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
-                       gparam->tbuilder->generic_container->owner.klass = klass;
-               }
-               param->param.owner = gparam->tbuilder->generic_container;
-       }
-
-       pklass = mono_class_from_generic_parameter_internal ((MonoGenericParam *) param);
-
-       gparam->type.type = &pklass->byval_arg;
-
-       mono_class_set_ref_info (pklass, gparam);
-       mono_image_append_class_to_reflection_info_set (pklass);
-
-       return TRUE;
-}
-
-void
-ves_icall_GenericTypeParameterBuilder_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
-{
-       MonoError error;
-       (void) reflection_initialize_generic_parameter (gparam, &error);
-       mono_error_set_pending_exception (&error);
-}
-
-
 typedef struct {
        MonoMethod *handle;
        MonoDomain *domain;
@@ -4646,16 +3764,17 @@ ensure_complete_type (MonoClass *klass, MonoError *error)
 gpointer
 mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
 {
+       MonoClass *oklass = obj->vtable->klass;
        gpointer result = NULL;
 
        mono_error_init (error);
 
-       if (strcmp (obj->vtable->klass->name, "String") == 0) {
+       if (strcmp (oklass->name, "String") == 0) {
                result = mono_string_intern_checked ((MonoString*)obj, error);
                return_val_if_nok (error, NULL);
                *handle_class = mono_defaults.string_class;
                g_assert (result);
-       } else if (strcmp (obj->vtable->klass->name, "RuntimeType") == 0) {
+       } else if (strcmp (oklass->name, "RuntimeType") == 0) {
                MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
                return_val_if_nok (error, NULL);
                MonoClass *mc = mono_class_from_mono_type (type);
@@ -4675,10 +3794,8 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
                }
                *handle_class = mono_defaults.typehandle_class;
                g_assert (result);
-       } else if (strcmp (obj->vtable->klass->name, "MonoMethod") == 0 ||
-                  strcmp (obj->vtable->klass->name, "MonoCMethod") == 0 ||
-                  strcmp (obj->vtable->klass->name, "MonoGenericCMethod") == 0 ||
-                  strcmp (obj->vtable->klass->name, "MonoGenericMethod") == 0) {
+       } else if (strcmp (oklass->name, "MonoMethod") == 0 ||
+                          strcmp (oklass->name, "MonoCMethod") == 0) {
                result = ((MonoReflectionMethod*)obj)->method;
                if (context) {
                        result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
@@ -4686,48 +3803,7 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
                }
                *handle_class = mono_defaults.methodhandle_class;
                g_assert (result);
-       } else if (strcmp (obj->vtable->klass->name, "MethodBuilder") == 0) {
-               MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder*)obj;
-               result = mb->mhandle;
-               if (!result) {
-                       /* Type is not yet created */
-                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
-
-                       mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
-                       return_val_if_nok (error, NULL);
-
-                       /*
-                        * Hopefully this has been filled in by calling CreateType() on the
-                        * TypeBuilder.
-                        */
-                       /*
-                        * TODO: This won't work if the application finishes another 
-                        * TypeBuilder instance instead of this one.
-                        */
-                       result = mb->mhandle;
-               }
-               if (context) {
-                       result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
-                       mono_error_assert_ok (error);
-               }
-               *handle_class = mono_defaults.methodhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "ConstructorBuilder") == 0) {
-               MonoReflectionCtorBuilder *cb = (MonoReflectionCtorBuilder*)obj;
-
-               result = cb->mhandle;
-               if (!result) {
-                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)cb->type;
-
-                       mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
-                       return_val_if_nok (error, NULL);
-                       result = cb->mhandle;
-               }
-               if (context) {
-                       result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
-                       mono_error_assert_ok (error);
-               }
-               *handle_class = mono_defaults.methodhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "MonoField") == 0) {
+       } else if (strcmp (oklass->name, "MonoField") == 0) {
                MonoClassField *field = ((MonoReflectionField*)obj)->field;
 
                ensure_complete_type (field->parent, error);
@@ -4752,31 +3828,7 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
                }
                *handle_class = mono_defaults.fieldhandle_class;
                g_assert (result);
-       } else if (strcmp (obj->vtable->klass->name, "FieldBuilder") == 0) {
-               MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder*)obj;
-               result = fb->handle;
-
-               if (!result) {
-                       MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)fb->typeb;
-
-                       mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
-                       return_val_if_nok (error, NULL);
-                       result = fb->handle;
-               }
-
-               if (fb->handle && fb->handle->parent->generic_container) {
-                       MonoClass *klass = fb->handle->parent;
-                       MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, context, error);
-                       return_val_if_nok (error, NULL);
-
-                       MonoClass *inflated = mono_class_from_mono_type (type);
-
-                       result = mono_class_get_field_from_name (inflated, mono_field_get_name (fb->handle));
-                       g_assert (result);
-                       mono_metadata_free_type (type);
-               }
-               *handle_class = mono_defaults.fieldhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "TypeBuilder") == 0) {
+       } else if (strcmp (oklass->name, "TypeBuilder") == 0) {
                MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
                MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
                return_val_if_nok (error, NULL);
@@ -4794,7 +3846,7 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
                        g_assert (result);
                }
                *handle_class = mono_defaults.typehandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "SignatureHelper") == 0) {
+       } else if (strcmp (oklass->name, "SignatureHelper") == 0) {
                MonoReflectionSigHelper *helper = (MonoReflectionSigHelper*)obj;
                MonoMethodSignature *sig;
                int nargs, i;
@@ -4830,112 +3882,13 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
 
                result = sig;
                *handle_class = NULL;
-       } else if (strcmp (obj->vtable->klass->name, "DynamicMethod") == 0) {
+       } else if (strcmp (oklass->name, "DynamicMethod") == 0) {
                MonoReflectionDynamicMethod *method = (MonoReflectionDynamicMethod*)obj;
                /* Already created by the managed code */
                g_assert (method->mhandle);
                result = method->mhandle;
                *handle_class = mono_defaults.methodhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "GenericTypeParameterBuilder") == 0) {
-               MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
-               return_val_if_nok (error, NULL);
-               type = mono_class_inflate_generic_type_checked (type, context, error);
-               return_val_if_nok (error, NULL);
-
-               result = mono_class_from_mono_type (type);
-               *handle_class = mono_defaults.typehandle_class;
-               g_assert (result);
-               mono_metadata_free_type (type);
-       } else if (strcmp (obj->vtable->klass->name, "MonoGenericClass") == 0) {
-               MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
-               return_val_if_nok (error, NULL);
-               type = mono_class_inflate_generic_type_checked (type, context, error);
-               return_val_if_nok (error, NULL);
-
-               result = mono_class_from_mono_type (type);
-               *handle_class = mono_defaults.typehandle_class;
-               g_assert (result);
-               mono_metadata_free_type (type);
-       } else if (strcmp (obj->vtable->klass->name, "FieldOnTypeBuilderInst") == 0) {
-               MonoReflectionFieldOnTypeBuilderInst *f = (MonoReflectionFieldOnTypeBuilderInst*)obj;
-               MonoClass *inflated;
-               MonoType *type;
-               MonoClassField *field;
-
-               if (is_sre_field_builder (mono_object_class (f->fb)))
-                       field = ((MonoReflectionFieldBuilder*)f->fb)->handle;
-               else if (is_sr_mono_field (mono_object_class (f->fb)))
-                       field = ((MonoReflectionField*)f->fb)->field;
-               else
-                       g_error ("resolve_object:: can't handle a FTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (f->fb)));
-
-               MonoType *finst = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, error);
-               return_val_if_nok (error, NULL);
-               type = mono_class_inflate_generic_type_checked (finst, context, error);
-               return_val_if_nok (error, NULL);
-
-               inflated = mono_class_from_mono_type (type);
-
-               result = field = mono_class_get_field_from_name (inflated, mono_field_get_name (field));
-               ensure_complete_type (field->parent, error);
-               if (!is_ok (error)) {
-                       mono_metadata_free_type (type);
-                       return NULL;
-               }
-
-               g_assert (result);
-               mono_metadata_free_type (type);
-               *handle_class = mono_defaults.fieldhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "ConstructorOnTypeBuilderInst") == 0) {
-               MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
-               MonoType *cinst = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, error);
-               return_val_if_nok (error, NULL);
-               MonoType *type = mono_class_inflate_generic_type_checked (cinst, context, error);
-               return_val_if_nok (error, NULL);
-
-               MonoClass *inflated_klass = mono_class_from_mono_type (type);
-               MonoMethod *method;
-
-               if (mono_is_sre_ctor_builder (mono_object_class (c->cb)))
-                       method = ((MonoReflectionCtorBuilder *)c->cb)->mhandle;
-               else if (mono_is_sr_mono_cmethod (mono_object_class (c->cb)))
-                       method = ((MonoReflectionMethod *)c->cb)->method;
-               else
-                       g_error ("resolve_object:: can't handle a CTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (c->cb)));
-
-               result = inflate_mono_method (inflated_klass, method, (MonoObject*)c->cb);
-               *handle_class = mono_defaults.methodhandle_class;
-               mono_metadata_free_type (type);
-       } else if (strcmp (obj->vtable->klass->name, "MethodOnTypeBuilderInst") == 0) {
-               MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
-               if (m->method_args) {
-                       result = mono_reflection_method_on_tb_inst_get_handle (m, error);
-                       return_val_if_nok (error, NULL);
-                       if (context) {
-                               result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
-                               mono_error_assert_ok (error);
-                       }
-               } else {
-                       MonoType *minst = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
-                       return_val_if_nok (error, NULL);
-                       MonoType *type = mono_class_inflate_generic_type_checked (minst, context, error);
-                       return_val_if_nok (error, NULL);
-
-                       MonoClass *inflated_klass = mono_class_from_mono_type (type);
-                       MonoMethod *method;
-
-                       if (is_sre_method_builder (mono_object_class (m->mb)))
-                               method = ((MonoReflectionMethodBuilder *)m->mb)->mhandle;
-                       else if (is_sr_mono_method (mono_object_class (m->mb)))
-                               method = ((MonoReflectionMethod *)m->mb)->method;
-                       else
-                               g_error ("resolve_object:: can't handle a MTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (m->mb)));
-
-                       result = inflate_mono_method (inflated_klass, method, (MonoObject*)m->mb);
-                       mono_metadata_free_type (type);
-               }
-               *handle_class = mono_defaults.methodhandle_class;
-       } else if (strcmp (obj->vtable->klass->name, "MonoArrayMethod") == 0) {
+       } else if (strcmp (oklass->name, "MonoArrayMethod") == 0) {
                MonoReflectionArrayMethod *m = (MonoReflectionArrayMethod*)obj;
                MonoType *mtype;
                MonoClass *klass;
@@ -4964,23 +3917,30 @@ mono_reflection_resolve_object (MonoImage *image, MonoObject *obj, MonoClass **h
 
                result = method;
                *handle_class = mono_defaults.methodhandle_class;
-       } else if (is_sre_array (mono_object_get_class(obj)) ||
-                               is_sre_byref (mono_object_get_class(obj)) ||
-                               is_sre_pointer (mono_object_get_class(obj))) {
-               MonoReflectionType *ref_type = (MonoReflectionType *)obj;
-               MonoType *type = mono_reflection_type_get_handle (ref_type, error);
-               return_val_if_nok (error, NULL);
-
-               if (context) {
-                       MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, error);
-                       return_val_if_nok (error, NULL);
-
-                       result = mono_class_from_mono_type (inflated);
-                       mono_metadata_free_type (inflated);
-               } else {
-                       result = mono_class_from_mono_type (type);
+       } else if (is_sre_method_builder (oklass) ||
+                          mono_is_sre_ctor_builder (oklass) ||
+                          is_sre_field_builder (oklass) ||
+                          is_sre_gparam_builder (oklass) ||
+                          is_sre_generic_instance (oklass) ||
+                          is_sre_array (oklass) ||
+                          is_sre_byref (oklass) ||
+                          is_sre_pointer (oklass) ||
+                          !strcmp (oklass->name, "FieldOnTypeBuilderInst") ||
+                          !strcmp (oklass->name, "MethodOnTypeBuilderInst") ||
+                          !strcmp (oklass->name, "ConstructorOnTypeBuilderInst")) {
+               static MonoMethod *resolve_method;
+               if (!resolve_method) {
+                       MonoMethod *m = mono_class_get_method_from_name_flags (mono_class_get_module_builder_class (), "RuntimeResolve", 1, 0);
+                       g_assert (m);
+                       mono_memory_barrier ();
+                       resolve_method = m;
                }
-               *handle_class = mono_defaults.typehandle_class;
+               void *args [16];
+               args [0] = obj;
+               obj = mono_runtime_invoke_checked (resolve_method, NULL, args, error);
+               mono_error_assert_ok (error);
+               g_assert (obj);
+               return mono_reflection_resolve_object (image, obj, handle_class, context, error);
        } else {
                g_print ("%s\n", obj->vtable->klass->name);
                g_assert_not_reached ();
@@ -4997,19 +3957,6 @@ mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObj
        return NULL;
 }
 
-void
-ves_icall_TypeBuilder_setup_internal_class (MonoReflectionTypeBuilder *tb)
-{
-       g_assert_not_reached ();
-}
-
-gboolean
-mono_reflection_create_generic_class (MonoReflectionTypeBuilder *tb, MonoError *error)
-{
-       g_assert_not_reached ();
-       return FALSE;
-}
-
 void
 mono_reflection_dynimage_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
 {
@@ -5044,12 +3991,6 @@ mono_image_create_token (MonoDynamicImage *assembly, MonoObject *obj,
        return 0;
 }
 
-void
-mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
-{
-       g_assert_not_reached ();
-}
-
 void
 mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error)
 {
@@ -5058,13 +3999,6 @@ mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides
        *num_overrides = 0;
 }
 
-MonoReflectionEvent *
-ves_icall_TypeBuilder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
-{
-       g_assert_not_reached ();
-       return NULL;
-}
-
 MonoReflectionType*
 ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb)
 {
@@ -5072,12 +4006,6 @@ ves_icall_TypeBuilder_create_runtime_class (MonoReflectionTypeBuilder *tb)
        return NULL;
 }
 
-void
-ves_icall_GenericTypeParameterBuilder_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
-{
-       g_assert_not_reached ();
-}
-
 void 
 ves_icall_DynamicMethod_create_dynamic_method (MonoReflectionDynamicMethod *mb)
 {
@@ -5094,27 +4022,12 @@ mono_reflection_type_get_handle (MonoReflectionType* ref, MonoError *error)
 
 #endif /* DISABLE_REFLECTION_EMIT */
 
-#ifndef DISABLE_REFLECTION_EMIT
-MonoMethod*
-mono_reflection_method_builder_to_mono_method (MonoReflectionMethodBuilder *mb, MonoError *error)
-{
-       MonoType *tb;
-       MonoClass *klass;
-
-       tb = mono_reflection_type_get_handle ((MonoReflectionType*)mb->type, error);
-       return_val_if_nok (error, NULL);
-       klass = mono_class_from_mono_type (tb);
-
-       return methodbuilder_to_mono_method (klass, mb, error);
-}
-#else /* DISABLE_REFLECTION_EMIT */
-MonoMethod*
-mono_reflection_method_builder_to_mono_method (MonoReflectionMethodBuilder *mb, MonoError *error)
+void
+mono_sre_generic_param_table_entry_free (GenericParamTableEntry *entry)
 {
-       g_assert_not_reached ();
-       return NULL;
+       mono_gc_deregister_root ((char*) &entry->gparam);
+       g_free (entry);
 }
-#endif /* DISABLE_REFLECTION_EMIT */
 
 gint32
 ves_icall_ModuleBuilder_getToken (MonoReflectionModuleBuilder *mb, MonoObject *obj, gboolean create_open_instance)
@@ -5175,21 +4088,6 @@ ves_icall_ModuleBuilder_GetRegisteredToken (MonoReflectionModuleBuilder *mb, gui
        return obj;
 }
 
-/**
- * ves_icall_TypeBuilder_create_generic_class:
- * @tb: a TypeBuilder object
- *
- * (icall)
- * Creates the generic class after all generic parameters have been added.
- */
-void
-ves_icall_TypeBuilder_create_generic_class (MonoReflectionTypeBuilder *tb)
-{
-       MonoError error;
-       (void) mono_reflection_create_generic_class (tb, &error);
-       mono_error_set_pending_exception (&error);
-}
-
 #ifndef DISABLE_REFLECTION_EMIT
 MonoArray*
 ves_icall_CustomAttributeBuilder_GetBlob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
@@ -5207,12 +4105,6 @@ ves_icall_AssemblyBuilder_basic_init (MonoReflectionAssemblyBuilder *assemblyb)
        mono_reflection_dynimage_basic_init (assemblyb);
 }
 
-MonoBoolean
-ves_icall_TypeBuilder_get_IsGenericParameter (MonoReflectionTypeBuilder *tb)
-{
-       return mono_type_is_generic_parameter (tb->type.type);
-}
-
 void
 ves_icall_EnumBuilder_setup_enum_type (MonoReflectionType *enumtype,
                                                                           MonoReflectionType *t)
index 61c69e0ba92819f02eb87b6e18e6021cecbc63fd..0b8aa7c4fb9a8f3a81632bd188c153adab92f204 100644 (file)
 #include <signal.h>
 #endif
 
+#if defined(HOST_WIN32)
+#include <objbase.h>
+#endif
+
 #if defined(PLATFORM_ANDROID) && !defined(TARGET_ARM64) && !defined(TARGET_AMD64)
 #define USE_TKILL_ON_ANDROID 1
 #endif
@@ -4917,7 +4921,7 @@ mono_threads_join_threads (void)
                        if (thread != pthread_self ()) {
                                MONO_ENTER_GC_SAFE;
                                /* This shouldn't block */
-                               pthread_join (thread, NULL);
+                               mono_native_thread_join (thread);
                                MONO_EXIT_GC_SAFE;
                        }
                } else {
@@ -4953,7 +4957,7 @@ mono_thread_join (gpointer tid)
                return;
        thread = (pthread_t)tid;
        MONO_ENTER_GC_SAFE;
-       pthread_join (thread, NULL);
+       mono_native_thread_join (thread);
        MONO_EXIT_GC_SAFE;
 #endif
 }
@@ -5121,6 +5125,7 @@ mono_thread_try_resume_interruption (void)
        return mono_thread_resume_interruption ();
 }
 
+#if 0
 /* Returns TRUE if the current thread is ready to be interrupted. */
 gboolean
 mono_threads_is_ready_to_be_interrupted (void)
@@ -5142,6 +5147,7 @@ mono_threads_is_ready_to_be_interrupted (void)
        UNLOCK_THREAD (thread);
        return TRUE;
 }
+#endif
 
 void
 mono_thread_internal_describe (MonoInternalThread *internal, GString *text)
index 6149ca75fa0996be2da5c08a5ed076fd8685a539..8d73080631e424bf475d8bab179cde569b069fa9 100644 (file)
@@ -149,7 +149,7 @@ static void
 bundle_save_library_initialize ()
 {
        bundle_save_library_initialized = 1;
-       char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX");
+       char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", NULL);
        bundled_dylibrary_directory = g_mkdtemp (path);
        g_free (path);
        if (bundled_dylibrary_directory == NULL)
@@ -161,19 +161,23 @@ static void
 save_library (int fd, uint64_t offset, uint64_t size, const char *destfname)
 {
        MonoDl *lib;
-       char *file, *buffer, *err;
+       char *file, *buffer, *err, *internal_path;
        if (!bundle_save_library_initialized)
                bundle_save_library_initialize ();
        
-       file = g_build_filename (bundled_dylibrary_directory, destfname);
+       file = g_build_filename (bundled_dylibrary_directory, destfname, NULL);
        buffer = load_from_region (fd, offset, size);
        g_file_set_contents (file, buffer, size, NULL);
+
        lib = mono_dl_open (file, MONO_DL_LAZY, &err);
-       if (err != NULL){
-               fprintf (stderr, "Error loading shared library: %s\n", file);
+       if (lib == NULL){
+               fprintf (stderr, "Error loading shared library: %s %s\n", file, err);
                exit (1);
        }
-       mono_loader_register_module (destfname, lib);
+       // Register the name with "." as this is how it will be found when embedded
+       internal_path = g_build_filename (".", destfname, NULL);
+       mono_loader_register_module (internal_path, lib);
+       g_free (internal_path);
        bundle_library_paths = g_slist_append (bundle_library_paths, file);
        
        g_free (buffer);
index b0d7a0709db70da65da166e78c821cdd66b50743..bdd3149c25bf25581ed0449fa8630a8eec6f02b0 100644 (file)
@@ -335,14 +335,8 @@ MONO_SIG_HANDLER_FUNC (static, profiler_signal_handler)
 
        /* See the comment in mono_runtime_shutdown_stat_profiler (). */
        if (mono_native_thread_id_get () == sampling_thread) {
-#ifdef HAVE_CLOCK_NANOSLEEP
-               if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS) {
-                       InterlockedIncrement (&profiler_interrupt_signals_received);
-                       return;
-               }
-#endif
-
-               g_error ("%s: Unexpected profiler signal received by the sampler thread", __func__);
+               InterlockedIncrement (&profiler_interrupt_signals_received);
+               return;
        }
 
        InterlockedIncrement (&profiler_signals_received);
@@ -761,7 +755,7 @@ mono_runtime_shutdown_stat_profiler (void)
 {
        InterlockedWrite (&sampling_thread_running, 0);
 
-#ifdef HAVE_CLOCK_NANOSLEEP
+#ifndef PLATFORM_MACOSX
        /*
         * There is a slight problem when we're using CLOCK_PROCESS_CPUTIME_ID: If
         * we're shutting down and there's largely no activity in the process other
@@ -774,28 +768,22 @@ mono_runtime_shutdown_stat_profiler (void)
         * sampling_thread_running upon an interrupt and return immediately if it's
         * zero. profiler_signal_handler () has a special case to ignore the signal
         * for the sampler thread.
-        *
-        * We do not need to do this on platforms where we use a regular sleep
-        * based on a monotonic clock. The sleep will return in a reasonable amount
-        * of time in those cases.
         */
-       if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS) {
-               MonoThreadInfo *info;
-
-               // Did it shut down already?
-               if ((info = mono_thread_info_lookup (sampling_thread))) {
-                       while (!InterlockedRead (&sampling_thread_exiting)) {
-                               mono_threads_pthread_kill (info, profiler_signal);
-                               mono_thread_info_usleep (10 * 1000 /* 10ms */);
-                       }
+       MonoThreadInfo *info;
 
-                       // Make sure info can be freed.
-                       mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
+       // Did it shut down already?
+       if ((info = mono_thread_info_lookup (sampling_thread))) {
+               while (!InterlockedRead (&sampling_thread_exiting)) {
+                       mono_threads_pthread_kill (info, profiler_signal);
+                       mono_thread_info_usleep (10 * 1000 /* 10ms */);
                }
+
+               // Make sure info can be freed.
+               mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1);
        }
 #endif
 
-       pthread_join (sampling_thread, NULL);
+       mono_native_thread_join (sampling_thread);
 
        /*
         * We can't safely remove the signal handler because we have no guarantee
index 3d7eb62e4004b07a10c4644c3086e9eedf21b66a..4f6c4acb204fc26e059d4c7c08d3e4c6315c8938 100644 (file)
@@ -73,10 +73,10 @@ libmono_profiler_iomap_la_LDFLAGS = $(prof_ldflags)
 libmono_profiler_iomap_static_la_SOURCES = mono-profiler-iomap.c
 libmono_profiler_iomap_static_la_LDFLAGS = -static
 
-libmono_profiler_log_la_SOURCES = proflog.c
+libmono_profiler_log_la_SOURCES = mono-profiler-log.c
 libmono_profiler_log_la_LIBADD = $(monodir)/mono/mini/$(LIBMONO_LA) $(GLIB_LIBS) $(Z_LIBS)
 libmono_profiler_log_la_LDFLAGS = $(prof_ldflags)
-libmono_profiler_log_static_la_SOURCES = proflog.c
+libmono_profiler_log_static_la_SOURCES = mono-profiler-log.c
 libmono_profiler_log_static_la_LDFLAGS = -static
 
 if HAVE_VTUNE
@@ -88,7 +88,7 @@ libmono_profiler_vtune_static_la_SOURCES = mono-profiler-vtune.c
 libmono_profiler_vtune_static_la_LDFLAGS = -static
 endif
 
-mprof_report_SOURCES = decode.c
+mprof_report_SOURCES = mprof-report.c
 mprof_report_LDADD = $(Z_LIBS) $(GLIB_LIBS) $(LIBICONV)
 
 PLOG_TESTS_SRC=test-alloc.cs test-busy.cs test-monitor.cs test-excleave.cs \
@@ -110,6 +110,7 @@ testlog: $(PLOG_TESTS)
 
 check-local: $(check_targets)
 
-EXTRA_DIST=utils.c utils.h proflog.h \
-       $(PLOG_TESTS_SRC) ptestrunner.pl \
+EXTRA_DIST=mono-profiler-log.h \
+       $(PLOG_TESTS_SRC) \
+       ptestrunner.pl \
        $(suppression_DATA)
diff --git a/mono/profiler/decode.c b/mono/profiler/decode.c
deleted file mode 100644 (file)
index 3381504..0000000
+++ /dev/null
@@ -1,4258 +0,0 @@
-/*
- * decode.c: mprof-report program source: decode and analyze the log profiler data
- *
- * Authors:
- *   Paolo Molaro (lupus@ximian.com)
- *   Alex Rønne Petersen (alexrp@xamarin.com)
- *
- * Copyright 2010 Novell, Inc (http://www.novell.com)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-/*
- * The Coverage XML output schema
- * <coverage>
- *   <assembly/>
- *   <class/>
- *   <method>
- *     <statement/>
- *   </method>
- * </coverage>
- *
- * Elements:
- *   <coverage> - The root element of the documentation. It can contain any number of
- *                <assembly>, <class> or <method> elements.
- *                Attributes:
- *                   - version: The version number for the file format - (eg: "0.3")
- *   <assembly> - Contains data about assemblies. Has no child elements
- *                Attributes:
- *                   - name: The name of the assembly - (eg: "System.Xml")
- *                   - guid: The GUID of the assembly
- *                   - filename: The filename of the assembly
- *                   - method-count: The number of methods in the assembly
- *                   - full: The number of fully covered methods
- *                   - partial: The number of partially covered methods
- *   <class> - Contains data about classes. Has no child elements
- *             Attributes:
- *                - name: The name of the class
- *                - method-count: The number of methods in the class
- *                - full: The number of fully covered methods
- *                - partial: The number of partially covered methods
- *   <method> - Contains data about methods. Can contain any number of <statement> elements
- *              Attributes:
- *                 - assembly: The name of the parent assembly
- *                 - class: The name of the parent class
- *                 - name: The name of the method, with all it's parameters
- *                 - filename: The name of the source file containing this method
- *                 - token
- *   <statement> - Contains data about IL statements. Has no child elements
- *                 Attributes:
- *                    - offset: The offset of the statement in the IL code after the previous
- *                              statement's offset
- *                    - counter: 1 if the line was covered, 0 if it was not
- *                    - line: The line number in the parent method's file
- *                    - column: The column on the line
- */
-#include <config.h>
-#include "utils.c"
-#include "proflog.h"
-#include <string.h>
-#include <assert.h>
-#include <stdio.h>
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
-#include <malloc.h>
-#endif
-#include <unistd.h>
-#include <stdlib.h>
-#if defined (HAVE_SYS_ZLIB)
-#include <zlib.h>
-#endif
-#include <glib.h>
-#include <mono/metadata/profiler.h>
-#include <mono/metadata/object.h>
-#include <mono/metadata/debug-helpers.h>
-#include <mono/utils/mono-counters.h>
-
-#define HASH_SIZE 9371
-#define SMALL_HASH_SIZE 31
-
-#if defined(__native_client__) || defined(__native_client_codegen__)
-volatile int __nacl_thread_suspension_needed = 0;
-void __nacl_suspend_thread_if_needed() {}
-#endif
-
-static int debug = 0;
-static int collect_traces = 0;
-static int show_traces = 0;
-static int trace_max = 6;
-static int verbose = 0;
-static uintptr_t *tracked_objects = 0;
-static int num_tracked_objects = 0;
-static uintptr_t thread_filter = 0;
-static uint64_t find_size = 0;
-static const char* find_name = NULL;
-static uint64_t time_from = 0;
-static uint64_t time_to = 0xffffffffffffffffULL;
-static int use_time_filter = 0;
-static uint64_t startup_time = 0;
-static FILE* outfile = NULL;
-static FILE* coverage_outfile = NULL;
-
-static int32_t
-read_int16 (unsigned char *p)
-{
-       int32_t value = *p++;
-       value |= (*p++) << 8;
-       return value;
-}
-
-static int32_t
-read_int32 (unsigned char *p)
-{
-       int32_t value = *p++;
-       value |= (*p++) << 8;
-       value |= (*p++) << 16;
-       value |= (uint32_t)(*p++) << 24;
-       return value;
-}
-
-static int64_t
-read_int64 (unsigned char *p)
-{
-       uint64_t value = *p++;
-       value |= (*p++) << 8;
-       value |= (*p++) << 16;
-       value |= (uint64_t)(*p++) << 24;
-       value |= (uint64_t)(*p++) << 32;
-       value |= (uint64_t)(*p++) << 40;
-       value |= (uint64_t)(*p++) << 48;
-       value |= (uint64_t)(*p++) << 54;
-       return value;
-}
-
-static char*
-pstrdup (const char *s)
-{
-       int len = strlen (s) + 1;
-       char *p = (char *)malloc (len);
-       memcpy (p, s, len);
-       return p;
-}
-
-typedef struct _CounterValue CounterValue;
-struct _CounterValue {
-       uint64_t timestamp;
-       unsigned char *buffer;
-       CounterValue *next;
-};
-
-typedef struct _Counter Counter;
-struct _Counter {
-       int index;
-       const char *section;
-       const char *name;
-       int type;
-       int unit;
-       int variance;
-       CounterValue *values;
-       CounterValue *values_last;
-};
-
-typedef struct _CounterList CounterList;
-struct _CounterList {
-       Counter *counter;
-       CounterList *next;
-};
-
-typedef struct _CounterSection CounterSection;
-struct _CounterSection {
-       const char *value;
-       CounterList *counters;
-       CounterList *counters_last;
-       CounterSection *next;
-};
-
-typedef struct _CounterTimestamp CounterTimestamp;
-struct _CounterTimestamp {
-       uint64_t value;
-       CounterSection *sections;
-       CounterSection *sections_last;
-       CounterTimestamp *next;
-};
-
-static CounterList *counters = NULL;
-static CounterSection *counters_sections = NULL;
-static CounterTimestamp *counters_timestamps = NULL;
-
-enum {
-       COUNTERS_SORT_TIME,
-       COUNTERS_SORT_CATEGORY
-};
-
-static int counters_sort_mode = COUNTERS_SORT_TIME;
-
-static void
-add_counter_to_section (Counter *counter)
-{
-       CounterSection *csection, *s;
-       CounterList *clist;
-
-       clist = (CounterList *)calloc (1, sizeof (CounterList));
-       clist->counter = counter;
-
-       for (csection = counters_sections; csection; csection = csection->next) {
-               if (strcmp (csection->value, counter->section) == 0) {
-                       /* If section exist */
-                       if (!csection->counters)
-                               csection->counters = clist;
-                       else
-                               csection->counters_last->next = clist;
-                       csection->counters_last = clist;
-                       return;
-               }
-       }
-
-       /* If section does not exist */
-       csection = (CounterSection *)calloc (1, sizeof (CounterSection));
-       csection->value = counter->section;
-       csection->counters = clist;
-       csection->counters_last = clist;
-
-       if (!counters_sections) {
-               counters_sections = csection;
-       } else {
-               s = counters_sections;
-               while (s->next)
-                       s = s->next;
-               s->next = csection;
-       }
-}
-
-static void
-add_counter (const char *section, const char *name, int type, int unit, int variance, int index)
-{
-       CounterList *list, *l;
-       Counter *counter;
-
-       for (list = counters; list; list = list->next)
-               if (list->counter->index == index)
-                       return;
-
-       counter = (Counter *)calloc (1, sizeof (Counter));
-       counter->section = section;
-       counter->name = name;
-       counter->type = type;
-       counter->unit = unit;
-       counter->variance = variance;
-       counter->index = index;
-
-       list = (CounterList *)calloc (1, sizeof (CounterList));
-       list->counter = counter;
-
-       if (!counters) {
-               counters = list;
-       } else {
-               l = counters;
-               while (l->next)
-                       l = l->next;
-               l->next = list;
-       }
-
-       if (counters_sort_mode == COUNTERS_SORT_CATEGORY || !verbose)
-               add_counter_to_section (counter);
-}
-
-static void
-add_counter_to_timestamp (uint64_t timestamp, Counter *counter)
-{
-       CounterTimestamp *ctimestamp, *t;
-       CounterSection *csection;
-       CounterList *clist;
-
-       clist = (CounterList *)calloc (1, sizeof (CounterList));
-       clist->counter = counter;
-
-       for (ctimestamp = counters_timestamps; ctimestamp; ctimestamp = ctimestamp->next) {
-               if (ctimestamp->value == timestamp) {
-                       for (csection = ctimestamp->sections; csection; csection = csection->next) {
-                               if (strcmp (csection->value, counter->section) == 0) {
-                                       /* if timestamp exist and section exist */
-                                       if (!csection->counters)
-                                               csection->counters = clist;
-                                       else
-                                               csection->counters_last->next = clist;
-                                       csection->counters_last = clist;
-                                       return;
-                               }
-                       }
-
-                       /* if timestamp exist and section does not exist */
-                       csection = (CounterSection *)calloc (1, sizeof (CounterSection));
-                       csection->value = counter->section;
-                       csection->counters = clist;
-                       csection->counters_last = clist;
-
-                       if (!ctimestamp->sections)
-                               ctimestamp->sections = csection;
-                       else
-                               ctimestamp->sections_last->next = csection;
-                       ctimestamp->sections_last = csection;
-                       return;
-               }
-       }
-
-       /* If timestamp do not exist and section does not exist */
-       csection = (CounterSection *)calloc (1, sizeof (CounterSection));
-       csection->value = counter->section;
-       csection->counters = clist;
-       csection->counters_last = clist;
-
-       ctimestamp = (CounterTimestamp *)calloc (1, sizeof (CounterTimestamp));
-       ctimestamp->value = timestamp;
-       ctimestamp->sections = csection;
-       ctimestamp->sections_last = csection;
-
-       if (!counters_timestamps) {
-               counters_timestamps = ctimestamp;
-       } else {
-               t = counters_timestamps;
-               while (t->next)
-                       t = t->next;
-               t->next = ctimestamp;
-       }
-}
-
-static void
-add_counter_value (int index, CounterValue *value)
-{
-       CounterList *list;
-
-       for (list = counters; list; list = list->next) {
-               if (list->counter->index == index) {
-                       if (!list->counter->values)
-                               list->counter->values = value;
-                       else
-                               list->counter->values_last->next = value;
-                       list->counter->values_last = value;
-
-                       if (counters_sort_mode == COUNTERS_SORT_TIME)
-                               add_counter_to_timestamp (value->timestamp, list->counter);
-
-                       return;
-               }
-       }
-}
-
-static const char*
-section_name (int section)
-{
-       switch (section) {
-       case MONO_COUNTER_JIT: return "Mono JIT";
-       case MONO_COUNTER_GC: return "Mono GC";
-       case MONO_COUNTER_METADATA: return "Mono Metadata";
-       case MONO_COUNTER_GENERICS: return "Mono Generics";
-       case MONO_COUNTER_SECURITY: return "Mono Security";
-       case MONO_COUNTER_RUNTIME: return "Mono Runtime";
-       case MONO_COUNTER_SYSTEM: return "Mono System";
-       case MONO_COUNTER_PROFILER: return "Mono Profiler";
-       default: return "<unknown>";
-       }
-}
-
-static const char*
-type_name (int type)
-{
-       switch (type) {
-       case MONO_COUNTER_INT: return "Int";
-       case MONO_COUNTER_UINT: return "UInt";
-       case MONO_COUNTER_WORD: return "Word";
-       case MONO_COUNTER_LONG: return "Long";
-       case MONO_COUNTER_ULONG: return "ULong";
-       case MONO_COUNTER_DOUBLE: return "Double";
-       case MONO_COUNTER_STRING: return "String";
-       case MONO_COUNTER_TIME_INTERVAL: return "Time Interval";
-       default: return "<unknown>";
-       }
-}
-
-static const char*
-unit_name (int unit)
-{
-       switch (unit) {
-       case MONO_COUNTER_RAW: return "Raw";
-       case MONO_COUNTER_BYTES: return "Bytes";
-       case MONO_COUNTER_TIME: return "Time";
-       case MONO_COUNTER_COUNT: return "Count";
-       case MONO_COUNTER_PERCENTAGE: return "Percentage";
-       default: return "<unknown>";
-       }
-}
-
-static const char*
-variance_name (int variance)
-{
-       switch (variance) {
-       case MONO_COUNTER_MONOTONIC: return "Monotonic";
-       case MONO_COUNTER_CONSTANT: return "Constant";
-       case MONO_COUNTER_VARIABLE: return "Variable";
-       default: return "<unknown>";
-       }
-}
-
-static void
-dump_counters_value (Counter *counter, const char *key_format, const char *key, void *value)
-{
-       char format[32];
-
-       if (value == NULL) {
-               snprintf (format, sizeof (format), "%s : %%s\n", key_format);
-               fprintf (outfile, format, key, "<null>");
-       } else {
-               switch (counter->type) {
-               case MONO_COUNTER_INT:
-#if SIZEOF_VOID_P == 4
-               case MONO_COUNTER_WORD:
-#endif
-                       snprintf (format, sizeof (format), "%s : %%d\n", key_format);
-                       fprintf (outfile, format, key, *(int32_t*)value);
-                       break;
-               case MONO_COUNTER_UINT:
-                       snprintf (format, sizeof (format), "%s : %%u\n", key_format);
-                       fprintf (outfile, format, key, *(uint32_t*)value);
-                       break;
-               case MONO_COUNTER_LONG:
-#if SIZEOF_VOID_P == 8
-               case MONO_COUNTER_WORD:
-#endif
-               case MONO_COUNTER_TIME_INTERVAL:
-                       if (counter->type == MONO_COUNTER_LONG && counter->unit == MONO_COUNTER_TIME) {
-                               snprintf (format, sizeof (format), "%s : %%0.3fms\n", key_format);
-                               fprintf (outfile, format, key, (double)*(int64_t*)value / 10000.0);
-                       } else if (counter->type == MONO_COUNTER_TIME_INTERVAL) {
-                               snprintf (format, sizeof (format), "%s : %%0.3fms\n", key_format);
-                               fprintf (outfile, format, key, (double)*(int64_t*)value / 1000.0);
-                       } else {
-                               snprintf (format, sizeof (format), "%s : %%u\n", key_format);
-                               fprintf (outfile, format, key, *(int64_t*)value);
-                       }
-                       break;
-               case MONO_COUNTER_ULONG:
-                       snprintf (format, sizeof (format), "%s : %%llu\n", key_format);
-                       fprintf (outfile, format, key, *(uint64_t*)value);
-                       break;
-               case MONO_COUNTER_DOUBLE:
-                       snprintf (format, sizeof (format), "%s : %%f\n", key_format);
-                       fprintf (outfile, format, key, *(double*)value);
-                       break;
-               case MONO_COUNTER_STRING:
-                       snprintf (format, sizeof (format), "%s : %%s\n", key_format);
-                       fprintf (outfile, format, key, *(char*)value);
-                       break;
-               }
-       }
-}
-
-static void
-dump_counters (void)
-{
-       Counter *counter;
-       CounterValue *cvalue;
-       CounterTimestamp *ctimestamp;
-       CounterSection *csection;
-       CounterList *clist;
-       char strtimestamp[17];
-       int i, section_printed;
-
-       fprintf (outfile, "\nCounters:\n");
-
-       if (!verbose) {
-               char counters_to_print[][64] = {
-                       "Methods from AOT",
-                       "Methods JITted using mono JIT",
-                       "Methods JITted using LLVM",
-                       "Total time spent JITting (sec)",
-                       "User Time",
-                       "System Time",
-                       "Total Time",
-                       "Working Set",
-                       "Private Bytes",
-                       "Virtual Bytes",
-                       "Page Faults",
-                       "CPU Load Average - 1min",
-                       "CPU Load Average - 5min",
-                       "CPU Load Average - 15min",
-                       ""
-               };
-
-               for (csection = counters_sections; csection; csection = csection->next) {
-                       section_printed = 0;
-
-                       for (clist = csection->counters; clist; clist = clist->next) {
-                               counter = clist->counter;
-                               if (!counter->values_last)
-                                       continue;
-
-                               for (i = 0; counters_to_print [i][0] != 0; i++) {
-                                       if (strcmp (counters_to_print [i], counter->name) == 0) {
-                                               if (!section_printed) {
-                                                       fprintf (outfile, "\t%s:\n", csection->value);
-                                                       section_printed = 1;
-                                               }
-
-                                               dump_counters_value (counter, "\t\t%-30s", counter->name, counter->values_last->buffer);
-                                               break;
-                                       }
-                               }
-                       }
-               }
-       } else if (counters_sort_mode == COUNTERS_SORT_TIME) {
-               for (ctimestamp = counters_timestamps; ctimestamp; ctimestamp = ctimestamp->next) {
-                       fprintf (outfile, "\t%llu:%02llu:%02llu:%02llu.%03llu:\n",
-                               (unsigned long long) (ctimestamp->value / 1000 / 60 / 60 / 24 % 1000),
-                               (unsigned long long) (ctimestamp->value / 1000 / 60 / 60 % 24),
-                               (unsigned long long) (ctimestamp->value / 1000 / 60 % 60),
-                               (unsigned long long) (ctimestamp->value / 1000 % 60),
-                               (unsigned long long) (ctimestamp->value % 1000));
-
-                       for (csection = ctimestamp->sections; csection; csection = csection->next) {
-                               fprintf (outfile, "\t\t%s:\n", csection->value);
-
-                               for (clist = csection->counters; clist; clist = clist->next) {
-                                       counter = clist->counter;
-                                       for (cvalue = counter->values; cvalue; cvalue = cvalue->next) {
-                                               if (cvalue->timestamp != ctimestamp->value)
-                                                       continue;
-
-                                               dump_counters_value (counter, "\t\t\t%-30s", counter->name, cvalue->buffer);
-                                       }
-                               }
-                       }
-               }
-       } else if (counters_sort_mode == COUNTERS_SORT_CATEGORY) {
-               for (csection = counters_sections; csection; csection = csection->next) {
-                       fprintf (outfile, "\t%s:\n", csection->value);
-
-                       for (clist = csection->counters; clist; clist = clist->next) {
-                               counter = clist->counter;
-                               fprintf (outfile, "\t\t%s: [type: %s, unit: %s, variance: %s]\n",
-                                       counter->name, type_name (counter->type), unit_name (counter->unit), variance_name (counter->variance));
-
-                               for (cvalue = counter->values; cvalue; cvalue = cvalue->next) {
-                                       snprintf (strtimestamp, sizeof (strtimestamp), "%llu:%02llu:%02llu:%02llu.%03llu",
-                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 / 60 / 24 % 1000),
-                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 / 60 % 24),
-                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 % 60),
-                                               (unsigned long long) (cvalue->timestamp / 1000 % 60),
-                                               (unsigned long long) (cvalue->timestamp % 1000));
-
-                                       dump_counters_value (counter, "\t\t\t%s", strtimestamp, cvalue->buffer);
-                               }
-                       }
-               }
-       }
-}
-
-static int num_images;
-typedef struct _ImageDesc ImageDesc;
-struct _ImageDesc {
-       ImageDesc *next;
-       intptr_t image;
-       char *filename;
-};
-
-static ImageDesc* image_hash [SMALL_HASH_SIZE] = {0};
-
-static void
-add_image (intptr_t image, char *name)
-{
-       int slot = ((image >> 2) & 0xffff) % SMALL_HASH_SIZE;
-       ImageDesc *cd = (ImageDesc *)malloc (sizeof (ImageDesc));
-       cd->image = image;
-       cd->filename = pstrdup (name);
-       cd->next = image_hash [slot];
-       image_hash [slot] = cd;
-       num_images++;
-}
-
-static int num_assemblies;
-
-typedef struct _AssemblyDesc AssemblyDesc;
-struct _AssemblyDesc {
-       AssemblyDesc *next;
-       intptr_t assembly;
-       char *asmname;
-};
-
-static AssemblyDesc* assembly_hash [SMALL_HASH_SIZE] = {0};
-
-static void
-add_assembly (intptr_t assembly, char *name)
-{
-       int slot = ((assembly >> 2) & 0xffff) % SMALL_HASH_SIZE;
-       AssemblyDesc *cd = (AssemblyDesc *)malloc (sizeof (AssemblyDesc));
-       cd->assembly = assembly;
-       cd->asmname = pstrdup (name);
-       cd->next = assembly_hash [slot];
-       assembly_hash [slot] = cd;
-       num_assemblies++;
-}
-
-typedef struct _BackTrace BackTrace;
-typedef struct {
-       uint64_t count;
-       BackTrace *bt;
-} CallContext;
-
-typedef struct {
-       int count;
-       int size;
-       CallContext *traces;
-} TraceDesc;
-
-typedef struct _ClassDesc ClassDesc;
-struct _ClassDesc {
-       ClassDesc *next;
-       intptr_t klass;
-       char *name;
-       intptr_t allocs;
-       uint64_t alloc_size;
-       TraceDesc traces;
-};
-
-static ClassDesc* class_hash [HASH_SIZE] = {0};
-static int num_classes = 0;
-
-static ClassDesc*
-add_class (intptr_t klass, const char *name)
-{
-       int slot = ((klass >> 2) & 0xffff) % HASH_SIZE;
-       ClassDesc *cd;
-       cd = class_hash [slot];
-       while (cd && cd->klass != klass)
-               cd = cd->next;
-       /* we resolved an unknown class (unless we had the code unloaded) */
-       if (cd) {
-               /*printf ("resolved unknown: %s\n", name);*/
-               g_free (cd->name);
-               cd->name = pstrdup (name);
-               return cd;
-       }
-       cd = (ClassDesc *)calloc (sizeof (ClassDesc), 1);
-       cd->klass = klass;
-       cd->name = pstrdup (name);
-       cd->next = class_hash [slot];
-       cd->allocs = 0;
-       cd->alloc_size = 0;
-       cd->traces.count = 0;
-       cd->traces.size = 0;
-       cd->traces.traces = NULL;
-       class_hash [slot] = cd;
-       num_classes++;
-       return cd;
-}
-
-static ClassDesc *
-lookup_class (intptr_t klass)
-{
-       int slot = ((klass >> 2) & 0xffff) % HASH_SIZE;
-       ClassDesc *cd = class_hash [slot];
-       while (cd && cd->klass != klass)
-               cd = cd->next;
-       if (!cd) {
-               char buf [128];
-               snprintf (buf, sizeof (buf), "unresolved class %p", (void*)klass);
-               return add_class (klass, buf);
-       }
-       return cd;
-}
-
-typedef struct _MethodDesc MethodDesc;
-struct _MethodDesc {
-       MethodDesc *next;
-       intptr_t method;
-       char *name;
-       intptr_t code;
-       int len;
-       int recurse_count;
-       int sample_hits;
-       int ignore_jit; /* when this is set, we collect the metadata but don't count this method fot jit time and code size, when filtering events */
-       uint64_t calls;
-       uint64_t total_time;
-       uint64_t callee_time;
-       uint64_t self_time;
-       TraceDesc traces;
-};
-
-static MethodDesc* method_hash [HASH_SIZE] = {0};
-static int num_methods = 0;
-
-static MethodDesc*
-add_method (intptr_t method, const char *name, intptr_t code, int len)
-{
-       int slot = ((method >> 2) & 0xffff) % HASH_SIZE;
-       MethodDesc *cd;
-       cd = method_hash [slot];
-       while (cd && cd->method != method)
-               cd = cd->next;
-       /* we resolved an unknown method (unless we had the code unloaded) */
-       if (cd) {
-               cd->code = code;
-               cd->len = len;
-               /*printf ("resolved unknown: %s\n", name);*/
-               g_free (cd->name);
-               cd->name = pstrdup (name);
-               return cd;
-       }
-       cd = (MethodDesc *)calloc (sizeof (MethodDesc), 1);
-       cd->method = method;
-       cd->name = pstrdup (name);
-       cd->code = code;
-       cd->len = len;
-       cd->calls = 0;
-       cd->total_time = 0;
-       cd->traces.count = 0;
-       cd->traces.size = 0;
-       cd->traces.traces = NULL;
-       cd->next = method_hash [slot];
-       method_hash [slot] = cd;
-       num_methods++;
-       return cd;
-}
-
-static MethodDesc *
-lookup_method (intptr_t method)
-{
-       int slot = ((method >> 2) & 0xffff) % HASH_SIZE;
-       MethodDesc *cd = method_hash [slot];
-       while (cd && cd->method != method)
-               cd = cd->next;
-       if (!cd) {
-               char buf [128];
-               snprintf (buf, sizeof (buf), "unknown method %p", (void*)method);
-               return add_method (method, buf, 0, 0);
-       }
-       return cd;
-}
-
-static int num_stat_samples = 0;
-static int size_stat_samples = 0;
-uintptr_t *stat_samples = NULL;
-int *stat_sample_desc = NULL;
-
-static void
-add_stat_sample (int type, uintptr_t ip) {
-       if (num_stat_samples == size_stat_samples) {
-               size_stat_samples *= 2;
-               if (!size_stat_samples)
-               size_stat_samples = 32;
-               stat_samples = (uintptr_t *)realloc (stat_samples, size_stat_samples * sizeof (uintptr_t));
-               stat_sample_desc = (int *)realloc (stat_sample_desc, size_stat_samples * sizeof (int));
-       }
-       stat_samples [num_stat_samples] = ip;
-       stat_sample_desc [num_stat_samples++] = type;
-}
-
-static MethodDesc*
-lookup_method_by_ip (uintptr_t ip)
-{
-       int i;
-       MethodDesc* m;
-       /* dumb */
-       for (i = 0; i < HASH_SIZE; ++i) {
-               m = method_hash [i];
-               while (m) {
-                       //printf ("checking %p against %p-%p\n", (void*)ip, (void*)(m->code), (void*)(m->code + m->len));
-                       if (ip >= (uintptr_t)m->code && ip < (uintptr_t)m->code + m->len) {
-                               return m;
-                       }
-                       m = m->next;
-               }
-       }
-       return NULL;
-}
-
-static int
-compare_method_samples (const void *a, const void *b)
-{
-       MethodDesc *const *A = (MethodDesc *const *)a;
-       MethodDesc *const *B = (MethodDesc *const *)b;
-       if ((*A)->sample_hits == (*B)->sample_hits)
-               return 0;
-       if ((*B)->sample_hits < (*A)->sample_hits)
-               return -1;
-       return 1;
-}
-
-typedef struct _UnmanagedSymbol UnmanagedSymbol;
-struct _UnmanagedSymbol {
-       UnmanagedSymbol *parent;
-       char *name;
-       int is_binary;
-       uintptr_t addr;
-       uintptr_t size;
-       uintptr_t sample_hits;
-};
-
-static UnmanagedSymbol **usymbols = NULL;
-static int usymbols_size = 0;
-static int usymbols_num = 0;
-
-static int
-compare_usymbol_addr (const void *a, const void *b)
-{
-       UnmanagedSymbol *const *A = (UnmanagedSymbol *const *)a;
-       UnmanagedSymbol *const *B = (UnmanagedSymbol *const *)b;
-       if ((*B)->addr == (*A)->addr)
-               return 0;
-       if ((*B)->addr > (*A)->addr)
-               return -1;
-       return 1;
-}
-
-static int
-compare_usymbol_samples (const void *a, const void *b)
-{
-       UnmanagedSymbol *const *A = (UnmanagedSymbol *const *)a;
-       UnmanagedSymbol *const *B = (UnmanagedSymbol *const *)b;
-       if ((*B)->sample_hits == (*A)->sample_hits)
-               return 0;
-       if ((*B)->sample_hits < (*A)->sample_hits)
-               return -1;
-       return 1;
-}
-
-static void
-add_unmanaged_symbol (uintptr_t addr, char *name, uintptr_t size)
-{
-       UnmanagedSymbol *sym;
-       if (usymbols_num == usymbols_size) {
-               int new_size = usymbols_size * 2;
-               if (!new_size)
-                       new_size = 16;
-               usymbols = (UnmanagedSymbol **)realloc (usymbols, sizeof (void*) * new_size);
-               usymbols_size = new_size;
-       }
-       sym = (UnmanagedSymbol *)calloc (sizeof (UnmanagedSymbol), 1);
-       sym->addr = addr;
-       sym->name = name;
-       sym->size = size;
-       usymbols [usymbols_num++] = sym;
-}
-
-/* only valid after the symbols are sorted */
-static UnmanagedSymbol*
-lookup_unmanaged_symbol (uintptr_t addr)
-{
-       int r = usymbols_num - 1;
-       int l = 0;
-       UnmanagedSymbol *sym;
-       int last_best = -1;
-       while (r >= l) {
-               int m = (l + r) / 2;
-               sym = usymbols [m];
-               if (addr == sym->addr)
-                       return sym;
-               if (addr < sym->addr) {
-                       r = m - 1;
-               } else if (addr > sym->addr) {
-                       l = m + 1;
-                       last_best = m;
-               }
-       }
-       if (last_best >= 0 && (addr - usymbols [last_best]->addr) < 4096)
-               return usymbols [last_best];
-       return NULL;
-}
-
-/* we use the same structure for binaries */
-static UnmanagedSymbol **ubinaries = NULL;
-static int ubinaries_size = 0;
-static int ubinaries_num = 0;
-
-static void
-add_unmanaged_binary (uintptr_t addr, char *name, uintptr_t size)
-{
-       UnmanagedSymbol *sym;
-       if (ubinaries_num == ubinaries_size) {
-               int new_size = ubinaries_size * 2;
-               if (!new_size)
-                       new_size = 16;
-               ubinaries = (UnmanagedSymbol **)realloc (ubinaries, sizeof (void*) * new_size);
-               ubinaries_size = new_size;
-       }
-       sym = (UnmanagedSymbol *)calloc (sizeof (UnmanagedSymbol), 1);
-       sym->addr = addr;
-       sym->name = name;
-       sym->size = size;
-       sym->is_binary = 1;
-       ubinaries [ubinaries_num++] = sym;
-}
-
-static UnmanagedSymbol*
-lookup_unmanaged_binary (uintptr_t addr)
-{
-       int i;
-       for (i = 0; i < ubinaries_num; ++i) {
-               UnmanagedSymbol *ubin = ubinaries [i];
-               if (addr >= ubin->addr && addr < ubin->addr + ubin->size) {
-                       return ubin;
-               }
-       }
-       return NULL;
-}
-
-static const char*
-sample_type_name (int type)
-{
-       switch (type) {
-       case SAMPLE_CYCLES: return "cycles";
-       case SAMPLE_INSTRUCTIONS: return "instructions retired";
-       case SAMPLE_CACHE_MISSES: return "cache misses";
-       case SAMPLE_CACHE_REFS: return "cache references";
-       case SAMPLE_BRANCHES: return "executed branches";
-       case SAMPLE_BRANCH_MISSES: return "unpredicted branches";
-       }
-       return "unknown";
-}
-
-static void
-set_usym_parent (UnmanagedSymbol** cachedus, int count)
-{
-       int i;
-       for (i = 0; i < count; ++i) {
-               UnmanagedSymbol *ubin = lookup_unmanaged_binary (cachedus [i]->addr);
-               if (ubin == cachedus [i])
-                       continue;
-               cachedus [i]->parent = ubin;
-       }
-}
-
-static void
-print_usym (UnmanagedSymbol* um)
-{
-       if (um->parent)
-               fprintf (outfile, "\t%6zd %6.2f %-36s in %s\n", um->sample_hits, um->sample_hits*100.0/num_stat_samples, um->name, um->parent->name);
-       else
-               fprintf (outfile, "\t%6zd %6.2f %s\n", um->sample_hits, um->sample_hits*100.0/num_stat_samples, um->name);
-}
-
-static int
-sym_percent (uintptr_t sample_hits)
-{
-       double pc;
-       if (verbose)
-               return 1;
-       pc = sample_hits*100.0/num_stat_samples;
-       return pc >= 0.1;
-}
-
-static void
-dump_samples (void)
-{
-       int i, u;
-       int count = 0, msize = 0;
-       int unmanaged_hits = 0;
-       int unresolved_hits = 0;
-       MethodDesc** cachedm = NULL;
-       int ucount = 0, usize = 0;
-       UnmanagedSymbol** cachedus = NULL;
-       if (!num_stat_samples)
-               return;
-       qsort (usymbols, usymbols_num, sizeof (UnmanagedSymbol*), compare_usymbol_addr);
-       for (i = 0; i < num_stat_samples; ++i) {
-               MethodDesc *m = lookup_method_by_ip (stat_samples [i]);
-               if (m) {
-                       if (!m->sample_hits) {
-                               if (count == msize) {
-                                       msize *= 2;
-                                       if (!msize)
-                                               msize = 4;
-                                       cachedm = (MethodDesc **)realloc (cachedm, sizeof (void*) * msize);
-                               }
-                               cachedm [count++] = m;
-                       }
-                       m->sample_hits++;
-               } else {
-                       UnmanagedSymbol *usym = lookup_unmanaged_symbol (stat_samples [i]);
-                       if (!usym) {
-                               unresolved_hits++;
-                               //printf ("unmanaged hit at %p\n", (void*)stat_samples [i]);
-                               usym = lookup_unmanaged_binary (stat_samples [i]);
-                       }
-                       if (usym) {
-                               if (!usym->sample_hits) {
-                                       if (ucount == usize) {
-                                               usize *= 2;
-                                               if (!usize)
-                                                       usize = 4;
-                                               cachedus = (UnmanagedSymbol **)realloc (cachedus, sizeof (void*) * usize);
-                                       }
-                                       cachedus [ucount++] = usym;
-                               }
-                               usym->sample_hits++;
-                       }
-                       unmanaged_hits++;
-               }
-       }
-       qsort (cachedm, count, sizeof (MethodDesc*), compare_method_samples);
-       qsort (cachedus, ucount, sizeof (UnmanagedSymbol*), compare_usymbol_samples);
-       set_usym_parent (cachedus, ucount);
-       fprintf (outfile, "\nStatistical samples summary\n");
-       fprintf (outfile, "\tSample type: %s\n", sample_type_name (stat_sample_desc [0]));
-       fprintf (outfile, "\tUnmanaged hits:  %6d (%4.1f%%)\n", unmanaged_hits, (100.0*unmanaged_hits)/num_stat_samples);
-       fprintf (outfile, "\tManaged hits:    %6d (%4.1f%%)\n", num_stat_samples - unmanaged_hits, (100.0*(num_stat_samples-unmanaged_hits))/num_stat_samples);
-       fprintf (outfile, "\tUnresolved hits: %6d (%4.1f%%)\n", unresolved_hits, (100.0*unresolved_hits)/num_stat_samples);
-       fprintf (outfile, "\t%6s %6s %s\n", "Hits", "%", "Method name");
-       i = 0;
-       u = 0;
-       while (i < count || u < ucount) {
-               if (i < count) {
-                       MethodDesc *m = cachedm [i];
-                       if (u < ucount) {
-                               UnmanagedSymbol *um = cachedus [u];
-                               if (um->sample_hits > m->sample_hits) {
-                                       if (!sym_percent (um->sample_hits))
-                                               break;
-                                       print_usym (um);
-                                       u++;
-                                       continue;
-                               }
-                       }
-                       if (!sym_percent (m->sample_hits))
-                               break;
-                       fprintf (outfile, "\t%6d %6.2f %s\n", m->sample_hits, m->sample_hits*100.0/num_stat_samples, m->name);
-                       i++;
-                       continue;
-               }
-               if (u < ucount) {
-                       UnmanagedSymbol *um = cachedus [u];
-                       if (!sym_percent (um->sample_hits))
-                               break;
-                       print_usym (um);
-                       u++;
-                       continue;
-               }
-       }
-}
-
-typedef struct _HeapClassDesc HeapClassDesc;
-typedef struct {
-       HeapClassDesc *klass;
-       uint64_t count;
-} HeapClassRevRef;
-
-struct _HeapClassDesc {
-       ClassDesc *klass;
-       int64_t count;
-       int64_t total_size;
-       HeapClassRevRef *rev_hash;
-       int rev_hash_size;
-       int rev_count;
-       uintptr_t pinned_references;
-       uintptr_t root_references;
-};
-
-static int
-add_rev_class_hashed (HeapClassRevRef *rev_hash, uintptr_t size, HeapClassDesc *hklass, uint64_t value)
-{
-       uintptr_t i;
-       uintptr_t start_pos;
-       start_pos = (hklass->klass->klass >> 2) % size;
-       assert (start_pos < size);
-       i = start_pos;
-       do {
-               if (rev_hash [i].klass == hklass) {
-                       rev_hash [i].count += value;
-                       return 0;
-               } else if (!rev_hash [i].klass) {
-                       rev_hash [i].klass = hklass;
-                       rev_hash [i].count += value;
-                       start_pos = 0;
-                       for (i = 0; i < size; ++i)
-                               if (rev_hash [i].klass && rev_hash [i].klass->klass == hklass->klass)
-                                       start_pos ++;
-                       assert (start_pos == 1);
-                       return 1;
-               }
-               /* wrap around */
-               if (++i == size)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       printf ("failed revref store\n");
-       return 0;
-}
-
-static void
-add_heap_class_rev (HeapClassDesc *from, HeapClassDesc *to)
-{
-       uintptr_t i;
-       if (to->rev_count * 2 >= to->rev_hash_size) {
-               HeapClassRevRef *n;
-               uintptr_t old_size = to->rev_hash_size;
-               to->rev_hash_size *= 2;
-               if (to->rev_hash_size == 0)
-                       to->rev_hash_size = 4;
-               n = (HeapClassRevRef *)calloc (sizeof (HeapClassRevRef) * to->rev_hash_size, 1);
-               for (i = 0; i < old_size; ++i) {
-                       if (to->rev_hash [i].klass)
-                               add_rev_class_hashed (n, to->rev_hash_size, to->rev_hash [i].klass, to->rev_hash [i].count);
-               }
-               if (to->rev_hash)
-                       g_free (to->rev_hash);
-               to->rev_hash = n;
-       }
-       to->rev_count += add_rev_class_hashed (to->rev_hash, to->rev_hash_size, from, 1);
-}
-
-typedef struct {
-       uintptr_t objaddr;
-       HeapClassDesc *hklass;
-       uintptr_t num_refs;
-       uintptr_t refs [0];
-} HeapObjectDesc;
-
-typedef struct _HeapShot HeapShot;
-struct _HeapShot {
-       HeapShot *next;
-       uint64_t timestamp;
-       int class_count;
-       int hash_size;
-       HeapClassDesc **class_hash;
-       HeapClassDesc **sorted;
-       HeapObjectDesc **objects_hash;
-       uintptr_t objects_count;
-       uintptr_t objects_hash_size;
-       uintptr_t num_roots;
-       uintptr_t *roots;
-       uintptr_t *roots_extra;
-       int *roots_types;
-};
-
-static HeapShot *heap_shots = NULL;
-static int num_heap_shots = 0;
-
-static HeapShot*
-new_heap_shot (uint64_t timestamp)
-{
-       HeapShot *hs = (HeapShot *)calloc (sizeof (HeapShot), 1);
-       hs->hash_size = 4;
-       hs->class_hash = (HeapClassDesc **)calloc (sizeof (void*), hs->hash_size);
-       hs->timestamp = timestamp;
-       num_heap_shots++;
-       hs->next = heap_shots;
-       heap_shots = hs;
-       return hs;
-}
-
-static HeapClassDesc*
-heap_class_lookup (HeapShot *hs, ClassDesc *klass)
-{
-       int i;
-       unsigned int start_pos;
-       start_pos = ((uintptr_t)klass->klass >> 2) % hs->hash_size;
-       i = start_pos;
-       do {
-               HeapClassDesc* cd = hs->class_hash [i];
-               if (!cd)
-                       return NULL;
-               if (cd->klass == klass)
-                       return cd;
-               /* wrap around */
-               if (++i == hs->hash_size)
-                       i = 0;
-       } while (i != start_pos);
-       return NULL;
-}
-
-static int
-add_heap_hashed (HeapClassDesc **hash, HeapClassDesc **retv, uintptr_t hsize, ClassDesc *klass, uint64_t size, uint64_t count)
-{
-       uintptr_t i;
-       uintptr_t start_pos;
-       start_pos = ((uintptr_t)klass->klass >> 2) % hsize;
-       i = start_pos;
-       do {
-               if (hash [i] && hash [i]->klass == klass) {
-                       hash [i]->total_size += size;
-                       hash [i]->count += count;
-                       *retv = hash [i];
-                       return 0;
-               } else if (!hash [i]) {
-                       if (*retv) {
-                               hash [i] = *retv;
-                               return 1;
-                       }
-                       hash [i] = (HeapClassDesc *)calloc (sizeof (HeapClassDesc), 1);
-                       hash [i]->klass = klass;
-                       hash [i]->total_size += size;
-                       hash [i]->count += count;
-                       *retv = hash [i];
-                       return 1;
-               }
-               /* wrap around */
-               if (++i == hsize)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       printf ("failed heap class store\n");
-       return 0;
-}
-
-static HeapClassDesc*
-add_heap_shot_class (HeapShot *hs, ClassDesc *klass, uint64_t size)
-{
-       HeapClassDesc *res;
-       int i;
-       if (hs->class_count * 2 >= hs->hash_size) {
-               HeapClassDesc **n;
-               int old_size = hs->hash_size;
-               hs->hash_size *= 2;
-               if (hs->hash_size == 0)
-                       hs->hash_size = 4;
-               n = (HeapClassDesc **)calloc (sizeof (void*) * hs->hash_size, 1);
-               for (i = 0; i < old_size; ++i) {
-                       res = hs->class_hash [i];
-                       if (hs->class_hash [i])
-                               add_heap_hashed (n, &res, hs->hash_size, hs->class_hash [i]->klass, hs->class_hash [i]->total_size, hs->class_hash [i]->count);
-               }
-               if (hs->class_hash)
-                       g_free (hs->class_hash);
-               hs->class_hash = n;
-       }
-       res = NULL;
-       hs->class_count += add_heap_hashed (hs->class_hash, &res, hs->hash_size, klass, size, 1);
-       //if (res->count == 1)
-       //      printf ("added heap class: %s\n", res->klass->name);
-       return res;
-}
-
-static HeapObjectDesc*
-alloc_heap_obj (uintptr_t objaddr, HeapClassDesc *hklass, uintptr_t num_refs)
-{
-       HeapObjectDesc* ho = (HeapObjectDesc *)calloc (sizeof (HeapObjectDesc) + num_refs * sizeof (uintptr_t), 1);
-       ho->objaddr = objaddr;
-       ho->hklass = hklass;
-       ho->num_refs = num_refs;
-       return ho;
-}
-
-static uintptr_t
-heap_shot_find_obj_slot (HeapShot *hs, uintptr_t objaddr)
-{
-       uintptr_t i;
-       uintptr_t start_pos;
-       HeapObjectDesc **hash = hs->objects_hash;
-       start_pos = ((uintptr_t)objaddr >> 3) % hs->objects_hash_size;
-       i = start_pos;
-       do {
-               if (hash [i] && hash [i]->objaddr == objaddr) {
-                       return i;
-               } else if (!hash [i]) {
-                       break; /* fail */
-               }
-               /* wrap around */
-               if (++i == hs->objects_hash_size)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       //printf ("failed heap obj slot\n");
-       return -1;
-}
-
-static HeapObjectDesc*
-heap_shot_obj_add_refs (HeapShot *hs, uintptr_t objaddr, uintptr_t num, uintptr_t *ref_offset)
-{
-       HeapObjectDesc **hash = hs->objects_hash;
-       uintptr_t i = heap_shot_find_obj_slot (hs, objaddr);
-       if (i >= 0) {
-               HeapObjectDesc* ho = alloc_heap_obj (objaddr, hash [i]->hklass, hash [i]->num_refs + num);
-               *ref_offset = hash [i]->num_refs;
-               memcpy (ho->refs, hash [i]->refs, hash [i]->num_refs * sizeof (uintptr_t));
-               g_free (hash [i]);
-               hash [i] = ho;
-               return ho;
-       }
-       /* should not happen */
-       printf ("failed heap obj update\n");
-       return NULL;
-
-}
-
-static uintptr_t
-add_heap_hashed_obj (HeapObjectDesc **hash, uintptr_t hsize, HeapObjectDesc *obj)
-{
-       uintptr_t i;
-       uintptr_t start_pos;
-       start_pos = ((uintptr_t)obj->objaddr >> 3) % hsize;
-       i = start_pos;
-       do {
-               if (hash [i] && hash [i]->objaddr == obj->objaddr) {
-                       printf ("duplicate object!\n");
-                       return 0;
-               } else if (!hash [i]) {
-                       hash [i] = obj;
-                       return 1;
-               }
-               /* wrap around */
-               if (++i == hsize)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       printf ("failed heap obj store\n");
-       return 0;
-}
-
-static void
-add_heap_shot_obj (HeapShot *hs, HeapObjectDesc *obj)
-{
-       uintptr_t i;
-       if (hs->objects_count * 2 >= hs->objects_hash_size) {
-               HeapObjectDesc **n;
-               uintptr_t old_size = hs->objects_hash_size;
-               hs->objects_hash_size *= 2;
-               if (hs->objects_hash_size == 0)
-                       hs->objects_hash_size = 4;
-               n = (HeapObjectDesc **)calloc (sizeof (void*) * hs->objects_hash_size, 1);
-               for (i = 0; i < old_size; ++i) {
-                       if (hs->objects_hash [i])
-                               add_heap_hashed_obj (n, hs->objects_hash_size, hs->objects_hash [i]);
-               }
-               if (hs->objects_hash)
-                       g_free (hs->objects_hash);
-               hs->objects_hash = n;
-       }
-       hs->objects_count += add_heap_hashed_obj (hs->objects_hash, hs->objects_hash_size, obj);
-}
-
-static void
-heap_shot_resolve_reverse_refs (HeapShot *hs)
-{
-       uintptr_t i;
-       for (i = 0; i < hs->objects_hash_size; ++i) {
-               uintptr_t r;
-               HeapObjectDesc *ho = hs->objects_hash [i];
-               if (!ho)
-                       continue;
-               for (r = 0; r < ho->num_refs; ++r) {
-                       uintptr_t oi = heap_shot_find_obj_slot (hs, ho->refs [r]);
-                       add_heap_class_rev (ho->hklass, hs->objects_hash [oi]->hklass);
-               }
-       }
-}
-
-#define MARK_GRAY 1
-#define MARK_BLACK 2
-
-static void
-heap_shot_mark_objects (HeapShot *hs)
-{
-       uintptr_t i, oi, r;
-       unsigned char *marks;
-       HeapObjectDesc *obj, *ref;
-       int marked_some;
-       uintptr_t num_marked = 0, num_unmarked;
-       for (i = 0; i < hs->num_roots; ++i) {
-               HeapClassDesc *cd;
-               oi = heap_shot_find_obj_slot (hs, hs->roots [i]);
-               if (oi == -1) {
-                       continue;
-               }
-               obj = hs->objects_hash [oi];
-               cd = obj->hklass;
-               if (hs->roots_types [i] & MONO_PROFILE_GC_ROOT_PINNING)
-                       cd->pinned_references++;
-               cd->root_references++;
-       }
-       if (!debug)
-               return;
-       /* consistency checks: it seems not all the objects are walked in the heap in some cases */
-       marks = (unsigned char *)calloc (hs->objects_hash_size, 1);
-       if (!marks)
-               return;
-       for (i = 0; i < hs->num_roots; ++i) {
-               oi = heap_shot_find_obj_slot (hs, hs->roots [i]);
-               if (oi == -1) {
-                       fprintf (outfile, "root type 0x%x for obj %p (%s) not found in heap\n", hs->roots_types [i], (void*)hs->roots [i], lookup_class (hs->roots_extra [i])->name);
-                       continue;
-               }
-               obj = hs->objects_hash [oi];
-               if (!marks [oi]) {
-                       marks [oi] = obj->num_refs? MARK_GRAY: MARK_BLACK;
-                       num_marked++;
-               }
-       }
-       marked_some = 1;
-       while (marked_some) {
-               marked_some = 0;
-               for (i = 0; i < hs->objects_hash_size; ++i) {
-                       if (marks [i] != MARK_GRAY)
-                               continue;
-                       marks [i] = MARK_BLACK;
-                       obj = hs->objects_hash [i];
-                       for (r = 0; r < obj->num_refs; ++r) {
-                               oi = heap_shot_find_obj_slot (hs, obj->refs [r]);
-                               if (oi == -1) {
-                                       fprintf (outfile, "referenced obj %p not found in heap\n", (void*)obj->refs [r]);
-                                       continue;
-                               }
-                               ref = hs->objects_hash [oi];
-                               if (!marks [oi]) {
-                                       marks [oi] = ref->num_refs? MARK_GRAY: MARK_BLACK;
-                               }
-                       }
-                       marked_some++;
-               }
-       }
-
-       num_unmarked = 0;
-       for (i = 0; i < hs->objects_hash_size; ++i) {
-               if (hs->objects_hash [i] && !marks [i]) {
-                       num_unmarked++;
-                       fprintf (outfile, "object %p (%s) unmarked\n", (void*)hs->objects_hash [i], hs->objects_hash [i]->hklass->klass->name);
-               }
-       }
-       fprintf (outfile, "Total unmarked: %zd/%zd\n", num_unmarked, hs->objects_count);
-       g_free (marks);
-}
-
-static void
-heap_shot_free_objects (HeapShot *hs)
-{
-       uintptr_t i;
-       for (i = 0; i < hs->objects_hash_size; ++i) {
-               HeapObjectDesc *ho = hs->objects_hash [i];
-               if (ho)
-                       g_free (ho);
-       }
-       if (hs->objects_hash)
-               g_free (hs->objects_hash);
-       hs->objects_hash = NULL;
-       hs->objects_hash_size = 0;
-       hs->objects_count = 0;
-}
-
-
-struct _BackTrace {
-       BackTrace *next;
-       unsigned int hash;
-       int count;
-       int id;
-       MethodDesc *methods [1];
-};
-
-static BackTrace *backtrace_hash [HASH_SIZE];
-static BackTrace **backtraces = NULL;
-static int num_backtraces = 0;
-static int next_backtrace = 0;
-
-static int
-hash_backtrace (int count, MethodDesc **methods)
-{
-       int hash = count;
-       int i;
-       for (i = 0; i < count; ++i) {
-               hash = (hash << 5) - hash + methods [i]->method;
-       }
-       return hash;
-}
-
-static int
-compare_backtrace (BackTrace *bt, int count, MethodDesc **methods)
-{
-       int i;
-       if (bt->count != count)
-               return 0;
-       for (i = 0; i < count; ++i)
-               if (methods [i] != bt->methods [i])
-                       return 0;
-       return 1;
-}
-
-static BackTrace*
-add_backtrace (int count, MethodDesc **methods)
-{
-       int hash = hash_backtrace (count, methods);
-       int slot = (hash & 0xffff) % HASH_SIZE;
-       BackTrace *bt = backtrace_hash [slot];
-       while (bt) {
-               if (bt->hash == hash && compare_backtrace (bt, count, methods))
-                       return bt;
-               bt = bt->next;
-       }
-       bt = (BackTrace *)malloc (sizeof (BackTrace) + ((count - 1) * sizeof (void*)));
-       bt->next = backtrace_hash [slot];
-       backtrace_hash [slot] = bt;
-       if (next_backtrace == num_backtraces) {
-               num_backtraces *= 2;
-               if (!num_backtraces)
-                       num_backtraces = 16;
-               backtraces = (BackTrace **)realloc (backtraces, sizeof (void*) * num_backtraces);
-       }
-       bt->id = next_backtrace++;
-       backtraces [bt->id] = bt;
-       bt->count = count;
-       bt->hash = hash;
-       for (slot = 0; slot < count; ++slot)
-               bt->methods [slot] = methods [slot];
-
-       return bt;
-}
-
-typedef struct _MonitorDesc MonitorDesc;
-typedef struct _ThreadContext ThreadContext;
-typedef struct _DomainContext DomainContext;
-typedef struct _RemCtxContext RemCtxContext;
-
-typedef struct {
-       FILE *file;
-#if defined (HAVE_SYS_ZLIB)
-       gzFile gzfile;
-#endif
-       unsigned char *buf;
-       int size;
-       int data_version;
-       int version_major;
-       int version_minor;
-       int timer_overhead;
-       int pid;
-       int port;
-       char *args;
-       char *arch;
-       char *os;
-       uint64_t startup_time;
-       ThreadContext *threads;
-       ThreadContext *current_thread;
-       DomainContext *domains;
-       DomainContext *current_domain;
-       RemCtxContext *remctxs;
-       RemCtxContext *current_remctx;
-} ProfContext;
-
-struct _ThreadContext {
-       ThreadContext *next;
-       intptr_t thread_id;
-       char *name;
-       /* emulated stack */
-       MethodDesc **stack;
-       uint64_t *time_stack;
-       uint64_t *callee_time_stack;
-       uint64_t last_time;
-       uint64_t contention_start;
-       MonitorDesc *monitor;
-       int stack_size;
-       int stack_id;
-       HeapShot *current_heap_shot;
-       uintptr_t num_roots;
-       uintptr_t size_roots;
-       uintptr_t *roots;
-       uintptr_t *roots_extra;
-       int *roots_types;
-       uint64_t gc_start_times [3];
-};
-
-struct _DomainContext {
-       DomainContext *next;
-       intptr_t domain_id;
-       const char *friendly_name;
-};
-
-struct _RemCtxContext {
-       RemCtxContext *next;
-       intptr_t remctx_id;
-       intptr_t domain_id;
-};
-
-static void
-ensure_buffer (ProfContext *ctx, int size)
-{
-       if (ctx->size < size) {
-               ctx->buf = (unsigned char *)realloc (ctx->buf, size);
-               ctx->size = size;
-       }
-}
-
-static int
-load_data (ProfContext *ctx, int size)
-{
-       ensure_buffer (ctx, size);
-#if defined (HAVE_SYS_ZLIB)
-       if (ctx->gzfile) {
-               int r = gzread (ctx->gzfile, ctx->buf, size);
-               if (r == 0)
-                       return size == 0? 1: 0;
-               return r == size;
-       } else
-#endif
-       {
-               int r = fread (ctx->buf, size, 1, ctx->file);
-               if (r == 0)
-                       return size == 0? 1: 0;
-               return r;
-       }
-}
-
-static ThreadContext*
-get_thread (ProfContext *ctx, intptr_t thread_id)
-{
-       ThreadContext *thread;
-       if (ctx->current_thread && ctx->current_thread->thread_id == thread_id)
-               return ctx->current_thread;
-       thread = ctx->threads;
-       while (thread) {
-               if (thread->thread_id == thread_id) {
-                       return thread;
-               }
-               thread = thread->next;
-       }
-       thread = (ThreadContext *)calloc (sizeof (ThreadContext), 1);
-       thread->next = ctx->threads;
-       ctx->threads = thread;
-       thread->thread_id = thread_id;
-       thread->last_time = 0;
-       thread->stack_id = 0;
-       thread->stack_size = 32;
-       thread->stack = (MethodDesc **)malloc (thread->stack_size * sizeof (void*));
-       thread->time_stack = (uint64_t *)malloc (thread->stack_size * sizeof (uint64_t));
-       thread->callee_time_stack = (uint64_t *)malloc (thread->stack_size * sizeof (uint64_t));
-       return thread;
-}
-
-static DomainContext *
-get_domain (ProfContext *ctx, intptr_t domain_id)
-{
-       if (ctx->current_domain && ctx->current_domain->domain_id == domain_id)
-               return ctx->current_domain;
-
-       DomainContext *domain = ctx->domains;
-
-       while (domain) {
-               if (domain->domain_id == domain_id)
-                       return domain;
-
-               domain = domain->next;
-       }
-
-       domain = (DomainContext *)calloc (sizeof (DomainContext), 1);
-       domain->next = ctx->domains;
-       ctx->domains = domain;
-       domain->domain_id = domain_id;
-
-       return domain;
-}
-
-static RemCtxContext *
-get_remctx (ProfContext *ctx, intptr_t remctx_id)
-{
-       if (ctx->current_remctx && ctx->current_remctx->remctx_id == remctx_id)
-               return ctx->current_remctx;
-
-       RemCtxContext *remctx = ctx->remctxs;
-
-       while (remctx) {
-               if (remctx->remctx_id == remctx_id)
-                       return remctx;
-
-               remctx = remctx->next;
-       }
-
-       remctx = (RemCtxContext *)calloc (sizeof (RemCtxContext), 1);
-       remctx->next = ctx->remctxs;
-       ctx->remctxs = remctx;
-       remctx->remctx_id = remctx_id;
-
-       return remctx;
-}
-
-static ThreadContext*
-load_thread (ProfContext *ctx, intptr_t thread_id)
-{
-       ThreadContext *thread = get_thread (ctx, thread_id);
-       ctx->current_thread = thread;
-       return thread;
-}
-
-static void
-ensure_thread_stack (ThreadContext *thread)
-{
-       if (thread->stack_id == thread->stack_size) {
-               thread->stack_size *= 2;
-               thread->stack = (MethodDesc **)realloc (thread->stack, thread->stack_size * sizeof (void*));
-               thread->time_stack = (uint64_t *)realloc (thread->time_stack, thread->stack_size * sizeof (uint64_t));
-               thread->callee_time_stack = (uint64_t *)realloc (thread->callee_time_stack, thread->stack_size * sizeof (uint64_t));
-       }
-}
-
-static int
-add_trace_hashed (CallContext *traces, int size, BackTrace *bt, uint64_t value)
-{
-       int i;
-       unsigned int start_pos;
-       start_pos = bt->hash % size;
-       i = start_pos;
-       do {
-               if (traces [i].bt == bt) {
-                       traces [i].count += value;
-                       return 0;
-               } else if (!traces [i].bt) {
-                       traces [i].bt = bt;
-                       traces [i].count += value;
-                       return 1;
-               }
-               /* wrap around */
-               if (++i == size)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       printf ("failed trace store\n");
-       return 0;
-}
-
-static void
-add_trace_bt (BackTrace *bt, TraceDesc *trace, uint64_t value)
-{
-       int i;
-       if (!collect_traces)
-               return;
-       if (trace->count * 2 >= trace->size) {
-               CallContext *n;
-               int old_size = trace->size;
-               trace->size *= 2;
-               if (trace->size == 0)
-                       trace->size = 4;
-               n = (CallContext *)calloc (sizeof (CallContext) * trace->size, 1);
-               for (i = 0; i < old_size; ++i) {
-                       if (trace->traces [i].bt)
-                               add_trace_hashed (n, trace->size, trace->traces [i].bt, trace->traces [i].count);
-               }
-               if (trace->traces)
-                       g_free (trace->traces);
-               trace->traces = n;
-       }
-       trace->count += add_trace_hashed (trace->traces, trace->size, bt, value);
-}
-
-static BackTrace*
-add_trace_thread (ThreadContext *thread, TraceDesc *trace, uint64_t value)
-{
-       BackTrace *bt;
-       int count = thread->stack_id;
-       if (!collect_traces)
-               return NULL;
-       if (count > trace_max)
-               count = trace_max;
-       bt = add_backtrace (count, thread->stack + thread->stack_id - count);
-       add_trace_bt (bt, trace, value);
-       return bt;
-}
-
-static BackTrace*
-add_trace_methods (MethodDesc **methods, int count, TraceDesc *trace, uint64_t value)
-{
-       BackTrace *bt;
-       if (!collect_traces)
-               return NULL;
-       if (count > trace_max)
-               count = trace_max;
-       bt = add_backtrace (count, methods);
-       add_trace_bt (bt, trace, value);
-       return bt;
-}
-
-static void
-thread_add_root (ThreadContext *ctx, uintptr_t obj, int root_type, uintptr_t extra_info)
-{
-       if (ctx->num_roots == ctx->size_roots) {
-               int new_size = ctx->size_roots * 2;
-               if (!new_size)
-                       new_size = 4;
-               ctx->roots = (uintptr_t *)realloc (ctx->roots, new_size * sizeof (uintptr_t));
-               ctx->roots_extra = (uintptr_t *)realloc (ctx->roots_extra, new_size * sizeof (uintptr_t));
-               ctx->roots_types = (int *)realloc (ctx->roots_types, new_size * sizeof (int));
-               ctx->size_roots = new_size;
-       }
-       ctx->roots_types [ctx->num_roots] = root_type;
-       ctx->roots_extra [ctx->num_roots] = extra_info;
-       ctx->roots [ctx->num_roots++] = obj;
-}
-
-static int
-compare_callc (const void *a, const void *b)
-{
-       const CallContext *A = (const CallContext *)a;
-       const CallContext *B = (const CallContext *)b;
-       if (B->count == A->count)
-               return 0;
-       if (B->count < A->count)
-               return -1;
-       return 1;
-}
-
-static void
-sort_context_array (TraceDesc* traces)
-{
-       int i, j;
-       for (i = 0, j = 0; i < traces->size; ++i) {
-               if (traces->traces [i].bt) {
-                       traces->traces [j].bt = traces->traces [i].bt;
-                       traces->traces [j].count = traces->traces [i].count;
-                       j++;
-               }
-       }
-       qsort (traces->traces, traces->count, sizeof (CallContext), compare_callc);
-}
-
-static void
-push_method (ThreadContext *thread, MethodDesc *method, uint64_t timestamp)
-{
-       ensure_thread_stack (thread);
-       thread->time_stack [thread->stack_id] = timestamp;
-       thread->callee_time_stack [thread->stack_id] = 0;
-       thread->stack [thread->stack_id++] = method;
-       method->recurse_count++;
-}
-
-static void
-pop_method (ThreadContext *thread, MethodDesc *method, uint64_t timestamp)
-{
-       method->recurse_count--;
-       if (thread->stack_id > 0 && thread->stack [thread->stack_id - 1] == method) {
-               uint64_t tdiff;
-               thread->stack_id--;
-               method->calls++;
-               if (timestamp < thread->time_stack [thread->stack_id])
-                       fprintf (outfile, "time went backwards for %s\n", method->name);
-               tdiff = timestamp - thread->time_stack [thread->stack_id];
-               if (thread->callee_time_stack [thread->stack_id] > tdiff)
-                       fprintf (outfile, "callee time bigger for %s\n", method->name);
-               method->self_time += tdiff - thread->callee_time_stack [thread->stack_id];
-               method->callee_time += thread->callee_time_stack [thread->stack_id];
-               if (thread->stack_id)
-                       thread->callee_time_stack [thread->stack_id - 1] += tdiff;
-               //fprintf (outfile, "method %s took %d\n", method->name, (int)(tdiff/1000));
-       } else {
-               fprintf (outfile, "unmatched leave at stack pos: %d for method %s\n", thread->stack_id, method->name);
-       }
-}
-
-typedef struct {
-       uint64_t total_time;
-       uint64_t max_time;
-       int count;
-} GCDesc;
-static GCDesc gc_info [3];
-static uint64_t max_heap_size;
-static uint64_t gc_object_moves;
-static int gc_resizes;
-typedef struct {
-       uint64_t created;
-       uint64_t destroyed;
-       uint64_t live;
-       uint64_t max_live;
-       TraceDesc traces;
-       TraceDesc destroy_traces;
-} HandleInfo;
-static HandleInfo handle_info [4];
-
-static const char*
-gc_event_name (int ev)
-{
-       switch (ev) {
-       case MONO_GC_EVENT_START: return "start";
-       case MONO_GC_EVENT_MARK_START: return "mark start";
-       case MONO_GC_EVENT_MARK_END: return "mark end";
-       case MONO_GC_EVENT_RECLAIM_START: return "reclaim start";
-       case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
-       case MONO_GC_EVENT_END: return "end";
-       case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
-       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
-       case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
-       case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
-       case MONO_GC_EVENT_POST_START_WORLD: return "post start";
-       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
-       default:
-               return "unknown";
-       }
-}
-
-static const char*
-sync_point_name (int type)
-{
-       switch (type) {
-       case SYNC_POINT_PERIODIC: return "periodic";
-       case SYNC_POINT_WORLD_STOP: return "world stop";
-       case SYNC_POINT_WORLD_START: return "world start";
-       default:
-               return "unknown";
-       }
-}
-
-static uint64_t clause_summary [MONO_EXCEPTION_CLAUSE_FAULT + 1];
-static uint64_t throw_count = 0;
-static TraceDesc exc_traces;
-
-static const char*
-clause_name (int type)
-{
-       switch (type) {
-       case MONO_EXCEPTION_CLAUSE_NONE: return "catch";
-       case MONO_EXCEPTION_CLAUSE_FILTER: return "filter";
-       case MONO_EXCEPTION_CLAUSE_FINALLY: return "finally";
-       case MONO_EXCEPTION_CLAUSE_FAULT: return "fault";
-       default: return "invalid";
-       }
-}
-
-static uint64_t monitor_contention;
-static uint64_t monitor_failed;
-static uint64_t monitor_acquired;
-
-struct _MonitorDesc {
-       MonitorDesc *next;
-       uintptr_t objid;
-       uintptr_t contentions;
-       uint64_t wait_time;
-       uint64_t max_wait_time;
-       TraceDesc traces;
-};
-
-static MonitorDesc* monitor_hash [SMALL_HASH_SIZE] = {0};
-static int num_monitors = 0;
-
-static MonitorDesc*
-lookup_monitor (uintptr_t objid)
-{
-       int slot = ((objid >> 3) & 0xffff) % SMALL_HASH_SIZE;
-       MonitorDesc *cd = monitor_hash [slot];
-       while (cd && cd->objid != objid)
-               cd = cd->next;
-       if (!cd) {
-               cd = (MonitorDesc *)calloc (sizeof (MonitorDesc), 1);
-               cd->objid = objid;
-               cd->next = monitor_hash [slot];
-               monitor_hash [slot] = cd;
-               num_monitors++;
-       }
-       return cd;
-}
-
-static const char*
-monitor_ev_name (int ev)
-{
-       switch (ev) {
-       case MONO_PROFILER_MONITOR_CONTENTION: return "contended";
-       case MONO_PROFILER_MONITOR_DONE: return "acquired";
-       case MONO_PROFILER_MONITOR_FAIL: return "not taken";
-       default: return "invalid";
-       }
-}
-
-static const char*
-get_handle_name (int htype)
-{
-       switch (htype) {
-       case 0: return "weak";
-       case 1: return "weaktrack";
-       case 2: return "normal";
-       case 3: return "pinned";
-       default: return "unknown";
-       }
-}
-
-static const char*
-get_root_name (int rtype)
-{
-       switch (rtype & MONO_PROFILE_GC_ROOT_TYPEMASK) {
-       case MONO_PROFILE_GC_ROOT_STACK: return "stack";
-       case MONO_PROFILE_GC_ROOT_FINALIZER: return "finalizer";
-       case MONO_PROFILE_GC_ROOT_HANDLE: return "handle";
-       case MONO_PROFILE_GC_ROOT_OTHER: return "other";
-       case MONO_PROFILE_GC_ROOT_MISC: return "misc";
-       default: return "unknown";
-       }
-}
-
-static MethodDesc**
-decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
-{
-       MethodDesc **frames;
-       int i;
-       if (ctx->data_version < 13)
-               decode_uleb128 (p, &p); /* flags */
-       int count = decode_uleb128 (p, &p);
-       if (count > *size)
-               frames = (MethodDesc **)malloc (count * sizeof (void*));
-       else
-               frames = sframes;
-       for (i = 0; i < count; ++i) {
-               intptr_t ptrdiff = decode_sleb128 (p, &p);
-               if (ctx->data_version > 12) {
-                       *method_base += ptrdiff;
-                       frames [i] = lookup_method (*method_base);
-               } else {
-                       frames [i] = lookup_method (ptr_base + ptrdiff);
-               }
-       }
-       *size = count;
-       *endp = p;
-       return frames;
-}
-
-static void
-tracked_creation (uintptr_t obj, ClassDesc *cd, uint64_t size, BackTrace *bt, uint64_t timestamp)
-{
-       int i;
-       for (i = 0; i < num_tracked_objects; ++i) {
-               if (tracked_objects [i] != obj)
-                       continue;
-               fprintf (outfile, "Object %p created (%s, %llu bytes) at %.3f secs.\n", (void*)obj, cd->name, (unsigned long long) size, (timestamp - startup_time)/1000000000.0);
-               if (bt && bt->count) {
-                       int k;
-                       for (k = 0; k < bt->count; ++k)
-                               fprintf (outfile, "\t%s\n", bt->methods [k]->name);
-               }
-       }
-}
-
-static void
-track_handle (uintptr_t obj, int htype, uint32_t handle, BackTrace *bt, uint64_t timestamp)
-{
-       int i;
-       for (i = 0; i < num_tracked_objects; ++i) {
-               if (tracked_objects [i] != obj)
-                       continue;
-               fprintf (outfile, "Object %p referenced from handle %u at %.3f secs.\n", (void*)obj, handle, (timestamp - startup_time) / 1000000000.0);
-               if (bt && bt->count) {
-                       int k;
-                       for (k = 0; k < bt->count; ++k)
-                               fprintf (outfile, "\t%s\n", bt->methods [k]->name);
-               }
-       }
-}
-
-static void
-track_move (uintptr_t src, uintptr_t dst)
-{
-       int i;
-       for (i = 0; i < num_tracked_objects; ++i) {
-               if (tracked_objects [i] == src)
-                       fprintf (outfile, "Object %p moved to %p\n", (void*)src, (void*)dst);
-               else if (tracked_objects [i] == dst)
-                       fprintf (outfile, "Object %p moved from %p\n", (void*)dst, (void*)src);
-       }
-}
-
-static void
-track_obj_reference (uintptr_t obj, uintptr_t parent, ClassDesc *cd)
-{
-       int i;
-       for (i = 0; i < num_tracked_objects; ++i) {
-               if (tracked_objects [i] == obj)
-                       fprintf (outfile, "Object %p referenced from %p (%s).\n", (void*)obj, (void*)parent, cd->name);
-       }
-}
-
-static void
-found_object (uintptr_t obj)
-{
-       num_tracked_objects ++;
-       tracked_objects = (uintptr_t *)realloc (tracked_objects, num_tracked_objects * sizeof (tracked_objects [0]));
-       tracked_objects [num_tracked_objects - 1] = obj;
-}
-
-static int num_jit_helpers = 0;
-static int jit_helpers_code_size = 0;
-
-static const char*
-code_buffer_desc (int type)
-{
-       switch (type) {
-       case MONO_PROFILER_CODE_BUFFER_METHOD:
-               return "method";
-       case MONO_PROFILER_CODE_BUFFER_METHOD_TRAMPOLINE:
-               return "method trampoline";
-       case MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE:
-               return "unbox trampoline";
-       case MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE:
-               return "imt trampoline";
-       case MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE:
-               return "generics trampoline";
-       case MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE:
-               return "specific trampoline";
-       case MONO_PROFILER_CODE_BUFFER_HELPER:
-               return "misc helper";
-       case MONO_PROFILER_CODE_BUFFER_MONITOR:
-               return "monitor/lock";
-       case MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE:
-               return "delegate invoke";
-       case MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING:
-               return "exception handling";
-       default:
-               return "unspecified";
-       }
-}
-
-typedef struct _CoverageAssembly CoverageAssembly;
-struct _CoverageAssembly {
-       char *name;
-       char *guid;
-       char *filename;
-       int number_of_methods;
-       int fully_covered;
-       int partially_covered;
-};
-
-typedef struct _CoverageClass CoverageClass;
-struct _CoverageClass {
-       char *assembly_name;
-       char *class_name;
-       int number_of_methods;
-       int fully_covered;
-       int partially_covered;
-};
-
-typedef struct _CoverageCoverage CoverageCoverage;
-struct _CoverageCoverage {
-       int method_id;
-       int offset;
-       int count;
-       int line;
-       int column;
-};
-
-typedef struct _CoverageMethod CoverageMethod;
-struct _CoverageMethod {
-       char *assembly_name;
-       char *class_name;
-       char *method_name;
-       char *method_signature;
-       char *filename;
-       int token;
-       int n_statements;
-       int method_id;
-       GPtrArray *coverage;
-};
-static GPtrArray *coverage_assemblies = NULL;
-static GPtrArray *coverage_methods = NULL;
-static GPtrArray *coverage_statements = NULL;
-static GHashTable *coverage_methods_hash = NULL;
-static GPtrArray *coverage_classes = NULL;
-static GHashTable *coverage_assembly_classes = NULL;
-
-static void
-gather_coverage_statements (void)
-{
-       for (guint i = 0; i < coverage_statements->len; i++) {
-               CoverageCoverage *coverage = (CoverageCoverage *)coverage_statements->pdata[i];
-               CoverageMethod *method = (CoverageMethod *)g_hash_table_lookup (coverage_methods_hash, GINT_TO_POINTER (coverage->method_id));
-               if (method == NULL) {
-                       fprintf (outfile, "Cannot find method with ID: %d\n", coverage->method_id);
-                       continue;
-               }
-
-               g_ptr_array_add (method->coverage, coverage);
-       }
-}
-
-static void
-coverage_add_assembly (CoverageAssembly *assembly)
-{
-       if (coverage_assemblies == NULL)
-               coverage_assemblies = g_ptr_array_new ();
-
-       g_ptr_array_add (coverage_assemblies, assembly);
-}
-
-static void
-coverage_add_method (CoverageMethod *method)
-{
-       if (coverage_methods == NULL) {
-               coverage_methods = g_ptr_array_new ();
-               coverage_methods_hash = g_hash_table_new (NULL, NULL);
-       }
-
-       g_ptr_array_add (coverage_methods, method);
-       g_hash_table_insert (coverage_methods_hash, GINT_TO_POINTER (method->method_id), method);
-}
-
-static void
-coverage_add_class (CoverageClass *klass)
-{
-       GPtrArray *classes = NULL;
-
-       if (coverage_classes == NULL) {
-               coverage_classes = g_ptr_array_new ();
-               coverage_assembly_classes = g_hash_table_new (g_str_hash, g_str_equal);
-       }
-
-       g_ptr_array_add (coverage_classes, klass);
-       classes = (GPtrArray *)g_hash_table_lookup (coverage_assembly_classes, klass->assembly_name);
-       if (classes == NULL) {
-               classes = g_ptr_array_new ();
-               g_hash_table_insert (coverage_assembly_classes, klass->assembly_name, classes);
-       }
-       g_ptr_array_add (classes, klass);
-}
-
-static void
-coverage_add_coverage (CoverageCoverage *coverage)
-{
-       if (coverage_statements == NULL)
-               coverage_statements = g_ptr_array_new ();
-
-       g_ptr_array_add (coverage_statements, coverage);
-}
-
-#define OBJ_ADDR(diff) ((obj_base + diff) << 3)
-#define LOG_TIME(base,diff) /*fprintf("outfile, time %llu + %llu near offset %d\n", base, diff, p - ctx->buf)*/
-
-
-/* Stats */
-#define BUFFER_HEADER_SIZE 48
-
-typedef struct {
-       int count, min_size, max_size, bytes;
-} EventStat;
-
-static int buffer_count;
-static EventStat stats [256];
-
-static void
-record_event_stats (int type, int size)
-{
-       ++stats [type].count;
-       if (!stats [type].min_size)
-               stats [type].min_size = size;
-       stats [type].min_size = MIN (stats [type].min_size, size);
-       stats [type].max_size = MAX (stats [type].max_size, size);
-       stats [type].bytes += size;
-}
-
-static int
-decode_buffer (ProfContext *ctx)
-{
-       unsigned char *p;
-       unsigned char *end;
-       intptr_t thread_id;
-       intptr_t ptr_base;
-       intptr_t obj_base;
-       intptr_t method_base;
-       uint64_t time_base;
-       uint64_t file_offset;
-       int len, i;
-       ThreadContext *thread;
-
-#ifdef HAVE_SYS_ZLIB
-       if (ctx->gzfile)
-               file_offset = gztell (ctx->gzfile);
-       else
-#endif
-               file_offset = ftell (ctx->file);
-       if (!load_data (ctx, 48))
-               return 0;
-       p = ctx->buf;
-       if (read_int32 (p) != BUF_ID) {
-               fprintf (outfile, "Incorrect buffer id: 0x%x\n", read_int32 (p));
-               for (i = 0; i < 48; ++i) {
-                       fprintf (outfile, "0x%x%s", p [i], i % 8?" ":"\n");
-               }
-               return 0;
-       }
-       len = read_int32 (p + 4);
-       time_base = read_int64 (p + 8);
-       ptr_base = read_int64 (p + 16);
-       obj_base = read_int64 (p + 24);
-       thread_id = read_int64 (p + 32);
-       method_base = read_int64 (p + 40);
-       if (debug)
-               fprintf (outfile, "buf: thread:%zx, len: %d, time: %llu, file offset: %llu\n", thread_id, len, (unsigned long long) time_base, (unsigned long long) file_offset);
-       thread = load_thread (ctx, thread_id);
-       if (!load_data (ctx, len))
-               return 0;
-
-       ++buffer_count;
-
-       if (!startup_time) {
-               startup_time = time_base;
-               if (use_time_filter) {
-                       time_from += startup_time;
-                       time_to += startup_time;
-               }
-       }
-       for (i = 0; i < thread->stack_id; ++i)
-               thread->stack [i]->recurse_count++;
-       p = ctx->buf;
-       end = p + len;
-       while (p < end) {
-               unsigned char *start = p;
-               unsigned char event = *p;
-               switch (*p & 0xf) {
-               case TYPE_GC: {
-                       int subtype = *p & 0xf0;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       if (subtype == TYPE_GC_RESIZE) {
-                               uint64_t new_size = decode_uleb128 (p, &p);
-                               if (debug)
-                                       fprintf (outfile, "gc heap resized to %llu\n", (unsigned long long) new_size);
-                               gc_resizes++;
-                               if (new_size > max_heap_size)
-                                       max_heap_size = new_size;
-                       } else if (subtype == TYPE_GC_EVENT) {
-                               uint64_t ev;
-                               if (ctx->data_version > 12)
-                                       ev = *p++;
-                               else
-                                       ev = decode_uleb128 (p, &p);
-                               int gen;
-                               if (ctx->data_version > 12)
-                                       gen = *p++;
-                               else
-                                       gen = decode_uleb128 (p, &p);
-                               if (debug)
-                                       fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
-                               if (gen > 2) {
-                                       fprintf (outfile, "incorrect gc gen: %d\n", gen);
-                                       break;
-                               }
-                               if (ev == MONO_GC_EVENT_START) {
-                                       thread->gc_start_times [gen] = time_base;
-                                       gc_info [gen].count++;
-                               } else if (ev == MONO_GC_EVENT_END) {
-                                       tdiff = time_base - thread->gc_start_times [gen];
-                                       gc_info [gen].total_time += tdiff;
-                                       if (tdiff > gc_info [gen].max_time)
-                                               gc_info [gen].max_time = tdiff;
-                               }
-                       } else if (subtype == TYPE_GC_MOVE) {
-                               int j, num = decode_uleb128 (p, &p);
-                               gc_object_moves += num / 2;
-                               for (j = 0; j < num; j += 2) {
-                                       intptr_t obj1diff = decode_sleb128 (p, &p);
-                                       intptr_t obj2diff = decode_sleb128 (p, &p);
-                                       if (num_tracked_objects)
-                                               track_move (OBJ_ADDR (obj1diff), OBJ_ADDR (obj2diff));
-                                       if (debug) {
-                                               fprintf (outfile, "moved obj %p to %p\n", (void*)OBJ_ADDR (obj1diff), (void*)OBJ_ADDR (obj2diff));
-                                       }
-                               }
-                       } else if (subtype == TYPE_GC_HANDLE_CREATED || subtype == TYPE_GC_HANDLE_CREATED_BT) {
-                               int has_bt = subtype == TYPE_GC_HANDLE_CREATED_BT;
-                               int num_bt = 0;
-                               MethodDesc *sframes [8];
-                               MethodDesc **frames = sframes;
-                               int htype = decode_uleb128 (p, &p);
-                               uint32_t handle = decode_uleb128 (p, &p);
-                               intptr_t objdiff = decode_sleb128 (p, &p);
-                               if (has_bt) {
-                                       num_bt = 8;
-                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
-                                       if (!frames) {
-                                               fprintf (outfile, "Cannot load backtrace\n");
-                                               return 0;
-                                       }
-                               }
-                               if (htype > 3)
-                                       return 0;
-                               if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
-                                       handle_info [htype].created++;
-                                       handle_info [htype].live++;
-                                       if (handle_info [htype].live > handle_info [htype].max_live)
-                                               handle_info [htype].max_live = handle_info [htype].live;
-                                       BackTrace *bt;
-                                       if (has_bt)
-                                               bt = add_trace_methods (frames, num_bt, &handle_info [htype].traces, 1);
-                                       else
-                                               bt = add_trace_thread (thread, &handle_info [htype].traces, 1);
-                                       if (num_tracked_objects)
-                                               track_handle (OBJ_ADDR (objdiff), htype, handle, bt, time_base);
-                               }
-                               if (debug)
-                                       fprintf (outfile, "handle (%s) %u created for object %p\n", get_handle_name (htype), handle, (void*)OBJ_ADDR (objdiff));
-                               if (frames != sframes)
-                                       g_free (frames);
-                       } else if (subtype == TYPE_GC_HANDLE_DESTROYED || subtype == TYPE_GC_HANDLE_DESTROYED_BT) {
-                               int has_bt = subtype == TYPE_GC_HANDLE_DESTROYED_BT;
-                               int num_bt = 0;
-                               MethodDesc *sframes [8];
-                               MethodDesc **frames = sframes;
-                               int htype = decode_uleb128 (p, &p);
-                               uint32_t handle = decode_uleb128 (p, &p);
-                               if (has_bt) {
-                                       num_bt = 8;
-                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
-                                       if (!frames) {
-                                               fprintf (outfile, "Cannot load backtrace\n");
-                                               return 0;
-                                       }
-                               }
-                               if (htype > 3)
-                                       return 0;
-                               if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
-                                       handle_info [htype].destroyed ++;
-                                       handle_info [htype].live--;
-                                       BackTrace *bt;
-                                       if (has_bt)
-                                               bt = add_trace_methods (frames, num_bt, &handle_info [htype].destroy_traces, 1);
-                                       else
-                                               bt = add_trace_thread (thread, &handle_info [htype].destroy_traces, 1);
-                                       /* TODO: track_handle_free () - would need to record and keep track of the associated object address... */
-                               }
-                               if (debug)
-                                       fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
-                               if (frames != sframes)
-                                       g_free (frames);
-                       } else if (subtype == TYPE_GC_FINALIZE_START) {
-                               // TODO: Generate a finalizer report based on these events.
-                               if (debug)
-                                       fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
-                       } else if (subtype == TYPE_GC_FINALIZE_END) {
-                               if (debug)
-                                       fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
-                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
-                               intptr_t objdiff = decode_sleb128 (p, &p);
-                               if (debug)
-                                       fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
-                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
-                               intptr_t objdiff = decode_sleb128 (p, &p);
-                               if (debug)
-                                       fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
-                       }
-                       break;
-               }
-               case TYPE_METADATA: {
-                       int subtype = *p & 0xf0;
-                       const char *load_str = subtype == TYPE_END_LOAD ? "loaded" : "unloaded";
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       int mtype = *p++;
-                       intptr_t ptrdiff = decode_sleb128 (p, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       if (mtype == TYPE_CLASS) {
-                               intptr_t imptrdiff = decode_sleb128 (p, &p);
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               if (debug)
-                                       fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
-                               if (subtype == TYPE_END_LOAD)
-                                       add_class (ptr_base + ptrdiff, (char*)p);
-                               while (*p) p++;
-                               p++;
-                       } else if (mtype == TYPE_IMAGE) {
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               if (debug)
-                                       fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
-                               if (subtype == TYPE_END_LOAD)
-                                       add_image (ptr_base + ptrdiff, (char*)p);
-                               while (*p) p++;
-                               p++;
-                       } else if (mtype == TYPE_ASSEMBLY) {
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               if (debug)
-                                       fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
-                               if (subtype == TYPE_END_LOAD)
-                                       add_assembly (ptr_base + ptrdiff, (char*)p);
-                               while (*p) p++;
-                               p++;
-                       } else if (mtype == TYPE_DOMAIN) {
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
-                               /* no subtype means it's a name event, rather than start/stop */
-                               if (subtype == 0)
-                                       nd->friendly_name = pstrdup ((char *) p);
-                               if (debug) {
-                                       if (subtype == 0)
-                                               fprintf (outfile, "domain %p named at %llu: %s\n", (void *) (ptr_base + ptrdiff), (unsigned long long) time_base, p);
-                                       else
-                                               fprintf (outfile, "%s thread %p at %llu\n", load_str, (void *) (ptr_base + ptrdiff), (unsigned long long) time_base);
-                               }
-                               if (subtype == 0) {
-                                       while (*p) p++;
-                                       p++;
-                               }
-                       } else if (mtype == TYPE_CONTEXT) {
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               intptr_t domaindiff = decode_sleb128 (p, &p);
-                               if (debug)
-                                       fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
-                               if (subtype == TYPE_END_LOAD)
-                                       get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
-                       } else if (mtype == TYPE_THREAD) {
-                               if (ctx->data_version < 13)
-                                       decode_uleb128 (p, &p); /* flags */
-                               ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
-                               /* no subtype means it's a name event, rather than start/stop */
-                               if (subtype == 0)
-                                       nt->name = pstrdup ((char*)p);
-                               if (debug) {
-                                       if (subtype == 0)
-                                               fprintf (outfile, "thread %p named at %llu: %s\n", (void*)(ptr_base + ptrdiff), (unsigned long long) time_base, p);
-                                       else
-                                               fprintf (outfile, "%s thread %p at %llu\n", load_str, (void *) (ptr_base + ptrdiff), (unsigned long long) time_base);
-                               }
-                               if (subtype == 0) {
-                                       while (*p) p++;
-                                       p++;
-                               }
-                       }
-                       break;
-               }
-               case TYPE_ALLOC: {
-                       int has_bt = *p & TYPE_ALLOC_BT;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       intptr_t ptrdiff = decode_sleb128 (p, &p);
-                       intptr_t objdiff = decode_sleb128 (p, &p);
-                       uint64_t len;
-                       int num_bt = 0;
-                       MethodDesc* sframes [8];
-                       MethodDesc** frames = sframes;
-                       ClassDesc *cd = lookup_class (ptr_base + ptrdiff);
-                       len = decode_uleb128 (p, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       if (debug)
-                               fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
-                       if (has_bt) {
-                               num_bt = 8;
-                               frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
-                               if (!frames) {
-                                       fprintf (outfile, "Cannot load backtrace\n");
-                                       return 0;
-                               }
-                       }
-                       if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
-                               BackTrace *bt;
-                               cd->allocs++;
-                               cd->alloc_size += len;
-                               if (has_bt)
-                                       bt = add_trace_methods (frames, num_bt, &cd->traces, len);
-                               else
-                                       bt = add_trace_thread (thread, &cd->traces, len);
-                               if (find_size && len >= find_size) {
-                                       if (!find_name || strstr (cd->name, find_name))
-                                               found_object (OBJ_ADDR (objdiff));
-                               } else if (!find_size && find_name && strstr (cd->name, find_name)) {
-                                       found_object (OBJ_ADDR (objdiff));
-                               }
-                               if (num_tracked_objects)
-                                       tracked_creation (OBJ_ADDR (objdiff), cd, len, bt, time_base);
-                       }
-                       if (frames != sframes)
-                               g_free (frames);
-                       break;
-               }
-               case TYPE_METHOD: {
-                       int subtype = *p & 0xf0;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       int64_t ptrdiff = decode_sleb128 (p, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       method_base += ptrdiff;
-                       if (subtype == TYPE_JIT) {
-                               intptr_t codediff = decode_sleb128 (p, &p);
-                               int codelen = decode_uleb128 (p, &p);
-                               MethodDesc *jitted_method;
-                               if (debug)
-                                       fprintf (outfile, "jitted method %p (%s), size: %d, code: %p\n", (void*)(method_base), p, codelen, (void*)(ptr_base + codediff));
-                               jitted_method = add_method (method_base, (char*)p, ptr_base + codediff, codelen);
-                               if (!(time_base >= time_from && time_base < time_to))
-                                       jitted_method->ignore_jit = 1;
-                               while (*p) p++;
-                               p++;
-                       } else {
-                               MethodDesc *method;
-                               if ((thread_filter && thread_filter != thread->thread_id))
-                                       break;
-                               if (!(time_base >= time_from && time_base < time_to))
-                                       break;
-                               method = lookup_method (method_base);
-                               if (subtype == TYPE_ENTER) {
-                                       add_trace_thread (thread, &method->traces, 1);
-                                       push_method (thread, method, time_base);
-                               } else {
-                                       pop_method (thread, method, time_base);
-                               }
-                               if (debug)
-                                       fprintf (outfile, "%s method %s\n", subtype == TYPE_ENTER? "enter": subtype == TYPE_EXC_LEAVE? "exleave": "leave", method->name);
-                       }
-                       break;
-               }
-               case TYPE_HEAP: {
-                       int subtype = *p & 0xf0;
-                       if (subtype == TYPE_HEAP_OBJECT) {
-                               HeapObjectDesc *ho = NULL;
-                               int i;
-                               intptr_t objdiff;
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       objdiff = decode_sleb128 (p, &p);
-                               } else
-                                       objdiff = decode_sleb128 (p + 1, &p);
-                               intptr_t ptrdiff = decode_sleb128 (p, &p);
-                               uint64_t size = decode_uleb128 (p, &p);
-                               uintptr_t num = decode_uleb128 (p, &p);
-                               uintptr_t ref_offset = 0;
-                               uintptr_t last_obj_offset = 0;
-                               ClassDesc *cd = lookup_class (ptr_base + ptrdiff);
-                               if (size) {
-                                       HeapClassDesc *hcd = add_heap_shot_class (thread->current_heap_shot, cd, size);
-                                       if (collect_traces) {
-                                               ho = alloc_heap_obj (OBJ_ADDR (objdiff), hcd, num);
-                                               add_heap_shot_obj (thread->current_heap_shot, ho);
-                                               ref_offset = 0;
-                                       }
-                               } else {
-                                       if (collect_traces)
-                                               ho = heap_shot_obj_add_refs (thread->current_heap_shot, OBJ_ADDR (objdiff), num, &ref_offset);
-                               }
-                               for (i = 0; i < num; ++i) {
-                                       /* FIXME: use object distance to measure how good
-                                        * the GC is at keeping related objects close
-                                        */
-                                       uintptr_t offset = ctx->data_version > 1? last_obj_offset + decode_uleb128 (p, &p): -1;
-                                       intptr_t obj1diff = decode_sleb128 (p, &p);
-                                       last_obj_offset = offset;
-                                       if (collect_traces)
-                                               ho->refs [ref_offset + i] = OBJ_ADDR (obj1diff);
-                                       if (num_tracked_objects)
-                                               track_obj_reference (OBJ_ADDR (obj1diff), OBJ_ADDR (objdiff), cd);
-                               }
-                               if (debug && size)
-                                       fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
-                       } else if (subtype == TYPE_HEAP_ROOT) {
-                               uintptr_t num;
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       num = decode_uleb128 (p, &p);
-                               } else
-                                       num = decode_uleb128 (p + 1, &p);
-                               uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
-                               int i;
-                               for (i = 0; i < num; ++i) {
-                                       intptr_t objdiff = decode_sleb128 (p, &p);
-                                       int root_type;
-                                       if (ctx->data_version > 12)
-                                               root_type = *p++;
-                                       else
-                                               root_type = decode_uleb128 (p, &p);
-                                       /* we just discard the extra info for now */
-                                       uintptr_t extra_info = decode_uleb128 (p, &p);
-                                       if (debug)
-                                               fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type));
-                                       if (collect_traces)
-                                               thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info);
-                               }
-                       } else if (subtype == TYPE_HEAP_END) {
-                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                               LOG_TIME (time_base, tdiff);
-                               time_base += tdiff;
-                               if (debug)
-                                       fprintf (outfile, "heap shot end\n");
-                               if (collect_traces) {
-                                       HeapShot *hs = thread->current_heap_shot;
-                                       if (hs && thread->num_roots) {
-                                               /* transfer the root ownershipt to the heapshot */
-                                               hs->num_roots = thread->num_roots;
-                                               hs->roots = thread->roots;
-                                               hs->roots_extra = thread->roots_extra;
-                                               hs->roots_types = thread->roots_types;
-                                       } else {
-                                               g_free (thread->roots);
-                                               g_free (thread->roots_extra);
-                                               g_free (thread->roots_types);
-                                       }
-                                       thread->num_roots = 0;
-                                       thread->size_roots = 0;
-                                       thread->roots = NULL;
-                                       thread->roots_extra = NULL;
-                                       thread->roots_types = NULL;
-                                       heap_shot_resolve_reverse_refs (hs);
-                                       heap_shot_mark_objects (hs);
-                                       heap_shot_free_objects (hs);
-                               }
-                               thread->current_heap_shot = NULL;
-                       } else if (subtype == TYPE_HEAP_START) {
-                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                               LOG_TIME (time_base, tdiff);
-                               time_base += tdiff;
-                               if (debug)
-                                       fprintf (outfile, "heap shot start\n");
-                               thread->current_heap_shot = new_heap_shot (time_base);
-                       }
-                       break;
-               }
-               case TYPE_MONITOR: {
-                       int event = (*p >> 4) & 0x3;
-                       int has_bt = *p & TYPE_MONITOR_BT;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       intptr_t objdiff = decode_sleb128 (p, &p);
-                       MethodDesc* sframes [8];
-                       MethodDesc** frames = sframes;
-                       int record;
-                       int num_bt = 0;
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       record = (!thread_filter || thread_filter == thread->thread_id);
-                       if (!(time_base >= time_from && time_base < time_to))
-                               record = 0;
-                       if (event == MONO_PROFILER_MONITOR_CONTENTION) {
-                               MonitorDesc *mdesc = lookup_monitor (OBJ_ADDR (objdiff));
-                               if (record) {
-                                       monitor_contention++;
-                                       mdesc->contentions++;
-                                       thread->monitor = mdesc;
-                                       thread->contention_start = time_base;
-                               }
-                               if (has_bt) {
-                                       num_bt = 8;
-                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
-                                       if (!frames) {
-                                               fprintf (outfile, "Cannot load backtrace\n");
-                                               return 0;
-                                       }
-                                       if (record)
-                                               add_trace_methods (frames, num_bt, &mdesc->traces, 1);
-                               } else {
-                                       if (record)
-                                               add_trace_thread (thread, &mdesc->traces, 1);
-                               }
-                       } else if (event == MONO_PROFILER_MONITOR_FAIL) {
-                               if (record) {
-                                       monitor_failed++;
-                                       if (thread->monitor && thread->contention_start) {
-                                               uint64_t wait_time = time_base - thread->contention_start;
-                                               if (wait_time > thread->monitor->max_wait_time)
-                                                       thread->monitor->max_wait_time = wait_time;
-                                               thread->monitor->wait_time += wait_time;
-                                               thread->monitor = NULL;
-                                               thread->contention_start = 0;
-                                       }
-                               }
-                       } else if (event == MONO_PROFILER_MONITOR_DONE) {
-                               if (record) {
-                                       monitor_acquired++;
-                                       if (thread->monitor && thread->contention_start) {
-                                               uint64_t wait_time = time_base - thread->contention_start;
-                                               if (wait_time > thread->monitor->max_wait_time)
-                                                       thread->monitor->max_wait_time = wait_time;
-                                               thread->monitor->wait_time += wait_time;
-                                               thread->monitor = NULL;
-                                               thread->contention_start = 0;
-                                       }
-                               }
-                       }
-                       if (debug)
-                               fprintf (outfile, "monitor %s for object %p\n", monitor_ev_name (event), (void*)OBJ_ADDR (objdiff));
-                       if (frames != sframes)
-                               g_free (frames);
-                       break;
-               }
-               case TYPE_EXCEPTION: {
-                       int subtype = *p & 0x70;
-                       int has_bt = *p & TYPE_THROW_BT;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       MethodDesc* sframes [8];
-                       MethodDesc** frames = sframes;
-                       int record;
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       record = (!thread_filter || thread_filter == thread->thread_id);
-                       if (!(time_base >= time_from && time_base < time_to))
-                               record = 0;
-                       if (subtype == TYPE_CLAUSE) {
-                               int clause_type;
-                               if (ctx->data_version > 12)
-                                       clause_type = *p++;
-                               else
-                                       clause_type = decode_uleb128 (p, &p);
-                               int clause_num = decode_uleb128 (p, &p);
-                               int64_t ptrdiff = decode_sleb128 (p, &p);
-                               method_base += ptrdiff;
-                               if (record)
-                                       clause_summary [clause_type]++;
-                               if (debug)
-                                       fprintf (outfile, "clause %s (%d) in method %s\n", clause_name (clause_type), clause_num, lookup_method (method_base)->name);
-                       } else {
-                               intptr_t objdiff = decode_sleb128 (p, &p);
-                               if (record)
-                                       throw_count++;
-                               if (has_bt) {
-                                       has_bt = 8;
-                                       frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
-                                       if (!frames) {
-                                               fprintf (outfile, "Cannot load backtrace\n");
-                                               return 0;
-                                       }
-                                       if (record)
-                                               add_trace_methods (frames, has_bt, &exc_traces, 1);
-                               } else {
-                                       if (record)
-                                               add_trace_thread (thread, &exc_traces, 1);
-                               }
-                               if (frames != sframes)
-                                       g_free (frames);
-                               if (debug)
-                                       fprintf (outfile, "throw %p\n", (void*)OBJ_ADDR (objdiff));
-                       }
-                       break;
-               }
-               case TYPE_RUNTIME: {
-                       int subtype = *p & 0xf0;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       if (subtype == TYPE_JITHELPER) {
-                               int type;
-                               if (ctx->data_version > 12)
-                                       type = *p++;
-                               else
-                                       type = decode_uleb128 (p, &p);
-                               intptr_t codediff = decode_sleb128 (p, &p);
-                               int codelen = decode_uleb128 (p, &p);
-                               const char *name;
-                               if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
-                                       name = (const char *)p;
-                                       while (*p) p++;
-                                               p++;
-                               } else {
-                                       name = code_buffer_desc (type);
-                               }
-                               num_jit_helpers++;
-                               jit_helpers_code_size += codelen;
-                               if (debug)
-                                       fprintf (outfile, "jit helper %s, size: %d, code: %p\n", name, codelen, (void*)(ptr_base + codediff));
-                       }
-                       break;
-               }
-               case TYPE_SAMPLE: {
-                       int subtype = *p & 0xf0;
-                       if (subtype == TYPE_SAMPLE_HIT) {
-                               int i;
-                               int sample_type;
-                               uint64_t tstamp;
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       sample_type = *p++;
-                                       tstamp = time_base;
-                               } else {
-                                       sample_type = decode_uleb128 (p + 1, &p);
-                                       tstamp = decode_uleb128 (p, &p);
-                               }
-                               void *tid = (void *) thread_id;
-                               if (ctx->data_version > 10)
-                                       tid = (void *) (ptr_base + decode_sleb128 (p, &p));
-                               int count = decode_uleb128 (p, &p);
-                               for (i = 0; i < count; ++i) {
-                                       uintptr_t ip = ptr_base + decode_sleb128 (p, &p);
-                                       if ((tstamp >= time_from && tstamp < time_to))
-                                               add_stat_sample (sample_type, ip);
-                                       if (debug)
-                                               fprintf (outfile, "sample hit, type: %d at %p for thread %p\n", sample_type, (void*)ip, tid);
-                               }
-                               if (ctx->data_version > 5) {
-                                       count = decode_uleb128 (p, &p);
-                                       for (i = 0; i < count; ++i) {
-                                               MethodDesc *method;
-                                               int64_t ptrdiff = decode_sleb128 (p, &p);
-                                               method_base += ptrdiff;
-                                               method = lookup_method (method_base);
-                                               if (debug)
-                                                       fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
-                                               if (ctx->data_version < 13) {
-                                                       decode_sleb128 (p, &p); /* il offset */
-                                                       decode_sleb128 (p, &p); /* native offset */
-                                               }
-                                       }
-                               }
-                       } else if (subtype == TYPE_SAMPLE_USYM) {
-                               /* un unmanaged symbol description */
-                               uintptr_t addr;
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       addr = ptr_base + decode_sleb128 (p, &p);
-                               } else
-                                       addr = ptr_base + decode_sleb128 (p + 1, &p);
-                               uintptr_t size = decode_uleb128 (p, &p);
-                               char *name;
-                               name = pstrdup ((char*)p);
-                               add_unmanaged_symbol (addr, name, size);
-                               if (debug)
-                                       fprintf (outfile, "unmanaged symbol %s at %p\n", name, (void*)addr);
-                               while (*p) p++;
-                               p++;
-                       } else if (subtype == TYPE_SAMPLE_UBIN) {
-                               /* un unmanaged binary loaded in memory */
-                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                               uintptr_t addr = decode_sleb128 (p, &p);
-                               uint64_t offset G_GNUC_UNUSED = decode_uleb128 (p, &p);
-                               uintptr_t size = decode_uleb128 (p, &p);
-                               char *name;
-                               LOG_TIME (time_base, tdiff);
-                               time_base += tdiff;
-                               name = pstrdup ((char*)p);
-                               add_unmanaged_binary (addr, name, size);
-                               if (debug)
-                                       fprintf (outfile, "unmanaged binary %s at %p\n", name, (void*)addr);
-                               while (*p) p++;
-                               p++;
-                       } else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
-                               uint64_t i, len;
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       len = decode_uleb128 (p, &p);
-                               } else
-                                       len = decode_uleb128 (p + 1, &p);
-                               for (i = 0; i < len; i++) {
-                                       uint64_t type, unit, variance, index;
-                                       uint64_t section = decode_uleb128 (p, &p);
-                                       char *section_str, *name;
-                                       if (section != MONO_COUNTER_PERFCOUNTERS) {
-                                               section_str = (char*) section_name (section);
-                                       } else {
-                                               section_str = pstrdup ((char*)p);
-                                               while (*p++);
-                                       }
-                                       name = pstrdup ((char*)p);
-                                       while (*p++);
-                                       if (ctx->data_version > 12) {
-                                               type = *p++;
-                                               unit = *p++;
-                                               variance = *p++;
-                                       } else {
-                                               type = decode_uleb128 (p, &p);
-                                               unit = decode_uleb128 (p, &p);
-                                               variance = decode_uleb128 (p, &p);
-                                       }
-                                       index = decode_uleb128 (p, &p);
-                                       add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
-                               }
-                       } else if (subtype == TYPE_SAMPLE_COUNTERS) {
-                               int i;
-                               CounterValue *value, *previous = NULL;
-                               CounterList *list;
-                               uint64_t timestamp; // milliseconds since startup
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                                       timestamp = (time_base - startup_time) / 1000 / 1000;
-                               } else
-                                       timestamp = decode_uleb128 (p + 1, &p);
-                               uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
-                               while (1) {
-                                       uint64_t type, index = decode_uleb128 (p, &p);
-                                       if (index == 0)
-                                               break;
-
-                                       for (list = counters; list; list = list->next) {
-                                               if (list->counter->index == (int)index) {
-                                                       previous = list->counter->values_last;
-                                                       break;
-                                               }
-                                       }
-
-                                       if (ctx->data_version > 12)
-                                               type = *p++;
-                                       else
-                                               type = decode_uleb128 (p, &p);
-
-                                       value = (CounterValue *)calloc (1, sizeof (CounterValue));
-                                       value->timestamp = timestamp;
-
-                                       switch (type) {
-                                       case MONO_COUNTER_INT:
-#if SIZEOF_VOID_P == 4
-                                       case MONO_COUNTER_WORD:
-#endif
-                                               value->buffer = (unsigned char *)malloc (sizeof (int32_t));
-                                               *(int32_t*)value->buffer = (int32_t)decode_sleb128 (p, &p) + (previous ? (*(int32_t*)previous->buffer) : 0);
-                                               break;
-                                       case MONO_COUNTER_UINT:
-                                               value->buffer = (unsigned char *)malloc (sizeof (uint32_t));
-                                               *(uint32_t*)value->buffer = (uint32_t)decode_uleb128 (p, &p) + (previous ? (*(uint32_t*)previous->buffer) : 0);
-                                               break;
-                                       case MONO_COUNTER_LONG:
-#if SIZEOF_VOID_P == 8
-                                       case MONO_COUNTER_WORD:
-#endif
-                                       case MONO_COUNTER_TIME_INTERVAL:
-                                               value->buffer = (unsigned char *)malloc (sizeof (int64_t));
-                                               *(int64_t*)value->buffer = (int64_t)decode_sleb128 (p, &p) + (previous ? (*(int64_t*)previous->buffer) : 0);
-                                               break;
-                                       case MONO_COUNTER_ULONG:
-                                               value->buffer = (unsigned char *)malloc (sizeof (uint64_t));
-                                               *(uint64_t*)value->buffer = (uint64_t)decode_uleb128 (p, &p) + (previous ? (*(uint64_t*)previous->buffer) : 0);
-                                               break;
-                                       case MONO_COUNTER_DOUBLE:
-                                               value->buffer = (unsigned char *)malloc (sizeof (double));
-#if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
-                                               for (i = 0; i < sizeof (double); i++)
-#else
-                                               for (i = sizeof (double) - 1; i >= 0; i--)
-#endif
-                                                       value->buffer[i] = *p++;
-                                               break;
-                                       case MONO_COUNTER_STRING:
-                                               if (*p++ == 0) {
-                                                       value->buffer = NULL;
-                                               } else {
-                                                       value->buffer = (unsigned char*) pstrdup ((char*)p);
-                                                       while (*p++);
-                                               }
-                                               break;
-                                       }
-                                       if (time_between >= time_from && time_between <= time_to)
-                                               add_counter_value (index, value);
-                               }
-                       } else {
-                               return 0;
-                       }
-                       break;
-               }
-               case TYPE_COVERAGE:{
-                       int subtype = *p & 0xf0;
-                       switch (subtype) {
-                       case TYPE_COVERAGE_METHOD: {
-                               CoverageMethod *method = g_new0 (CoverageMethod, 1);
-                               const char *assembly, *klass, *name, *sig, *filename;
-                               int token, n_offsets, method_id;
-
-                               p++;
-
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                               }
-
-                               assembly = (const char *)p; while (*p) p++; p++;
-                               klass = (const char *)p; while (*p) p++; p++;
-                               name = (const char *)p; while (*p) p++; p++;
-                               sig = (const char *)p; while (*p) p++; p++;
-                               filename = (const char *)p; while (*p) p++; p++;
-
-                               token = decode_uleb128 (p, &p);
-                               method_id = decode_uleb128 (p, &p);
-                               n_offsets = decode_uleb128 (p, &p);
-
-                               method->assembly_name = g_strdup (assembly);
-                               method->class_name = g_strdup (klass);
-                               method->method_name = g_strdup (name);
-                               method->method_signature = g_strdup (sig);
-                               method->filename = g_strdup (filename);
-                               method->token = token;
-                               method->n_statements = n_offsets;
-                               method->coverage = g_ptr_array_new ();
-                               method->method_id = method_id;
-
-                               coverage_add_method (method);
-
-                               break;
-                       }
-                       case TYPE_COVERAGE_STATEMENT: {
-                               CoverageCoverage *coverage = g_new0 (CoverageCoverage, 1);
-                               int offset, count, line, column, method_id;
-
-                               p++;
-
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                               }
-
-                               method_id = decode_uleb128 (p, &p);
-                               offset = decode_uleb128 (p, &p);
-                               count = decode_uleb128 (p, &p);
-                               line = decode_uleb128 (p, &p);
-                               column = decode_uleb128 (p, &p);
-
-                               coverage->method_id = method_id;
-                               coverage->offset = offset;
-                               coverage->count = count;
-                               coverage->line = line;
-                               coverage->column = column;
-
-                               coverage_add_coverage (coverage);
-                               break;
-                       }
-                       case TYPE_COVERAGE_ASSEMBLY: {
-                               CoverageAssembly *assembly = g_new0 (CoverageAssembly, 1);
-                               char *name, *guid, *filename;
-                               int number_of_methods, fully_covered, partially_covered;
-                               p++;
-
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                               }
-
-                               name = (char *)p; while (*p) p++; p++;
-                               guid = (char *)p; while (*p) p++; p++;
-                               filename = (char *)p; while (*p) p++; p++;
-                               number_of_methods = decode_uleb128 (p, &p);
-                               fully_covered = decode_uleb128 (p, &p);
-                               partially_covered = decode_uleb128 (p, &p);
-
-                               assembly->name = g_strdup (name);
-                               assembly->guid = g_strdup (guid);
-                               assembly->filename = g_strdup (filename);
-                               assembly->number_of_methods = number_of_methods;
-                               assembly->fully_covered = fully_covered;
-                               assembly->partially_covered = partially_covered;
-
-                               coverage_add_assembly (assembly);
-                               break;
-                       }
-                       case TYPE_COVERAGE_CLASS: {
-                               CoverageClass *klass = g_new0 (CoverageClass, 1);
-                               char *assembly_name, *class_name;
-                               int number_of_methods, fully_covered, partially_covered;
-                               p++;
-
-                               if (ctx->data_version > 12) {
-                                       uint64_t tdiff = decode_uleb128 (p, &p);
-                                       LOG_TIME (time_base, tdiff);
-                                       time_base += tdiff;
-                               }
-
-                               assembly_name = (char *)p; while (*p) p++; p++;
-                               class_name = (char *)p; while (*p) p++; p++;
-                               number_of_methods = decode_uleb128 (p, &p);
-                               fully_covered = decode_uleb128 (p, &p);
-                               partially_covered = decode_uleb128 (p, &p);
-
-                               klass->assembly_name = g_strdup (assembly_name);
-                               klass->class_name = g_strdup (class_name);
-                               klass->number_of_methods = number_of_methods;
-                               klass->fully_covered = fully_covered;
-                               klass->partially_covered = partially_covered;
-
-                               coverage_add_class (klass);
-                               break;
-                       }
-
-                       default:
-                               break;
-                       }
-                       break;
-               }
-               case TYPE_META: {
-                       int subtype = *p & 0xf0;
-                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
-                       LOG_TIME (time_base, tdiff);
-                       time_base += tdiff;
-                       if (subtype == TYPE_SYNC_POINT) {
-                               int type = *p++;
-                               if (debug)
-                                       fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
-                       }
-                       break;
-               }
-               default:
-                       fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
-                       exit (1);
-               }
-               record_event_stats (event, p - start);
-       }
-       thread->last_time = time_base;
-       for (i = 0; i < thread->stack_id; ++i)
-               thread->stack [i]->recurse_count = 0;
-       return 1;
-}
-
-static int
-read_header_string (ProfContext *ctx, char **field)
-{
-       if (!load_data (ctx, 4))
-               return 0;
-
-       if (!load_data (ctx, read_int32 (ctx->buf)))
-               return 0;
-
-       *field = pstrdup ((const char *) ctx->buf);
-
-       return 1;
-}
-
-static ProfContext*
-load_file (char *name)
-{
-       unsigned char *p;
-       ProfContext *ctx = (ProfContext *)calloc (sizeof (ProfContext), 1);
-       if (strcmp (name, "-") == 0)
-               ctx->file = stdin;
-       else
-               ctx->file = fopen (name, "rb");
-       if (!ctx->file) {
-               printf ("Cannot open file: %s\n", name);
-               exit (1);
-       }
-#if defined (HAVE_SYS_ZLIB)
-       if (ctx->file != stdin)
-               ctx->gzfile = gzdopen (fileno (ctx->file), "rb");
-#endif
-       if (!load_data (ctx, 30))
-               return NULL;
-       p = ctx->buf;
-       if (read_int32 (p) != LOG_HEADER_ID || p [6] > LOG_DATA_VERSION)
-               return NULL;
-       ctx->version_major = p [4];
-       ctx->version_minor = p [5];
-       ctx->data_version = p [6];
-       /* reading 64 bit files on 32 bit systems not supported yet */
-       if (p [7] > sizeof (void*))
-               return NULL;
-       if (read_int32 (p + 20)) /* flags must be 0 */
-               return NULL;
-       ctx->startup_time = read_int64 (p + 8);
-       ctx->timer_overhead = read_int32 (p + 16);
-       ctx->pid = read_int32 (p + 24);
-       ctx->port = read_int16 (p + 28);
-       if (ctx->version_major >= 1) {
-               if (!read_header_string (ctx, &ctx->args))
-                       return NULL;
-               if (!read_header_string (ctx, &ctx->arch))
-                       return NULL;
-               if (!read_header_string (ctx, &ctx->os))
-                       return NULL;
-       } else {
-               if (!load_data (ctx, 2)) /* old opsys field, was never used */
-                       return NULL;
-       }
-       return ctx;
-}
-
-enum {
-       ALLOC_SORT_BYTES,
-       ALLOC_SORT_COUNT
-};
-static int alloc_sort_mode = ALLOC_SORT_BYTES;
-
-static int
-compare_class (const void *a, const void *b)
-{
-       ClassDesc *const *A = (ClassDesc *const *)a;
-       ClassDesc *const *B = (ClassDesc *const *)b;
-       uint64_t vala, valb;
-       if (alloc_sort_mode == ALLOC_SORT_BYTES) {
-               vala = (*A)->alloc_size;
-               valb = (*B)->alloc_size;
-       } else {
-               vala = (*A)->allocs;
-               valb = (*B)->allocs;
-       }
-       if (valb == vala)
-               return 0;
-       if (valb < vala)
-               return -1;
-       return 1;
-}
-
-static void
-dump_header (ProfContext *ctx)
-{
-       time_t st = ctx->startup_time / 1000;
-       char *t = ctime (&st);
-       fprintf (outfile, "\nMono log profiler data\n");
-       fprintf (outfile, "\tProfiler version: %d.%d\n", ctx->version_major, ctx->version_minor);
-       fprintf (outfile, "\tData version: %d\n", ctx->data_version);
-       if (ctx->version_major >= 1) {
-               fprintf (outfile, "\tArguments: %s\n", ctx->args);
-               fprintf (outfile, "\tArchitecture: %s\n", ctx->arch);
-               fprintf (outfile, "\tOperating system: %s\n", ctx->os);
-       }
-       fprintf (outfile, "\tMean timer overhead: %d nanoseconds\n", ctx->timer_overhead);
-       fprintf (outfile, "\tProgram startup: %s", t);
-       if (ctx->pid)
-               fprintf (outfile, "\tProgram ID: %d\n", ctx->pid);
-       if (ctx->port)
-               fprintf (outfile, "\tServer listening on: %d\n", ctx->port);
-}
-
-static void
-dump_traces (TraceDesc *traces, const char *desc)
-{
-       int j;
-       if (!show_traces)
-               return;
-       if (!traces->count)
-               return;
-       sort_context_array (traces);
-       for (j = 0; j < traces->count; ++j) {
-               int k;
-               BackTrace *bt;
-               bt = traces->traces [j].bt;
-               if (!bt->count)
-                       continue;
-               fprintf (outfile, "\t%llu %s from:\n", (unsigned long long) traces->traces [j].count, desc);
-               for (k = 0; k < bt->count; ++k)
-                       fprintf (outfile, "\t\t%s\n", bt->methods [k]->name);
-       }
-}
-
-static void
-dump_threads (ProfContext *ctx)
-{
-       ThreadContext *thread;
-       fprintf (outfile, "\nThread summary\n");
-       for (thread = ctx->threads; thread; thread = thread->next) {
-               if (thread->thread_id) {
-                       fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
-               }
-       }
-}
-
-static void
-dump_domains (ProfContext *ctx)
-{
-       fprintf (outfile, "\nDomain summary\n");
-
-       for (DomainContext *domain = ctx->domains; domain; domain = domain->next)
-               fprintf (outfile, "\tDomain: %p, friendly name: \"%s\"\n", (void *) domain->domain_id, domain->friendly_name);
-}
-
-static void
-dump_remctxs (ProfContext *ctx)
-{
-       fprintf (outfile, "\nContext summary\n");
-
-       for (RemCtxContext *remctx = ctx->remctxs; remctx; remctx = remctx->next)
-               fprintf (outfile, "\tContext: %p, domain: %p\n", (void *) remctx->remctx_id, (void *) remctx->domain_id);
-}
-
-static void
-dump_exceptions (void)
-{
-       int i;
-       fprintf (outfile, "\nException summary\n");
-       fprintf (outfile, "\tThrows: %llu\n", (unsigned long long) throw_count);
-       dump_traces (&exc_traces, "throws");
-       for (i = 0; i <= MONO_EXCEPTION_CLAUSE_FAULT; ++i) {
-               if (!clause_summary [i])
-                       continue;
-               fprintf (outfile, "\tExecuted %s clauses: %llu\n", clause_name (i), (unsigned long long) clause_summary [i]);
-       }
-}
-
-static int
-compare_monitor (const void *a, const void *b)
-{
-       MonitorDesc *const *A = (MonitorDesc *const *)a;
-       MonitorDesc *const *B = (MonitorDesc *const *)b;
-       if ((*B)->wait_time == (*A)->wait_time)
-               return 0;
-       if ((*B)->wait_time < (*A)->wait_time)
-               return -1;
-       return 1;
-}
-
-static void
-dump_monitors (void)
-{
-       MonitorDesc **monitors;
-       int i, j;
-       if (!num_monitors)
-               return;
-       monitors = (MonitorDesc **)malloc (sizeof (void*) * num_monitors);
-       for (i = 0, j = 0; i < SMALL_HASH_SIZE; ++i) {
-               MonitorDesc *mdesc = monitor_hash [i];
-               while (mdesc) {
-                       monitors [j++] = mdesc;
-                       mdesc = mdesc->next;
-               }
-       }
-       qsort (monitors, num_monitors, sizeof (void*), compare_monitor);
-       fprintf (outfile, "\nMonitor lock summary\n");
-       for (i = 0; i < num_monitors; ++i) {
-               MonitorDesc *mdesc = monitors [i];
-               fprintf (outfile, "\tLock object %p: %d contentions\n", (void*)mdesc->objid, (int)mdesc->contentions);
-               fprintf (outfile, "\t\t%.6f secs total wait time, %.6f max, %.6f average\n",
-                       mdesc->wait_time/1000000000.0, mdesc->max_wait_time/1000000000.0, mdesc->wait_time/1000000000.0/mdesc->contentions);
-               dump_traces (&mdesc->traces, "contentions");
-       }
-       fprintf (outfile, "\tLock contentions: %llu\n", (unsigned long long) monitor_contention);
-       fprintf (outfile, "\tLock acquired: %llu\n", (unsigned long long) monitor_acquired);
-       fprintf (outfile, "\tLock failures: %llu\n", (unsigned long long) monitor_failed);
-}
-
-static void
-dump_gcs (void)
-{
-       int i;
-       fprintf (outfile, "\nGC summary\n");
-       fprintf (outfile, "\tGC resizes: %d\n", gc_resizes);
-       fprintf (outfile, "\tMax heap size: %llu\n", (unsigned long long) max_heap_size);
-       fprintf (outfile, "\tObject moves: %llu\n", (unsigned long long) gc_object_moves);
-       for (i = 0; i < 3; ++i) {
-               if (!gc_info [i].count)
-                       continue;
-               fprintf (outfile, "\tGen%d collections: %d, max time: %lluus, total time: %lluus, average: %lluus\n",
-                       i, gc_info [i].count,
-                       (unsigned long long) (gc_info [i].max_time / 1000),
-                       (unsigned long long) (gc_info [i].total_time / 1000),
-                       (unsigned long long) (gc_info [i].total_time / gc_info [i].count / 1000));
-       }
-       for (i = 0; i < 3; ++i) {
-               if (!handle_info [i].max_live)
-                       continue;
-               fprintf (outfile, "\tGC handles %s: created: %llu, destroyed: %llu, max: %llu\n",
-                       get_handle_name (i),
-                       (unsigned long long) (handle_info [i].created),
-                       (unsigned long long) (handle_info [i].destroyed),
-                       (unsigned long long) (handle_info [i].max_live));
-               dump_traces (&handle_info [i].traces, "created");
-               dump_traces (&handle_info [i].destroy_traces, "destroyed");
-       }
-}
-
-static void
-dump_jit (void)
-{
-       int i;
-       int code_size = 0;
-       int compiled_methods = 0;
-       MethodDesc* m;
-       fprintf (outfile, "\nJIT summary\n");
-       for (i = 0; i < HASH_SIZE; ++i) {
-               m = method_hash [i];
-               for (m = method_hash [i]; m; m = m->next) {
-                       if (!m->code || m->ignore_jit)
-                               continue;
-                       compiled_methods++;
-                       code_size += m->len;
-               }
-       }
-       fprintf (outfile, "\tCompiled methods: %d\n", compiled_methods);
-       fprintf (outfile, "\tGenerated code size: %d\n", code_size);
-       fprintf (outfile, "\tJIT helpers: %d\n", num_jit_helpers);
-       fprintf (outfile, "\tJIT helpers code size: %d\n", jit_helpers_code_size);
-}
-
-static void
-dump_allocations (void)
-{
-       int i, c;
-       intptr_t allocs = 0;
-       uint64_t size = 0;
-       int header_done = 0;
-       ClassDesc **classes = (ClassDesc **)malloc (num_classes * sizeof (void*));
-       ClassDesc *cd;
-       c = 0;
-       for (i = 0; i < HASH_SIZE; ++i) {
-               cd = class_hash [i];
-               while (cd) {
-                       classes [c++] = cd;
-                       cd = cd->next;
-               }
-       }
-       qsort (classes, num_classes, sizeof (void*), compare_class);
-       for (i = 0; i < num_classes; ++i) {
-               cd = classes [i];
-               if (!cd->allocs)
-                       continue;
-               allocs += cd->allocs;
-               size += cd->alloc_size;
-               if (!header_done++) {
-                       fprintf (outfile, "\nAllocation summary\n");
-                       fprintf (outfile, "%10s %10s %8s Type name\n", "Bytes", "Count", "Average");
-               }
-               fprintf (outfile, "%10llu %10zd %8llu %s\n",
-                       (unsigned long long) (cd->alloc_size),
-                       cd->allocs,
-                       (unsigned long long) (cd->alloc_size / cd->allocs),
-                       cd->name);
-               dump_traces (&cd->traces, "bytes");
-       }
-       if (allocs)
-               fprintf (outfile, "Total memory allocated: %llu bytes in %zd objects\n", (unsigned long long) size, allocs);
-}
-
-enum {
-       METHOD_SORT_TOTAL,
-       METHOD_SORT_SELF,
-       METHOD_SORT_CALLS
-};
-
-static int method_sort_mode = METHOD_SORT_TOTAL;
-
-static int
-compare_method (const void *a, const void *b)
-{
-       MethodDesc *const *A = (MethodDesc *const *)a;
-       MethodDesc *const *B = (MethodDesc *const *)b;
-       uint64_t vala, valb;
-       if (method_sort_mode == METHOD_SORT_SELF) {
-               vala = (*A)->self_time;
-               valb = (*B)->self_time;
-       } else if (method_sort_mode == METHOD_SORT_CALLS) {
-               vala = (*A)->calls;
-               valb = (*B)->calls;
-       } else {
-               vala = (*A)->total_time;
-               valb = (*B)->total_time;
-       }
-       if (vala == valb)
-               return 0;
-       if (valb < vala)
-               return -1;
-       return 1;
-}
-
-static void
-dump_metadata (void)
-{
-       fprintf (outfile, "\nMetadata summary\n");
-       fprintf (outfile, "\tLoaded images: %d\n", num_images);
-       if (verbose) {
-               ImageDesc *image;
-               int i;
-               for (i = 0; i < SMALL_HASH_SIZE; ++i) {
-                       image = image_hash [i];
-                       while (image) {
-                               fprintf (outfile, "\t\t%s\n", image->filename);
-                               image = image->next;
-                       }
-               }
-       }
-       fprintf (outfile, "\tLoaded assemblies: %d\n", num_assemblies);
-       if (verbose) {
-               AssemblyDesc *assembly;
-               int i;
-               for (i = 0; i < SMALL_HASH_SIZE; ++i) {
-                       assembly = assembly_hash [i];
-                       while (assembly) {
-                               fprintf (outfile, "\t\t%s\n", assembly->asmname);
-                               assembly = assembly->next;
-                       }
-               }
-       }
-}
-
-static void
-dump_methods (void)
-{
-       int i, c;
-       uint64_t calls = 0;
-       int header_done = 0;
-       MethodDesc **methods = (MethodDesc **)malloc (num_methods * sizeof (void*));
-       MethodDesc *cd;
-       c = 0;
-       for (i = 0; i < HASH_SIZE; ++i) {
-               cd = method_hash [i];
-               while (cd) {
-                       cd->total_time = cd->self_time + cd->callee_time;
-                       methods [c++] = cd;
-                       cd = cd->next;
-               }
-       }
-       qsort (methods, num_methods, sizeof (void*), compare_method);
-       for (i = 0; i < num_methods; ++i) {
-               uint64_t msecs;
-               uint64_t smsecs;
-               cd = methods [i];
-               if (!cd->calls)
-                       continue;
-               calls += cd->calls;
-               msecs = cd->total_time / 1000000;
-               smsecs = (cd->total_time - cd->callee_time) / 1000000;
-               if (!msecs && !verbose)
-                       continue;
-               if (!header_done++) {
-                       fprintf (outfile, "\nMethod call summary\n");
-                       fprintf (outfile, "%8s %8s %10s Method name\n", "Total(ms)", "Self(ms)", "Calls");
-               }
-               fprintf (outfile, "%8llu %8llu %10llu %s\n",
-                       (unsigned long long) (msecs),
-                       (unsigned long long) (smsecs),
-                       (unsigned long long) (cd->calls),
-                       cd->name);
-               dump_traces (&cd->traces, "calls");
-       }
-       if (calls)
-               fprintf (outfile, "Total calls: %llu\n", (unsigned long long) calls);
-}
-
-static int
-compare_heap_class (const void *a, const void *b)
-{
-       HeapClassDesc *const *A = (HeapClassDesc *const *)a;
-       HeapClassDesc *const *B = (HeapClassDesc *const *)b;
-       uint64_t vala, valb;
-       if (alloc_sort_mode == ALLOC_SORT_BYTES) {
-               vala = (*A)->total_size;
-               valb = (*B)->total_size;
-       } else {
-               vala = (*A)->count;
-               valb = (*B)->count;
-       }
-       if (valb == vala)
-               return 0;
-       if (valb < vala)
-               return -1;
-       return 1;
-}
-
-static int
-compare_rev_class (const void *a, const void *b)
-{
-       const HeapClassRevRef *A = (const HeapClassRevRef *)a;
-       const HeapClassRevRef *B = (const HeapClassRevRef *)b;
-       if (B->count == A->count)
-               return 0;
-       if (B->count < A->count)
-               return -1;
-       return 1;
-}
-
-static void
-dump_rev_claases (HeapClassRevRef *revs, int count)
-{
-       int j;
-       if (!show_traces)
-               return;
-       if (!count)
-               return;
-       for (j = 0; j < count; ++j) {
-               HeapClassDesc *cd = revs [j].klass;
-               fprintf (outfile, "\t\t%llu references from: %s\n",
-                       (unsigned long long) (revs [j].count),
-                       cd->klass->name);
-       }
-}
-
-static void
-heap_shot_summary (HeapShot *hs, int hs_num, HeapShot *last_hs)
-{
-       uint64_t size = 0;
-       uint64_t count = 0;
-       int ccount = 0;
-       int i;
-       HeapClassDesc *cd;
-       HeapClassDesc **sorted;
-       sorted = (HeapClassDesc **)malloc (sizeof (void*) * hs->class_count);
-       for (i = 0; i < hs->hash_size; ++i) {
-               cd = hs->class_hash [i];
-               if (!cd)
-                       continue;
-               count += cd->count;
-               size += cd->total_size;
-               sorted [ccount++] = cd;
-       }
-       hs->sorted = sorted;
-       qsort (sorted, ccount, sizeof (void*), compare_heap_class);
-       fprintf (outfile, "\n\tHeap shot %d at %.3f secs: size: %llu, object count: %llu, class count: %d, roots: %zd\n",
-               hs_num,
-               (hs->timestamp - startup_time)/1000000000.0,
-               (unsigned long long) (size),
-               (unsigned long long) (count),
-               ccount, hs->num_roots);
-       if (!verbose && ccount > 30)
-               ccount = 30;
-       fprintf (outfile, "\t%10s %10s %8s Class name\n", "Bytes", "Count", "Average");
-       for (i = 0; i < ccount; ++i) {
-               HeapClassRevRef *rev_sorted;
-               int j, k;
-               HeapClassDesc *ocd = NULL;
-               cd = sorted [i];
-               if (last_hs)
-                       ocd = heap_class_lookup (last_hs, cd->klass);
-               fprintf (outfile, "\t%10llu %10llu %8llu %s",
-                       (unsigned long long) (cd->total_size),
-                       (unsigned long long) (cd->count),
-                       (unsigned long long) (cd->total_size / cd->count),
-                       cd->klass->name);
-               if (ocd) {
-                       int64_t bdiff = cd->total_size - ocd->total_size;
-                       int64_t cdiff = cd->count - ocd->count;
-                       fprintf (outfile, " (bytes: %+lld, count: %+lld)\n", (long long) bdiff, (long long) cdiff);
-               } else {
-                       fprintf (outfile, "\n");
-               }
-               if (!collect_traces)
-                       continue;
-               rev_sorted = (HeapClassRevRef *)malloc (cd->rev_count * sizeof (HeapClassRevRef));
-               k = 0;
-               for (j = 0; j < cd->rev_hash_size; ++j) {
-                       if (cd->rev_hash [j].klass)
-                               rev_sorted [k++] = cd->rev_hash [j];
-               }
-               assert (cd->rev_count == k);
-               qsort (rev_sorted, cd->rev_count, sizeof (HeapClassRevRef), compare_rev_class);
-               if (cd->root_references)
-                       fprintf (outfile, "\t\t%zd root references (%zd pinning)\n", cd->root_references, cd->pinned_references);
-               dump_rev_claases (rev_sorted, cd->rev_count);
-               g_free (rev_sorted);
-       }
-       g_free (sorted);
-}
-
-static int
-compare_heap_shots (const void *a, const void *b)
-{
-       HeapShot *const *A = (HeapShot *const *)a;
-       HeapShot *const *B = (HeapShot *const *)b;
-       if ((*B)->timestamp == (*A)->timestamp)
-               return 0;
-       if ((*B)->timestamp > (*A)->timestamp)
-               return -1;
-       return 1;
-}
-
-static void
-dump_heap_shots (void)
-{
-       HeapShot **hs_sorted;
-       HeapShot *hs;
-       HeapShot *last_hs = NULL;
-       int i;
-       if (!heap_shots)
-               return;
-       hs_sorted = (HeapShot **)malloc (num_heap_shots * sizeof (void*));
-       fprintf (outfile, "\nHeap shot summary\n");
-       i = 0;
-       for (hs = heap_shots; hs; hs = hs->next)
-               hs_sorted [i++] = hs;
-       qsort (hs_sorted, num_heap_shots, sizeof (void*), compare_heap_shots);
-       for (i = 0; i < num_heap_shots; ++i) {
-               hs = hs_sorted [i];
-               heap_shot_summary (hs, i, last_hs);
-               last_hs = hs;
-       }
-}
-
-/* This is a very basic escape function that escapes < > and &
-   Ideally we'd use g_markup_escape_string but that function isn't
-        available in Mono's eglib. This was written without looking at the
-        source of that function in glib. */
-static char *
-escape_string_for_xml (const char *string)
-{
-       GString *string_builder = g_string_new (NULL);
-       const char *start, *p;
-
-       start = p = string;
-       while (*p) {
-               while (*p && *p != '&' && *p != '<' && *p != '>')
-                       p++;
-
-               g_string_append_len (string_builder, start, p - start);
-
-               if (*p == '\0')
-                       break;
-
-               switch (*p) {
-               case '<':
-                       g_string_append (string_builder, "&lt;");
-                       break;
-
-               case '>':
-                       g_string_append (string_builder, "&gt;");
-                       break;
-
-               case '&':
-                       g_string_append (string_builder, "&amp;");
-                       break;
-
-               default:
-                       break;
-               }
-
-               p++;
-               start = p;
-       }
-
-       return g_string_free (string_builder, FALSE);
-}
-
-static int
-sort_assemblies (gconstpointer a, gconstpointer b)
-{
-       CoverageAssembly *assembly_a = *(CoverageAssembly **)a;
-       CoverageAssembly *assembly_b = *(CoverageAssembly **)b;
-
-       if (assembly_a->name == NULL && assembly_b->name == NULL)
-               return 0;
-       else if (assembly_a->name == NULL)
-               return -1;
-       else if (assembly_b->name == NULL)
-               return 1;
-
-       return strcmp (assembly_a->name, assembly_b->name);
-}
-
-static void
-dump_coverage (void)
-{
-       if (!coverage_methods && !coverage_assemblies)
-               return;
-
-       gather_coverage_statements ();
-       fprintf (outfile, "\nCoverage Summary:\n");
-
-       if (coverage_outfile) {
-               fprintf (coverage_outfile, "<?xml version=\"1.0\"?>\n");
-               fprintf (coverage_outfile, "<coverage version=\"0.3\">\n");
-       }
-
-       g_ptr_array_sort (coverage_assemblies, sort_assemblies);
-
-       for (guint i = 0; i < coverage_assemblies->len; i++) {
-               CoverageAssembly *assembly = (CoverageAssembly *)coverage_assemblies->pdata[i];
-               GPtrArray *classes;
-
-               if (assembly->number_of_methods != 0) {
-                       int percentage = ((assembly->fully_covered + assembly->partially_covered) * 100) / assembly->number_of_methods;
-                       fprintf (outfile, "\t%s (%s) %d%% covered (%d methods - %d covered)\n", assembly->name, assembly->filename, percentage, assembly->number_of_methods, assembly->fully_covered);
-               } else
-                       fprintf (outfile, "\t%s (%s) ?%% covered (%d methods - %d covered)\n", assembly->name, assembly->filename, assembly->number_of_methods, assembly->fully_covered);
-
-               if (coverage_outfile) {
-                       char *escaped_name, *escaped_filename;
-                       escaped_name = escape_string_for_xml (assembly->name);
-                       escaped_filename = escape_string_for_xml (assembly->filename);
-
-                       fprintf (coverage_outfile, "\t<assembly name=\"%s\" guid=\"%s\" filename=\"%s\" method-count=\"%d\" full=\"%d\" partial=\"%d\"/>\n", escaped_name, assembly->guid, escaped_filename, assembly->number_of_methods, assembly->fully_covered, assembly->partially_covered);
-
-                       g_free (escaped_name);
-                       g_free (escaped_filename);
-               }
-
-               classes = (GPtrArray *)g_hash_table_lookup (coverage_assembly_classes, assembly->name);
-               if (classes) {
-                       for (guint j = 0; j < classes->len; j++) {
-                               CoverageClass *klass = (CoverageClass *)classes->pdata [j];
-
-                               if (klass->number_of_methods > 0) {
-                                       int percentage = ((klass->fully_covered + klass->partially_covered) * 100) / klass->number_of_methods;
-                                       fprintf (outfile, "\t\t%s %d%% covered (%d methods - %d covered)\n", klass->class_name, percentage, klass->number_of_methods, klass->fully_covered);
-                               } else
-                                       fprintf (outfile, "\t\t%s ?%% covered (%d methods - %d covered)\n", klass->class_name, klass->number_of_methods, klass->fully_covered);
-
-                               if (coverage_outfile) {
-                                       char *escaped_name;
-                                       escaped_name = escape_string_for_xml (klass->class_name);
-
-                                       fprintf (coverage_outfile, "\t\t<class name=\"%s\" method-count=\"%d\" full=\"%d\" partial=\"%d\"/>\n", escaped_name, klass->number_of_methods, klass->fully_covered, klass->partially_covered);
-                                       g_free (escaped_name);
-                               }
-                       }
-               }
-       }
-
-       for (guint i = 0; i < coverage_methods->len; i++) {
-               CoverageMethod *method = (CoverageMethod *)coverage_methods->pdata [i];
-
-               if (coverage_outfile) {
-                       char *escaped_assembly, *escaped_class, *escaped_method, *escaped_sig, *escaped_filename;
-
-                       escaped_assembly = escape_string_for_xml (method->assembly_name);
-                       escaped_class = escape_string_for_xml (method->class_name);
-                       escaped_method = escape_string_for_xml (method->method_name);
-                       escaped_sig = escape_string_for_xml (method->method_signature);
-                       escaped_filename = escape_string_for_xml (method->filename);
-
-                       fprintf (coverage_outfile, "\t<method assembly=\"%s\" class=\"%s\" name=\"%s (%s)\" filename=\"%s\" token=\"%d\">\n", escaped_assembly, escaped_class, escaped_method, escaped_sig, escaped_filename, method->token);
-
-                       g_free (escaped_assembly);
-                       g_free (escaped_class);
-                       g_free (escaped_method);
-                       g_free (escaped_sig);
-                       g_free (escaped_filename);
-
-                       for (guint j = 0; j < method->coverage->len; j++) {
-                               CoverageCoverage *coverage = (CoverageCoverage *)method->coverage->pdata [j];
-                               fprintf (coverage_outfile, "\t\t<statement offset=\"%d\" counter=\"%d\" line=\"%d\" column=\"%d\"/>\n", coverage->offset, coverage->count, coverage->line, coverage->column);
-                       }
-                       fprintf (coverage_outfile, "\t</method>\n");
-               }
-       }
-
-       if (coverage_outfile) {
-               fprintf (coverage_outfile, "</coverage>\n");
-               fclose (coverage_outfile);
-               coverage_outfile = NULL;
-       }
-}
-
-#define DUMP_EVENT_STAT(EVENT,SUBTYPE) dump_event (#EVENT, #SUBTYPE, EVENT, SUBTYPE);
-
-static void
-dump_event (const char *event_name, const char *subtype_name, int event, int subtype)
-{
-       int idx = event | subtype;
-       EventStat evt = stats [idx];
-       if (!evt.count)
-               return;
-
-       fprintf (outfile, "\t%16s\t%26s\tcount %6d\tmin %3d\tmax %6d\tbytes %d\n", event_name, subtype_name, evt.count, evt.min_size, evt.max_size, evt.bytes);
-}
-
-static void
-dump_stats (void)
-{
-       fprintf (outfile, "\nMlpd statistics\n");
-       fprintf (outfile, "\tBuffer count %d\toverhead %d (%d bytes per header)\n", buffer_count, buffer_count * BUFFER_HEADER_SIZE, BUFFER_HEADER_SIZE);
-       fprintf (outfile, "\nEvent details:\n");
-
-       DUMP_EVENT_STAT (TYPE_ALLOC, TYPE_ALLOC_NO_BT);
-       DUMP_EVENT_STAT (TYPE_ALLOC, TYPE_ALLOC_BT);
-
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_EVENT);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_RESIZE);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_MOVE);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_CREATED);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_DESTROYED);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_CREATED_BT);
-       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_DESTROYED_BT);
-
-       DUMP_EVENT_STAT (TYPE_METADATA, TYPE_END_LOAD);
-       DUMP_EVENT_STAT (TYPE_METADATA, TYPE_END_UNLOAD);
-
-       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_LEAVE);
-       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_ENTER);
-       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_EXC_LEAVE);
-       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_JIT);
-
-       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_NO_BT);
-       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_BT);
-       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_CLAUSE);
-
-       DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_NO_BT);
-       DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_BT);
-
-       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_START);
-       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_END);
-       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_OBJECT);
-       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_ROOT);
-
-       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_HIT);
-       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_USYM);
-       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_UBIN);
-       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_COUNTERS_DESC);
-       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_COUNTERS);
-
-       DUMP_EVENT_STAT (TYPE_RUNTIME, TYPE_JITHELPER);
-
-       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_ASSEMBLY);
-       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
-       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
-       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
-
-       DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
-}
-
-
-
-static void
-flush_context (ProfContext *ctx)
-{
-       ThreadContext *thread;
-       /* FIXME: sometimes there are leftovers: indagate */
-       for (thread = ctx->threads; thread; thread = thread->next) {
-               while (thread->stack_id) {
-                       if (debug)
-                               fprintf (outfile, "thread %p has %d items on stack\n", (void*)thread->thread_id, thread->stack_id);
-                       pop_method (thread, thread->stack [thread->stack_id - 1], thread->last_time);
-               }
-       }
-}
-
-static const char *reports = "header,jit,gc,sample,alloc,call,metadata,exception,monitor,thread,heapshot,counters,coverage";
-
-static const char*
-match_option (const char *p, const char *opt)
-{
-       int len = strlen (opt);
-       if (strncmp (p, opt, len) == 0) {
-               if (p [len] == ',')
-                       len++;
-               return p + len;
-       }
-       return p;
-}
-
-static int
-print_reports (ProfContext *ctx, const char *reps, int parse_only)
-{
-       const char *opt;
-       const char *p;
-       for (p = reps; *p; p = opt) {
-               if ((opt = match_option (p, "header")) != p) {
-                       if (!parse_only)
-                               dump_header (ctx);
-                       continue;
-               }
-               if ((opt = match_option (p, "thread")) != p) {
-                       if (!parse_only)
-                               dump_threads (ctx);
-                       continue;
-               }
-               if ((opt = match_option (p, "domain")) != p) {
-                       if (!parse_only)
-                               dump_domains (ctx);
-                       continue;
-               }
-               if ((opt = match_option (p, "context")) != p) {
-                       if (!parse_only)
-                               dump_remctxs (ctx);
-                       continue;
-               }
-               if ((opt = match_option (p, "gc")) != p) {
-                       if (!parse_only)
-                               dump_gcs ();
-                       continue;
-               }
-               if ((opt = match_option (p, "jit")) != p) {
-                       if (!parse_only)
-                               dump_jit ();
-                       continue;
-               }
-               if ((opt = match_option (p, "alloc")) != p) {
-                       if (!parse_only)
-                               dump_allocations ();
-                       continue;
-               }
-               if ((opt = match_option (p, "call")) != p) {
-                       if (!parse_only)
-                               dump_methods ();
-                       continue;
-               }
-               if ((opt = match_option (p, "metadata")) != p) {
-                       if (!parse_only)
-                               dump_metadata ();
-                       continue;
-               }
-               if ((opt = match_option (p, "exception")) != p) {
-                       if (!parse_only)
-                               dump_exceptions ();
-                       continue;
-               }
-               if ((opt = match_option (p, "monitor")) != p) {
-                       if (!parse_only)
-                               dump_monitors ();
-                       continue;
-               }
-               if ((opt = match_option (p, "heapshot")) != p) {
-                       if (!parse_only)
-                               dump_heap_shots ();
-                       continue;
-               }
-               if ((opt = match_option (p, "sample")) != p) {
-                       if (!parse_only)
-                               dump_samples ();
-                       continue;
-               }
-               if ((opt = match_option (p, "counters")) != p) {
-                       if (!parse_only)
-                               dump_counters ();
-                       continue;
-               }
-               if ((opt = match_option (p, "coverage")) != p) {
-                       if (!parse_only)
-                               dump_coverage ();
-                       continue;
-               }
-               if ((opt = match_option (p, "stats")) != p) {
-                       if (!parse_only)
-                               dump_stats ();
-                       continue;
-               }
-               return 0;
-       }
-       return 1;
-}
-
-static int
-add_find_spec (const char *p)
-{
-       if (p [0] == 'S' && p [1] == ':') {
-               char *vale;
-               find_size = strtoul (p + 2, &vale, 10);
-               return 1;
-       } else if (p [0] == 'T' && p [1] == ':') {
-               find_name = p + 2;
-               return 1;
-       }
-       return 0;
-}
-
-static void
-usage (void)
-{
-       printf ("Mono log profiler report version %d.%d\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR);
-       printf ("Usage: mprof-report [OPTIONS] FILENAME\n");
-       printf ("FILENAME can be '-' to read from standard input.\n");
-       printf ("Options:\n");
-       printf ("\t--help               display this help\n");
-       printf ("\t--out=FILE           write to FILE instead of stdout\n");
-       printf ("\t--traces             collect and show backtraces\n");
-       printf ("\t--maxframes=NUM      limit backtraces to NUM entries\n");
-       printf ("\t--reports=R1[,R2...] print the specified reports. Defaults are:\n");
-       printf ("\t                     %s\n", reports);
-       printf ("\t--method-sort=MODE   sort methods according to MODE: total, self, calls\n");
-       printf ("\t--alloc-sort=MODE    sort allocations according to MODE: bytes, count\n");
-       printf ("\t--counters-sort=MODE sort counters according to MODE: time, category\n");
-       printf ("\t                     only accessible in verbose mode\n");
-       printf ("\t--track=OB1[,OB2...] track what happens to objects OBJ1, O2 etc.\n");
-       printf ("\t--find=FINDSPEC      find and track objects matching FINFSPEC, where FINDSPEC is:\n");
-       printf ("\t                     S:minimum_size or T:partial_name\n");
-       printf ("\t--thread=THREADID    consider just the data for thread THREADID\n");
-       printf ("\t--time=FROM-TO       consider data FROM seconds from startup up to TO seconds\n");
-       printf ("\t--verbose            increase verbosity level\n");
-       printf ("\t--debug              display decoding debug info for mprof-report devs\n");
-       printf ("\t--coverage-out=FILE  write the coverage info to FILE as XML\n");
-}
-
-int
-main (int argc, char *argv[])
-{
-       ProfContext *ctx;
-       int i;
-       outfile = stdout;
-       for (i = 1; i < argc; ++i) {
-               if (strcmp ("--debug", argv [i]) == 0) {
-                       debug++;
-               } else if (strcmp ("--help", argv [i]) == 0) {
-                       usage ();
-                       return 0;
-               } else if (strncmp ("--alloc-sort=", argv [i], 13) == 0) {
-                       const char *val = argv [i] + 13;
-                       if (strcmp (val, "bytes") == 0) {
-                               alloc_sort_mode = ALLOC_SORT_BYTES;
-                       } else if (strcmp (val, "count") == 0) {
-                               alloc_sort_mode = ALLOC_SORT_COUNT;
-                       } else {
-                               usage ();
-                               return 1;
-                       }
-               } else if (strncmp ("--method-sort=", argv [i], 14) == 0) {
-                       const char *val = argv [i] + 14;
-                       if (strcmp (val, "total") == 0) {
-                               method_sort_mode = METHOD_SORT_TOTAL;
-                       } else if (strcmp (val, "self") == 0) {
-                               method_sort_mode = METHOD_SORT_SELF;
-                       } else if (strcmp (val, "calls") == 0) {
-                               method_sort_mode = METHOD_SORT_CALLS;
-                       } else {
-                               usage ();
-                               return 1;
-                       }
-               } else if (strncmp ("--counters-sort=", argv [i], 16) == 0) {
-                       const char *val = argv [i] + 16;
-                       if (strcmp (val, "time") == 0) {
-                               counters_sort_mode = COUNTERS_SORT_TIME;
-                       } else if (strcmp (val, "category") == 0) {
-                               counters_sort_mode = COUNTERS_SORT_CATEGORY;
-                       } else {
-                               usage ();
-                               return 1;
-                       }
-               } else if (strncmp ("--reports=", argv [i], 10) == 0) {
-                       const char *val = argv [i] + 10;
-                       if (!print_reports (NULL, val, 1)) {
-                               usage ();
-                               return 1;
-                       }
-                       reports = val;
-               } else if (strncmp ("--out=", argv [i], 6) == 0) {
-                       const char *val = argv [i] + 6;
-                       outfile = fopen (val, "w");
-                       if (!outfile) {
-                               printf ("Cannot open output file: %s\n", val);
-                               return 1;
-                       }
-               } else if (strncmp ("--maxframes=", argv [i], 12) == 0) {
-                       const char *val = argv [i] + 12;
-                       char *vale;
-                       trace_max = strtoul (val, &vale, 10);
-               } else if (strncmp ("--find=", argv [i], 7) == 0) {
-                       const char *val = argv [i] + 7;
-                       if (!add_find_spec (val)) {
-                               usage ();
-                               return 1;
-                       }
-               } else if (strncmp ("--track=", argv [i], 8) == 0) {
-                       const char *val = argv [i] + 8;
-                       char *vale;
-                       while (*val) {
-                               uintptr_t tracked_obj;
-                               if (*val == ',') {
-                                       val++;
-                                       continue;
-                               }
-                               tracked_obj = strtoul (val, &vale, 0);
-                               found_object (tracked_obj);
-                               val = vale;
-                       }
-               } else if (strncmp ("--thread=", argv [i], 9) == 0) {
-                       const char *val = argv [i] + 9;
-                       char *vale;
-                       thread_filter = strtoul (val, &vale, 0);
-               } else if (strncmp ("--time=", argv [i], 7) == 0) {
-                       char *val = pstrdup (argv [i] + 7);
-                       double from_secs, to_secs;
-                       char *top = strchr (val, '-');
-                       if (!top) {
-                               usage ();
-                               return 1;
-                       }
-                       *top++ = 0;
-                       from_secs = atof (val);
-                       to_secs = atof (top);
-                       g_free (val);
-                       if (from_secs > to_secs) {
-                               usage ();
-                               return 1;
-                       }
-                       time_from = from_secs * 1000000000;
-                       time_to = to_secs * 1000000000;
-                       use_time_filter = 1;
-               } else if (strcmp ("--verbose", argv [i]) == 0) {
-                       verbose++;
-               } else if (strcmp ("--traces", argv [i]) == 0) {
-                       show_traces = 1;
-                       collect_traces = 1;
-               } else if (strncmp ("--coverage-out=", argv [i], 15) == 0) {
-                       const char *val = argv [i] + 15;
-                       coverage_outfile = fopen (val, "w");
-                       if (!coverage_outfile) {
-                               printf ("Cannot open output file: %s\n", val);
-                               return 1;
-                       }
-               } else {
-                       break;
-               }
-       }
-       if (i >= argc) {
-               usage ();
-               return 2;
-       }
-       ctx = load_file (argv [i]);
-       if (!ctx) {
-               printf ("Not a log profiler data file (or unsupported version).\n");
-               return 1;
-       }
-       while (decode_buffer (ctx));
-       flush_context (ctx);
-       if (num_tracked_objects)
-               return 0;
-       print_reports (ctx, reports, 0);
-       return 0;
-}
diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c
new file mode 100644 (file)
index 0000000..ae6c720
--- /dev/null
@@ -0,0 +1,5025 @@
+/*
+ * mono-profiler-log.c: mono log profiler
+ *
+ * Authors:
+ *   Paolo Molaro (lupus@ximian.com)
+ *   Alex Rønne Petersen (alexrp@xamarin.com)
+ *
+ * Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+#include <config.h>
+#include <mono/metadata/assembly.h>
+#include <mono/metadata/debug-helpers.h>
+#include "../metadata/metadata-internals.h"
+#include <mono/metadata/mono-config.h>
+#include <mono/metadata/mono-gc.h>
+#include <mono/metadata/mono-perfcounters.h>
+#include <mono/metadata/profiler.h>
+#include <mono/utils/atomic.h>
+#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/lock-free-alloc.h>
+#include <mono/utils/lock-free-queue.h>
+#include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-linked-list-set.h>
+#include <mono/utils/mono-membar.h>
+#include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-os-mutex.h>
+#include <mono/utils/mono-os-semaphore.h>
+#include <mono/utils/mono-threads.h>
+#include <mono/utils/mono-threads-api.h>
+#include "mono-profiler-log.h"
+
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_LINK_H
+#include <link.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined(__APPLE__)
+#include <mach/mach_time.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
+#endif
+#include <sys/socket.h>
+#if defined (HAVE_SYS_ZLIB)
+#include <zlib.h>
+#endif
+
+#define BUFFER_SIZE (4096 * 16)
+
+/* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
+#define LEB128_SIZE 10
+
+/* Size of a value encoded as a single byte. */
+#undef BYTE_SIZE // mach/i386/vm_param.h on OS X defines this to 8, but it isn't used for anything.
+#define BYTE_SIZE 1
+
+/* Size in bytes of the event prefix (ID + time). */
+#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
+
+static volatile gint32 runtime_inited;
+static volatile gint32 in_shutdown;
+
+static gboolean no_counters;
+static int nocalls = 0;
+static int notraces = 0;
+static int use_zip = 0;
+static int do_report = 0;
+static int do_heap_shot = 0;
+static int max_call_depth = 100;
+static int command_port = 0;
+static int heapshot_requested = 0;
+static int sample_freq = 0;
+static int do_mono_sample = 0;
+static int do_debug = 0;
+static int do_coverage = 0;
+static gboolean only_coverage;
+static gboolean debug_coverage = FALSE;
+static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
+static int max_allocated_sample_hits;
+
+// Statistics for internal profiler data structures.
+static gint32 sample_allocations_ctr,
+              buffer_allocations_ctr;
+
+// Statistics for profiler events.
+static gint32 sync_points_ctr,
+              heap_objects_ctr,
+              heap_starts_ctr,
+              heap_ends_ctr,
+              heap_roots_ctr,
+              gc_events_ctr,
+              gc_resizes_ctr,
+              gc_allocs_ctr,
+              gc_moves_ctr,
+              gc_handle_creations_ctr,
+              gc_handle_deletions_ctr,
+              finalize_begins_ctr,
+              finalize_ends_ctr,
+              finalize_object_begins_ctr,
+              finalize_object_ends_ctr,
+              image_loads_ctr,
+              image_unloads_ctr,
+              assembly_loads_ctr,
+              assembly_unloads_ctr,
+              class_loads_ctr,
+              class_unloads_ctr,
+              method_entries_ctr,
+              method_exits_ctr,
+              method_exception_exits_ctr,
+              method_jits_ctr,
+              code_buffers_ctr,
+              exception_throws_ctr,
+              exception_clauses_ctr,
+              monitor_contentions_ctr,
+              monitor_acquisitions_ctr,
+              monitor_failures_ctr,
+              thread_starts_ctr,
+              thread_ends_ctr,
+              thread_names_ctr,
+              domain_loads_ctr,
+              domain_unloads_ctr,
+              domain_names_ctr,
+              context_loads_ctr,
+              context_unloads_ctr,
+              sample_ubins_ctr,
+              sample_usyms_ctr,
+              sample_hits_ctr,
+              counter_descriptors_ctr,
+              counter_samples_ctr,
+              perfcounter_descriptors_ctr,
+              perfcounter_samples_ctr,
+              coverage_methods_ctr,
+              coverage_statements_ctr,
+              coverage_classes_ctr,
+              coverage_assemblies_ctr;
+
+static MonoLinkedListSet profiler_thread_list;
+
+/*
+ * file format:
+ * [header] [buffer]*
+ *
+ * The file is composed by a header followed by 0 or more buffers.
+ * Each buffer contains events that happened on a thread: for a given thread
+ * buffers that appear later in the file are guaranteed to contain events
+ * that happened later in time. Buffers from separate threads could be interleaved,
+ * though.
+ * Buffers are not required to be aligned.
+ *
+ * header format:
+ * [id: 4 bytes] constant value: LOG_HEADER_ID
+ * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler
+ * [format: 1 byte] version of the data format for the rest of the file
+ * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program
+ * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started
+ * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer
+ * [flags: 4 bytes] file format flags, should be 0 for now
+ * [pid: 4 bytes] pid of the profiled process
+ * [port: 2 bytes] tcp port for server if != 0
+ * [args size: 4 bytes] size of args
+ * [args: string] arguments passed to the profiler
+ * [arch size: 4 bytes] size of arch
+ * [arch: string] architecture the profiler is running on
+ * [os size: 4 bytes] size of os
+ * [os: string] operating system the profiler is running on
+ *
+ * The multiple byte integers are in little-endian format.
+ *
+ * buffer format:
+ * [buffer header] [event]*
+ * Buffers have a fixed-size header followed by 0 or more bytes of event data.
+ * Timing information and other values in the event data are usually stored
+ * as uleb128 or sleb128 integers. To save space, as noted for each item below,
+ * some data is represented as a difference between the actual value and
+ * either the last value of the same type (like for timing information) or
+ * as the difference from a value stored in a buffer header.
+ *
+ * For timing information the data is stored as uleb128, since timing
+ * increases in a monotonic way in each thread: the value is the number of
+ * nanoseconds to add to the last seen timing data in a buffer. The first value
+ * in a buffer will be calculated from the time_base field in the buffer head.
+ *
+ * Object or heap sizes are stored as uleb128.
+ * Pointer differences are stored as sleb128, instead.
+ *
+ * If an unexpected value is found, the rest of the buffer should be ignored,
+ * as generally the later values need the former to be interpreted correctly.
+ *
+ * buffer header format:
+ * [bufid: 4 bytes] constant value: BUF_ID
+ * [len: 4 bytes] size of the data following the buffer header
+ * [time_base: 8 bytes] time base in nanoseconds since an unspecified epoch
+ * [ptr_base: 8 bytes] base value for pointers
+ * [obj_base: 8 bytes] base value for object addresses
+ * [thread id: 8 bytes] system-specific thread ID (pthread_t for example)
+ * [method_base: 8 bytes] base value for MonoMethod pointers
+ *
+ * event format:
+ * [extended info: upper 4 bits] [type: lower 4 bits]
+ * [time diff: uleb128] nanoseconds since last timing
+ * [data]*
+ * The data that follows depends on type and the extended info.
+ * Type is one of the enum values in mono-profiler-log.h: TYPE_ALLOC, TYPE_GC,
+ * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
+ * The extended info bits are interpreted based on type, see
+ * each individual event description below.
+ * strings are represented as a 0-terminated utf8 sequence.
+ *
+ * backtrace format:
+ * [num: uleb128] number of frames following
+ * [frame: sleb128]* mum MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ *
+ * type alloc format:
+ * type: TYPE_ALLOC
+ * exinfo: flags: TYPE_ALLOC_BT
+ * [ptr: sleb128] class as a byte difference from ptr_base
+ * [obj: sleb128] object address as a byte difference from obj_base
+ * [size: uleb128] size of the object in the heap
+ * If the TYPE_ALLOC_BT flag is set, a backtrace follows.
+ *
+ * type GC format:
+ * type: TYPE_GC
+ * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
+ * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
+ * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
+ * if exinfo == TYPE_GC_RESIZE
+ *     [heap_size: uleb128] new heap size
+ * if exinfo == TYPE_GC_EVENT
+ *     [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
+ *     [generation: byte] GC generation event refers to
+ * if exinfo == TYPE_GC_MOVE
+ *     [num_objects: uleb128] number of object moves that follow
+ *     [objaddr: sleb128]+ num_objects object pointer differences from obj_base
+ *     num is always an even number: the even items are the old
+ *     addresses, the odd numbers are the respective new object addresses
+ * if exinfo == TYPE_GC_HANDLE_CREATED[_BT]
+ *     [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
+ *     upper bits reserved as flags
+ *     [handle: uleb128] GC handle value
+ *     [objaddr: sleb128] object pointer differences from obj_base
+ *     If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT]
+ *     [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
+ *     upper bits reserved as flags
+ *     [handle: uleb128] GC handle value
+ *     If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
+ *     [object: sleb128] the object as a difference from obj_base
+ *
+ * type metadata format:
+ * type: TYPE_METADATA
+ * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN)
+ * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
+ * TYPE_THREAD, TYPE_CONTEXT
+ * [pointer: sleb128] pointer of the metadata type depending on mtype
+ * if mtype == TYPE_CLASS
+ *     [image: sleb128] MonoImage* as a pointer difference from ptr_base
+ *     [name: string] full class name
+ * if mtype == TYPE_IMAGE
+ *     [name: string] image file name
+ * if mtype == TYPE_ASSEMBLY
+ *     [name: string] assembly name
+ * if mtype == TYPE_DOMAIN && exinfo == 0
+ *     [name: string] domain friendly name
+ * if mtype == TYPE_CONTEXT
+ *     [domain: sleb128] domain id as pointer
+ * if mtype == TYPE_THREAD && exinfo == 0
+ *     [name: string] thread name
+ *
+ * type method format:
+ * type: TYPE_METHOD
+ * exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
+ * [method: sleb128] MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ * if exinfo == TYPE_JIT
+ *     [code address: sleb128] pointer to the native code as a diff from ptr_base
+ *     [code size: uleb128] size of the generated code
+ *     [name: string] full method name
+ *
+ * type exception format:
+ * type: TYPE_EXCEPTION
+ * exinfo: TYPE_THROW_BT flag or one of: TYPE_CLAUSE
+ * if exinfo == TYPE_CLAUSE
+ *     [clause type: byte] MonoExceptionEnum enum value
+ *     [clause index: uleb128] index of the current clause
+ *     [method: sleb128] MonoMethod* as a pointer difference from the last such
+ *     pointer or the buffer method_base
+ * else
+ *     [object: sleb128] the exception object as a difference from obj_base
+ *     if exinfo has TYPE_THROW_BT set, a backtrace follows.
+ *
+ * type runtime format:
+ * type: TYPE_RUNTIME
+ * exinfo: one of: TYPE_JITHELPER
+ * if exinfo == TYPE_JITHELPER
+ *     [type: byte] MonoProfilerCodeBufferType enum value
+ *     [buffer address: sleb128] pointer to the native code as a diff from ptr_base
+ *     [buffer size: uleb128] size of the generated code
+ *     if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
+ *             [name: string] buffer description name
+ *
+ * type monitor format:
+ * type: TYPE_MONITOR
+ * exinfo: TYPE_MONITOR_BT flag and one of: MONO_PROFILER_MONITOR_(CONTENTION|FAIL|DONE)
+ * [object: sleb128] the lock object as a difference from obj_base
+ * if exinfo.low3bits == MONO_PROFILER_MONITOR_CONTENTION
+ *     If the TYPE_MONITOR_BT flag is set, a backtrace follows.
+ *
+ * type heap format
+ * type: TYPE_HEAP
+ * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
+ * if exinfo == TYPE_HEAP_OBJECT
+ *     [object: sleb128] the object as a difference from obj_base
+ *     [class: sleb128] the object MonoClass* as a difference from ptr_base
+ *     [size: uleb128] size of the object on the heap
+ *     [num_refs: uleb128] number of object references
+ *     each referenced objref is preceded by a uleb128 encoded offset: the
+ *     first offset is from the object address and each next offset is relative
+ *     to the previous one
+ *     [objrefs: sleb128]+ object referenced as a difference from obj_base
+ *     The same object can appear multiple times, but only the first time
+ *     with size != 0: in the other cases this data will only be used to
+ *     provide additional referenced objects.
+ * if exinfo == TYPE_HEAP_ROOT
+ *     [num_roots: uleb128] number of root references
+ *     [num_gc: uleb128] number of major gcs
+ *     [object: sleb128] the object as a difference from obj_base
+ *     [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
+ *     [extra_info: uleb128] the extra_info value
+ *     object, root_type and extra_info are repeated num_roots times
+ *
+ * type sample format
+ * type: TYPE_SAMPLE
+ * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
+ * if exinfo == TYPE_SAMPLE_HIT
+ *     [thread: sleb128] thread id as difference from ptr_base
+ *     [count: uleb128] number of following instruction addresses
+ *     [ip: sleb128]* instruction pointer as difference from ptr_base
+ *     [mbt_count: uleb128] number of managed backtrace frames
+ *     [method: sleb128]* MonoMethod* as a pointer difference from the last such
+ *     pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
+ * if exinfo == TYPE_SAMPLE_USYM
+ *     [address: sleb128] symbol address as a difference from ptr_base
+ *     [size: uleb128] symbol size (may be 0 if unknown)
+ *     [name: string] symbol name
+ * if exinfo == TYPE_SAMPLE_UBIN
+ *     [address: sleb128] address where binary has been loaded
+ *     [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
+ *     [size: uleb128] memory size
+ *     [name: string] binary name
+ * if exinfo == TYPE_SAMPLE_COUNTERS_DESC
+ *     [len: uleb128] number of counters
+ *     for i = 0 to len
+ *             [section: uleb128] section of counter
+ *             if section == MONO_COUNTER_PERFCOUNTERS:
+ *                     [section_name: string] section name of counter
+ *             [name: string] name of counter
+ *             [type: byte] type of counter
+ *             [unit: byte] unit of counter
+ *             [variance: byte] variance of counter
+ *             [index: uleb128] unique index of counter
+ * if exinfo == TYPE_SAMPLE_COUNTERS
+ *     while true:
+ *             [index: uleb128] unique index of counter
+ *             if index == 0:
+ *                     break
+ *             [type: byte] type of counter value
+ *             if type == string:
+ *                     if value == null:
+ *                             [0: uleb128] 0 -> value is null
+ *                     else:
+ *                             [1: uleb128] 1 -> value is not null
+ *                             [value: string] counter value
+ *             else:
+ *                     [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type)
+ *
+ * type coverage format
+ * type: TYPE_COVERAGE
+ * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS
+ * if exinfo == TYPE_COVERAGE_METHOD
+ *  [assembly: string] name of assembly
+ *  [class: string] name of the class
+ *  [name: string] name of the method
+ *  [signature: string] the signature of the method
+ *  [filename: string] the file path of the file that contains this method
+ *  [token: uleb128] the method token
+ *  [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS
+ *  [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method
+ * if exinfo == TYPE_COVERAGE_STATEMENTS
+ *  [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with
+ *  [offset: uleb128] the il offset relative to the previous offset
+ *  [counter: uleb128] the counter for this instruction
+ *  [line: uleb128] the line of filename containing this instruction
+ *  [column: uleb128] the column containing this instruction
+ * if exinfo == TYPE_COVERAGE_ASSEMBLY
+ *  [name: string] assembly name
+ *  [guid: string] assembly GUID
+ *  [filename: string] assembly filename
+ *  [number_of_methods: uleb128] the number of methods in this assembly
+ *  [fully_covered: uleb128] the number of fully covered methods
+ *  [partially_covered: uleb128] the number of partially covered methods
+ *    currently partially_covered will always be 0, and fully_covered is the
+ *    number of methods that are fully and partially covered.
+ * if exinfo == TYPE_COVERAGE_CLASS
+ *  [name: string] assembly name
+ *  [class: string] class name
+ *  [number_of_methods: uleb128] the number of methods in this class
+ *  [fully_covered: uleb128] the number of fully covered methods
+ *  [partially_covered: uleb128] the number of partially covered methods
+ *    currently partially_covered will always be 0, and fully_covered is the
+ *    number of methods that are fully and partially covered.
+ *
+ * type meta format:
+ * type: TYPE_META
+ * exinfo: one of: TYPE_SYNC_POINT
+ * if exinfo == TYPE_SYNC_POINT
+ *     [type: byte] MonoProfilerSyncPointType enum value
+ */
+
+// Pending data to be written to the log, for a single thread.
+// Threads periodically flush their own LogBuffers by calling safe_send
+typedef struct _LogBuffer LogBuffer;
+struct _LogBuffer {
+       // Next (older) LogBuffer in processing queue
+       LogBuffer *next;
+
+       uint64_t time_base;
+       uint64_t last_time;
+       uintptr_t ptr_base;
+       uintptr_t method_base;
+       uintptr_t last_method;
+       uintptr_t obj_base;
+       uintptr_t thread_id;
+
+       // Bytes allocated for this LogBuffer
+       int size;
+
+       // Start of currently unused space in buffer
+       unsigned char* cursor;
+
+       // Pointer to start-of-structure-plus-size (for convenience)
+       unsigned char* buf_end;
+
+       // Start of data in buffer. Contents follow "buffer format" described above.
+       unsigned char buf [1];
+};
+
+typedef struct {
+       MonoLinkedListSetNode node;
+
+       // Convenience pointer to the profiler structure.
+       MonoProfiler *profiler;
+
+       // Was this thread added to the LLS?
+       gboolean attached;
+
+       // The current log buffer for this thread.
+       LogBuffer *buffer;
+
+       // Methods referenced by events in `buffer`, see `MethodInfo`.
+       GPtrArray *methods;
+
+       // Current call depth for enter/leave events.
+       int call_depth;
+
+       // Indicates whether this thread is currently writing to its `buffer`.
+       gboolean busy;
+
+       // Has this thread written a thread end event to `buffer`?
+       gboolean ended;
+} MonoProfilerThread;
+
+static uintptr_t
+thread_id (void)
+{
+       return (uintptr_t) mono_native_thread_id_get ();
+}
+
+static uintptr_t
+process_id (void)
+{
+#ifdef HOST_WIN32
+       return (uintptr_t) GetCurrentProcessId ();
+#else
+       return (uintptr_t) getpid ();
+#endif
+}
+
+#ifdef __APPLE__
+static mach_timebase_info_data_t timebase_info;
+#elif defined (HOST_WIN32)
+static LARGE_INTEGER pcounter_freq;
+#endif
+
+#define TICKS_PER_SEC 1000000000LL
+
+static uint64_t
+current_time (void)
+{
+#ifdef __APPLE__
+       uint64_t time = mach_absolute_time ();
+
+       time *= timebase_info.numer;
+       time /= timebase_info.denom;
+
+       return time;
+#elif defined (HOST_WIN32)
+       LARGE_INTEGER value;
+
+       QueryPerformanceCounter (&value);
+
+       return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart;
+#elif defined (CLOCK_MONOTONIC)
+       struct timespec tspec;
+
+       clock_gettime (CLOCK_MONOTONIC, &tspec);
+
+       return ((uint64_t) tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
+#else
+       struct timeval tv;
+
+       gettimeofday (&tv, NULL);
+
+       return ((uint64_t) tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
+#endif
+}
+
+static int timer_overhead;
+
+static void
+init_time (void)
+{
+#ifdef __APPLE__
+       mach_timebase_info (&timebase_info);
+#elif defined (HOST_WIN32)
+       QueryPerformanceFrequency (&pcounter_freq);
+#endif
+
+       uint64_t time_start = current_time ();
+
+       for (int i = 0; i < 256; ++i)
+               current_time ();
+
+       uint64_t time_end = current_time ();
+
+       timer_overhead = (time_end - time_start) / 256;
+}
+
+/*
+ * These macros should be used when writing an event to a log buffer. They take
+ * care of a bunch of stuff that can be repetitive and error-prone, such as
+ * acquiring/releasing the buffer lock, incrementing the event counter,
+ * expanding the log buffer, processing requests, etc. They also create a scope
+ * so that it's harder to leak the LogBuffer pointer, which can be problematic
+ * as the pointer is unstable when the buffer lock isn't acquired.
+ */
+
+#define ENTER_LOG(COUNTER, BUFFER, SIZE) \
+       do { \
+               MonoProfilerThread *thread__ = PROF_TLS_GET (); \
+               if (thread__->attached) \
+                       buffer_lock (); \
+               g_assert (!thread__->busy && "Why are we trying to write a new event while already writing one?"); \
+               thread__->busy = TRUE; \
+               InterlockedIncrement ((COUNTER)); \
+               LogBuffer *BUFFER = ensure_logbuf_unsafe (thread__, (SIZE))
+
+#define EXIT_LOG_EXPLICIT(SEND, REQUESTS) \
+               thread__->busy = FALSE; \
+               if ((SEND)) \
+                       send_log_unsafe (TRUE); \
+               if (thread__->attached) \
+                       buffer_unlock (); \
+               if ((REQUESTS)) \
+                       process_requests (); \
+       } while (0)
+
+// Pass these to EXIT_LOG_EXPLICIT () for easier reading.
+#define DO_SEND TRUE
+#define NO_SEND FALSE
+#define DO_REQUESTS TRUE
+#define NO_REQUESTS FALSE
+
+#define EXIT_LOG EXIT_LOG_EXPLICIT (DO_SEND, DO_REQUESTS)
+
+static volatile gint32 buffer_rwlock_count;
+static volatile gpointer buffer_rwlock_exclusive;
+
+// Can be used recursively.
+static void
+buffer_lock (void)
+{
+       /*
+        * If the thread holding the exclusive lock tries to modify the
+        * reader count, just make it a no-op. This way, we also avoid
+        * invoking the GC safe point macros below, which could break if
+        * done from a thread that is currently the initiator of STW.
+        *
+        * In other words, we rely on the fact that the GC thread takes
+        * the exclusive lock in the gc_event () callback when the world
+        * is about to stop.
+        */
+       if (InterlockedReadPointer (&buffer_rwlock_exclusive) != (gpointer) thread_id ()) {
+               MONO_ENTER_GC_SAFE;
+
+               while (InterlockedReadPointer (&buffer_rwlock_exclusive))
+                       mono_thread_info_yield ();
+
+               InterlockedIncrement (&buffer_rwlock_count);
+
+               MONO_EXIT_GC_SAFE;
+       }
+
+       mono_memory_barrier ();
+}
+
+static void
+buffer_unlock (void)
+{
+       mono_memory_barrier ();
+
+       // See the comment in buffer_lock ().
+       if (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id ())
+               return;
+
+       g_assert (InterlockedRead (&buffer_rwlock_count) && "Why are we trying to decrement a zero reader count?");
+
+       InterlockedDecrement (&buffer_rwlock_count);
+}
+
+// Cannot be used recursively.
+static void
+buffer_lock_excl (void)
+{
+       gpointer tid = (gpointer) thread_id ();
+
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) != tid && "Why are we taking the exclusive lock twice?");
+
+       MONO_ENTER_GC_SAFE;
+
+       while (InterlockedCompareExchangePointer (&buffer_rwlock_exclusive, tid, 0))
+               mono_thread_info_yield ();
+
+       while (InterlockedRead (&buffer_rwlock_count))
+               mono_thread_info_yield ();
+
+       MONO_EXIT_GC_SAFE;
+
+       mono_memory_barrier ();
+}
+
+static void
+buffer_unlock_excl (void)
+{
+       mono_memory_barrier ();
+
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why is the exclusive lock not held?");
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why does another thread hold the exclusive lock?");
+       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why are there readers when the exclusive lock is held?");
+
+       InterlockedWritePointer (&buffer_rwlock_exclusive, NULL);
+}
+
+typedef struct _BinaryObject BinaryObject;
+struct _BinaryObject {
+       BinaryObject *next;
+       void *addr;
+       char *name;
+};
+
+struct _MonoProfiler {
+       FILE* file;
+#if defined (HAVE_SYS_ZLIB)
+       gzFile gzfile;
+#endif
+       char *args;
+       uint64_t startup_time;
+       int pipe_output;
+       int command_port;
+       int server_socket;
+       int pipes [2];
+       MonoNativeThreadId helper_thread;
+       MonoNativeThreadId writer_thread;
+       MonoNativeThreadId dumper_thread;
+       volatile gint32 run_writer_thread;
+       MonoLockFreeAllocSizeClass writer_entry_size_class;
+       MonoLockFreeAllocator writer_entry_allocator;
+       MonoLockFreeQueue writer_queue;
+       MonoSemType writer_queue_sem;
+       MonoConcurrentHashTable *method_table;
+       mono_mutex_t method_table_mutex;
+       volatile gint32 run_dumper_thread;
+       MonoLockFreeQueue dumper_queue;
+       MonoSemType dumper_queue_sem;
+       MonoLockFreeAllocSizeClass sample_size_class;
+       MonoLockFreeAllocator sample_allocator;
+       MonoLockFreeQueue sample_reuse_queue;
+       BinaryObject *binary_objects;
+       GPtrArray *coverage_filters;
+};
+
+typedef struct {
+       MonoLockFreeQueueNode node;
+       GPtrArray *methods;
+       LogBuffer *buffer;
+} WriterQueueEntry;
+
+#define WRITER_ENTRY_BLOCK_SIZE (mono_pagesize ())
+
+typedef struct {
+       MonoMethod *method;
+       MonoJitInfo *ji;
+       uint64_t time;
+} MethodInfo;
+
+#ifdef HOST_WIN32
+
+#define PROF_TLS_SET(VAL) (TlsSetValue (profiler_tls, (VAL)))
+#define PROF_TLS_GET() ((MonoProfilerThread *) TlsGetValue (profiler_tls))
+#define PROF_TLS_INIT() (profiler_tls = TlsAlloc ())
+#define PROF_TLS_FREE() (TlsFree (profiler_tls))
+
+static DWORD profiler_tls;
+
+#elif HAVE_KW_THREAD
+
+#define PROF_TLS_SET(VAL) (profiler_tls = (VAL))
+#define PROF_TLS_GET() (profiler_tls)
+#define PROF_TLS_INIT()
+#define PROF_TLS_FREE()
+
+static __thread MonoProfilerThread *profiler_tls;
+
+#else
+
+#define PROF_TLS_SET(VAL) (pthread_setspecific (profiler_tls, (VAL)))
+#define PROF_TLS_GET() ((MonoProfilerThread *) pthread_getspecific (profiler_tls))
+#define PROF_TLS_INIT() (pthread_key_create (&profiler_tls, NULL))
+#define PROF_TLS_FREE() (pthread_key_delete (profiler_tls))
+
+static pthread_key_t profiler_tls;
+
+#endif
+
+static char*
+pstrdup (const char *s)
+{
+       int len = strlen (s) + 1;
+       char *p = (char *) g_malloc (len);
+       memcpy (p, s, len);
+       return p;
+}
+
+static void *
+alloc_buffer (int size)
+{
+       return mono_valloc (NULL, size, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_ANON | MONO_MMAP_PRIVATE, MONO_MEM_ACCOUNT_PROFILER);
+}
+
+static void
+free_buffer (void *buf, int size)
+{
+       mono_vfree (buf, size, MONO_MEM_ACCOUNT_PROFILER);
+}
+
+static LogBuffer*
+create_buffer (uintptr_t tid)
+{
+       LogBuffer* buf = (LogBuffer *) alloc_buffer (BUFFER_SIZE);
+
+       InterlockedIncrement (&buffer_allocations_ctr);
+
+       buf->size = BUFFER_SIZE;
+       buf->time_base = current_time ();
+       buf->last_time = buf->time_base;
+       buf->buf_end = (unsigned char *) buf + buf->size;
+       buf->cursor = buf->buf;
+       buf->thread_id = tid;
+
+       return buf;
+}
+
+/*
+ * Must be called with the reader lock held if thread is the current thread, or
+ * the exclusive lock if thread is a different thread. However, if thread is
+ * the current thread, and init_thread () was called with add_to_lls = FALSE,
+ * then no locking is necessary.
+ */
+static void
+init_buffer_state (MonoProfilerThread *thread)
+{
+       thread->buffer = create_buffer (thread->node.key);
+       thread->methods = NULL;
+}
+
+static void
+clear_hazard_pointers (MonoThreadHazardPointers *hp)
+{
+       mono_hazard_pointer_clear (hp, 0);
+       mono_hazard_pointer_clear (hp, 1);
+       mono_hazard_pointer_clear (hp, 2);
+}
+
+static MonoProfilerThread *
+init_thread (MonoProfiler *prof, gboolean add_to_lls)
+{
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+
+       /*
+        * Sometimes we may try to initialize a thread twice. One example is the
+        * main thread: We initialize it when setting up the profiler, but we will
+        * also get a thread_start () callback for it. Another example is when
+        * attaching new threads to the runtime: We may get a gc_alloc () callback
+        * for that thread's thread object (where we initialize it), soon followed
+        * by a thread_start () callback.
+        *
+        * These cases are harmless anyhow. Just return if we've already done the
+        * initialization work.
+        */
+       if (thread)
+               return thread;
+
+       thread = g_malloc (sizeof (MonoProfilerThread));
+       thread->node.key = thread_id ();
+       thread->profiler = prof;
+       thread->attached = add_to_lls;
+       thread->call_depth = 0;
+       thread->busy = 0;
+       thread->ended = FALSE;
+
+       init_buffer_state (thread);
+
+       /*
+        * Some internal profiler threads don't need to be cleaned up
+        * by the main thread on shutdown.
+        */
+       if (add_to_lls) {
+               MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+               g_assert (mono_lls_insert (&profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
+               clear_hazard_pointers (hp);
+       }
+
+       PROF_TLS_SET (thread);
+
+       return thread;
+}
+
+// Only valid if init_thread () was called with add_to_lls = FALSE.
+static void
+deinit_thread (MonoProfilerThread *thread)
+{
+       g_assert (!thread->attached && "Why are we manually freeing an attached thread?");
+
+       g_free (thread);
+       PROF_TLS_SET (NULL);
+}
+
+// Only valid if init_thread () was called with add_to_lls = FALSE.
+static LogBuffer *
+ensure_logbuf_unsafe (MonoProfilerThread *thread, int bytes)
+{
+       LogBuffer *old = thread->buffer;
+
+       if (old && old->cursor + bytes + 100 < old->buf_end)
+               return old;
+
+       LogBuffer *new_ = create_buffer (thread->node.key);
+       new_->next = old;
+       thread->buffer = new_;
+
+       return new_;
+}
+
+static void
+encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
+{
+       uint8_t *p = buf;
+
+       do {
+               uint8_t b = value & 0x7f;
+               value >>= 7;
+
+               if (value != 0) /* more bytes to come */
+                       b |= 0x80;
+
+               *p ++ = b;
+       } while (value);
+
+       *endbuf = p;
+}
+
+static void
+encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
+{
+       int more = 1;
+       int negative = (value < 0);
+       unsigned int size = sizeof (intptr_t) * 8;
+       uint8_t byte;
+       uint8_t *p = buf;
+
+       while (more) {
+               byte = value & 0x7f;
+               value >>= 7;
+
+               /* the following is unnecessary if the
+                * implementation of >>= uses an arithmetic rather
+                * than logical shift for a signed left operand
+                */
+               if (negative)
+                       /* sign extend */
+                       value |= - ((intptr_t) 1 <<(size - 7));
+
+               /* sign bit of byte is second high order bit (0x40) */
+               if ((value == 0 && !(byte & 0x40)) ||
+                   (value == -1 && (byte & 0x40)))
+                       more = 0;
+               else
+                       byte |= 0x80;
+
+               *p ++= byte;
+       }
+
+       *endbuf = p;
+}
+
+static void
+emit_byte (LogBuffer *logbuffer, int value)
+{
+       logbuffer->cursor [0] = value;
+       logbuffer->cursor++;
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_value (LogBuffer *logbuffer, int value)
+{
+       encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_time (LogBuffer *logbuffer, uint64_t value)
+{
+       uint64_t tdiff = value - logbuffer->last_time;
+       encode_uleb128 (tdiff, logbuffer->cursor, &logbuffer->cursor);
+       logbuffer->last_time = value;
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_event_time (LogBuffer *logbuffer, int event, uint64_t time)
+{
+       emit_byte (logbuffer, event);
+       emit_time (logbuffer, time);
+}
+
+static void
+emit_event (LogBuffer *logbuffer, int event)
+{
+       emit_event_time (logbuffer, event, current_time ());
+}
+
+static void
+emit_svalue (LogBuffer *logbuffer, int64_t value)
+{
+       encode_sleb128 (value, logbuffer->cursor, &logbuffer->cursor);
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_uvalue (LogBuffer *logbuffer, uint64_t value)
+{
+       encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_ptr (LogBuffer *logbuffer, void *ptr)
+{
+       if (!logbuffer->ptr_base)
+               logbuffer->ptr_base = (uintptr_t) ptr;
+
+       emit_svalue (logbuffer, (intptr_t) ptr - logbuffer->ptr_base);
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_method_inner (LogBuffer *logbuffer, void *method)
+{
+       if (!logbuffer->method_base) {
+               logbuffer->method_base = (intptr_t) method;
+               logbuffer->last_method = (intptr_t) method;
+       }
+
+       encode_sleb128 ((intptr_t) ((char *) method - (char *) logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor);
+       logbuffer->last_method = (intptr_t) method;
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+register_method_local (MonoMethod *method, MonoJitInfo *ji)
+{
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+
+       if (!mono_conc_hashtable_lookup (thread->profiler->method_table, method)) {
+               MethodInfo *info = (MethodInfo *) g_malloc (sizeof (MethodInfo));
+
+               info->method = method;
+               info->ji = ji;
+               info->time = current_time ();
+
+               GPtrArray *arr = thread->methods ? thread->methods : (thread->methods = g_ptr_array_new ());
+               g_ptr_array_add (arr, info);
+       }
+}
+
+static void
+emit_method (LogBuffer *logbuffer, MonoMethod *method)
+{
+       register_method_local (method, NULL);
+       emit_method_inner (logbuffer, method);
+}
+
+static void
+emit_obj (LogBuffer *logbuffer, void *ptr)
+{
+       if (!logbuffer->obj_base)
+               logbuffer->obj_base = (uintptr_t) ptr >> 3;
+
+       emit_svalue (logbuffer, ((uintptr_t) ptr >> 3) - logbuffer->obj_base);
+
+       g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
+}
+
+static void
+emit_string (LogBuffer *logbuffer, const char *str, size_t size)
+{
+       size_t i = 0;
+       if (str) {
+               for (; i < size; i++) {
+                       if (str[i] == '\0')
+                               break;
+                       emit_byte (logbuffer, str [i]);
+               }
+       }
+       emit_byte (logbuffer, '\0');
+}
+
+static void
+emit_double (LogBuffer *logbuffer, double value)
+{
+       int i;
+       unsigned char buffer[8];
+       memcpy (buffer, &value, 8);
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+       for (i = 7; i >= 0; i--)
+#else
+       for (i = 0; i < 8; i++)
+#endif
+               emit_byte (logbuffer, buffer[i]);
+}
+
+static char*
+write_int16 (char *buf, int32_t value)
+{
+       int i;
+       for (i = 0; i < 2; ++i) {
+               buf [i] = value;
+               value >>= 8;
+       }
+       return buf + 2;
+}
+
+static char*
+write_int32 (char *buf, int32_t value)
+{
+       int i;
+       for (i = 0; i < 4; ++i) {
+               buf [i] = value;
+               value >>= 8;
+       }
+       return buf + 4;
+}
+
+static char*
+write_int64 (char *buf, int64_t value)
+{
+       int i;
+       for (i = 0; i < 8; ++i) {
+               buf [i] = value;
+               value >>= 8;
+       }
+       return buf + 8;
+}
+
+static char *
+write_header_string (char *p, const char *str)
+{
+       size_t len = strlen (str) + 1;
+
+       p = write_int32 (p, len);
+       strcpy (p, str);
+
+       return p + len;
+}
+
+static void
+dump_header (MonoProfiler *profiler)
+{
+       const char *args = profiler->args;
+       const char *arch = mono_config_get_cpu ();
+       const char *os = mono_config_get_os ();
+
+       char *hbuf = g_malloc (
+               sizeof (gint32) /* header id */ +
+               sizeof (gint8) /* major version */ +
+               sizeof (gint8) /* minor version */ +
+               sizeof (gint8) /* data version */ +
+               sizeof (gint8) /* word size */ +
+               sizeof (gint64) /* startup time */ +
+               sizeof (gint32) /* timer overhead */ +
+               sizeof (gint32) /* flags */ +
+               sizeof (gint32) /* process id */ +
+               sizeof (gint16) /* command port */ +
+               sizeof (gint32) + strlen (args) + 1 /* arguments */ +
+               sizeof (gint32) + strlen (arch) + 1 /* architecture */ +
+               sizeof (gint32) + strlen (os) + 1 /* operating system */
+       );
+       char *p = hbuf;
+
+       p = write_int32 (p, LOG_HEADER_ID);
+       *p++ = LOG_VERSION_MAJOR;
+       *p++ = LOG_VERSION_MINOR;
+       *p++ = LOG_DATA_VERSION;
+       *p++ = sizeof (void *);
+       p = write_int64 (p, ((uint64_t) time (NULL)) * 1000);
+       p = write_int32 (p, timer_overhead);
+       p = write_int32 (p, 0); /* flags */
+       p = write_int32 (p, process_id ());
+       p = write_int16 (p, profiler->command_port);
+       p = write_header_string (p, args);
+       p = write_header_string (p, arch);
+       p = write_header_string (p, os);
+
+#if defined (HAVE_SYS_ZLIB)
+       if (profiler->gzfile) {
+               gzwrite (profiler->gzfile, hbuf, p - hbuf);
+       } else
+#endif
+       {
+               fwrite (hbuf, p - hbuf, 1, profiler->file);
+               fflush (profiler->file);
+       }
+
+       g_free (hbuf);
+}
+
+/*
+ * Must be called with the reader lock held if thread is the current thread, or
+ * the exclusive lock if thread is a different thread. However, if thread is
+ * the current thread, and init_thread () was called with add_to_lls = FALSE,
+ * then no locking is necessary.
+ */
+static void
+send_buffer (MonoProfilerThread *thread)
+{
+       WriterQueueEntry *entry = mono_lock_free_alloc (&thread->profiler->writer_entry_allocator);
+       entry->methods = thread->methods;
+       entry->buffer = thread->buffer;
+
+       mono_lock_free_queue_node_init (&entry->node, FALSE);
+
+       mono_lock_free_queue_enqueue (&thread->profiler->writer_queue, &entry->node);
+       mono_os_sem_post (&thread->profiler->writer_queue_sem);
+}
+
+static void
+free_thread (gpointer p)
+{
+       MonoProfilerThread *thread = p;
+
+       if (!thread->ended) {
+               /*
+                * The thread is being cleaned up by the main thread during
+                * shutdown. This typically happens for internal runtime
+                * threads. We need to synthesize a thread end event.
+                */
+
+               InterlockedIncrement (&thread_ends_ctr);
+
+               LogBuffer *buf = ensure_logbuf_unsafe (thread,
+                       EVENT_SIZE /* event */ +
+                       BYTE_SIZE /* type */ +
+                       LEB128_SIZE /* tid */
+               );
+
+               emit_event (buf, TYPE_END_UNLOAD | TYPE_METADATA);
+               emit_byte (buf, TYPE_THREAD);
+               emit_ptr (buf, (void *) thread->node.key);
+       }
+
+       send_buffer (thread);
+
+       g_free (thread);
+}
+
+static void
+remove_thread (MonoProfilerThread *thread)
+{
+       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+
+       if (mono_lls_remove (&profiler_thread_list, hp, &thread->node))
+               mono_thread_hazardous_try_free (thread, free_thread);
+
+       clear_hazard_pointers (hp);
+}
+
+static void
+dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
+{
+       char hbuf [128];
+       char *p = hbuf;
+
+       if (buf->next)
+               dump_buffer (profiler, buf->next);
+
+       if (buf->cursor - buf->buf) {
+               p = write_int32 (p, BUF_ID);
+               p = write_int32 (p, buf->cursor - buf->buf);
+               p = write_int64 (p, buf->time_base);
+               p = write_int64 (p, buf->ptr_base);
+               p = write_int64 (p, buf->obj_base);
+               p = write_int64 (p, buf->thread_id);
+               p = write_int64 (p, buf->method_base);
+
+#if defined (HAVE_SYS_ZLIB)
+               if (profiler->gzfile) {
+                       gzwrite (profiler->gzfile, hbuf, p - hbuf);
+                       gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
+               } else
+#endif
+               {
+                       fwrite (hbuf, p - hbuf, 1, profiler->file);
+                       fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
+                       fflush (profiler->file);
+               }
+       }
+
+       free_buffer (buf, buf->size);
+}
+
+static void
+dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf)
+{
+       for (LogBuffer *iter = buf; iter; iter = iter->next)
+               iter->thread_id = 0;
+
+       dump_buffer (profiler, buf);
+}
+
+static void
+process_requests (void)
+{
+       if (heapshot_requested)
+               mono_gc_collect (mono_gc_max_generation ());
+}
+
+// Only valid if init_thread () was called with add_to_lls = FALSE.
+static void
+send_log_unsafe (gboolean if_needed)
+{
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+
+       if (!if_needed || (if_needed && thread->buffer->next)) {
+               if (!thread->attached)
+                       for (LogBuffer *iter = thread->buffer; iter; iter = iter->next)
+                               iter->thread_id = 0;
+
+               send_buffer (thread);
+               init_buffer_state (thread);
+       }
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point_flush (void)
+{
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+       MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+               g_assert (thread->attached && "Why is a thread in the LLS not attached?");
+
+               send_buffer (thread);
+               init_buffer_state (thread);
+       } MONO_LLS_FOREACH_SAFE_END
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point_mark (MonoProfilerSyncPointType type)
+{
+       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+       ENTER_LOG (&sync_points_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* type */
+       );
+
+       emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
+       emit_byte (logbuffer, type);
+
+       EXIT_LOG_EXPLICIT (NO_SEND, NO_REQUESTS);
+
+       send_log_unsafe (FALSE);
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point (MonoProfilerSyncPointType type)
+{
+       sync_point_flush ();
+       sync_point_mark (type);
+}
+
+static int
+gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data)
+{
+       /* account for object alignment in the heap */
+       size += 7;
+       size &= ~7;
+
+       ENTER_LOG (&heap_objects_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* obj */ +
+               LEB128_SIZE /* klass */ +
+               LEB128_SIZE /* size */ +
+               LEB128_SIZE /* num */ +
+               num * (
+                       LEB128_SIZE /* offset */ +
+                       LEB128_SIZE /* ref */
+               )
+       );
+
+       emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
+       emit_obj (logbuffer, obj);
+       emit_ptr (logbuffer, klass);
+       emit_value (logbuffer, size);
+       emit_value (logbuffer, num);
+
+       uintptr_t last_offset = 0;
+
+       for (int i = 0; i < num; ++i) {
+               emit_value (logbuffer, offsets [i] - last_offset);
+               last_offset = offsets [i];
+               emit_obj (logbuffer, refs [i]);
+       }
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+       return 0;
+}
+
+static unsigned int hs_mode_ms = 0;
+static unsigned int hs_mode_gc = 0;
+static unsigned int hs_mode_ondemand = 0;
+static unsigned int gc_count = 0;
+static uint64_t last_hs_time = 0;
+static gboolean do_heap_walk = FALSE;
+
+static void
+heap_walk (MonoProfiler *profiler)
+{
+       ENTER_LOG (&heap_starts_ctr, logbuffer,
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+       mono_gc_walk_heap (0, gc_reference, NULL);
+
+       ENTER_LOG (&heap_ends_ctr, logbuffer,
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+static void
+gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info)
+{
+       ENTER_LOG (&heap_roots_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* num */ +
+               LEB128_SIZE /* collections */ +
+               num * (
+                       LEB128_SIZE /* object */ +
+                       LEB128_SIZE /* root type */ +
+                       LEB128_SIZE /* extra info */
+               )
+       );
+
+       emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
+       emit_value (logbuffer, num);
+       emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ()));
+
+       for (int i = 0; i < num; ++i) {
+               emit_obj (logbuffer, objects [i]);
+               emit_byte (logbuffer, root_types [i]);
+               emit_value (logbuffer, extra_info [i]);
+       }
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+static void
+gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation)
+{
+       ENTER_LOG (&gc_events_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* gc event */ +
+               BYTE_SIZE /* generation */
+       );
+
+       emit_event (logbuffer, TYPE_GC_EVENT | TYPE_GC);
+       emit_byte (logbuffer, ev);
+       emit_byte (logbuffer, generation);
+
+       EXIT_LOG_EXPLICIT (NO_SEND, NO_REQUESTS);
+
+       switch (ev) {
+       case MONO_GC_EVENT_START:
+               if (generation == mono_gc_max_generation ())
+                       gc_count++;
+
+               uint64_t now = current_time ();
+
+               if (hs_mode_ms && (now - last_hs_time) / 1000 * 1000 >= hs_mode_ms)
+                       do_heap_walk = TRUE;
+               else if (hs_mode_gc && !(gc_count % hs_mode_gc))
+                       do_heap_walk = TRUE;
+               else if (hs_mode_ondemand)
+                       do_heap_walk = heapshot_requested;
+               else if (!hs_mode_ms && !hs_mode_gc && generation == mono_gc_max_generation ())
+                       do_heap_walk = TRUE;
+               break;
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
+               /*
+                * Ensure that no thread can be in the middle of writing to
+                * a buffer when the world stops...
+                */
+               buffer_lock_excl ();
+               break;
+       case MONO_GC_EVENT_POST_STOP_WORLD:
+               /*
+                * ... So that we now have a consistent view of all buffers.
+                * This allows us to flush them. We need to do this because
+                * they may contain object allocation events that need to be
+                * committed to the log file before any object move events
+                * that will be produced during this GC.
+                */
+               sync_point (SYNC_POINT_WORLD_STOP);
+               break;
+       case MONO_GC_EVENT_PRE_START_WORLD:
+               if (do_heap_shot && do_heap_walk) {
+                       heap_walk (profiler);
+
+                       do_heap_walk = FALSE;
+                       heapshot_requested = 0;
+                       last_hs_time = current_time ();
+               }
+               break;
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
+               /*
+                * Similarly, we must now make sure that any object moves
+                * written to the GC thread's buffer are flushed. Otherwise,
+                * object allocation events for certain addresses could come
+                * after the move events that made those addresses available.
+                */
+               sync_point_mark (SYNC_POINT_WORLD_START);
+
+               /*
+                * Finally, it is safe to allow other threads to write to
+                * their buffers again.
+                */
+               buffer_unlock_excl ();
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+gc_resize (MonoProfiler *profiler, int64_t new_size)
+{
+       ENTER_LOG (&gc_resizes_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* new size */
+       );
+
+       emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
+       emit_value (logbuffer, new_size);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+// If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
+#define MAX_FRAMES 32
+
+typedef struct {
+       int count;
+       MonoMethod* methods [MAX_FRAMES];
+       int32_t il_offsets [MAX_FRAMES];
+       int32_t native_offsets [MAX_FRAMES];
+} FrameData;
+
+static int num_frames = MAX_FRAMES;
+
+static mono_bool
+walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_bool managed, void* data)
+{
+       FrameData *frame = (FrameData *)data;
+       if (method && frame->count < num_frames) {
+               frame->il_offsets [frame->count] = il_offset;
+               frame->native_offsets [frame->count] = native_offset;
+               frame->methods [frame->count++] = method;
+               //printf ("In %d %s at %d (native: %d)\n", frame->count, mono_method_get_name (method), il_offset, native_offset);
+       }
+       return frame->count == num_frames;
+}
+
+/*
+ * a note about stack walks: they can cause more profiler events to fire,
+ * so we need to make sure they don't happen after we started emitting an
+ * event, hence the collect_bt/emit_bt split.
+ */
+static void
+collect_bt (FrameData *data)
+{
+       data->count = 0;
+       mono_stack_walk_no_il (walk_stack, data);
+}
+
+static void
+emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
+{
+       /* FIXME: this is actually tons of data and we should
+        * just output it the first time and use an id the next
+        */
+       if (data->count > num_frames)
+               printf ("bad num frames: %d\n", data->count);
+       emit_value (logbuffer, data->count);
+       //if (*p != data.count) {
+       //      printf ("bad num frames enc at %d: %d -> %d\n", count, data.count, *p); printf ("frames end: %p->%p\n", p, logbuffer->cursor); exit(0);}
+       while (data->count) {
+               emit_method (logbuffer, data->methods [--data->count]);
+       }
+}
+
+static void
+gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
+{
+       init_thread (prof, TRUE);
+
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
+       FrameData data;
+       uintptr_t len = mono_object_get_size (obj);
+       /* account for object alignment in the heap */
+       len += 7;
+       len &= ~7;
+
+       if (do_bt)
+               collect_bt (&data);
+
+       ENTER_LOG (&gc_allocs_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* klass */ +
+               LEB128_SIZE /* obj */ +
+               LEB128_SIZE /* size */ +
+               (do_bt ? (
+                       LEB128_SIZE /* count */ +
+                       data.count * (
+                               LEB128_SIZE /* method */
+                       )
+               ) : 0)
+       );
+
+       emit_event (logbuffer, do_bt | TYPE_ALLOC);
+       emit_ptr (logbuffer, klass);
+       emit_obj (logbuffer, obj);
+       emit_value (logbuffer, len);
+
+       if (do_bt)
+               emit_bt (prof, logbuffer, &data);
+
+       EXIT_LOG;
+}
+
+static void
+gc_moves (MonoProfiler *prof, void **objects, int num)
+{
+       ENTER_LOG (&gc_moves_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* num */ +
+               num * (
+                       LEB128_SIZE /* object */
+               )
+       );
+
+       emit_event (logbuffer, TYPE_GC_MOVE | TYPE_GC);
+       emit_value (logbuffer, num);
+
+       for (int i = 0; i < num; ++i)
+               emit_obj (logbuffer, objects [i]);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+static void
+gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj)
+{
+       int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces;
+       FrameData data;
+
+       if (do_bt)
+               collect_bt (&data);
+
+       gint32 *ctr = op == MONO_PROFILER_GC_HANDLE_CREATED ? &gc_handle_creations_ctr : &gc_handle_deletions_ctr;
+
+       ENTER_LOG (ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* type */ +
+               LEB128_SIZE /* handle */ +
+               (op == MONO_PROFILER_GC_HANDLE_CREATED ? (
+                       LEB128_SIZE /* obj */
+               ) : 0) +
+               (do_bt ? (
+                       LEB128_SIZE /* count */ +
+                       data.count * (
+                               LEB128_SIZE /* method */
+                       )
+               ) : 0)
+       );
+
+       if (op == MONO_PROFILER_GC_HANDLE_CREATED)
+               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
+       else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED)
+               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
+       else
+               g_assert_not_reached ();
+
+       emit_value (logbuffer, type);
+       emit_value (logbuffer, handle);
+
+       if (op == MONO_PROFILER_GC_HANDLE_CREATED)
+               emit_obj (logbuffer, obj);
+
+       if (do_bt)
+               emit_bt (prof, logbuffer, &data);
+
+       EXIT_LOG;
+}
+
+static void
+finalize_begin (MonoProfiler *prof)
+{
+       ENTER_LOG (&finalize_begins_ctr, buf,
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC);
+
+       EXIT_LOG;
+}
+
+static void
+finalize_end (MonoProfiler *prof)
+{
+       ENTER_LOG (&finalize_ends_ctr, buf,
+               EVENT_SIZE /* event */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC);
+
+       EXIT_LOG;
+}
+
+static void
+finalize_object_begin (MonoProfiler *prof, MonoObject *obj)
+{
+       ENTER_LOG (&finalize_object_begins_ctr, buf,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* obj */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC);
+       emit_obj (buf, obj);
+
+       EXIT_LOG;
+}
+
+static void
+finalize_object_end (MonoProfiler *prof, MonoObject *obj)
+{
+       ENTER_LOG (&finalize_object_ends_ctr, buf,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* obj */
+       );
+
+       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC);
+       emit_obj (buf, obj);
+
+       EXIT_LOG;
+}
+
+static char*
+push_nesting (char *p, MonoClass *klass)
+{
+       MonoClass *nesting;
+       const char *name;
+       const char *nspace;
+       nesting = mono_class_get_nesting_type (klass);
+       if (nesting) {
+               p = push_nesting (p, nesting);
+               *p++ = '/';
+               *p = 0;
+       }
+       name = mono_class_get_name (klass);
+       nspace = mono_class_get_namespace (klass);
+       if (*nspace) {
+               strcpy (p, nspace);
+               p += strlen (nspace);
+               *p++ = '.';
+               *p = 0;
+       }
+       strcpy (p, name);
+       p += strlen (name);
+       return p;
+}
+
+static char*
+type_name (MonoClass *klass)
+{
+       char buf [1024];
+       char *p;
+       push_nesting (buf, klass);
+       p = (char *) g_malloc (strlen (buf) + 1);
+       strcpy (p, buf);
+       return p;
+}
+
+static void
+image_loaded (MonoProfiler *prof, MonoImage *image, int result)
+{
+       if (result != MONO_PROFILE_OK)
+               return;
+
+       const char *name = mono_image_get_filename (image);
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG (&image_loads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* image */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_IMAGE);
+       emit_ptr (logbuffer, image);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+}
+
+static void
+image_unloaded (MonoProfiler *prof, MonoImage *image)
+{
+       const char *name = mono_image_get_filename (image);
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG (&image_unloads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* image */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_IMAGE);
+       emit_ptr (logbuffer, image);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+}
+
+static void
+assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result)
+{
+       if (result != MONO_PROFILE_OK)
+               return;
+
+       char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG (&assembly_loads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* assembly */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_ASSEMBLY);
+       emit_ptr (logbuffer, assembly);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+
+       mono_free (name);
+}
+
+static void
+assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly)
+{
+       char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG (&assembly_unloads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* assembly */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_ASSEMBLY);
+       emit_ptr (logbuffer, assembly);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+
+       mono_free (name);
+}
+
+static void
+class_loaded (MonoProfiler *prof, MonoClass *klass, int result)
+{
+       if (result != MONO_PROFILE_OK)
+               return;
+
+       char *name;
+
+       if (InterlockedRead (&runtime_inited))
+               name = mono_type_get_name (mono_class_get_type (klass));
+       else
+               name = type_name (klass);
+
+       int nlen = strlen (name) + 1;
+       MonoImage *image = mono_class_get_image (klass);
+
+       ENTER_LOG (&class_loads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* klass */ +
+               LEB128_SIZE /* image */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_CLASS);
+       emit_ptr (logbuffer, klass);
+       emit_ptr (logbuffer, image);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+
+       if (runtime_inited)
+               mono_free (name);
+       else
+               g_free (name);
+}
+
+static void
+class_unloaded (MonoProfiler *prof, MonoClass *klass)
+{
+       char *name;
+
+       if (InterlockedRead (&runtime_inited))
+               name = mono_type_get_name (mono_class_get_type (klass));
+       else
+               name = type_name (klass);
+
+       int nlen = strlen (name) + 1;
+       MonoImage *image = mono_class_get_image (klass);
+
+       ENTER_LOG (&class_unloads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* klass */ +
+               LEB128_SIZE /* image */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_CLASS);
+       emit_ptr (logbuffer, klass);
+       emit_ptr (logbuffer, image);
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+
+       if (runtime_inited)
+               mono_free (name);
+       else
+               g_free (name);
+}
+
+static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method);
+
+static void
+method_enter (MonoProfiler *prof, MonoMethod *method)
+{
+       process_method_enter_coverage (prof, method);
+
+       if (!only_coverage && PROF_TLS_GET ()->call_depth++ <= max_call_depth) {
+               ENTER_LOG (&method_entries_ctr, logbuffer,
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
+
+               emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
+               emit_method (logbuffer, method);
+
+               EXIT_LOG;
+       }
+}
+
+static void
+method_leave (MonoProfiler *prof, MonoMethod *method)
+{
+       if (!only_coverage && --PROF_TLS_GET ()->call_depth <= max_call_depth) {
+               ENTER_LOG (&method_exits_ctr, logbuffer,
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
+
+               emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
+               emit_method (logbuffer, method);
+
+               EXIT_LOG;
+       }
+}
+
+static void
+method_exc_leave (MonoProfiler *prof, MonoMethod *method)
+{
+       if (!only_coverage && !nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) {
+               ENTER_LOG (&method_exception_exits_ctr, logbuffer,
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method */
+               );
+
+               emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
+               emit_method (logbuffer, method);
+
+               EXIT_LOG;
+       }
+}
+
+static void
+method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int result)
+{
+       if (result != MONO_PROFILE_OK)
+               return;
+
+       register_method_local (method, ji);
+
+       process_requests ();
+}
+
+static void
+code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data)
+{
+       char *name;
+       int nlen;
+
+       if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
+               name = (char *) data;
+               nlen = strlen (name) + 1;
+       } else {
+               name = NULL;
+               nlen = 0;
+       }
+
+       ENTER_LOG (&code_buffers_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* buffer */ +
+               LEB128_SIZE /* size */ +
+               (name ? (
+                       nlen /* name */
+               ) : 0)
+       );
+
+       emit_event (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
+       emit_byte (logbuffer, type);
+       emit_ptr (logbuffer, buffer);
+       emit_value (logbuffer, size);
+
+       if (name) {
+               memcpy (logbuffer->cursor, name, nlen);
+               logbuffer->cursor += nlen;
+       }
+
+       EXIT_LOG;
+}
+
+static void
+throw_exc (MonoProfiler *prof, MonoObject *object)
+{
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_THROW_BT : 0;
+       FrameData data;
+
+       if (do_bt)
+               collect_bt (&data);
+
+       ENTER_LOG (&exception_throws_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* object */ +
+               (do_bt ? (
+                       LEB128_SIZE /* count */ +
+                       data.count * (
+                               LEB128_SIZE /* method */
+                       )
+               ) : 0)
+       );
+
+       emit_event (logbuffer, do_bt | TYPE_EXCEPTION);
+       emit_obj (logbuffer, object);
+
+       if (do_bt)
+               emit_bt (prof, logbuffer, &data);
+
+       EXIT_LOG;
+}
+
+static void
+clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num)
+{
+       ENTER_LOG (&exception_clauses_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* clause type */ +
+               LEB128_SIZE /* clause num */ +
+               LEB128_SIZE /* method */
+       );
+
+       emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
+       emit_byte (logbuffer, clause_type);
+       emit_value (logbuffer, clause_num);
+       emit_method (logbuffer, method);
+
+       EXIT_LOG;
+}
+
+static void
+monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEvent event)
+{
+       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces && event == MONO_PROFILER_MONITOR_CONTENTION) ? TYPE_MONITOR_BT : 0;
+       FrameData data;
+
+       if (do_bt)
+               collect_bt (&data);
+
+       gint32 *ctr;
+
+       switch (event) {
+       case MONO_PROFILER_MONITOR_CONTENTION:
+               ctr = &monitor_contentions_ctr;
+               break;
+       case MONO_PROFILER_MONITOR_DONE:
+               ctr = &monitor_acquisitions_ctr;
+               break;
+       case MONO_PROFILER_MONITOR_FAIL:
+               ctr = &monitor_failures_ctr;
+               break;
+       default:
+               g_assert_not_reached ();
+               break;
+       }
+
+       ENTER_LOG (ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* object */ +
+               (do_bt ? (
+                       LEB128_SIZE /* count */ +
+                       data.count * (
+                               LEB128_SIZE /* method */
+                       )
+               ) : 0)
+       );
+
+       emit_event (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
+       emit_obj (logbuffer, object);
+
+       if (do_bt)
+               emit_bt (profiler, logbuffer, &data);
+
+       EXIT_LOG;
+}
+
+static void
+thread_start (MonoProfiler *prof, uintptr_t tid)
+{
+       init_thread (prof, TRUE);
+
+       ENTER_LOG (&thread_starts_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* tid */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_THREAD);
+       emit_ptr (logbuffer, (void*) tid);
+
+       EXIT_LOG;
+}
+
+static void
+thread_end (MonoProfiler *prof, uintptr_t tid)
+{
+       ENTER_LOG (&thread_ends_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* tid */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_THREAD);
+       emit_ptr (logbuffer, (void*) tid);
+
+       EXIT_LOG_EXPLICIT (NO_SEND, NO_REQUESTS);
+
+       MonoProfilerThread *thread = PROF_TLS_GET ();
+
+       thread->ended = TRUE;
+       remove_thread (thread);
+
+       PROF_TLS_SET (NULL);
+}
+
+static void
+thread_name (MonoProfiler *prof, uintptr_t tid, const char *name)
+{
+       int len = strlen (name) + 1;
+
+       ENTER_LOG (&thread_names_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* tid */ +
+               len /* name */
+       );
+
+       emit_event (logbuffer, TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_THREAD);
+       emit_ptr (logbuffer, (void*)tid);
+       memcpy (logbuffer->cursor, name, len);
+       logbuffer->cursor += len;
+
+       EXIT_LOG;
+}
+
+static void
+domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result)
+{
+       if (result != MONO_PROFILE_OK)
+               return;
+
+       ENTER_LOG (&domain_loads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* domain id */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_DOMAIN);
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
+
+       EXIT_LOG;
+}
+
+static void
+domain_unloaded (MonoProfiler *prof, MonoDomain *domain)
+{
+       ENTER_LOG (&domain_unloads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* domain id */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_DOMAIN);
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
+
+       EXIT_LOG;
+}
+
+static void
+domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name)
+{
+       int nlen = strlen (name) + 1;
+
+       ENTER_LOG (&domain_names_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* domain id */ +
+               nlen /* name */
+       );
+
+       emit_event (logbuffer, TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_DOMAIN);
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
+       memcpy (logbuffer->cursor, name, nlen);
+       logbuffer->cursor += nlen;
+
+       EXIT_LOG;
+}
+
+static void
+context_loaded (MonoProfiler *prof, MonoAppContext *context)
+{
+       ENTER_LOG (&context_loads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* context id */ +
+               LEB128_SIZE /* domain id */
+       );
+
+       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_CONTEXT);
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
+
+       EXIT_LOG;
+}
+
+static void
+context_unloaded (MonoProfiler *prof, MonoAppContext *context)
+{
+       ENTER_LOG (&context_unloads_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               BYTE_SIZE /* type */ +
+               LEB128_SIZE /* context id */ +
+               LEB128_SIZE /* domain id */
+       );
+
+       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
+       emit_byte (logbuffer, TYPE_CONTEXT);
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
+       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
+
+       EXIT_LOG;
+}
+
+typedef struct {
+       MonoMethod *method;
+       MonoDomain *domain;
+       void *base_address;
+       int offset;
+} AsyncFrameInfo;
+
+typedef struct {
+       MonoLockFreeQueueNode node;
+       MonoProfiler *prof;
+       uint64_t time;
+       uintptr_t tid;
+       void *ip;
+       int count;
+       AsyncFrameInfo frames [MONO_ZERO_LEN_ARRAY];
+} SampleHit;
+
+static mono_bool
+async_walk_stack (MonoMethod *method, MonoDomain *domain, void *base_address, int offset, void *data)
+{
+       SampleHit *sample = (SampleHit *) data;
+
+       if (sample->count < num_frames) {
+               int i = sample->count;
+
+               sample->frames [i].method = method;
+               sample->frames [i].domain = domain;
+               sample->frames [i].base_address = base_address;
+               sample->frames [i].offset = offset;
+
+               sample->count++;
+       }
+
+       return sample->count == num_frames;
+}
+
+#define SAMPLE_SLOT_SIZE(FRAMES) (sizeof (SampleHit) + sizeof (AsyncFrameInfo) * (FRAMES - MONO_ZERO_LEN_ARRAY))
+#define SAMPLE_BLOCK_SIZE (mono_pagesize ())
+
+static void
+enqueue_sample_hit (gpointer p)
+{
+       SampleHit *sample = p;
+
+       mono_lock_free_queue_node_unpoison (&sample->node);
+       mono_lock_free_queue_enqueue (&sample->prof->dumper_queue, &sample->node);
+       mono_os_sem_post (&sample->prof->dumper_queue_sem);
+}
+
+static void
+mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
+{
+       /*
+        * Please note: We rely on the runtime loading the profiler with
+        * MONO_DL_EAGER (RTLD_NOW) so that references to runtime functions within
+        * this function (and its siblings) are resolved when the profiler is
+        * loaded. Otherwise, we would potentially invoke the dynamic linker when
+        * invoking runtime functions, which is not async-signal-safe.
+        */
+
+       if (InterlockedRead (&in_shutdown))
+               return;
+
+       SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
+
+       if (!sample) {
+               /*
+                * If we're out of reusable sample events and we're not allowed to
+                * allocate more, we have no choice but to drop the event.
+                */
+               if (InterlockedRead (&sample_allocations_ctr) >= max_allocated_sample_hits)
+                       return;
+
+               sample = mono_lock_free_alloc (&profiler->sample_allocator);
+               sample->prof = profiler;
+               mono_lock_free_queue_node_init (&sample->node, TRUE);
+
+               InterlockedIncrement (&sample_allocations_ctr);
+       }
+
+       sample->count = 0;
+       mono_stack_walk_async_safe (&async_walk_stack, context, sample);
+
+       sample->time = current_time ();
+       sample->tid = thread_id ();
+       sample->ip = ip;
+
+       mono_thread_hazardous_try_free (sample, enqueue_sample_hit);
+}
+
+static uintptr_t *code_pages = 0;
+static int num_code_pages = 0;
+static int size_code_pages = 0;
+#define CPAGE_SHIFT (9)
+#define CPAGE_SIZE (1 << CPAGE_SHIFT)
+#define CPAGE_MASK (~(CPAGE_SIZE - 1))
+#define CPAGE_ADDR(p) ((p) & CPAGE_MASK)
+
+static uintptr_t
+add_code_page (uintptr_t *hash, uintptr_t hsize, uintptr_t page)
+{
+       uintptr_t i;
+       uintptr_t start_pos;
+       start_pos = (page >> CPAGE_SHIFT) % hsize;
+       i = start_pos;
+       do {
+               if (hash [i] && CPAGE_ADDR (hash [i]) == CPAGE_ADDR (page)) {
+                       return 0;
+               } else if (!hash [i]) {
+                       hash [i] = page;
+                       return 1;
+               }
+               /* wrap around */
+               if (++i == hsize)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       printf ("failed code page store\n");
+       return 0;
+}
+
+static void
+add_code_pointer (uintptr_t ip)
+{
+       uintptr_t i;
+       if (num_code_pages * 2 >= size_code_pages) {
+               uintptr_t *n;
+               uintptr_t old_size = size_code_pages;
+               size_code_pages *= 2;
+               if (size_code_pages == 0)
+                       size_code_pages = 16;
+               n = (uintptr_t *) g_calloc (sizeof (uintptr_t) * size_code_pages, 1);
+               for (i = 0; i < old_size; ++i) {
+                       if (code_pages [i])
+                               add_code_page (n, size_code_pages, code_pages [i]);
+               }
+               if (code_pages)
+                       g_free (code_pages);
+               code_pages = n;
+       }
+       num_code_pages += add_code_page (code_pages, size_code_pages, ip & CPAGE_MASK);
+}
+
+/* ELF code crashes on some systems. */
+//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+#if 0
+static void
+dump_ubin (MonoProfiler *prof, const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
+{
+       int len = strlen (filename) + 1;
+
+       ENTER_LOG (&sample_ubins_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* load address */ +
+               LEB128_SIZE /* offset */ +
+               LEB128_SIZE /* size */ +
+               nlen /* file name */
+       );
+
+       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
+       emit_svalue (logbuffer, load_addr);
+       emit_uvalue (logbuffer, offset);
+       emit_uvalue (logbuffer, size);
+       memcpy (logbuffer->cursor, filename, len);
+       logbuffer->cursor += len;
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+#endif
+
+static void
+dump_usym (MonoProfiler *prof, const char *name, uintptr_t value, uintptr_t size)
+{
+       int len = strlen (name) + 1;
+
+       ENTER_LOG (&sample_usyms_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* value */ +
+               LEB128_SIZE /* size */ +
+               len /* name */
+       );
+
+       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
+       emit_ptr (logbuffer, (void*)value);
+       emit_value (logbuffer, size);
+       memcpy (logbuffer->cursor, name, len);
+       logbuffer->cursor += len;
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+/* ELF code crashes on some systems. */
+//#if defined(ELFMAG0)
+#if 0
+
+#if SIZEOF_VOID_P == 4
+#define ELF_WSIZE 32
+#else
+#define ELF_WSIZE 64
+#endif
+#ifndef ElfW
+#define ElfW(type)      _ElfW (Elf, ELF_WSIZE, type)
+#define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e,w,t)  e##w##t
+#endif
+
+static void
+dump_elf_symbols (MonoProfiler *prof, ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
+{
+       int i;
+       for (i = 0; i < num_symbols; ++i) {
+               const char* sym;
+               sym =  strtab + symbols [i].st_name;
+               if (!symbols [i].st_name || !symbols [i].st_size || (symbols [i].st_info & 0xf) != STT_FUNC)
+                       continue;
+               //printf ("symbol %s at %d\n", sym, symbols [i].st_value);
+               dump_usym (sym, (uintptr_t)load_addr + symbols [i].st_value, symbols [i].st_size);
+       }
+}
+
+static int
+read_elf_symbols (MonoProfiler *prof, const char *filename, void *load_addr)
+{
+       int fd, i;
+       void *data;
+       struct stat statb;
+       uint64_t file_size;
+       ElfW(Ehdr) *header;
+       ElfW(Shdr) *sheader;
+       ElfW(Shdr) *shstrtabh;
+       ElfW(Shdr) *symtabh = NULL;
+       ElfW(Shdr) *strtabh = NULL;
+       ElfW(Sym) *symbols = NULL;
+       const char *strtab;
+       int num_symbols;
+
+       fd = open (filename, O_RDONLY);
+       if (fd < 0)
+               return 0;
+       if (fstat (fd, &statb) != 0) {
+               close (fd);
+               return 0;
+       }
+       file_size = statb.st_size;
+       data = mmap (NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       close (fd);
+       if (data == MAP_FAILED)
+               return 0;
+       header = data;
+       if (header->e_ident [EI_MAG0] != ELFMAG0 ||
+                       header->e_ident [EI_MAG1] != ELFMAG1 ||
+                       header->e_ident [EI_MAG2] != ELFMAG2 ||
+                       header->e_ident [EI_MAG3] != ELFMAG3 ) {
+               munmap (data, file_size);
+               return 0;
+       }
+       sheader = (void*)((char*)data + header->e_shoff);
+       shstrtabh = (void*)((char*)sheader + (header->e_shentsize * header->e_shstrndx));
+       strtab = (const char*)data + shstrtabh->sh_offset;
+       for (i = 0; i < header->e_shnum; ++i) {
+               //printf ("section header: %d\n", sheader->sh_type);
+               if (sheader->sh_type == SHT_SYMTAB) {
+                       symtabh = sheader;
+                       strtabh = (void*)((char*)data + header->e_shoff + sheader->sh_link * header->e_shentsize);
+                       /*printf ("symtab section header: %d, .strstr: %d\n", i, sheader->sh_link);*/
+                       break;
+               }
+               sheader = (void*)((char*)sheader + header->e_shentsize);
+       }
+       if (!symtabh || !strtabh) {
+               munmap (data, file_size);
+               return 0;
+       }
+       strtab = (const char*)data + strtabh->sh_offset;
+       num_symbols = symtabh->sh_size / symtabh->sh_entsize;
+       symbols = (void*)((char*)data + symtabh->sh_offset);
+       dump_elf_symbols (symbols, num_symbols, strtab, load_addr);
+       munmap (data, file_size);
+       return 1;
+}
+#endif
+
+/* ELF code crashes on some systems. */
+//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+#if 0
+static int
+elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data)
+{
+       MonoProfiler *prof = data;
+       char buf [256];
+       const char *filename;
+       BinaryObject *obj;
+       char *a = (void*)info->dlpi_addr;
+       int i, num_sym;
+       ElfW(Dyn) *dyn = NULL;
+       ElfW(Sym) *symtab = NULL;
+       ElfW(Word) *hash_table = NULL;
+       ElfW(Ehdr) *header = NULL;
+       const char* strtab = NULL;
+       for (obj = prof->binary_objects; obj; obj = obj->next) {
+               if (obj->addr == a)
+                       return 0;
+       }
+       filename = info->dlpi_name;
+       if (!filename)
+               return 0;
+       if (!info->dlpi_addr && !filename [0]) {
+               int l = readlink ("/proc/self/exe", buf, sizeof (buf) - 1);
+               if (l > 0) {
+                       buf [l] = 0;
+                       filename = buf;
+               }
+       }
+       obj = g_calloc (sizeof (BinaryObject), 1);
+       obj->addr = (void*)info->dlpi_addr;
+       obj->name = pstrdup (filename);
+       obj->next = prof->binary_objects;
+       prof->binary_objects = obj;
+       //printf ("loaded file: %s at %p, segments: %d\n", filename, (void*)info->dlpi_addr, info->dlpi_phnum);
+       a = NULL;
+       for (i = 0; i < info->dlpi_phnum; ++i) {
+               //printf ("segment type %d file offset: %d, size: %d\n", info->dlpi_phdr[i].p_type, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
+               if (info->dlpi_phdr[i].p_type == PT_LOAD && !header) {
+                       header = (ElfW(Ehdr)*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+                       if (header->e_ident [EI_MAG0] != ELFMAG0 ||
+                                       header->e_ident [EI_MAG1] != ELFMAG1 ||
+                                       header->e_ident [EI_MAG2] != ELFMAG2 ||
+                                       header->e_ident [EI_MAG3] != ELFMAG3 ) {
+                               header = NULL;
+                       }
+                       dump_ubin (prof, filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
+               } else if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
+                       dyn = (ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
+               }
+       }
+       if (read_elf_symbols (prof, filename, (void*)info->dlpi_addr))
+               return 0;
+       if (!info->dlpi_name || !info->dlpi_name[0])
+               return 0;
+       if (!dyn)
+               return 0;
+       for (i = 0; dyn [i].d_tag != DT_NULL; ++i) {
+               if (dyn [i].d_tag == DT_SYMTAB) {
+                       if (symtab && do_debug)
+                               printf ("multiple symtabs: %d\n", i);
+                       symtab = (ElfW(Sym) *)(a + dyn [i].d_un.d_ptr);
+               } else if (dyn [i].d_tag == DT_HASH) {
+                       hash_table = (ElfW(Word) *)(a + dyn [i].d_un.d_ptr);
+               } else if (dyn [i].d_tag == DT_STRTAB) {
+                       strtab = (const char*)(a + dyn [i].d_un.d_ptr);
+               }
+       }
+       if (!hash_table)
+               return 0;
+       num_sym = hash_table [1];
+       dump_elf_symbols (prof, symtab, num_sym, strtab, (void*)info->dlpi_addr);
+       return 0;
+}
+
+static int
+load_binaries (MonoProfiler *prof)
+{
+       dl_iterate_phdr (elf_dl_callback, prof);
+       return 1;
+}
+#else
+static int
+load_binaries (MonoProfiler *prof)
+{
+       return 0;
+}
+#endif
+
+static const char*
+symbol_for (uintptr_t code)
+{
+#ifdef HAVE_DLADDR
+       void *ip = (void*)code;
+       Dl_info di;
+       if (dladdr (ip, &di)) {
+               if (di.dli_sname)
+                       return di.dli_sname;
+       } else {
+       /*      char **names;
+               names = backtrace_symbols (&ip, 1);
+               if (names) {
+                       const char* p = names [0];
+                       g_free (names);
+                       return p;
+               }
+               */
+       }
+#endif
+       return NULL;
+}
+
+static void
+dump_unmanaged_coderefs (MonoProfiler *prof)
+{
+       int i;
+       const char* last_symbol;
+       uintptr_t addr, page_end;
+
+       if (load_binaries (prof))
+               return;
+       for (i = 0; i < size_code_pages; ++i) {
+               const char* sym;
+               if (!code_pages [i] || code_pages [i] & 1)
+                       continue;
+               last_symbol = NULL;
+               addr = CPAGE_ADDR (code_pages [i]);
+               page_end = addr + CPAGE_SIZE;
+               code_pages [i] |= 1;
+               /* we dump the symbols for the whole page */
+               for (; addr < page_end; addr += 16) {
+                       sym = symbol_for (addr);
+                       if (sym && sym == last_symbol)
+                               continue;
+                       last_symbol = sym;
+                       if (!sym)
+                               continue;
+                       dump_usym (prof, sym, addr, 0); /* let's not guess the size */
+                       //printf ("found symbol at %p: %s\n", (void*)addr, sym);
+               }
+       }
+}
+
+static int
+mono_cpu_count (void)
+{
+#ifdef PLATFORM_ANDROID
+       /* Android tries really hard to save power by powering off CPUs on SMP phones which
+        * means the normal way to query cpu count returns a wrong value with userspace API.
+        * Instead we use /sys entries to query the actual hardware CPU count.
+        */
+       int count = 0;
+       char buffer[8] = {'\0'};
+       int present = open ("/sys/devices/system/cpu/present", O_RDONLY);
+       /* Format of the /sys entry is a cpulist of indexes which in the case
+        * of present is always of the form "0-(n-1)" when there is more than
+        * 1 core, n being the number of CPU cores in the system. Otherwise
+        * the value is simply 0
+        */
+       if (present != -1 && read (present, (char*)buffer, sizeof (buffer)) > 3)
+               count = strtol (((char*)buffer) + 2, NULL, 10);
+       if (present != -1)
+               close (present);
+       if (count > 0)
+               return count + 1;
+#endif
+
+#if defined(HOST_ARM) || defined (HOST_ARM64)
+
+       /* ARM platforms tries really hard to save power by powering off CPUs on SMP phones which
+        * means the normal way to query cpu count returns a wrong value with userspace API. */
+
+#ifdef _SC_NPROCESSORS_CONF
+       {
+               int count = sysconf (_SC_NPROCESSORS_CONF);
+               if (count > 0)
+                       return count;
+       }
+#endif
+
+#else
+
+#ifdef HAVE_SCHED_GETAFFINITY
+       {
+               cpu_set_t set;
+               if (sched_getaffinity (getpid (), sizeof (set), &set) == 0)
+                       return CPU_COUNT (&set);
+       }
+#endif
+#ifdef _SC_NPROCESSORS_ONLN
+       {
+               int count = sysconf (_SC_NPROCESSORS_ONLN);
+               if (count > 0)
+                       return count;
+       }
+#endif
+
+#endif /* defined(HOST_ARM) || defined (HOST_ARM64) */
+
+#ifdef USE_SYSCTL
+       {
+               int count;
+               int mib [2];
+               size_t len = sizeof (int);
+               mib [0] = CTL_HW;
+               mib [1] = HW_NCPU;
+               if (sysctl (mib, 2, &count, &len, NULL, 0) == 0)
+                       return count;
+       }
+#endif
+#ifdef HOST_WIN32
+       {
+               SYSTEM_INFO info;
+               GetSystemInfo (&info);
+               return info.dwNumberOfProcessors;
+       }
+#endif
+
+       static gboolean warned;
+
+       if (!warned) {
+               g_warning ("Don't know how to determine CPU count on this platform; assuming 1");
+               warned = TRUE;
+       }
+
+       return 1;
+}
+
+typedef struct MonoCounterAgent {
+       MonoCounter *counter;
+       // MonoCounterAgent specific data :
+       void *value;
+       size_t value_size;
+       short index;
+       short emitted;
+       struct MonoCounterAgent *next;
+} MonoCounterAgent;
+
+static MonoCounterAgent* counters;
+static int counters_index = 1;
+static mono_mutex_t counters_mutex;
+
+static void
+counters_add_agent (MonoCounter *counter)
+{
+       if (InterlockedRead (&in_shutdown))
+               return;
+
+       MonoCounterAgent *agent, *item;
+
+       mono_os_mutex_lock (&counters_mutex);
+
+       for (agent = counters; agent; agent = agent->next) {
+               if (agent->counter == counter) {
+                       agent->value_size = 0;
+                       if (agent->value) {
+                               g_free (agent->value);
+                               agent->value = NULL;
+                       }
+                       goto done;
+               }
+       }
+
+       agent = (MonoCounterAgent *) g_malloc (sizeof (MonoCounterAgent));
+       agent->counter = counter;
+       agent->value = NULL;
+       agent->value_size = 0;
+       agent->index = counters_index++;
+       agent->emitted = 0;
+       agent->next = NULL;
+
+       if (!counters) {
+               counters = agent;
+       } else {
+               item = counters;
+               while (item->next)
+                       item = item->next;
+               item->next = agent;
+       }
+
+done:
+       mono_os_mutex_unlock (&counters_mutex);
+}
+
+static mono_bool
+counters_init_foreach_callback (MonoCounter *counter, gpointer data)
+{
+       counters_add_agent (counter);
+       return TRUE;
+}
+
+static void
+counters_init (MonoProfiler *profiler)
+{
+       mono_os_mutex_init (&counters_mutex);
+
+       mono_counters_on_register (&counters_add_agent);
+       mono_counters_foreach (counters_init_foreach_callback, NULL);
+}
+
+static void
+counters_emit (MonoProfiler *profiler)
+{
+       MonoCounterAgent *agent;
+       int len = 0;
+       int size =
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* len */
+       ;
+
+       mono_os_mutex_lock (&counters_mutex);
+
+       for (agent = counters; agent; agent = agent->next) {
+               if (agent->emitted)
+                       continue;
+
+               size +=
+                       LEB128_SIZE /* section */ +
+                       strlen (mono_counter_get_name (agent->counter)) + 1 /* name */ +
+                       BYTE_SIZE /* type */ +
+                       BYTE_SIZE /* unit */ +
+                       BYTE_SIZE /* variance */ +
+                       LEB128_SIZE /* index */
+               ;
+
+               len++;
+       }
+
+       if (!len)
+               goto done;
+
+       ENTER_LOG (&counter_descriptors_ctr, logbuffer, size);
+
+       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+       emit_value (logbuffer, len);
+
+       for (agent = counters; agent; agent = agent->next) {
+               const char *name;
+
+               if (agent->emitted)
+                       continue;
+
+               name = mono_counter_get_name (agent->counter);
+               emit_value (logbuffer, mono_counter_get_section (agent->counter));
+               emit_string (logbuffer, name, strlen (name) + 1);
+               emit_byte (logbuffer, mono_counter_get_type (agent->counter));
+               emit_byte (logbuffer, mono_counter_get_unit (agent->counter));
+               emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
+               emit_value (logbuffer, agent->index);
+
+               agent->emitted = 1;
+       }
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+done:
+       mono_os_mutex_unlock (&counters_mutex);
+}
+
+static void
+counters_sample (MonoProfiler *profiler, uint64_t timestamp)
+{
+       MonoCounterAgent *agent;
+       MonoCounter *counter;
+       int type;
+       int buffer_size;
+       void *buffer;
+       int size;
+
+       counters_emit (profiler);
+
+       buffer_size = 8;
+       buffer = g_calloc (1, buffer_size);
+
+       mono_os_mutex_lock (&counters_mutex);
+
+       size =
+               EVENT_SIZE /* event */
+       ;
+
+       for (agent = counters; agent; agent = agent->next) {
+               size +=
+                       LEB128_SIZE /* index */ +
+                       BYTE_SIZE /* type */ +
+                       mono_counter_get_size (agent->counter) /* value */
+               ;
+       }
+
+       size +=
+               LEB128_SIZE /* stop marker */
+       ;
+
+       ENTER_LOG (&counter_samples_ctr, logbuffer, size);
+
+       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
+
+       for (agent = counters; agent; agent = agent->next) {
+               size_t size;
+
+               counter = agent->counter;
+
+               size = mono_counter_get_size (counter);
+
+               if (size > buffer_size) {
+                       buffer_size = size;
+                       buffer = g_realloc (buffer, buffer_size);
+               }
+
+               memset (buffer, 0, buffer_size);
+
+               g_assert (mono_counters_sample (counter, buffer, size));
+
+               type = mono_counter_get_type (counter);
+
+               if (!agent->value) {
+                       agent->value = g_calloc (1, size);
+                       agent->value_size = size;
+               } else {
+                       if (type == MONO_COUNTER_STRING) {
+                               if (strcmp (agent->value, buffer) == 0)
+                                       continue;
+                       } else {
+                               if (agent->value_size == size && memcmp (agent->value, buffer, size) == 0)
+                                       continue;
+                       }
+               }
+
+               emit_uvalue (logbuffer, agent->index);
+               emit_byte (logbuffer, type);
+               switch (type) {
+               case MONO_COUNTER_INT:
+#if SIZEOF_VOID_P == 4
+               case MONO_COUNTER_WORD:
+#endif
+                       emit_svalue (logbuffer, *(int*)buffer - *(int*)agent->value);
+                       break;
+               case MONO_COUNTER_UINT:
+                       emit_uvalue (logbuffer, *(guint*)buffer - *(guint*)agent->value);
+                       break;
+               case MONO_COUNTER_TIME_INTERVAL:
+               case MONO_COUNTER_LONG:
+#if SIZEOF_VOID_P == 8
+               case MONO_COUNTER_WORD:
+#endif
+                       emit_svalue (logbuffer, *(gint64*)buffer - *(gint64*)agent->value);
+                       break;
+               case MONO_COUNTER_ULONG:
+                       emit_uvalue (logbuffer, *(guint64*)buffer - *(guint64*)agent->value);
+                       break;
+               case MONO_COUNTER_DOUBLE:
+                       emit_double (logbuffer, *(double*)buffer);
+                       break;
+               case MONO_COUNTER_STRING:
+                       if (size == 0) {
+                               emit_byte (logbuffer, 0);
+                       } else {
+                               emit_byte (logbuffer, 1);
+                               emit_string (logbuffer, (char*)buffer, size);
+                       }
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+
+               if (type == MONO_COUNTER_STRING && size > agent->value_size) {
+                       agent->value = g_realloc (agent->value, size);
+                       agent->value_size = size;
+               }
+
+               if (size > 0)
+                       memcpy (agent->value, buffer, size);
+       }
+       g_free (buffer);
+
+       emit_value (logbuffer, 0);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+       mono_os_mutex_unlock (&counters_mutex);
+}
+
+typedef struct _PerfCounterAgent PerfCounterAgent;
+struct _PerfCounterAgent {
+       PerfCounterAgent *next;
+       int index;
+       char *category_name;
+       char *name;
+       int type;
+       gint64 value;
+       guint8 emitted;
+       guint8 updated;
+       guint8 deleted;
+};
+
+static PerfCounterAgent *perfcounters = NULL;
+
+static void
+perfcounters_emit (MonoProfiler *profiler)
+{
+       PerfCounterAgent *pcagent;
+       int len = 0;
+       int size =
+               EVENT_SIZE /* event */ +
+               LEB128_SIZE /* len */
+       ;
+
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+               if (pcagent->emitted)
+                       continue;
+
+               size +=
+                       LEB128_SIZE /* section */ +
+                       strlen (pcagent->category_name) + 1 /* category name */ +
+                       strlen (pcagent->name) + 1 /* name */ +
+                       BYTE_SIZE /* type */ +
+                       BYTE_SIZE /* unit */ +
+                       BYTE_SIZE /* variance */ +
+                       LEB128_SIZE /* index */
+               ;
+
+               len++;
+       }
+
+       if (!len)
+               return;
+
+       ENTER_LOG (&perfcounter_descriptors_ctr, logbuffer, size);
+
+       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+       emit_value (logbuffer, len);
+
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+               if (pcagent->emitted)
+                       continue;
+
+               emit_value (logbuffer, MONO_COUNTER_PERFCOUNTERS);
+               emit_string (logbuffer, pcagent->category_name, strlen (pcagent->category_name) + 1);
+               emit_string (logbuffer, pcagent->name, strlen (pcagent->name) + 1);
+               emit_byte (logbuffer, MONO_COUNTER_LONG);
+               emit_byte (logbuffer, MONO_COUNTER_RAW);
+               emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
+               emit_value (logbuffer, pcagent->index);
+
+               pcagent->emitted = 1;
+       }
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+static gboolean
+perfcounters_foreach (char *category_name, char *name, unsigned char type, gint64 value, gpointer user_data)
+{
+       PerfCounterAgent *pcagent;
+
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+               if (strcmp (pcagent->category_name, category_name) != 0 || strcmp (pcagent->name, name) != 0)
+                       continue;
+               if (pcagent->value == value)
+                       return TRUE;
+
+               pcagent->value = value;
+               pcagent->updated = 1;
+               pcagent->deleted = 0;
+               return TRUE;
+       }
+
+       pcagent = g_new0 (PerfCounterAgent, 1);
+       pcagent->next = perfcounters;
+       pcagent->index = counters_index++;
+       pcagent->category_name = g_strdup (category_name);
+       pcagent->name = g_strdup (name);
+       pcagent->type = (int) type;
+       pcagent->value = value;
+       pcagent->emitted = 0;
+       pcagent->updated = 1;
+       pcagent->deleted = 0;
+
+       perfcounters = pcagent;
+
+       return TRUE;
+}
+
+static void
+perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
+{
+       PerfCounterAgent *pcagent;
+       int len = 0;
+       int size;
+
+       mono_os_mutex_lock (&counters_mutex);
+
+       /* mark all perfcounters as deleted, foreach will unmark them as necessary */
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next)
+               pcagent->deleted = 1;
+
+       mono_perfcounter_foreach (perfcounters_foreach, perfcounters);
+
+       perfcounters_emit (profiler);
+
+       size =
+               EVENT_SIZE /* event */
+       ;
+
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+               if (pcagent->deleted || !pcagent->updated)
+                       continue;
+
+               size +=
+                       LEB128_SIZE /* index */ +
+                       BYTE_SIZE /* type */ +
+                       LEB128_SIZE /* value */
+               ;
+
+               len++;
+       }
+
+       if (!len)
+               goto done;
+
+       size +=
+               LEB128_SIZE /* stop marker */
+       ;
+
+       ENTER_LOG (&perfcounter_samples_ctr, logbuffer, size);
+
+       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
+
+       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
+               if (pcagent->deleted || !pcagent->updated)
+                       continue;
+               emit_uvalue (logbuffer, pcagent->index);
+               emit_byte (logbuffer, MONO_COUNTER_LONG);
+               emit_svalue (logbuffer, pcagent->value);
+
+               pcagent->updated = 0;
+       }
+
+       emit_value (logbuffer, 0);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+done:
+       mono_os_mutex_unlock (&counters_mutex);
+}
+
+static void
+counters_and_perfcounters_sample (MonoProfiler *prof)
+{
+       uint64_t now = current_time ();
+
+       counters_sample (prof, now);
+       perfcounters_sample (prof, now);
+}
+
+#define COVERAGE_DEBUG(x) if (debug_coverage) {x}
+static mono_mutex_t coverage_mutex;
+static MonoConcurrentHashTable *coverage_methods = NULL;
+static MonoConcurrentHashTable *coverage_assemblies = NULL;
+static MonoConcurrentHashTable *coverage_classes = NULL;
+
+static MonoConcurrentHashTable *filtered_classes = NULL;
+static MonoConcurrentHashTable *entered_methods = NULL;
+static MonoConcurrentHashTable *image_to_methods = NULL;
+static MonoConcurrentHashTable *suppressed_assemblies = NULL;
+static gboolean coverage_initialized = FALSE;
+
+static GPtrArray *coverage_data = NULL;
+static int previous_offset = 0;
+
+typedef struct {
+       MonoLockFreeQueueNode node;
+       MonoMethod *method;
+} MethodNode;
+
+typedef struct {
+       int offset;
+       int counter;
+       char *filename;
+       int line;
+       int column;
+} CoverageEntry;
+
+static void
+free_coverage_entry (gpointer data, gpointer userdata)
+{
+       CoverageEntry *entry = (CoverageEntry *)data;
+       g_free (entry->filename);
+       g_free (entry);
+}
+
+static void
+obtain_coverage_for_method (MonoProfiler *prof, const MonoProfileCoverageEntry *entry)
+{
+       int offset = entry->iloffset - previous_offset;
+       CoverageEntry *e = g_new (CoverageEntry, 1);
+
+       previous_offset = entry->iloffset;
+
+       e->offset = offset;
+       e->counter = entry->counter;
+       e->filename = g_strdup(entry->filename ? entry->filename : "");
+       e->line = entry->line;
+       e->column = entry->col;
+
+       g_ptr_array_add (coverage_data, e);
+}
+
+static char *
+parse_generic_type_names(char *name)
+{
+       char *new_name, *ret;
+       int within_generic_declaration = 0, generic_members = 1;
+
+       if (name == NULL || *name == '\0')
+               return g_strdup ("");
+
+       if (!(ret = new_name = (char *) g_calloc (strlen (name) * 4 + 1, sizeof (char))))
+               return NULL;
+
+       do {
+               switch (*name) {
+                       case '<':
+                               within_generic_declaration = 1;
+                               break;
+
+                       case '>':
+                               within_generic_declaration = 0;
+
+                               if (*(name - 1) != '<') {
+                                       *new_name++ = '`';
+                                       *new_name++ = '0' + generic_members;
+                               } else {
+                                       memcpy (new_name, "&lt;&gt;", 8);
+                                       new_name += 8;
+                               }
+
+                               generic_members = 0;
+                               break;
+
+                       case ',':
+                               generic_members++;
+                               break;
+
+                       default:
+                               if (!within_generic_declaration)
+                                       *new_name++ = *name;
+
+                               break;
+               }
+       } while (*name++);
+
+       return ret;
+}
+
+static int method_id;
+static void
+build_method_buffer (gpointer key, gpointer value, gpointer userdata)
+{
+       MonoMethod *method = (MonoMethod *)value;
+       MonoProfiler *prof = (MonoProfiler *)userdata;
+       MonoClass *klass;
+       MonoImage *image;
+       char *class_name;
+       const char *image_name, *method_name, *sig, *first_filename;
+       guint i;
+
+       previous_offset = 0;
+       coverage_data = g_ptr_array_new ();
+
+       mono_profiler_coverage_get (prof, method, obtain_coverage_for_method);
+
+       klass = mono_method_get_class (method);
+       image = mono_class_get_image (klass);
+       image_name = mono_image_get_name (image);
+
+       sig = mono_signature_get_desc (mono_method_signature (method), TRUE);
+       class_name = parse_generic_type_names (mono_type_get_name (mono_class_get_type (klass)));
+       method_name = mono_method_get_name (method);
+
+       if (coverage_data->len != 0) {
+               CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[0];
+               first_filename = entry->filename ? entry->filename : "";
+       } else
+               first_filename = "";
+
+       image_name = image_name ? image_name : "";
+       sig = sig ? sig : "";
+       method_name = method_name ? method_name : "";
+
+       ENTER_LOG (&coverage_methods_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               strlen (image_name) + 1 /* image name */ +
+               strlen (class_name) + 1 /* class name */ +
+               strlen (method_name) + 1 /* method name */ +
+               strlen (sig) + 1 /* signature */ +
+               strlen (first_filename) + 1 /* first file name */ +
+               LEB128_SIZE /* token */ +
+               LEB128_SIZE /* method id */ +
+               LEB128_SIZE /* entries */
+       );
+
+       emit_event (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
+       emit_string (logbuffer, image_name, strlen (image_name) + 1);
+       emit_string (logbuffer, class_name, strlen (class_name) + 1);
+       emit_string (logbuffer, method_name, strlen (method_name) + 1);
+       emit_string (logbuffer, sig, strlen (sig) + 1);
+       emit_string (logbuffer, first_filename, strlen (first_filename) + 1);
+
+       emit_uvalue (logbuffer, mono_method_get_token (method));
+       emit_uvalue (logbuffer, method_id);
+       emit_value (logbuffer, coverage_data->len);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+       for (i = 0; i < coverage_data->len; i++) {
+               CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
+
+               ENTER_LOG (&coverage_statements_ctr, logbuffer,
+                       EVENT_SIZE /* event */ +
+                       LEB128_SIZE /* method id */ +
+                       LEB128_SIZE /* offset */ +
+                       LEB128_SIZE /* counter */ +
+                       LEB128_SIZE /* line */ +
+                       LEB128_SIZE /* column */
+               );
+
+               emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
+               emit_uvalue (logbuffer, method_id);
+               emit_uvalue (logbuffer, entry->offset);
+               emit_uvalue (logbuffer, entry->counter);
+               emit_uvalue (logbuffer, entry->line);
+               emit_uvalue (logbuffer, entry->column);
+
+               EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+       }
+
+       method_id++;
+
+       g_free (class_name);
+
+       g_ptr_array_foreach (coverage_data, free_coverage_entry, NULL);
+       g_ptr_array_free (coverage_data, TRUE);
+       coverage_data = NULL;
+}
+
+/* This empties the queue */
+static guint
+count_queue (MonoLockFreeQueue *queue)
+{
+       MonoLockFreeQueueNode *node;
+       guint count = 0;
+
+       while ((node = mono_lock_free_queue_dequeue (queue))) {
+               count++;
+               mono_thread_hazardous_try_free (node, g_free);
+       }
+
+       return count;
+}
+
+static void
+build_class_buffer (gpointer key, gpointer value, gpointer userdata)
+{
+       MonoClass *klass = (MonoClass *)key;
+       MonoLockFreeQueue *class_methods = (MonoLockFreeQueue *)value;
+       MonoImage *image;
+       char *class_name;
+       const char *assembly_name;
+       int number_of_methods, partially_covered;
+       guint fully_covered;
+
+       image = mono_class_get_image (klass);
+       assembly_name = mono_image_get_name (image);
+       class_name = mono_type_get_name (mono_class_get_type (klass));
+
+       assembly_name = assembly_name ? assembly_name : "";
+       number_of_methods = mono_class_num_methods (klass);
+       fully_covered = count_queue (class_methods);
+       /* We don't handle partial covered yet */
+       partially_covered = 0;
+
+       ENTER_LOG (&coverage_classes_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               strlen (assembly_name) + 1 /* assembly name */ +
+               strlen (class_name) + 1 /* class name */ +
+               LEB128_SIZE /* no. methods */ +
+               LEB128_SIZE /* fully covered */ +
+               LEB128_SIZE /* partially covered */
+       );
+
+       emit_event (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
+       emit_string (logbuffer, assembly_name, strlen (assembly_name) + 1);
+       emit_string (logbuffer, class_name, strlen (class_name) + 1);
+       emit_uvalue (logbuffer, number_of_methods);
+       emit_uvalue (logbuffer, fully_covered);
+       emit_uvalue (logbuffer, partially_covered);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+       g_free (class_name);
+}
+
+static void
+get_coverage_for_image (MonoImage *image, int *number_of_methods, guint *fully_covered, int *partially_covered)
+{
+       MonoLockFreeQueue *image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
+
+       *number_of_methods = mono_image_get_table_rows (image, MONO_TABLE_METHOD);
+       if (image_methods)
+               *fully_covered = count_queue (image_methods);
+       else
+               *fully_covered = 0;
+
+       // FIXME: We don't handle partially covered yet.
+       *partially_covered = 0;
+}
+
+static void
+build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
+{
+       MonoAssembly *assembly = (MonoAssembly *)value;
+       MonoImage *image = mono_assembly_get_image (assembly);
+       const char *name, *guid, *filename;
+       int number_of_methods = 0, partially_covered = 0;
+       guint fully_covered = 0;
+
+       name = mono_image_get_name (image);
+       guid = mono_image_get_guid (image);
+       filename = mono_image_get_filename (image);
+
+       name = name ? name : "";
+       guid = guid ? guid : "";
+       filename = filename ? filename : "";
+
+       get_coverage_for_image (image, &number_of_methods, &fully_covered, &partially_covered);
+
+       ENTER_LOG (&coverage_assemblies_ctr, logbuffer,
+               EVENT_SIZE /* event */ +
+               strlen (name) + 1 /* name */ +
+               strlen (guid) + 1 /* guid */ +
+               strlen (filename) + 1 /* file name */ +
+               LEB128_SIZE /* no. methods */ +
+               LEB128_SIZE /* fully covered */ +
+               LEB128_SIZE /* partially covered */
+       );
+
+       emit_event (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
+       emit_string (logbuffer, name, strlen (name) + 1);
+       emit_string (logbuffer, guid, strlen (guid) + 1);
+       emit_string (logbuffer, filename, strlen (filename) + 1);
+       emit_uvalue (logbuffer, number_of_methods);
+       emit_uvalue (logbuffer, fully_covered);
+       emit_uvalue (logbuffer, partially_covered);
+
+       EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+}
+
+static void
+dump_coverage (MonoProfiler *prof)
+{
+       if (!coverage_initialized)
+               return;
+
+       COVERAGE_DEBUG(fprintf (stderr, "Coverage: Started dump\n");)
+       method_id = 0;
+
+       mono_os_mutex_lock (&coverage_mutex);
+       mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, NULL);
+       mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, NULL);
+       mono_conc_hashtable_foreach (coverage_methods, build_method_buffer, prof);
+       mono_os_mutex_unlock (&coverage_mutex);
+
+       COVERAGE_DEBUG(fprintf (stderr, "Coverage: Finished dump\n");)
+}
+
+static void
+process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method)
+{
+       MonoClass *klass;
+       MonoImage *image;
+
+       if (!coverage_initialized)
+               return;
+
+       klass = mono_method_get_class (method);
+       image = mono_class_get_image (klass);
+
+       if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)))
+               return;
+
+       mono_os_mutex_lock (&coverage_mutex);
+       mono_conc_hashtable_insert (entered_methods, method, method);
+       mono_os_mutex_unlock (&coverage_mutex);
+}
+
+static MonoLockFreeQueueNode *
+create_method_node (MonoMethod *method)
+{
+       MethodNode *node = (MethodNode *) g_malloc (sizeof (MethodNode));
+       mono_lock_free_queue_node_init ((MonoLockFreeQueueNode *) node, FALSE);
+       node->method = method;
+
+       return (MonoLockFreeQueueNode *) node;
+}
+
+static gboolean
+coverage_filter (MonoProfiler *prof, MonoMethod *method)
+{
+       MonoError error;
+       MonoClass *klass;
+       MonoImage *image;
+       MonoAssembly *assembly;
+       MonoMethodHeader *header;
+       guint32 iflags, flags, code_size;
+       char *fqn, *classname;
+       gboolean has_positive, found;
+       MonoLockFreeQueue *image_methods, *class_methods;
+       MonoLockFreeQueueNode *node;
+
+       g_assert (coverage_initialized && "Why are we being asked for coverage filter info when we're not doing coverage?");
+
+       COVERAGE_DEBUG(fprintf (stderr, "Coverage filter for %s\n", mono_method_get_name (method));)
+
+       flags = mono_method_get_flags (method, &iflags);
+       if ((iflags & 0x1000 /*METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL*/) ||
+           (flags & 0x2000 /*METHOD_ATTRIBUTE_PINVOKE_IMPL*/)) {
+               COVERAGE_DEBUG(fprintf (stderr, "   Internal call or pinvoke - ignoring\n");)
+               return FALSE;
+       }
+
+       // Don't need to do anything else if we're already tracking this method
+       if (mono_conc_hashtable_lookup (coverage_methods, method)) {
+               COVERAGE_DEBUG(fprintf (stderr, "   Already tracking\n");)
+               return TRUE;
+       }
+
+       klass = mono_method_get_class (method);
+       image = mono_class_get_image (klass);
+
+       // Don't handle coverage for the core assemblies
+       if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)) != NULL)
+               return FALSE;
+
+       if (prof->coverage_filters) {
+               /* Check already filtered classes first */
+               if (mono_conc_hashtable_lookup (filtered_classes, klass)) {
+                       COVERAGE_DEBUG(fprintf (stderr, "   Already filtered\n");)
+                       return FALSE;
+               }
+
+               classname = mono_type_get_name (mono_class_get_type (klass));
+
+               fqn = g_strdup_printf ("[%s]%s", mono_image_get_name (image), classname);
+
+               COVERAGE_DEBUG(fprintf (stderr, "   Looking for %s in filter\n", fqn);)
+               // Check positive filters first
+               has_positive = FALSE;
+               found = FALSE;
+               for (guint i = 0; i < prof->coverage_filters->len; ++i) {
+                       char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
+
+                       if (filter [0] == '+') {
+                               filter = &filter [1];
+
+                               COVERAGE_DEBUG(fprintf (stderr, "   Checking against +%s ...", filter);)
+
+                               if (strstr (fqn, filter) != NULL) {
+                                       COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
+                                       found = TRUE;
+                               } else
+                                       COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
+
+                               has_positive = TRUE;
+                       }
+               }
+
+               if (has_positive && !found) {
+                       COVERAGE_DEBUG(fprintf (stderr, "   Positive match was not found\n");)
+
+                       mono_os_mutex_lock (&coverage_mutex);
+                       mono_conc_hashtable_insert (filtered_classes, klass, klass);
+                       mono_os_mutex_unlock (&coverage_mutex);
+                       g_free (fqn);
+                       g_free (classname);
+
+                       return FALSE;
+               }
+
+               for (guint i = 0; i < prof->coverage_filters->len; ++i) {
+                       // FIXME: Is substring search sufficient?
+                       char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
+                       if (filter [0] == '+')
+                               continue;
+
+                       // Skip '-'
+                       filter = &filter [1];
+                       COVERAGE_DEBUG(fprintf (stderr, "   Checking against -%s ...", filter);)
+
+                       if (strstr (fqn, filter) != NULL) {
+                               COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
+
+                               mono_os_mutex_lock (&coverage_mutex);
+                               mono_conc_hashtable_insert (filtered_classes, klass, klass);
+                               mono_os_mutex_unlock (&coverage_mutex);
+                               g_free (fqn);
+                               g_free (classname);
+
+                               return FALSE;
+                       } else
+                               COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
+
+               }
+
+               g_free (fqn);
+               g_free (classname);
+       }
+
+       COVERAGE_DEBUG(fprintf (stderr, "   Handling coverage for %s\n", mono_method_get_name (method));)
+       header = mono_method_get_header_checked (method, &error);
+       mono_error_cleanup (&error);
+
+       mono_method_header_get_code (header, &code_size, NULL);
+
+       assembly = mono_image_get_assembly (image);
+
+       // Need to keep the assemblies around for as long as they are kept in the hashtable
+       // Nunit, for example, has a habit of unloading them before the coverage statistics are
+       // generated causing a crash. See https://bugzilla.xamarin.com/show_bug.cgi?id=39325
+       mono_assembly_addref (assembly);
+
+       mono_os_mutex_lock (&coverage_mutex);
+       mono_conc_hashtable_insert (coverage_methods, method, method);
+       mono_conc_hashtable_insert (coverage_assemblies, assembly, assembly);
+       mono_os_mutex_unlock (&coverage_mutex);
+
+       image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
+
+       if (image_methods == NULL) {
+               image_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue));
+               mono_lock_free_queue_init (image_methods);
+               mono_os_mutex_lock (&coverage_mutex);
+               mono_conc_hashtable_insert (image_to_methods, image, image_methods);
+               mono_os_mutex_unlock (&coverage_mutex);
+       }
+
+       node = create_method_node (method);
+       mono_lock_free_queue_enqueue (image_methods, node);
+
+       class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (coverage_classes, klass);
+
+       if (class_methods == NULL) {
+               class_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue));
+               mono_lock_free_queue_init (class_methods);
+               mono_os_mutex_lock (&coverage_mutex);
+               mono_conc_hashtable_insert (coverage_classes, klass, class_methods);
+               mono_os_mutex_unlock (&coverage_mutex);
+       }
+
+       node = create_method_node (method);
+       mono_lock_free_queue_enqueue (class_methods, node);
+
+       return TRUE;
+}
+
+#define LINE_BUFFER_SIZE 4096
+/* Max file limit of 128KB */
+#define MAX_FILE_SIZE 128 * 1024
+static char *
+get_file_content (FILE *stream)
+{
+       char *buffer;
+       ssize_t bytes_read;
+       long filesize;
+       int res, offset = 0;
+
+       res = fseek (stream, 0, SEEK_END);
+       if (res < 0)
+         return NULL;
+
+       filesize = ftell (stream);
+       if (filesize < 0)
+         return NULL;
+
+       res = fseek (stream, 0, SEEK_SET);
+       if (res < 0)
+         return NULL;
+
+       if (filesize > MAX_FILE_SIZE)
+         return NULL;
+
+       buffer = (char *) g_malloc ((filesize + 1) * sizeof (char));
+       while ((bytes_read = fread (buffer + offset, 1, LINE_BUFFER_SIZE, stream)) > 0)
+               offset += bytes_read;
+
+       /* NULL terminate our buffer */
+       buffer[filesize] = '\0';
+       return buffer;
+}
+
+static char *
+get_next_line (char *contents, char **next_start)
+{
+       char *p = contents;
+
+       if (p == NULL || *p == '\0') {
+               *next_start = NULL;
+               return NULL;
+       }
+
+       while (*p != '\n' && *p != '\0')
+               p++;
+
+       if (*p == '\n') {
+               *p = '\0';
+               *next_start = p + 1;
+       } else
+               *next_start = NULL;
+
+       return contents;
+}
+
+static void
+init_suppressed_assemblies (void)
+{
+       char *content;
+       char *line;
+       FILE *sa_file;
+
+       suppressed_assemblies = mono_conc_hashtable_new (g_str_hash, g_str_equal);
+       sa_file = fopen (SUPPRESSION_DIR "/mono-profiler-log.suppression", "r");
+       if (sa_file == NULL)
+               return;
+
+       /* Don't need to free @content as it is referred to by the lines stored in @suppressed_assemblies */
+       content = get_file_content (sa_file);
+       if (content == NULL) {
+               g_error ("mono-profiler-log.suppression is greater than 128kb - aborting\n");
+       }
+
+       while ((line = get_next_line (content, &content))) {
+               line = g_strchomp (g_strchug (line));
+               /* No locking needed as we're doing initialization */
+               mono_conc_hashtable_insert (suppressed_assemblies, line, line);
+       }
+
+       fclose (sa_file);
+}
+
+static void
+coverage_init (MonoProfiler *prof)
+{
+       g_assert (!coverage_initialized && "Why are we initializing coverage twice?");
+
+       COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");)
+
+       mono_os_mutex_init (&coverage_mutex);
+       coverage_methods = mono_conc_hashtable_new (NULL, NULL);
+       coverage_assemblies = mono_conc_hashtable_new (NULL, NULL);
+       coverage_classes = mono_conc_hashtable_new (NULL, NULL);
+       filtered_classes = mono_conc_hashtable_new (NULL, NULL);
+       entered_methods = mono_conc_hashtable_new (NULL, NULL);
+       image_to_methods = mono_conc_hashtable_new (NULL, NULL);
+       init_suppressed_assemblies ();
+
+       coverage_initialized = TRUE;
+}
+
+static void
+unref_coverage_assemblies (gpointer key, gpointer value, gpointer userdata)
+{
+       MonoAssembly *assembly = (MonoAssembly *)value;
+       mono_assembly_close (assembly);
+}
+
+static void
+free_sample_hit (gpointer p)
+{
+       mono_lock_free_free (p, SAMPLE_BLOCK_SIZE);
+}
+
+static void
+cleanup_reusable_samples (MonoProfiler *prof)
+{
+       SampleHit *sample;
+
+       while ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->sample_reuse_queue)))
+               mono_thread_hazardous_try_free (sample, free_sample_hit);
+}
+
+static void
+log_shutdown (MonoProfiler *prof)
+{
+       InterlockedWrite (&in_shutdown, 1);
+
+       if (!no_counters)
+               counters_and_perfcounters_sample (prof);
+
+       dump_coverage (prof);
+
+       char c = 1;
+
+       if (write (prof->pipes [1], &c, 1) != 1) {
+               fprintf (stderr, "Could not write to pipe: %s\n", strerror (errno));
+               exit (1);
+       }
+
+       mono_native_thread_join (prof->helper_thread);
+
+       mono_os_mutex_destroy (&counters_mutex);
+
+       MonoCounterAgent *mc_next;
+
+       for (MonoCounterAgent *cur = counters; cur; cur = mc_next) {
+               mc_next = cur->next;
+               g_free (cur);
+       }
+
+       PerfCounterAgent *pc_next;
+
+       for (PerfCounterAgent *cur = perfcounters; cur; cur = pc_next) {
+               pc_next = cur->next;
+               g_free (cur);
+       }
+
+       /*
+        * Ensure that we empty the LLS completely, even if some nodes are
+        * not immediately removed upon calling mono_lls_remove (), by
+        * iterating until the head is NULL.
+        */
+       while (profiler_thread_list.head) {
+               MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+                       g_assert (thread->attached && "Why is a thread in the LLS not attached?");
+
+                       remove_thread (thread);
+               } MONO_LLS_FOREACH_SAFE_END
+       }
+
+       /*
+        * Ensure that all threads have been freed, so that we don't miss any
+        * buffers when we shut down the writer thread below.
+        */
+       mono_thread_hazardous_try_free_all ();
+
+       InterlockedWrite (&prof->run_dumper_thread, 0);
+       mono_os_sem_post (&prof->dumper_queue_sem);
+       mono_native_thread_join (prof->dumper_thread);
+       mono_os_sem_destroy (&prof->dumper_queue_sem);
+
+       InterlockedWrite (&prof->run_writer_thread, 0);
+       mono_os_sem_post (&prof->writer_queue_sem);
+       mono_native_thread_join (prof->writer_thread);
+       mono_os_sem_destroy (&prof->writer_queue_sem);
+
+       /*
+        * Free all writer queue entries, and ensure that all sample hits will be
+        * added to the sample reuse queue.
+        */
+       mono_thread_hazardous_try_free_all ();
+
+       cleanup_reusable_samples (prof);
+
+       /*
+        * Finally, make sure that all sample hits are freed. This should cover all
+        * hazardous data from the profiler. We can now be sure that the runtime
+        * won't later invoke free functions in the profiler library after it has
+        * been unloaded.
+        */
+       mono_thread_hazardous_try_free_all ();
+
+       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why is the reader count still non-zero?");
+       g_assert (!InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why does someone still hold the exclusive lock?");
+
+#if defined (HAVE_SYS_ZLIB)
+       if (prof->gzfile)
+               gzclose (prof->gzfile);
+#endif
+       if (prof->pipe_output)
+               pclose (prof->file);
+       else
+               fclose (prof->file);
+
+       mono_conc_hashtable_destroy (prof->method_table);
+       mono_os_mutex_destroy (&prof->method_table_mutex);
+
+       if (coverage_initialized) {
+               mono_os_mutex_lock (&coverage_mutex);
+               mono_conc_hashtable_foreach (coverage_assemblies, unref_coverage_assemblies, prof);
+               mono_os_mutex_unlock (&coverage_mutex);
+
+               mono_conc_hashtable_destroy (coverage_methods);
+               mono_conc_hashtable_destroy (coverage_assemblies);
+               mono_conc_hashtable_destroy (coverage_classes);
+               mono_conc_hashtable_destroy (filtered_classes);
+
+               mono_conc_hashtable_destroy (entered_methods);
+               mono_conc_hashtable_destroy (image_to_methods);
+               mono_conc_hashtable_destroy (suppressed_assemblies);
+               mono_os_mutex_destroy (&coverage_mutex);
+       }
+
+       PROF_TLS_FREE ();
+
+       g_free (prof->args);
+       g_free (prof);
+}
+
+static char*
+new_filename (const char* filename)
+{
+       time_t t = time (NULL);
+       int pid = process_id ();
+       char pid_buf [16];
+       char time_buf [16];
+       char *res, *d;
+       const char *p;
+       int count_dates = 0;
+       int count_pids = 0;
+       int s_date, s_pid;
+       struct tm *ts;
+       for (p = filename; *p; p++) {
+               if (*p != '%')
+                       continue;
+               p++;
+               if (*p == 't')
+                       count_dates++;
+               else if (*p == 'p')
+                       count_pids++;
+               else if (*p == 0)
+                       break;
+       }
+       if (!count_dates && !count_pids)
+               return pstrdup (filename);
+       snprintf (pid_buf, sizeof (pid_buf), "%d", pid);
+       ts = gmtime (&t);
+       snprintf (time_buf, sizeof (time_buf), "%d%02d%02d%02d%02d%02d",
+               1900 + ts->tm_year, 1 + ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
+       s_date = strlen (time_buf);
+       s_pid = strlen (pid_buf);
+       d = res = (char *) g_malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids);
+       for (p = filename; *p; p++) {
+               if (*p != '%') {
+                       *d++ = *p;
+                       continue;
+               }
+               p++;
+               if (*p == 't') {
+                       strcpy (d, time_buf);
+                       d += s_date;
+                       continue;
+               } else if (*p == 'p') {
+                       strcpy (d, pid_buf);
+                       d += s_pid;
+                       continue;
+               } else if (*p == '%') {
+                       *d++ = '%';
+                       continue;
+               } else if (*p == 0)
+                       break;
+               *d++ = '%';
+               *d++ = *p;
+       }
+       *d = 0;
+       return res;
+}
+
+static void
+add_to_fd_set (fd_set *set, int fd, int *max_fd)
+{
+       /*
+        * This should only trigger for the basic FDs (server socket, pipes) at
+        * startup if for some mysterious reason they're too large. In this case,
+        * the profiler really can't function, and we're better off printing an
+        * error and exiting.
+        */
+       if (fd >= FD_SETSIZE) {
+               fprintf (stderr, "File descriptor is out of bounds for fd_set: %d\n", fd);
+               exit (1);
+       }
+
+       FD_SET (fd, set);
+
+       if (*max_fd < fd)
+               *max_fd = fd;
+}
+
+static void *
+helper_thread (void *arg)
+{
+       MonoProfiler *prof = (MonoProfiler *) arg;
+
+       mono_threads_attach_tools_thread ();
+       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
+
+       MonoProfilerThread *thread = init_thread (prof, FALSE);
+
+       GArray *command_sockets = g_array_new (FALSE, FALSE, sizeof (int));
+
+       while (1) {
+               fd_set rfds;
+               int max_fd = -1;
+
+               FD_ZERO (&rfds);
+
+               add_to_fd_set (&rfds, prof->server_socket, &max_fd);
+               add_to_fd_set (&rfds, prof->pipes [0], &max_fd);
+
+               for (gint i = 0; i < command_sockets->len; i++)
+                       add_to_fd_set (&rfds, g_array_index (command_sockets, int, i), &max_fd);
+
+               struct timeval tv = { .tv_sec = 1, .tv_usec = 0 };
+
+               // Sleep for 1sec or until a file descriptor has data.
+               if (select (max_fd + 1, &rfds, NULL, NULL, &tv) == -1) {
+                       if (errno == EINTR)
+                               continue;
+
+                       fprintf (stderr, "Error in mono-profiler-log server: %s", strerror (errno));
+                       exit (1);
+               }
+
+               if (!no_counters)
+                       counters_and_perfcounters_sample (prof);
+
+               buffer_lock_excl ();
+
+               sync_point (SYNC_POINT_PERIODIC);
+
+               buffer_unlock_excl ();
+
+               // Are we shutting down?
+               if (FD_ISSET (prof->pipes [0], &rfds)) {
+                       char c;
+                       read (prof->pipes [0], &c, 1);
+                       break;
+               }
+
+               for (gint i = 0; i < command_sockets->len; i++) {
+                       int fd = g_array_index (command_sockets, int, i);
+
+                       if (!FD_ISSET (fd, &rfds))
+                               continue;
+
+                       char buf [64];
+                       int len = read (fd, buf, sizeof (buf) - 1);
+
+                       if (len == -1)
+                               continue;
+
+                       if (!len) {
+                               // The other end disconnected.
+                               g_array_remove_index (command_sockets, i);
+                               close (fd);
+
+                               continue;
+                       }
+
+                       buf [len] = 0;
+
+                       if (!strcmp (buf, "heapshot\n") && hs_mode_ondemand) {
+                               // Rely on the finalization callbacks invoking process_requests ().
+                               heapshot_requested = 1;
+                               mono_gc_finalize_notify ();
+                       }
+               }
+
+               if (FD_ISSET (prof->server_socket, &rfds)) {
+                       int fd = accept (prof->server_socket, NULL, NULL);
+
+                       if (fd != -1) {
+                               if (fd >= FD_SETSIZE)
+                                       close (fd);
+                               else
+                                       g_array_append_val (command_sockets, fd);
+                       }
+               }
+       }
+
+       for (gint i = 0; i < command_sockets->len; i++)
+               close (g_array_index (command_sockets, int, i));
+
+       g_array_free (command_sockets, TRUE);
+
+       send_log_unsafe (FALSE);
+       deinit_thread (thread);
+
+       mono_thread_info_detach ();
+
+       return NULL;
+}
+
+static void
+start_helper_thread (MonoProfiler* prof)
+{
+       if (pipe (prof->pipes) == -1) {
+               fprintf (stderr, "Cannot create pipe: %s\n", strerror (errno));
+               exit (1);
+       }
+
+       prof->server_socket = socket (PF_INET, SOCK_STREAM, 0);
+
+       if (prof->server_socket == -1) {
+               fprintf (stderr, "Cannot create server socket: %s\n", strerror (errno));
+               exit (1);
+       }
+
+       struct sockaddr_in server_address;
+
+       memset (&server_address, 0, sizeof (server_address));
+       server_address.sin_family = AF_INET;
+       server_address.sin_addr.s_addr = INADDR_ANY;
+       server_address.sin_port = htons (prof->command_port);
+
+       if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) == -1) {
+               fprintf (stderr, "Cannot bind server socket on port %d: %s\n", prof->command_port, strerror (errno));
+               close (prof->server_socket);
+               exit (1);
+       }
+
+       if (listen (prof->server_socket, 1) == -1) {
+               fprintf (stderr, "Cannot listen on server socket: %s\n", strerror (errno));
+               close (prof->server_socket);
+               exit (1);
+       }
+
+       socklen_t slen = sizeof (server_address);
+
+       if (getsockname (prof->server_socket, (struct sockaddr *) &server_address, &slen)) {
+               fprintf (stderr, "Could not get assigned port: %s\n", strerror (errno));
+               close (prof->server_socket);
+               exit (1);
+       }
+
+       prof->command_port = ntohs (server_address.sin_port);
+
+       if (!mono_native_thread_create (&prof->helper_thread, helper_thread, prof)) {
+               fprintf (stderr, "Could not start helper thread\n");
+               close (prof->server_socket);
+               exit (1);
+       }
+}
+
+static void
+free_writer_entry (gpointer p)
+{
+       mono_lock_free_free (p, WRITER_ENTRY_BLOCK_SIZE);
+}
+
+static gboolean
+handle_writer_queue_entry (MonoProfiler *prof)
+{
+       WriterQueueEntry *entry;
+
+       if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
+               if (!entry->methods)
+                       goto no_methods;
+
+               gboolean wrote_methods = FALSE;
+
+               /*
+                * Encode the method events in a temporary log buffer that we
+                * flush to disk before the main buffer, ensuring that all
+                * methods have metadata emitted before they're referenced.
+                *
+                * We use a 'proper' thread-local buffer for this as opposed
+                * to allocating and freeing a buffer by hand because the call
+                * to mono_method_full_name () below may trigger class load
+                * events when it retrieves the signature of the method. So a
+                * thread-local buffer needs to exist when such events occur.
+                */
+               for (guint i = 0; i < entry->methods->len; i++) {
+                       MethodInfo *info = (MethodInfo *) g_ptr_array_index (entry->methods, i);
+
+                       if (mono_conc_hashtable_lookup (prof->method_table, info->method))
+                               goto free_info; // This method already has metadata emitted.
+
+                       /*
+                        * Other threads use this hash table to get a general
+                        * idea of whether a method has already been emitted to
+                        * the stream. Due to the way we add to this table, it
+                        * can easily happen that multiple threads queue up the
+                        * same methods, but that's OK since eventually all
+                        * methods will be in this table and the thread-local
+                        * method lists will just be empty for the rest of the
+                        * app's lifetime.
+                        */
+                       mono_os_mutex_lock (&prof->method_table_mutex);
+                       mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
+                       mono_os_mutex_unlock (&prof->method_table_mutex);
+
+                       char *name = mono_method_full_name (info->method, 1);
+                       int nlen = strlen (name) + 1;
+                       void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
+                       int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
+
+                       ENTER_LOG (&method_jits_ctr, logbuffer,
+                               EVENT_SIZE /* event */ +
+                               LEB128_SIZE /* method */ +
+                               LEB128_SIZE /* start */ +
+                               LEB128_SIZE /* size */ +
+                               nlen /* name */
+                       );
+
+                       emit_event_time (logbuffer, TYPE_JIT | TYPE_METHOD, info->time);
+                       emit_method_inner (logbuffer, info->method);
+                       emit_ptr (logbuffer, cstart);
+                       emit_value (logbuffer, csize);
+
+                       memcpy (logbuffer->cursor, name, nlen);
+                       logbuffer->cursor += nlen;
+
+                       EXIT_LOG_EXPLICIT (NO_SEND, NO_REQUESTS);
+
+                       mono_free (name);
+
+                       wrote_methods = TRUE;
+
+               free_info:
+                       g_free (info);
+               }
+
+               g_ptr_array_free (entry->methods, TRUE);
+
+               if (wrote_methods) {
+                       dump_buffer_threadless (prof, PROF_TLS_GET ()->buffer);
+                       init_buffer_state (PROF_TLS_GET ());
+               }
+
+       no_methods:
+               dump_buffer (prof, entry->buffer);
+
+               mono_thread_hazardous_try_free (entry, free_writer_entry);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void *
+writer_thread (void *arg)
+{
+       MonoProfiler *prof = (MonoProfiler *)arg;
+
+       mono_threads_attach_tools_thread ();
+       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler writer");
+
+       dump_header (prof);
+
+       MonoProfilerThread *thread = init_thread (prof, FALSE);
+
+       while (InterlockedRead (&prof->run_writer_thread)) {
+               mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
+               handle_writer_queue_entry (prof);
+       }
+
+       /* Drain any remaining entries on shutdown. */
+       while (handle_writer_queue_entry (prof));
+
+       free_buffer (thread->buffer, thread->buffer->size);
+       deinit_thread (thread);
+
+       mono_thread_info_detach ();
+
+       return NULL;
+}
+
+static void
+start_writer_thread (MonoProfiler* prof)
+{
+       InterlockedWrite (&prof->run_writer_thread, 1);
+
+       if (!mono_native_thread_create (&prof->writer_thread, writer_thread, prof)) {
+               fprintf (stderr, "Could not start writer thread\n");
+               exit (1);
+       }
+}
+
+static void
+reuse_sample_hit (gpointer p)
+{
+       SampleHit *sample = p;
+
+       mono_lock_free_queue_node_unpoison (&sample->node);
+       mono_lock_free_queue_enqueue (&sample->prof->sample_reuse_queue, &sample->node);
+}
+
+static gboolean
+handle_dumper_queue_entry (MonoProfiler *prof)
+{
+       SampleHit *sample;
+
+       if ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->dumper_queue))) {
+               for (int i = 0; i < sample->count; ++i) {
+                       MonoMethod *method = sample->frames [i].method;
+                       MonoDomain *domain = sample->frames [i].domain;
+                       void *address = sample->frames [i].base_address;
+
+                       if (!method) {
+                               g_assert (domain && "What happened to the domain pointer?");
+                               g_assert (address && "What happened to the instruction pointer?");
+
+                               MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *) address);
+
+                               if (ji)
+                                       sample->frames [i].method = mono_jit_info_get_method (ji);
+                       }
+               }
+
+               ENTER_LOG (&sample_hits_ctr, logbuffer,
+                       EVENT_SIZE /* event */ +
+                       BYTE_SIZE /* type */ +
+                       LEB128_SIZE /* tid */ +
+                       LEB128_SIZE /* count */ +
+                       1 * (
+                               LEB128_SIZE /* ip */
+                       ) +
+                       LEB128_SIZE /* managed count */ +
+                       sample->count * (
+                               LEB128_SIZE /* method */
+                       )
+               );
+
+               emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time);
+               emit_byte (logbuffer, SAMPLE_CYCLES);
+               emit_ptr (logbuffer, (void *) sample->tid);
+               emit_value (logbuffer, 1);
+
+               // TODO: Actual native unwinding.
+               for (int i = 0; i < 1; ++i) {
+                       emit_ptr (logbuffer, sample->ip);
+                       add_code_pointer ((uintptr_t) sample->ip);
+               }
+
+               /* new in data version 6 */
+               emit_uvalue (logbuffer, sample->count);
+
+               for (int i = 0; i < sample->count; ++i)
+                       emit_method (logbuffer, sample->frames [i].method);
+
+               EXIT_LOG_EXPLICIT (DO_SEND, NO_REQUESTS);
+
+               mono_thread_hazardous_try_free (sample, reuse_sample_hit);
+
+               dump_unmanaged_coderefs (prof);
+       }
+
+       return FALSE;
+}
+
+static void *
+dumper_thread (void *arg)
+{
+       MonoProfiler *prof = (MonoProfiler *)arg;
+
+       mono_threads_attach_tools_thread ();
+       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
+
+       MonoProfilerThread *thread = init_thread (prof, FALSE);
+
+       while (InterlockedRead (&prof->run_dumper_thread)) {
+               mono_os_sem_wait (&prof->dumper_queue_sem, MONO_SEM_FLAGS_NONE);
+               handle_dumper_queue_entry (prof);
+       }
+
+       /* Drain any remaining entries on shutdown. */
+       while (handle_dumper_queue_entry (prof));
+
+       send_log_unsafe (FALSE);
+       deinit_thread (thread);
+
+       mono_thread_info_detach ();
+
+       return NULL;
+}
+
+static void
+start_dumper_thread (MonoProfiler* prof)
+{
+       InterlockedWrite (&prof->run_dumper_thread, 1);
+
+       if (!mono_native_thread_create (&prof->dumper_thread, dumper_thread, prof)) {
+               fprintf (stderr, "Could not start dumper thread\n");
+               exit (1);
+       }
+}
+
+static void
+register_counter (const char *name, gint32 *counter)
+{
+       mono_counters_register (name, MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, counter);
+}
+
+static void
+runtime_initialized (MonoProfiler *profiler)
+{
+       InterlockedWrite (&runtime_inited, 1);
+
+       start_writer_thread (profiler);
+       start_dumper_thread (profiler);
+
+       register_counter ("Sample events allocated", &sample_allocations_ctr);
+       register_counter ("Log buffers allocated", &buffer_allocations_ctr);
+
+       register_counter ("Event: Sync points", &sync_points_ctr);
+       register_counter ("Event: Heap objects", &heap_objects_ctr);
+       register_counter ("Event: Heap starts", &heap_starts_ctr);
+       register_counter ("Event: Heap ends", &heap_ends_ctr);
+       register_counter ("Event: Heap roots", &heap_roots_ctr);
+       register_counter ("Event: GC events", &gc_events_ctr);
+       register_counter ("Event: GC resizes", &gc_resizes_ctr);
+       register_counter ("Event: GC allocations", &gc_allocs_ctr);
+       register_counter ("Event: GC moves", &gc_moves_ctr);
+       register_counter ("Event: GC handle creations", &gc_handle_creations_ctr);
+       register_counter ("Event: GC handle deletions", &gc_handle_deletions_ctr);
+       register_counter ("Event: GC finalize starts", &finalize_begins_ctr);
+       register_counter ("Event: GC finalize ends", &finalize_ends_ctr);
+       register_counter ("Event: GC finalize object starts", &finalize_object_begins_ctr);
+       register_counter ("Event: GC finalize object ends", &finalize_object_ends_ctr);
+       register_counter ("Event: Image loads", &image_loads_ctr);
+       register_counter ("Event: Image unloads", &image_unloads_ctr);
+       register_counter ("Event: Assembly loads", &assembly_loads_ctr);
+       register_counter ("Event: Assembly unloads", &assembly_unloads_ctr);
+       register_counter ("Event: Class loads", &class_loads_ctr);
+       register_counter ("Event: Class unloads", &class_unloads_ctr);
+       register_counter ("Event: Method entries", &method_entries_ctr);
+       register_counter ("Event: Method exits", &method_exits_ctr);
+       register_counter ("Event: Method exception leaves", &method_exception_exits_ctr);
+       register_counter ("Event: Method JITs", &method_jits_ctr);
+       register_counter ("Event: Code buffers", &code_buffers_ctr);
+       register_counter ("Event: Exception throws", &exception_throws_ctr);
+       register_counter ("Event: Exception clauses", &exception_clauses_ctr);
+       register_counter ("Event: Monitor contentions", &monitor_contentions_ctr);
+       register_counter ("Event: Monitor acquisitions", &monitor_acquisitions_ctr);
+       register_counter ("Event: Monitor failures", &monitor_failures_ctr);
+       register_counter ("Event: Thread starts", &thread_starts_ctr);
+       register_counter ("Event: Thread ends", &thread_ends_ctr);
+       register_counter ("Event: Thread names", &thread_names_ctr);
+       register_counter ("Event: Domain loads", &domain_loads_ctr);
+       register_counter ("Event: Domain unloads", &domain_unloads_ctr);
+       register_counter ("Event: Domain names", &domain_names_ctr);
+       register_counter ("Event: Context loads", &context_loads_ctr);
+       register_counter ("Event: Context unloads", &context_unloads_ctr);
+       register_counter ("Event: Sample binaries", &sample_ubins_ctr);
+       register_counter ("Event: Sample symbols", &sample_usyms_ctr);
+       register_counter ("Event: Sample hits", &sample_hits_ctr);
+       register_counter ("Event: Counter descriptors", &counter_descriptors_ctr);
+       register_counter ("Event: Counter samples", &counter_samples_ctr);
+       register_counter ("Event: Performance counter descriptors", &perfcounter_descriptors_ctr);
+       register_counter ("Event: Performance counter samples", &perfcounter_samples_ctr);
+       register_counter ("Event: Coverage methods", &coverage_methods_ctr);
+       register_counter ("Event: Coverage statements", &coverage_statements_ctr);
+       register_counter ("Event: Coverage classes", &coverage_classes_ctr);
+       register_counter ("Event: Coverage assemblies", &coverage_assemblies_ctr);
+
+       counters_init (profiler);
+
+       start_helper_thread (profiler);
+}
+
+static MonoProfiler*
+create_profiler (const char *args, const char *filename, GPtrArray *filters)
+{
+       MonoProfiler *prof;
+       char *nf;
+       int force_delete = 0;
+       prof = (MonoProfiler *) g_calloc (1, sizeof (MonoProfiler));
+
+       prof->args = pstrdup (args);
+       prof->command_port = command_port;
+       if (filename && *filename == '-') {
+               force_delete = 1;
+               filename++;
+       }
+       if (!filename) {
+               if (do_report)
+                       filename = "|mprof-report -";
+               else
+                       filename = "output.mlpd";
+               nf = (char*)filename;
+       } else {
+               nf = new_filename (filename);
+               if (do_report) {
+                       int s = strlen (nf) + 32;
+                       char *p = (char *) g_malloc (s);
+                       snprintf (p, s, "|mprof-report '--out=%s' -", nf);
+                       g_free (nf);
+                       nf = p;
+               }
+       }
+       if (*nf == '|') {
+               prof->file = popen (nf + 1, "w");
+               prof->pipe_output = 1;
+       } else if (*nf == '#') {
+               int fd = strtol (nf + 1, NULL, 10);
+               prof->file = fdopen (fd, "a");
+       } else {
+               if (force_delete)
+                       unlink (nf);
+               prof->file = fopen (nf, "wb");
+       }
+       if (!prof->file) {
+               fprintf (stderr, "Cannot create profiler output: %s\n", nf);
+               exit (1);
+       }
+
+#if defined (HAVE_SYS_ZLIB)
+       if (use_zip)
+               prof->gzfile = gzdopen (fileno (prof->file), "wb");
+#endif
+
+       /*
+        * If you hit this assert while increasing MAX_FRAMES, you need to increase
+        * SAMPLE_BLOCK_SIZE as well.
+        */
+       g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE));
+
+       // FIXME: We should free this stuff too.
+       mono_lock_free_allocator_init_size_class (&prof->sample_size_class, SAMPLE_SLOT_SIZE (num_frames), SAMPLE_BLOCK_SIZE);
+       mono_lock_free_allocator_init_allocator (&prof->sample_allocator, &prof->sample_size_class, MONO_MEM_ACCOUNT_PROFILER);
+
+       mono_lock_free_queue_init (&prof->sample_reuse_queue);
+
+       g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
+
+       // FIXME: We should free this stuff too.
+       mono_lock_free_allocator_init_size_class (&prof->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
+       mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER);
+
+       mono_lock_free_queue_init (&prof->writer_queue);
+       mono_os_sem_init (&prof->writer_queue_sem, 0);
+
+       mono_lock_free_queue_init (&prof->dumper_queue);
+       mono_os_sem_init (&prof->dumper_queue_sem, 0);
+
+       mono_os_mutex_init (&prof->method_table_mutex);
+       prof->method_table = mono_conc_hashtable_new (NULL, NULL);
+
+       if (do_coverage)
+               coverage_init (prof);
+       prof->coverage_filters = filters;
+
+       prof->startup_time = current_time ();
+       return prof;
+}
+
+static void
+usage (int do_exit)
+{
+       printf ("Log profiler version %d.%d (format: %d)\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
+       printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
+       printf ("Options:\n");
+       printf ("\thelp                 show this usage info\n");
+       printf ("\t[no]alloc            enable/disable recording allocation info\n");
+       printf ("\t[no]calls            enable/disable recording enter/leave method events\n");
+       printf ("\theapshot[=MODE]      record heap shot info (by default at each major collection)\n");
+       printf ("\t                     MODE: every XXms milliseconds, every YYgc collections, ondemand\n");
+       printf ("\tcounters             sample counters every 1s\n");
+       printf ("\tsample[=TYPE]        use statistical sampling mode (by default cycles/100)\n");
+       printf ("\t                     TYPE: cycles,instr,cacherefs,cachemiss,branches,branchmiss\n");
+       printf ("\t                     TYPE can be followed by /FREQUENCY\n");
+       printf ("\tmaxframes=NUM        collect up to NUM stack frames\n");
+       printf ("\tcalldepth=NUM        ignore method events for call chain depth bigger than NUM\n");
+       printf ("\toutput=FILENAME      write the data to file FILENAME (-FILENAME to overwrite)\n");
+       printf ("\toutput=|PROGRAM      write the data to the stdin of PROGRAM\n");
+       printf ("\t                     %%t is subtituted with date and time, %%p with the pid\n");
+       printf ("\treport               create a report instead of writing the raw data to a file\n");
+       printf ("\tzip                  compress the output data\n");
+       printf ("\tport=PORTNUM         use PORTNUM for the listening command server\n");
+       printf ("\tcoverage             enable collection of code coverage data\n");
+       printf ("\tcovfilter=ASSEMBLY   add an assembly to the code coverage filters\n");
+       printf ("\t                     add a + to include the assembly or a - to exclude it\n");
+       printf ("\t                     filter=-mscorlib\n");
+       printf ("\tcovfilter-file=FILE  use FILE to generate the list of assemblies to be filtered\n");
+       if (do_exit)
+               exit (1);
+}
+
+static const char*
+match_option (const char* p, const char *opt, char **rval)
+{
+       int len = strlen (opt);
+       if (strncmp (p, opt, len) == 0) {
+               if (rval) {
+                       if (p [len] == '=' && p [len + 1]) {
+                               const char *opt = p + len + 1;
+                               const char *end = strchr (opt, ',');
+                               char *val;
+                               int l;
+                               if (end == NULL) {
+                                       l = strlen (opt);
+                               } else {
+                                       l = end - opt;
+                               }
+                               val = (char *) g_malloc (l + 1);
+                               memcpy (val, opt, l);
+                               val [l] = 0;
+                               *rval = val;
+                               return opt + l;
+                       }
+                       if (p [len] == 0 || p [len] == ',') {
+                               *rval = NULL;
+                               return p + len + (p [len] == ',');
+                       }
+                       usage (1);
+               } else {
+                       if (p [len] == 0)
+                               return p + len;
+                       if (p [len] == ',')
+                               return p + len + 1;
+               }
+       }
+       return p;
+}
+
+static void
+set_sample_freq (char *val)
+{
+       do_mono_sample = 1;
+       sample_freq = 100;
+
+       if (!val)
+               return;
+
+       char *p = val;
+
+       // Is it only the frequency (new option style)?
+       if (isdigit (*p))
+               goto parse;
+
+       // Skip the sample type for backwards compatibility.
+       while (isalpha (*p))
+               p++;
+
+       // Skip the forward slash only if we got a sample type.
+       if (p != val && *p == '/') {
+               p++;
+
+               char *end;
+
+       parse:
+               sample_freq = strtoul (p, &end, 10);
+
+               if (p == end)
+                       usage (1);
+
+               p = end;
+       }
+
+       if (*p)
+               usage (1);
+
+       g_free (val);
+}
+
+static void
+set_hsmode (char* val, int allow_empty)
+{
+       char *end;
+       unsigned int count;
+       if (allow_empty && !val)
+               return;
+       if (strcmp (val, "ondemand") == 0) {
+               hs_mode_ondemand = 1;
+               g_free (val);
+               return;
+       }
+       count = strtoul (val, &end, 10);
+       if (val == end)
+               usage (1);
+       if (strcmp (end, "ms") == 0)
+               hs_mode_ms = count;
+       else if (strcmp (end, "gc") == 0)
+               hs_mode_gc = count;
+       else
+               usage (1);
+       g_free (val);
+}
+
+/*
+ * declaration to silence the compiler: this is the entry point that
+ * mono will load from the shared library and call.
+ */
+extern void
+mono_profiler_startup (const char *desc);
+
+extern void
+mono_profiler_startup_log (const char *desc);
+
+/*
+ * this is the entry point that will be used when the profiler
+ * is embedded inside the main executable.
+ */
+void
+mono_profiler_startup_log (const char *desc)
+{
+       mono_profiler_startup (desc);
+}
+
+void
+mono_profiler_startup (const char *desc)
+{
+       MonoProfiler *prof;
+       GPtrArray *filters = NULL;
+       char *filename = NULL;
+       const char *p;
+       const char *opt;
+       int calls_enabled = 0;
+       int allocs_enabled = 0;
+       int events = MONO_PROFILE_GC|MONO_PROFILE_ALLOCATIONS|
+               MONO_PROFILE_GC_MOVES|MONO_PROFILE_CLASS_EVENTS|MONO_PROFILE_THREADS|
+               MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS|
+               MONO_PROFILE_MONITOR_EVENTS|MONO_PROFILE_MODULE_EVENTS|MONO_PROFILE_GC_ROOTS|
+               MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
+               MONO_PROFILE_ASSEMBLY_EVENTS|MONO_PROFILE_GC_FINALIZATION;
+
+       max_allocated_sample_hits = mono_cpu_count () * 1000;
+
+       p = desc;
+       if (strncmp (p, "log", 3))
+               usage (1);
+       p += 3;
+       if (*p == ':')
+               p++;
+       for (; *p; p = opt) {
+               char *val;
+               if (*p == ',') {
+                       opt = p + 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "help", NULL)) != p) {
+                       usage (0);
+                       continue;
+               }
+               if ((opt = match_option (p, "calls", NULL)) != p) {
+                       calls_enabled = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "nocalls", NULL)) != p) {
+                       events &= ~MONO_PROFILE_ENTER_LEAVE;
+                       nocalls = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "alloc", NULL)) != p) {
+                       allocs_enabled = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "noalloc", NULL)) != p) {
+                       events &= ~MONO_PROFILE_ALLOCATIONS;
+                       events &= ~MONO_PROFILE_GC_MOVES;
+                       continue;
+               }
+               if ((opt = match_option (p, "nocounters", NULL)) != p) {
+                       no_counters = TRUE;
+                       continue;
+               }
+               if ((opt = match_option (p, "time", &val)) != p) {
+                       // For backwards compatibility.
+                       if (strcmp (val, "fast") && strcmp (val, "null"))
+                               usage (1);
+                       g_free (val);
+                       continue;
+               }
+               if ((opt = match_option (p, "report", NULL)) != p) {
+                       do_report = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "debug", NULL)) != p) {
+                       do_debug = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "sampling-real", NULL)) != p) {
+                       sampling_mode = MONO_PROFILER_STAT_MODE_REAL;
+                       continue;
+               }
+               if ((opt = match_option (p, "sampling-process", NULL)) != p) {
+                       sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
+                       continue;
+               }
+               if ((opt = match_option (p, "heapshot", &val)) != p) {
+                       events &= ~MONO_PROFILE_ALLOCATIONS;
+                       events &= ~MONO_PROFILE_GC_MOVES;
+                       events &= ~MONO_PROFILE_ENTER_LEAVE;
+                       nocalls = 1;
+                       do_heap_shot = 1;
+                       set_hsmode (val, 1);
+                       continue;
+               }
+               if ((opt = match_option (p, "sample", &val)) != p) {
+                       events &= ~MONO_PROFILE_ALLOCATIONS;
+                       events &= ~MONO_PROFILE_GC_MOVES;
+                       events &= ~MONO_PROFILE_ENTER_LEAVE;
+                       nocalls = 1;
+                       set_sample_freq (val);
+                       continue;
+               }
+               if ((opt = match_option (p, "zip", NULL)) != p) {
+                       use_zip = 1;
+                       continue;
+               }
+               if ((opt = match_option (p, "output", &val)) != p) {
+                       filename = val;
+                       continue;
+               }
+               if ((opt = match_option (p, "port", &val)) != p) {
+                       char *end;
+                       command_port = strtoul (val, &end, 10);
+                       g_free (val);
+                       continue;
+               }
+               if ((opt = match_option (p, "maxframes", &val)) != p) {
+                       char *end;
+                       num_frames = strtoul (val, &end, 10);
+                       if (num_frames > MAX_FRAMES)
+                               num_frames = MAX_FRAMES;
+                       g_free (val);
+                       notraces = num_frames == 0;
+                       continue;
+               }
+               if ((opt = match_option (p, "maxsamples", &val)) != p) {
+                       char *end;
+                       max_allocated_sample_hits = strtoul (val, &end, 10);
+                       if (!max_allocated_sample_hits)
+                               max_allocated_sample_hits = G_MAXINT32;
+                       g_free (val);
+                       continue;
+               }
+               if ((opt = match_option (p, "calldepth", &val)) != p) {
+                       char *end;
+                       max_call_depth = strtoul (val, &end, 10);
+                       g_free (val);
+                       continue;
+               }
+               if ((opt = match_option (p, "counters", NULL)) != p) {
+                       // For backwards compatibility.
+                       continue;
+               }
+               if ((opt = match_option (p, "coverage", NULL)) != p) {
+                       do_coverage = 1;
+                       events |= MONO_PROFILE_ENTER_LEAVE;
+                       debug_coverage = (g_getenv ("MONO_PROFILER_DEBUG_COVERAGE") != NULL);
+                       continue;
+               }
+               if ((opt = match_option (p, "onlycoverage", NULL)) != p) {
+                       only_coverage = TRUE;
+                       continue;
+               }
+               if ((opt = match_option (p, "covfilter-file", &val)) != p) {
+                       FILE *filter_file;
+                       char *line, *content;
+
+                       if (filters == NULL)
+                               filters = g_ptr_array_new ();
+
+                       filter_file = fopen (val, "r");
+                       if (filter_file == NULL) {
+                               fprintf (stderr, "Unable to open %s\n", val);
+                               exit (0);
+                       }
+
+                       /* Don't need to free content as it is referred to by the lines stored in @filters */
+                       content = get_file_content (filter_file);
+                       if (content == NULL)
+                               fprintf (stderr, "WARNING: %s is greater than 128kb - ignoring\n", val);
+
+                       while ((line = get_next_line (content, &content)))
+                               g_ptr_array_add (filters, g_strchug (g_strchomp (line)));
+
+                       fclose (filter_file);
+                       continue;
+               }
+               if ((opt = match_option (p, "covfilter", &val)) != p) {
+                       if (filters == NULL)
+                               filters = g_ptr_array_new ();
+
+                       g_ptr_array_add (filters, val);
+                       continue;
+               }
+               if (opt == p) {
+                       usage (0);
+                       exit (0);
+               }
+       }
+
+       if (calls_enabled) {
+               events |= MONO_PROFILE_ENTER_LEAVE;
+               nocalls = 0;
+       }
+
+       if (allocs_enabled) {
+               events |= MONO_PROFILE_ALLOCATIONS;
+               events |= MONO_PROFILE_GC_MOVES;
+       }
+
+       // Only activate the bare minimum events the profiler needs to function.
+       if (only_coverage) {
+               if (!do_coverage) {
+                       fprintf (stderr, "The onlycoverage option is only valid when paired with the coverage option\n");
+                       exit (1);
+               }
+
+               no_counters = TRUE;
+               events = MONO_PROFILE_GC | MONO_PROFILE_THREADS | MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE;
+       }
+
+       init_time ();
+
+       PROF_TLS_INIT ();
+
+       prof = create_profiler (desc, filename, filters);
+       if (!prof) {
+               PROF_TLS_FREE ();
+               return;
+       }
+
+       mono_lls_init (&profiler_thread_list, NULL);
+
+       init_thread (prof, TRUE);
+
+       mono_profiler_install (prof, log_shutdown);
+       mono_profiler_install_gc (gc_event, gc_resize);
+       mono_profiler_install_allocation (gc_alloc);
+       mono_profiler_install_gc_moves (gc_moves);
+       mono_profiler_install_gc_roots (gc_handle, gc_roots);
+       mono_profiler_install_gc_finalize (finalize_begin, finalize_object_begin, finalize_object_end, finalize_end);
+       mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL);
+       mono_profiler_install_appdomain_name (domain_name);
+       mono_profiler_install_context (context_loaded, context_unloaded);
+       mono_profiler_install_class (NULL, class_loaded, class_unloaded, NULL);
+       mono_profiler_install_module (NULL, image_loaded, image_unloaded, NULL);
+       mono_profiler_install_assembly (NULL, assembly_loaded, assembly_unloaded, NULL);
+       mono_profiler_install_thread (thread_start, thread_end);
+       mono_profiler_install_thread_name (thread_name);
+       mono_profiler_install_enter_leave (method_enter, method_leave);
+       mono_profiler_install_jit_end (method_jitted);
+       mono_profiler_install_code_buffer_new (code_buffer_new);
+       mono_profiler_install_exception (throw_exc, method_exc_leave, clause_exc);
+       mono_profiler_install_monitor (monitor_event);
+       mono_profiler_install_runtime_initialized (runtime_initialized);
+       if (do_coverage)
+               mono_profiler_install_coverage_filter (coverage_filter);
+
+       if (do_mono_sample && sample_freq) {
+               events |= MONO_PROFILE_STATISTICAL;
+               mono_profiler_set_statistical_mode (sampling_mode, sample_freq);
+               mono_profiler_install_statistical (mono_sample_hit);
+       }
+
+       mono_profiler_set_events ((MonoProfileFlags)events);
+}
diff --git a/mono/profiler/mono-profiler-log.h b/mono/profiler/mono-profiler-log.h
new file mode 100644 (file)
index 0000000..99b5782
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef __MONO_PROFLOG_H__
+#define __MONO_PROFLOG_H__
+
+#define BUF_ID 0x4D504C01
+#define LOG_HEADER_ID 0x4D505A01
+#define LOG_VERSION_MAJOR 1
+#define LOG_VERSION_MINOR 1
+#define LOG_DATA_VERSION 13
+
+/*
+ * Changes in major/minor versions:
+ * version 1.0: removed sysid field from header
+ *              added args, arch, os fields to header
+ *
+ * Changes in data versions:
+ * version 2: added offsets in heap walk
+ * version 3: added GC roots
+ * version 4: added sample/statistical profiling
+ * version 5: added counters sampling
+ * version 6: added optional backtrace in sampling info
+ * version 8: added TYPE_RUNTIME and JIT helpers/trampolines
+ * version 9: added MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING
+ * version 10: added TYPE_COVERAGE
+ * version 11: added thread ID to TYPE_SAMPLE_HIT
+               added more load/unload events
+                   unload for class
+                   unload for image
+                   load/unload for appdomain
+                   load/unload for contexts
+                   load/unload/name for assemblies
+               removed TYPE_LOAD_ERR flag (profiler never generated it, now removed from the format itself)
+               added TYPE_GC_HANDLE_{CREATED,DESTROYED}_BT
+               TYPE_JIT events are no longer guaranteed to have code start/size info (can be zero)
+ * version 12: added MONO_COUNTER_PROFILER
+ * version 13: added MONO_GC_EVENT_{PRE_STOP_WORLD_LOCKED,POST_START_WORLD_UNLOCKED}
+               added TYPE_META + TYPE_SYNC_POINT
+               removed il and native offset in TYPE_SAMPLE_HIT
+               methods in backtraces are now encoded as proper method pointers
+               removed flags in backtrace format
+               removed flags in metadata events
+               changed the following fields to a single byte rather than leb128
+                   TYPE_GC_EVENT: event_type, generation
+                   TYPE_HEAP_ROOT: root_type
+                   TYPE_JITHELPER: type
+                   TYPE_SAMPLE_HIT: sample_type
+                   TYPE_CLAUSE: clause_type
+                   TYPE_SAMPLE_COUNTERS_DESC: type, unit, variance
+                   TYPE_SAMPLE_COUNTERS: type
+               added time fields to all events that were missing one
+                   TYPE_HEAP_OBJECT
+                   TYPE_HEAP_ROOT
+                   TYPE_SAMPLE_USYM
+                   TYPE_SAMPLE_COUNTERS_DESC
+                   TYPE_COVERAGE_METHOD
+                   TYPE_COVERAGE_STATEMENT
+                   TYPE_COVERAGE_CLASS
+                   TYPE_COVERAGE_ASSEMBLY
+               moved the time field in TYPE_SAMPLE_HIT to right after the event byte, now encoded as a regular time field
+               changed the time field in TYPE_SAMPLE_COUNTERS to be encoded as a regular time field (in nanoseconds)
+               added TYPE_GC_FINALIZE_{START,END,OBJECT_START,OBJECT_END}
+ */
+
+enum {
+       TYPE_ALLOC,
+       TYPE_GC,
+       TYPE_METADATA,
+       TYPE_METHOD,
+       TYPE_EXCEPTION,
+       TYPE_MONITOR,
+       TYPE_HEAP,
+       TYPE_SAMPLE,
+       TYPE_RUNTIME,
+       TYPE_COVERAGE,
+       TYPE_META,
+       /* extended type for TYPE_HEAP */
+       TYPE_HEAP_START  = 0 << 4,
+       TYPE_HEAP_END    = 1 << 4,
+       TYPE_HEAP_OBJECT = 2 << 4,
+       TYPE_HEAP_ROOT   = 3 << 4,
+       /* extended type for TYPE_METADATA */
+       TYPE_END_LOAD     = 2 << 4,
+       TYPE_END_UNLOAD   = 4 << 4,
+       /* extended type for TYPE_GC */
+       TYPE_GC_EVENT  = 1 << 4,
+       TYPE_GC_RESIZE = 2 << 4,
+       TYPE_GC_MOVE   = 3 << 4,
+       TYPE_GC_HANDLE_CREATED      = 4 << 4,
+       TYPE_GC_HANDLE_DESTROYED    = 5 << 4,
+       TYPE_GC_HANDLE_CREATED_BT   = 6 << 4,
+       TYPE_GC_HANDLE_DESTROYED_BT = 7 << 4,
+       TYPE_GC_FINALIZE_START = 8 << 4,
+       TYPE_GC_FINALIZE_END = 9 << 4,
+       TYPE_GC_FINALIZE_OBJECT_START = 10 << 4,
+       TYPE_GC_FINALIZE_OBJECT_END = 11 << 4,
+       /* extended type for TYPE_METHOD */
+       TYPE_LEAVE     = 1 << 4,
+       TYPE_ENTER     = 2 << 4,
+       TYPE_EXC_LEAVE = 3 << 4,
+       TYPE_JIT       = 4 << 4,
+       /* extended type for TYPE_EXCEPTION */
+       TYPE_THROW_NO_BT = 0 << 7,
+       TYPE_THROW_BT    = 1 << 7,
+       TYPE_CLAUSE      = 1 << 4,
+       /* extended type for TYPE_ALLOC */
+       TYPE_ALLOC_NO_BT  = 0 << 4,
+       TYPE_ALLOC_BT     = 1 << 4,
+       /* extended type for TYPE_MONITOR */
+       TYPE_MONITOR_NO_BT  = 0 << 7,
+       TYPE_MONITOR_BT     = 1 << 7,
+       /* extended type for TYPE_SAMPLE */
+       TYPE_SAMPLE_HIT           = 0 << 4,
+       TYPE_SAMPLE_USYM          = 1 << 4,
+       TYPE_SAMPLE_UBIN          = 2 << 4,
+       TYPE_SAMPLE_COUNTERS_DESC = 3 << 4,
+       TYPE_SAMPLE_COUNTERS      = 4 << 4,
+       /* extended type for TYPE_RUNTIME */
+       TYPE_JITHELPER = 1 << 4,
+       /* extended type for TYPE_COVERAGE */
+       TYPE_COVERAGE_ASSEMBLY = 0 << 4,
+       TYPE_COVERAGE_METHOD   = 1 << 4,
+       TYPE_COVERAGE_STATEMENT = 2 << 4,
+       TYPE_COVERAGE_CLASS = 3 << 4,
+       /* extended type for TYPE_META */
+       TYPE_SYNC_POINT = 0 << 4,
+       TYPE_END
+};
+
+enum {
+       /* metadata type byte for TYPE_METADATA */
+       TYPE_CLASS    = 1,
+       TYPE_IMAGE    = 2,
+       TYPE_ASSEMBLY = 3,
+       TYPE_DOMAIN   = 4,
+       TYPE_THREAD   = 5,
+       TYPE_CONTEXT  = 6,
+};
+
+typedef enum {
+       SYNC_POINT_PERIODIC,
+       SYNC_POINT_WORLD_STOP,
+       SYNC_POINT_WORLD_START
+} MonoProfilerSyncPointType;
+
+// Sampling sources
+// Unless you have compiled with --enable-perf-events, only SAMPLE_CYCLES is available
+enum {
+       SAMPLE_CYCLES = 1,
+       SAMPLE_INSTRUCTIONS,
+       SAMPLE_CACHE_MISSES,
+       SAMPLE_CACHE_REFS,
+       SAMPLE_BRANCHES,
+       SAMPLE_BRANCH_MISSES,
+       SAMPLE_LAST
+};
+
+#endif /* __MONO_PROFLOG_H__ */
diff --git a/mono/profiler/mprof-report.c b/mono/profiler/mprof-report.c
new file mode 100644 (file)
index 0000000..1017d1f
--- /dev/null
@@ -0,0 +1,4306 @@
+/*
+ * mprof-report.c: mprof-report program source: decode and analyze the log profiler data
+ *
+ * Authors:
+ *   Paolo Molaro (lupus@ximian.com)
+ *   Alex Rønne Petersen (alexrp@xamarin.com)
+ *
+ * Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
+ */
+
+/*
+ * The Coverage XML output schema
+ * <coverage>
+ *   <assembly/>
+ *   <class/>
+ *   <method>
+ *     <statement/>
+ *   </method>
+ * </coverage>
+ *
+ * Elements:
+ *   <coverage> - The root element of the documentation. It can contain any number of
+ *                <assembly>, <class> or <method> elements.
+ *                Attributes:
+ *                   - version: The version number for the file format - (eg: "0.3")
+ *   <assembly> - Contains data about assemblies. Has no child elements
+ *                Attributes:
+ *                   - name: The name of the assembly - (eg: "System.Xml")
+ *                   - guid: The GUID of the assembly
+ *                   - filename: The filename of the assembly
+ *                   - method-count: The number of methods in the assembly
+ *                   - full: The number of fully covered methods
+ *                   - partial: The number of partially covered methods
+ *   <class> - Contains data about classes. Has no child elements
+ *             Attributes:
+ *                - name: The name of the class
+ *                - method-count: The number of methods in the class
+ *                - full: The number of fully covered methods
+ *                - partial: The number of partially covered methods
+ *   <method> - Contains data about methods. Can contain any number of <statement> elements
+ *              Attributes:
+ *                 - assembly: The name of the parent assembly
+ *                 - class: The name of the parent class
+ *                 - name: The name of the method, with all it's parameters
+ *                 - filename: The name of the source file containing this method
+ *                 - token
+ *   <statement> - Contains data about IL statements. Has no child elements
+ *                 Attributes:
+ *                    - offset: The offset of the statement in the IL code after the previous
+ *                              statement's offset
+ *                    - counter: 1 if the line was covered, 0 if it was not
+ *                    - line: The line number in the parent method's file
+ *                    - column: The column on the line
+ */
+#include <config.h>
+#include "mono-profiler-log.h"
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <time.h>
+#if !defined(__APPLE__) && !defined(__FreeBSD__)
+#include <malloc.h>
+#endif
+#include <unistd.h>
+#include <stdlib.h>
+#if defined (HAVE_SYS_ZLIB)
+#include <zlib.h>
+#endif
+#include <glib.h>
+#include <mono/metadata/profiler.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/debug-helpers.h>
+#include <mono/utils/mono-counters.h>
+
+#define HASH_SIZE 9371
+#define SMALL_HASH_SIZE 31
+
+#if defined(__native_client__) || defined(__native_client_codegen__)
+volatile int __nacl_thread_suspension_needed = 0;
+void __nacl_suspend_thread_if_needed() {}
+#endif
+
+static int debug = 0;
+static int collect_traces = 0;
+static int show_traces = 0;
+static int trace_max = 6;
+static int verbose = 0;
+static uintptr_t *tracked_objects = 0;
+static int num_tracked_objects = 0;
+static uintptr_t thread_filter = 0;
+static uint64_t find_size = 0;
+static const char* find_name = NULL;
+static uint64_t time_from = 0;
+static uint64_t time_to = 0xffffffffffffffffULL;
+static int use_time_filter = 0;
+static uint64_t startup_time = 0;
+static FILE* outfile = NULL;
+static FILE* coverage_outfile = NULL;
+
+static int32_t
+read_int16 (unsigned char *p)
+{
+       int32_t value = *p++;
+       value |= (*p++) << 8;
+       return value;
+}
+
+static int32_t
+read_int32 (unsigned char *p)
+{
+       int32_t value = *p++;
+       value |= (*p++) << 8;
+       value |= (*p++) << 16;
+       value |= (uint32_t)(*p++) << 24;
+       return value;
+}
+
+static int64_t
+read_int64 (unsigned char *p)
+{
+       uint64_t value = *p++;
+       value |= (*p++) << 8;
+       value |= (*p++) << 16;
+       value |= (uint64_t)(*p++) << 24;
+       value |= (uint64_t)(*p++) << 32;
+       value |= (uint64_t)(*p++) << 40;
+       value |= (uint64_t)(*p++) << 48;
+       value |= (uint64_t)(*p++) << 54;
+       return value;
+}
+
+static char*
+pstrdup (const char *s)
+{
+       int len = strlen (s) + 1;
+       char *p = (char *) g_malloc (len);
+       memcpy (p, s, len);
+       return p;
+}
+
+typedef struct _CounterValue CounterValue;
+struct _CounterValue {
+       uint64_t timestamp;
+       unsigned char *buffer;
+       CounterValue *next;
+};
+
+typedef struct _Counter Counter;
+struct _Counter {
+       int index;
+       const char *section;
+       const char *name;
+       int type;
+       int unit;
+       int variance;
+       CounterValue *values;
+       CounterValue *values_last;
+};
+
+typedef struct _CounterList CounterList;
+struct _CounterList {
+       Counter *counter;
+       CounterList *next;
+};
+
+typedef struct _CounterSection CounterSection;
+struct _CounterSection {
+       const char *value;
+       CounterList *counters;
+       CounterList *counters_last;
+       CounterSection *next;
+};
+
+typedef struct _CounterTimestamp CounterTimestamp;
+struct _CounterTimestamp {
+       uint64_t value;
+       CounterSection *sections;
+       CounterSection *sections_last;
+       CounterTimestamp *next;
+};
+
+static CounterList *counters = NULL;
+static CounterSection *counters_sections = NULL;
+static CounterTimestamp *counters_timestamps = NULL;
+
+enum {
+       COUNTERS_SORT_TIME,
+       COUNTERS_SORT_CATEGORY
+};
+
+static int counters_sort_mode = COUNTERS_SORT_TIME;
+
+static void
+add_counter_to_section (Counter *counter)
+{
+       CounterSection *csection, *s;
+       CounterList *clist;
+
+       clist = (CounterList *) g_calloc (1, sizeof (CounterList));
+       clist->counter = counter;
+
+       for (csection = counters_sections; csection; csection = csection->next) {
+               if (strcmp (csection->value, counter->section) == 0) {
+                       /* If section exist */
+                       if (!csection->counters)
+                               csection->counters = clist;
+                       else
+                               csection->counters_last->next = clist;
+                       csection->counters_last = clist;
+                       return;
+               }
+       }
+
+       /* If section does not exist */
+       csection = (CounterSection *) g_calloc (1, sizeof (CounterSection));
+       csection->value = counter->section;
+       csection->counters = clist;
+       csection->counters_last = clist;
+
+       if (!counters_sections) {
+               counters_sections = csection;
+       } else {
+               s = counters_sections;
+               while (s->next)
+                       s = s->next;
+               s->next = csection;
+       }
+}
+
+static void
+add_counter (const char *section, const char *name, int type, int unit, int variance, int index)
+{
+       CounterList *list, *l;
+       Counter *counter;
+
+       for (list = counters; list; list = list->next)
+               if (list->counter->index == index)
+                       return;
+
+       counter = (Counter *) g_calloc (1, sizeof (Counter));
+       counter->section = section;
+       counter->name = name;
+       counter->type = type;
+       counter->unit = unit;
+       counter->variance = variance;
+       counter->index = index;
+
+       list = (CounterList *) g_calloc (1, sizeof (CounterList));
+       list->counter = counter;
+
+       if (!counters) {
+               counters = list;
+       } else {
+               l = counters;
+               while (l->next)
+                       l = l->next;
+               l->next = list;
+       }
+
+       if (counters_sort_mode == COUNTERS_SORT_CATEGORY || !verbose)
+               add_counter_to_section (counter);
+}
+
+static void
+add_counter_to_timestamp (uint64_t timestamp, Counter *counter)
+{
+       CounterTimestamp *ctimestamp, *t;
+       CounterSection *csection;
+       CounterList *clist;
+
+       clist = (CounterList *) g_calloc (1, sizeof (CounterList));
+       clist->counter = counter;
+
+       for (ctimestamp = counters_timestamps; ctimestamp; ctimestamp = ctimestamp->next) {
+               if (ctimestamp->value == timestamp) {
+                       for (csection = ctimestamp->sections; csection; csection = csection->next) {
+                               if (strcmp (csection->value, counter->section) == 0) {
+                                       /* if timestamp exist and section exist */
+                                       if (!csection->counters)
+                                               csection->counters = clist;
+                                       else
+                                               csection->counters_last->next = clist;
+                                       csection->counters_last = clist;
+                                       return;
+                               }
+                       }
+
+                       /* if timestamp exist and section does not exist */
+                       csection = (CounterSection *) g_calloc (1, sizeof (CounterSection));
+                       csection->value = counter->section;
+                       csection->counters = clist;
+                       csection->counters_last = clist;
+
+                       if (!ctimestamp->sections)
+                               ctimestamp->sections = csection;
+                       else
+                               ctimestamp->sections_last->next = csection;
+                       ctimestamp->sections_last = csection;
+                       return;
+               }
+       }
+
+       /* If timestamp do not exist and section does not exist */
+       csection = (CounterSection *) g_calloc (1, sizeof (CounterSection));
+       csection->value = counter->section;
+       csection->counters = clist;
+       csection->counters_last = clist;
+
+       ctimestamp = (CounterTimestamp *) g_calloc (1, sizeof (CounterTimestamp));
+       ctimestamp->value = timestamp;
+       ctimestamp->sections = csection;
+       ctimestamp->sections_last = csection;
+
+       if (!counters_timestamps) {
+               counters_timestamps = ctimestamp;
+       } else {
+               t = counters_timestamps;
+               while (t->next)
+                       t = t->next;
+               t->next = ctimestamp;
+       }
+}
+
+static void
+add_counter_value (int index, CounterValue *value)
+{
+       CounterList *list;
+
+       for (list = counters; list; list = list->next) {
+               if (list->counter->index == index) {
+                       if (!list->counter->values)
+                               list->counter->values = value;
+                       else
+                               list->counter->values_last->next = value;
+                       list->counter->values_last = value;
+
+                       if (counters_sort_mode == COUNTERS_SORT_TIME)
+                               add_counter_to_timestamp (value->timestamp, list->counter);
+
+                       return;
+               }
+       }
+}
+
+static const char*
+section_name (int section)
+{
+       switch (section) {
+       case MONO_COUNTER_JIT: return "Mono JIT";
+       case MONO_COUNTER_GC: return "Mono GC";
+       case MONO_COUNTER_METADATA: return "Mono Metadata";
+       case MONO_COUNTER_GENERICS: return "Mono Generics";
+       case MONO_COUNTER_SECURITY: return "Mono Security";
+       case MONO_COUNTER_RUNTIME: return "Mono Runtime";
+       case MONO_COUNTER_SYSTEM: return "Mono System";
+       case MONO_COUNTER_PROFILER: return "Mono Profiler";
+       default: return "<unknown>";
+       }
+}
+
+static const char*
+type_name (int type)
+{
+       switch (type) {
+       case MONO_COUNTER_INT: return "Int";
+       case MONO_COUNTER_UINT: return "UInt";
+       case MONO_COUNTER_WORD: return "Word";
+       case MONO_COUNTER_LONG: return "Long";
+       case MONO_COUNTER_ULONG: return "ULong";
+       case MONO_COUNTER_DOUBLE: return "Double";
+       case MONO_COUNTER_STRING: return "String";
+       case MONO_COUNTER_TIME_INTERVAL: return "Time Interval";
+       default: return "<unknown>";
+       }
+}
+
+static const char*
+unit_name (int unit)
+{
+       switch (unit) {
+       case MONO_COUNTER_RAW: return "Raw";
+       case MONO_COUNTER_BYTES: return "Bytes";
+       case MONO_COUNTER_TIME: return "Time";
+       case MONO_COUNTER_COUNT: return "Count";
+       case MONO_COUNTER_PERCENTAGE: return "Percentage";
+       default: return "<unknown>";
+       }
+}
+
+static const char*
+variance_name (int variance)
+{
+       switch (variance) {
+       case MONO_COUNTER_MONOTONIC: return "Monotonic";
+       case MONO_COUNTER_CONSTANT: return "Constant";
+       case MONO_COUNTER_VARIABLE: return "Variable";
+       default: return "<unknown>";
+       }
+}
+
+static void
+dump_counters_value (Counter *counter, const char *key_format, const char *key, void *value)
+{
+       char format[32];
+
+       if (value == NULL) {
+               snprintf (format, sizeof (format), "%s : %%s\n", key_format);
+               fprintf (outfile, format, key, "<null>");
+       } else {
+               switch (counter->type) {
+               case MONO_COUNTER_INT:
+#if SIZEOF_VOID_P == 4
+               case MONO_COUNTER_WORD:
+#endif
+                       snprintf (format, sizeof (format), "%s : %%d\n", key_format);
+                       fprintf (outfile, format, key, *(int32_t*)value);
+                       break;
+               case MONO_COUNTER_UINT:
+                       snprintf (format, sizeof (format), "%s : %%u\n", key_format);
+                       fprintf (outfile, format, key, *(uint32_t*)value);
+                       break;
+               case MONO_COUNTER_LONG:
+#if SIZEOF_VOID_P == 8
+               case MONO_COUNTER_WORD:
+#endif
+               case MONO_COUNTER_TIME_INTERVAL:
+                       if (counter->type == MONO_COUNTER_LONG && counter->unit == MONO_COUNTER_TIME) {
+                               snprintf (format, sizeof (format), "%s : %%0.3fms\n", key_format);
+                               fprintf (outfile, format, key, (double)*(int64_t*)value / 10000.0);
+                       } else if (counter->type == MONO_COUNTER_TIME_INTERVAL) {
+                               snprintf (format, sizeof (format), "%s : %%0.3fms\n", key_format);
+                               fprintf (outfile, format, key, (double)*(int64_t*)value / 1000.0);
+                       } else {
+                               snprintf (format, sizeof (format), "%s : %%u\n", key_format);
+                               fprintf (outfile, format, key, *(int64_t*)value);
+                       }
+                       break;
+               case MONO_COUNTER_ULONG:
+                       snprintf (format, sizeof (format), "%s : %%llu\n", key_format);
+                       fprintf (outfile, format, key, *(uint64_t*)value);
+                       break;
+               case MONO_COUNTER_DOUBLE:
+                       snprintf (format, sizeof (format), "%s : %%f\n", key_format);
+                       fprintf (outfile, format, key, *(double*)value);
+                       break;
+               case MONO_COUNTER_STRING:
+                       snprintf (format, sizeof (format), "%s : %%s\n", key_format);
+                       fprintf (outfile, format, key, *(char*)value);
+                       break;
+               }
+       }
+}
+
+static void
+dump_counters (void)
+{
+       Counter *counter;
+       CounterValue *cvalue;
+       CounterTimestamp *ctimestamp;
+       CounterSection *csection;
+       CounterList *clist;
+       char strtimestamp[17];
+       int i, section_printed;
+
+       fprintf (outfile, "\nCounters:\n");
+
+       if (!verbose) {
+               char counters_to_print[][64] = {
+                       "Methods from AOT",
+                       "Methods JITted using mono JIT",
+                       "Methods JITted using LLVM",
+                       "Total time spent JITting (sec)",
+                       "User Time",
+                       "System Time",
+                       "Total Time",
+                       "Working Set",
+                       "Private Bytes",
+                       "Virtual Bytes",
+                       "Page Faults",
+                       "CPU Load Average - 1min",
+                       "CPU Load Average - 5min",
+                       "CPU Load Average - 15min",
+                       ""
+               };
+
+               for (csection = counters_sections; csection; csection = csection->next) {
+                       section_printed = 0;
+
+                       for (clist = csection->counters; clist; clist = clist->next) {
+                               counter = clist->counter;
+                               if (!counter->values_last)
+                                       continue;
+
+                               for (i = 0; counters_to_print [i][0] != 0; i++) {
+                                       if (strcmp (counters_to_print [i], counter->name) == 0) {
+                                               if (!section_printed) {
+                                                       fprintf (outfile, "\t%s:\n", csection->value);
+                                                       section_printed = 1;
+                                               }
+
+                                               dump_counters_value (counter, "\t\t%-30s", counter->name, counter->values_last->buffer);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       } else if (counters_sort_mode == COUNTERS_SORT_TIME) {
+               for (ctimestamp = counters_timestamps; ctimestamp; ctimestamp = ctimestamp->next) {
+                       fprintf (outfile, "\t%llu:%02llu:%02llu:%02llu.%03llu:\n",
+                               (unsigned long long) (ctimestamp->value / 1000 / 60 / 60 / 24 % 1000),
+                               (unsigned long long) (ctimestamp->value / 1000 / 60 / 60 % 24),
+                               (unsigned long long) (ctimestamp->value / 1000 / 60 % 60),
+                               (unsigned long long) (ctimestamp->value / 1000 % 60),
+                               (unsigned long long) (ctimestamp->value % 1000));
+
+                       for (csection = ctimestamp->sections; csection; csection = csection->next) {
+                               fprintf (outfile, "\t\t%s:\n", csection->value);
+
+                               for (clist = csection->counters; clist; clist = clist->next) {
+                                       counter = clist->counter;
+                                       for (cvalue = counter->values; cvalue; cvalue = cvalue->next) {
+                                               if (cvalue->timestamp != ctimestamp->value)
+                                                       continue;
+
+                                               dump_counters_value (counter, "\t\t\t%-30s", counter->name, cvalue->buffer);
+                                       }
+                               }
+                       }
+               }
+       } else if (counters_sort_mode == COUNTERS_SORT_CATEGORY) {
+               for (csection = counters_sections; csection; csection = csection->next) {
+                       fprintf (outfile, "\t%s:\n", csection->value);
+
+                       for (clist = csection->counters; clist; clist = clist->next) {
+                               counter = clist->counter;
+                               fprintf (outfile, "\t\t%s: [type: %s, unit: %s, variance: %s]\n",
+                                       counter->name, type_name (counter->type), unit_name (counter->unit), variance_name (counter->variance));
+
+                               for (cvalue = counter->values; cvalue; cvalue = cvalue->next) {
+                                       snprintf (strtimestamp, sizeof (strtimestamp), "%llu:%02llu:%02llu:%02llu.%03llu",
+                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 / 60 / 24 % 1000),
+                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 / 60 % 24),
+                                               (unsigned long long) (cvalue->timestamp / 1000 / 60 % 60),
+                                               (unsigned long long) (cvalue->timestamp / 1000 % 60),
+                                               (unsigned long long) (cvalue->timestamp % 1000));
+
+                                       dump_counters_value (counter, "\t\t\t%s", strtimestamp, cvalue->buffer);
+                               }
+                       }
+               }
+       }
+}
+
+static int num_images;
+typedef struct _ImageDesc ImageDesc;
+struct _ImageDesc {
+       ImageDesc *next;
+       intptr_t image;
+       char *filename;
+};
+
+static ImageDesc* image_hash [SMALL_HASH_SIZE] = {0};
+
+static void
+add_image (intptr_t image, char *name)
+{
+       int slot = ((image >> 2) & 0xffff) % SMALL_HASH_SIZE;
+       ImageDesc *cd = (ImageDesc *) g_malloc (sizeof (ImageDesc));
+       cd->image = image;
+       cd->filename = pstrdup (name);
+       cd->next = image_hash [slot];
+       image_hash [slot] = cd;
+       num_images++;
+}
+
+static int num_assemblies;
+
+typedef struct _AssemblyDesc AssemblyDesc;
+struct _AssemblyDesc {
+       AssemblyDesc *next;
+       intptr_t assembly;
+       char *asmname;
+};
+
+static AssemblyDesc* assembly_hash [SMALL_HASH_SIZE] = {0};
+
+static void
+add_assembly (intptr_t assembly, char *name)
+{
+       int slot = ((assembly >> 2) & 0xffff) % SMALL_HASH_SIZE;
+       AssemblyDesc *cd = (AssemblyDesc *) g_malloc (sizeof (AssemblyDesc));
+       cd->assembly = assembly;
+       cd->asmname = pstrdup (name);
+       cd->next = assembly_hash [slot];
+       assembly_hash [slot] = cd;
+       num_assemblies++;
+}
+
+typedef struct _BackTrace BackTrace;
+typedef struct {
+       uint64_t count;
+       BackTrace *bt;
+} CallContext;
+
+typedef struct {
+       int count;
+       int size;
+       CallContext *traces;
+} TraceDesc;
+
+typedef struct _ClassDesc ClassDesc;
+struct _ClassDesc {
+       ClassDesc *next;
+       intptr_t klass;
+       char *name;
+       intptr_t allocs;
+       uint64_t alloc_size;
+       TraceDesc traces;
+};
+
+static ClassDesc* class_hash [HASH_SIZE] = {0};
+static int num_classes = 0;
+
+static ClassDesc*
+add_class (intptr_t klass, const char *name)
+{
+       int slot = ((klass >> 2) & 0xffff) % HASH_SIZE;
+       ClassDesc *cd;
+       cd = class_hash [slot];
+       while (cd && cd->klass != klass)
+               cd = cd->next;
+       /* we resolved an unknown class (unless we had the code unloaded) */
+       if (cd) {
+               /*printf ("resolved unknown: %s\n", name);*/
+               g_free (cd->name);
+               cd->name = pstrdup (name);
+               return cd;
+       }
+       cd = (ClassDesc *) g_calloc (sizeof (ClassDesc), 1);
+       cd->klass = klass;
+       cd->name = pstrdup (name);
+       cd->next = class_hash [slot];
+       cd->allocs = 0;
+       cd->alloc_size = 0;
+       cd->traces.count = 0;
+       cd->traces.size = 0;
+       cd->traces.traces = NULL;
+       class_hash [slot] = cd;
+       num_classes++;
+       return cd;
+}
+
+static ClassDesc *
+lookup_class (intptr_t klass)
+{
+       int slot = ((klass >> 2) & 0xffff) % HASH_SIZE;
+       ClassDesc *cd = class_hash [slot];
+       while (cd && cd->klass != klass)
+               cd = cd->next;
+       if (!cd) {
+               char buf [128];
+               snprintf (buf, sizeof (buf), "unresolved class %p", (void*)klass);
+               return add_class (klass, buf);
+       }
+       return cd;
+}
+
+typedef struct _MethodDesc MethodDesc;
+struct _MethodDesc {
+       MethodDesc *next;
+       intptr_t method;
+       char *name;
+       intptr_t code;
+       int len;
+       int recurse_count;
+       int sample_hits;
+       int ignore_jit; /* when this is set, we collect the metadata but don't count this method fot jit time and code size, when filtering events */
+       uint64_t calls;
+       uint64_t total_time;
+       uint64_t callee_time;
+       uint64_t self_time;
+       TraceDesc traces;
+};
+
+static MethodDesc* method_hash [HASH_SIZE] = {0};
+static int num_methods = 0;
+
+static MethodDesc*
+add_method (intptr_t method, const char *name, intptr_t code, int len)
+{
+       int slot = ((method >> 2) & 0xffff) % HASH_SIZE;
+       MethodDesc *cd;
+       cd = method_hash [slot];
+       while (cd && cd->method != method)
+               cd = cd->next;
+       /* we resolved an unknown method (unless we had the code unloaded) */
+       if (cd) {
+               cd->code = code;
+               cd->len = len;
+               /*printf ("resolved unknown: %s\n", name);*/
+               g_free (cd->name);
+               cd->name = pstrdup (name);
+               return cd;
+       }
+       cd = (MethodDesc *) g_calloc (sizeof (MethodDesc), 1);
+       cd->method = method;
+       cd->name = pstrdup (name);
+       cd->code = code;
+       cd->len = len;
+       cd->calls = 0;
+       cd->total_time = 0;
+       cd->traces.count = 0;
+       cd->traces.size = 0;
+       cd->traces.traces = NULL;
+       cd->next = method_hash [slot];
+       method_hash [slot] = cd;
+       num_methods++;
+       return cd;
+}
+
+static MethodDesc *
+lookup_method (intptr_t method)
+{
+       int slot = ((method >> 2) & 0xffff) % HASH_SIZE;
+       MethodDesc *cd = method_hash [slot];
+       while (cd && cd->method != method)
+               cd = cd->next;
+       if (!cd) {
+               char buf [128];
+               snprintf (buf, sizeof (buf), "unknown method %p", (void*)method);
+               return add_method (method, buf, 0, 0);
+       }
+       return cd;
+}
+
+static int num_stat_samples = 0;
+static int size_stat_samples = 0;
+uintptr_t *stat_samples = NULL;
+int *stat_sample_desc = NULL;
+
+static void
+add_stat_sample (int type, uintptr_t ip) {
+       if (num_stat_samples == size_stat_samples) {
+               size_stat_samples *= 2;
+               if (!size_stat_samples)
+               size_stat_samples = 32;
+               stat_samples = (uintptr_t *) g_realloc (stat_samples, size_stat_samples * sizeof (uintptr_t));
+               stat_sample_desc = (int *) g_realloc (stat_sample_desc, size_stat_samples * sizeof (int));
+       }
+       stat_samples [num_stat_samples] = ip;
+       stat_sample_desc [num_stat_samples++] = type;
+}
+
+static MethodDesc*
+lookup_method_by_ip (uintptr_t ip)
+{
+       int i;
+       MethodDesc* m;
+       /* dumb */
+       for (i = 0; i < HASH_SIZE; ++i) {
+               m = method_hash [i];
+               while (m) {
+                       //printf ("checking %p against %p-%p\n", (void*)ip, (void*)(m->code), (void*)(m->code + m->len));
+                       if (ip >= (uintptr_t)m->code && ip < (uintptr_t)m->code + m->len) {
+                               return m;
+                       }
+                       m = m->next;
+               }
+       }
+       return NULL;
+}
+
+static int
+compare_method_samples (const void *a, const void *b)
+{
+       MethodDesc *const *A = (MethodDesc *const *)a;
+       MethodDesc *const *B = (MethodDesc *const *)b;
+       if ((*A)->sample_hits == (*B)->sample_hits)
+               return 0;
+       if ((*B)->sample_hits < (*A)->sample_hits)
+               return -1;
+       return 1;
+}
+
+typedef struct _UnmanagedSymbol UnmanagedSymbol;
+struct _UnmanagedSymbol {
+       UnmanagedSymbol *parent;
+       char *name;
+       int is_binary;
+       uintptr_t addr;
+       uintptr_t size;
+       uintptr_t sample_hits;
+};
+
+static UnmanagedSymbol **usymbols = NULL;
+static int usymbols_size = 0;
+static int usymbols_num = 0;
+
+static int
+compare_usymbol_addr (const void *a, const void *b)
+{
+       UnmanagedSymbol *const *A = (UnmanagedSymbol *const *)a;
+       UnmanagedSymbol *const *B = (UnmanagedSymbol *const *)b;
+       if ((*B)->addr == (*A)->addr)
+               return 0;
+       if ((*B)->addr > (*A)->addr)
+               return -1;
+       return 1;
+}
+
+static int
+compare_usymbol_samples (const void *a, const void *b)
+{
+       UnmanagedSymbol *const *A = (UnmanagedSymbol *const *)a;
+       UnmanagedSymbol *const *B = (UnmanagedSymbol *const *)b;
+       if ((*B)->sample_hits == (*A)->sample_hits)
+               return 0;
+       if ((*B)->sample_hits < (*A)->sample_hits)
+               return -1;
+       return 1;
+}
+
+static void
+add_unmanaged_symbol (uintptr_t addr, char *name, uintptr_t size)
+{
+       UnmanagedSymbol *sym;
+       if (usymbols_num == usymbols_size) {
+               int new_size = usymbols_size * 2;
+               if (!new_size)
+                       new_size = 16;
+               usymbols = (UnmanagedSymbol **) g_realloc (usymbols, sizeof (void*) * new_size);
+               usymbols_size = new_size;
+       }
+       sym = (UnmanagedSymbol *) g_calloc (sizeof (UnmanagedSymbol), 1);
+       sym->addr = addr;
+       sym->name = name;
+       sym->size = size;
+       usymbols [usymbols_num++] = sym;
+}
+
+/* only valid after the symbols are sorted */
+static UnmanagedSymbol*
+lookup_unmanaged_symbol (uintptr_t addr)
+{
+       int r = usymbols_num - 1;
+       int l = 0;
+       UnmanagedSymbol *sym;
+       int last_best = -1;
+       while (r >= l) {
+               int m = (l + r) / 2;
+               sym = usymbols [m];
+               if (addr == sym->addr)
+                       return sym;
+               if (addr < sym->addr) {
+                       r = m - 1;
+               } else if (addr > sym->addr) {
+                       l = m + 1;
+                       last_best = m;
+               }
+       }
+       if (last_best >= 0 && (addr - usymbols [last_best]->addr) < 4096)
+               return usymbols [last_best];
+       return NULL;
+}
+
+/* we use the same structure for binaries */
+static UnmanagedSymbol **ubinaries = NULL;
+static int ubinaries_size = 0;
+static int ubinaries_num = 0;
+
+static void
+add_unmanaged_binary (uintptr_t addr, char *name, uintptr_t size)
+{
+       UnmanagedSymbol *sym;
+       if (ubinaries_num == ubinaries_size) {
+               int new_size = ubinaries_size * 2;
+               if (!new_size)
+                       new_size = 16;
+               ubinaries = (UnmanagedSymbol **) g_realloc (ubinaries, sizeof (void*) * new_size);
+               ubinaries_size = new_size;
+       }
+       sym = (UnmanagedSymbol *) g_calloc (sizeof (UnmanagedSymbol), 1);
+       sym->addr = addr;
+       sym->name = name;
+       sym->size = size;
+       sym->is_binary = 1;
+       ubinaries [ubinaries_num++] = sym;
+}
+
+static UnmanagedSymbol*
+lookup_unmanaged_binary (uintptr_t addr)
+{
+       int i;
+       for (i = 0; i < ubinaries_num; ++i) {
+               UnmanagedSymbol *ubin = ubinaries [i];
+               if (addr >= ubin->addr && addr < ubin->addr + ubin->size) {
+                       return ubin;
+               }
+       }
+       return NULL;
+}
+
+static const char*
+sample_type_name (int type)
+{
+       switch (type) {
+       case SAMPLE_CYCLES: return "cycles";
+       case SAMPLE_INSTRUCTIONS: return "instructions retired";
+       case SAMPLE_CACHE_MISSES: return "cache misses";
+       case SAMPLE_CACHE_REFS: return "cache references";
+       case SAMPLE_BRANCHES: return "executed branches";
+       case SAMPLE_BRANCH_MISSES: return "unpredicted branches";
+       }
+       return "unknown";
+}
+
+static void
+set_usym_parent (UnmanagedSymbol** cachedus, int count)
+{
+       int i;
+       for (i = 0; i < count; ++i) {
+               UnmanagedSymbol *ubin = lookup_unmanaged_binary (cachedus [i]->addr);
+               if (ubin == cachedus [i])
+                       continue;
+               cachedus [i]->parent = ubin;
+       }
+}
+
+static void
+print_usym (UnmanagedSymbol* um)
+{
+       if (um->parent)
+               fprintf (outfile, "\t%6zd %6.2f %-36s in %s\n", um->sample_hits, um->sample_hits*100.0/num_stat_samples, um->name, um->parent->name);
+       else
+               fprintf (outfile, "\t%6zd %6.2f %s\n", um->sample_hits, um->sample_hits*100.0/num_stat_samples, um->name);
+}
+
+static int
+sym_percent (uintptr_t sample_hits)
+{
+       double pc;
+       if (verbose)
+               return 1;
+       pc = sample_hits*100.0/num_stat_samples;
+       return pc >= 0.1;
+}
+
+static void
+dump_samples (void)
+{
+       int i, u;
+       int count = 0, msize = 0;
+       int unmanaged_hits = 0;
+       int unresolved_hits = 0;
+       MethodDesc** cachedm = NULL;
+       int ucount = 0, usize = 0;
+       UnmanagedSymbol** cachedus = NULL;
+       if (!num_stat_samples)
+               return;
+       qsort (usymbols, usymbols_num, sizeof (UnmanagedSymbol*), compare_usymbol_addr);
+       for (i = 0; i < num_stat_samples; ++i) {
+               MethodDesc *m = lookup_method_by_ip (stat_samples [i]);
+               if (m) {
+                       if (!m->sample_hits) {
+                               if (count == msize) {
+                                       msize *= 2;
+                                       if (!msize)
+                                               msize = 4;
+                                       cachedm = (MethodDesc **) g_realloc (cachedm, sizeof (void*) * msize);
+                               }
+                               cachedm [count++] = m;
+                       }
+                       m->sample_hits++;
+               } else {
+                       UnmanagedSymbol *usym = lookup_unmanaged_symbol (stat_samples [i]);
+                       if (!usym) {
+                               unresolved_hits++;
+                               //printf ("unmanaged hit at %p\n", (void*)stat_samples [i]);
+                               usym = lookup_unmanaged_binary (stat_samples [i]);
+                       }
+                       if (usym) {
+                               if (!usym->sample_hits) {
+                                       if (ucount == usize) {
+                                               usize *= 2;
+                                               if (!usize)
+                                                       usize = 4;
+                                               cachedus = (UnmanagedSymbol **) g_realloc (cachedus, sizeof (void*) * usize);
+                                       }
+                                       cachedus [ucount++] = usym;
+                               }
+                               usym->sample_hits++;
+                       }
+                       unmanaged_hits++;
+               }
+       }
+       qsort (cachedm, count, sizeof (MethodDesc*), compare_method_samples);
+       qsort (cachedus, ucount, sizeof (UnmanagedSymbol*), compare_usymbol_samples);
+       set_usym_parent (cachedus, ucount);
+       fprintf (outfile, "\nStatistical samples summary\n");
+       fprintf (outfile, "\tSample type: %s\n", sample_type_name (stat_sample_desc [0]));
+       fprintf (outfile, "\tUnmanaged hits:  %6d (%4.1f%%)\n", unmanaged_hits, (100.0*unmanaged_hits)/num_stat_samples);
+       fprintf (outfile, "\tManaged hits:    %6d (%4.1f%%)\n", num_stat_samples - unmanaged_hits, (100.0*(num_stat_samples-unmanaged_hits))/num_stat_samples);
+       fprintf (outfile, "\tUnresolved hits: %6d (%4.1f%%)\n", unresolved_hits, (100.0*unresolved_hits)/num_stat_samples);
+       fprintf (outfile, "\t%6s %6s %s\n", "Hits", "%", "Method name");
+       i = 0;
+       u = 0;
+       while (i < count || u < ucount) {
+               if (i < count) {
+                       MethodDesc *m = cachedm [i];
+                       if (u < ucount) {
+                               UnmanagedSymbol *um = cachedus [u];
+                               if (um->sample_hits > m->sample_hits) {
+                                       if (!sym_percent (um->sample_hits))
+                                               break;
+                                       print_usym (um);
+                                       u++;
+                                       continue;
+                               }
+                       }
+                       if (!sym_percent (m->sample_hits))
+                               break;
+                       fprintf (outfile, "\t%6d %6.2f %s\n", m->sample_hits, m->sample_hits*100.0/num_stat_samples, m->name);
+                       i++;
+                       continue;
+               }
+               if (u < ucount) {
+                       UnmanagedSymbol *um = cachedus [u];
+                       if (!sym_percent (um->sample_hits))
+                               break;
+                       print_usym (um);
+                       u++;
+                       continue;
+               }
+       }
+}
+
+typedef struct _HeapClassDesc HeapClassDesc;
+typedef struct {
+       HeapClassDesc *klass;
+       uint64_t count;
+} HeapClassRevRef;
+
+struct _HeapClassDesc {
+       ClassDesc *klass;
+       int64_t count;
+       int64_t total_size;
+       HeapClassRevRef *rev_hash;
+       int rev_hash_size;
+       int rev_count;
+       uintptr_t pinned_references;
+       uintptr_t root_references;
+};
+
+static int
+add_rev_class_hashed (HeapClassRevRef *rev_hash, uintptr_t size, HeapClassDesc *hklass, uint64_t value)
+{
+       uintptr_t i;
+       uintptr_t start_pos;
+       start_pos = (hklass->klass->klass >> 2) % size;
+       assert (start_pos < size);
+       i = start_pos;
+       do {
+               if (rev_hash [i].klass == hklass) {
+                       rev_hash [i].count += value;
+                       return 0;
+               } else if (!rev_hash [i].klass) {
+                       rev_hash [i].klass = hklass;
+                       rev_hash [i].count += value;
+                       start_pos = 0;
+                       for (i = 0; i < size; ++i)
+                               if (rev_hash [i].klass && rev_hash [i].klass->klass == hklass->klass)
+                                       start_pos ++;
+                       assert (start_pos == 1);
+                       return 1;
+               }
+               /* wrap around */
+               if (++i == size)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       printf ("failed revref store\n");
+       return 0;
+}
+
+static void
+add_heap_class_rev (HeapClassDesc *from, HeapClassDesc *to)
+{
+       uintptr_t i;
+       if (to->rev_count * 2 >= to->rev_hash_size) {
+               HeapClassRevRef *n;
+               uintptr_t old_size = to->rev_hash_size;
+               to->rev_hash_size *= 2;
+               if (to->rev_hash_size == 0)
+                       to->rev_hash_size = 4;
+               n = (HeapClassRevRef *) g_calloc (sizeof (HeapClassRevRef) * to->rev_hash_size, 1);
+               for (i = 0; i < old_size; ++i) {
+                       if (to->rev_hash [i].klass)
+                               add_rev_class_hashed (n, to->rev_hash_size, to->rev_hash [i].klass, to->rev_hash [i].count);
+               }
+               if (to->rev_hash)
+                       g_free (to->rev_hash);
+               to->rev_hash = n;
+       }
+       to->rev_count += add_rev_class_hashed (to->rev_hash, to->rev_hash_size, from, 1);
+}
+
+typedef struct {
+       uintptr_t objaddr;
+       HeapClassDesc *hklass;
+       uintptr_t num_refs;
+       uintptr_t refs [0];
+} HeapObjectDesc;
+
+typedef struct _HeapShot HeapShot;
+struct _HeapShot {
+       HeapShot *next;
+       uint64_t timestamp;
+       int class_count;
+       int hash_size;
+       HeapClassDesc **class_hash;
+       HeapClassDesc **sorted;
+       HeapObjectDesc **objects_hash;
+       uintptr_t objects_count;
+       uintptr_t objects_hash_size;
+       uintptr_t num_roots;
+       uintptr_t *roots;
+       uintptr_t *roots_extra;
+       int *roots_types;
+};
+
+static HeapShot *heap_shots = NULL;
+static int num_heap_shots = 0;
+
+static HeapShot*
+new_heap_shot (uint64_t timestamp)
+{
+       HeapShot *hs = (HeapShot *) g_calloc (sizeof (HeapShot), 1);
+       hs->hash_size = 4;
+       hs->class_hash = (HeapClassDesc **) g_calloc (sizeof (void*), hs->hash_size);
+       hs->timestamp = timestamp;
+       num_heap_shots++;
+       hs->next = heap_shots;
+       heap_shots = hs;
+       return hs;
+}
+
+static HeapClassDesc*
+heap_class_lookup (HeapShot *hs, ClassDesc *klass)
+{
+       int i;
+       unsigned int start_pos;
+       start_pos = ((uintptr_t)klass->klass >> 2) % hs->hash_size;
+       i = start_pos;
+       do {
+               HeapClassDesc* cd = hs->class_hash [i];
+               if (!cd)
+                       return NULL;
+               if (cd->klass == klass)
+                       return cd;
+               /* wrap around */
+               if (++i == hs->hash_size)
+                       i = 0;
+       } while (i != start_pos);
+       return NULL;
+}
+
+static int
+add_heap_hashed (HeapClassDesc **hash, HeapClassDesc **retv, uintptr_t hsize, ClassDesc *klass, uint64_t size, uint64_t count)
+{
+       uintptr_t i;
+       uintptr_t start_pos;
+       start_pos = ((uintptr_t)klass->klass >> 2) % hsize;
+       i = start_pos;
+       do {
+               if (hash [i] && hash [i]->klass == klass) {
+                       hash [i]->total_size += size;
+                       hash [i]->count += count;
+                       *retv = hash [i];
+                       return 0;
+               } else if (!hash [i]) {
+                       if (*retv) {
+                               hash [i] = *retv;
+                               return 1;
+                       }
+                       hash [i] = (HeapClassDesc *) g_calloc (sizeof (HeapClassDesc), 1);
+                       hash [i]->klass = klass;
+                       hash [i]->total_size += size;
+                       hash [i]->count += count;
+                       *retv = hash [i];
+                       return 1;
+               }
+               /* wrap around */
+               if (++i == hsize)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       printf ("failed heap class store\n");
+       return 0;
+}
+
+static HeapClassDesc*
+add_heap_shot_class (HeapShot *hs, ClassDesc *klass, uint64_t size)
+{
+       HeapClassDesc *res;
+       int i;
+       if (hs->class_count * 2 >= hs->hash_size) {
+               HeapClassDesc **n;
+               int old_size = hs->hash_size;
+               hs->hash_size *= 2;
+               if (hs->hash_size == 0)
+                       hs->hash_size = 4;
+               n = (HeapClassDesc **) g_calloc (sizeof (void*) * hs->hash_size, 1);
+               for (i = 0; i < old_size; ++i) {
+                       res = hs->class_hash [i];
+                       if (hs->class_hash [i])
+                               add_heap_hashed (n, &res, hs->hash_size, hs->class_hash [i]->klass, hs->class_hash [i]->total_size, hs->class_hash [i]->count);
+               }
+               if (hs->class_hash)
+                       g_free (hs->class_hash);
+               hs->class_hash = n;
+       }
+       res = NULL;
+       hs->class_count += add_heap_hashed (hs->class_hash, &res, hs->hash_size, klass, size, 1);
+       //if (res->count == 1)
+       //      printf ("added heap class: %s\n", res->klass->name);
+       return res;
+}
+
+static HeapObjectDesc*
+alloc_heap_obj (uintptr_t objaddr, HeapClassDesc *hklass, uintptr_t num_refs)
+{
+       HeapObjectDesc* ho = (HeapObjectDesc *) g_calloc (sizeof (HeapObjectDesc) + num_refs * sizeof (uintptr_t), 1);
+       ho->objaddr = objaddr;
+       ho->hklass = hklass;
+       ho->num_refs = num_refs;
+       return ho;
+}
+
+static uintptr_t
+heap_shot_find_obj_slot (HeapShot *hs, uintptr_t objaddr)
+{
+       uintptr_t i;
+       uintptr_t start_pos;
+       HeapObjectDesc **hash = hs->objects_hash;
+       start_pos = ((uintptr_t)objaddr >> 3) % hs->objects_hash_size;
+       i = start_pos;
+       do {
+               if (hash [i] && hash [i]->objaddr == objaddr) {
+                       return i;
+               } else if (!hash [i]) {
+                       break; /* fail */
+               }
+               /* wrap around */
+               if (++i == hs->objects_hash_size)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       //printf ("failed heap obj slot\n");
+       return -1;
+}
+
+static HeapObjectDesc*
+heap_shot_obj_add_refs (HeapShot *hs, uintptr_t objaddr, uintptr_t num, uintptr_t *ref_offset)
+{
+       HeapObjectDesc **hash = hs->objects_hash;
+       uintptr_t i = heap_shot_find_obj_slot (hs, objaddr);
+       if (i >= 0) {
+               HeapObjectDesc* ho = alloc_heap_obj (objaddr, hash [i]->hklass, hash [i]->num_refs + num);
+               *ref_offset = hash [i]->num_refs;
+               memcpy (ho->refs, hash [i]->refs, hash [i]->num_refs * sizeof (uintptr_t));
+               g_free (hash [i]);
+               hash [i] = ho;
+               return ho;
+       }
+       /* should not happen */
+       printf ("failed heap obj update\n");
+       return NULL;
+
+}
+
+static uintptr_t
+add_heap_hashed_obj (HeapObjectDesc **hash, uintptr_t hsize, HeapObjectDesc *obj)
+{
+       uintptr_t i;
+       uintptr_t start_pos;
+       start_pos = ((uintptr_t)obj->objaddr >> 3) % hsize;
+       i = start_pos;
+       do {
+               if (hash [i] && hash [i]->objaddr == obj->objaddr) {
+                       printf ("duplicate object!\n");
+                       return 0;
+               } else if (!hash [i]) {
+                       hash [i] = obj;
+                       return 1;
+               }
+               /* wrap around */
+               if (++i == hsize)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       printf ("failed heap obj store\n");
+       return 0;
+}
+
+static void
+add_heap_shot_obj (HeapShot *hs, HeapObjectDesc *obj)
+{
+       uintptr_t i;
+       if (hs->objects_count * 2 >= hs->objects_hash_size) {
+               HeapObjectDesc **n;
+               uintptr_t old_size = hs->objects_hash_size;
+               hs->objects_hash_size *= 2;
+               if (hs->objects_hash_size == 0)
+                       hs->objects_hash_size = 4;
+               n = (HeapObjectDesc **) g_calloc (sizeof (void*) * hs->objects_hash_size, 1);
+               for (i = 0; i < old_size; ++i) {
+                       if (hs->objects_hash [i])
+                               add_heap_hashed_obj (n, hs->objects_hash_size, hs->objects_hash [i]);
+               }
+               if (hs->objects_hash)
+                       g_free (hs->objects_hash);
+               hs->objects_hash = n;
+       }
+       hs->objects_count += add_heap_hashed_obj (hs->objects_hash, hs->objects_hash_size, obj);
+}
+
+static void
+heap_shot_resolve_reverse_refs (HeapShot *hs)
+{
+       uintptr_t i;
+       for (i = 0; i < hs->objects_hash_size; ++i) {
+               uintptr_t r;
+               HeapObjectDesc *ho = hs->objects_hash [i];
+               if (!ho)
+                       continue;
+               for (r = 0; r < ho->num_refs; ++r) {
+                       uintptr_t oi = heap_shot_find_obj_slot (hs, ho->refs [r]);
+                       add_heap_class_rev (ho->hklass, hs->objects_hash [oi]->hklass);
+               }
+       }
+}
+
+#define MARK_GRAY 1
+#define MARK_BLACK 2
+
+static void
+heap_shot_mark_objects (HeapShot *hs)
+{
+       uintptr_t i, oi, r;
+       unsigned char *marks;
+       HeapObjectDesc *obj, *ref;
+       int marked_some;
+       uintptr_t num_marked = 0, num_unmarked;
+       for (i = 0; i < hs->num_roots; ++i) {
+               HeapClassDesc *cd;
+               oi = heap_shot_find_obj_slot (hs, hs->roots [i]);
+               if (oi == -1) {
+                       continue;
+               }
+               obj = hs->objects_hash [oi];
+               cd = obj->hklass;
+               if (hs->roots_types [i] & MONO_PROFILE_GC_ROOT_PINNING)
+                       cd->pinned_references++;
+               cd->root_references++;
+       }
+       if (!debug)
+               return;
+       /* consistency checks: it seems not all the objects are walked in the heap in some cases */
+       marks = (unsigned char *) g_calloc (hs->objects_hash_size, 1);
+       if (!marks)
+               return;
+       for (i = 0; i < hs->num_roots; ++i) {
+               oi = heap_shot_find_obj_slot (hs, hs->roots [i]);
+               if (oi == -1) {
+                       fprintf (outfile, "root type 0x%x for obj %p (%s) not found in heap\n", hs->roots_types [i], (void*)hs->roots [i], lookup_class (hs->roots_extra [i])->name);
+                       continue;
+               }
+               obj = hs->objects_hash [oi];
+               if (!marks [oi]) {
+                       marks [oi] = obj->num_refs? MARK_GRAY: MARK_BLACK;
+                       num_marked++;
+               }
+       }
+       marked_some = 1;
+       while (marked_some) {
+               marked_some = 0;
+               for (i = 0; i < hs->objects_hash_size; ++i) {
+                       if (marks [i] != MARK_GRAY)
+                               continue;
+                       marks [i] = MARK_BLACK;
+                       obj = hs->objects_hash [i];
+                       for (r = 0; r < obj->num_refs; ++r) {
+                               oi = heap_shot_find_obj_slot (hs, obj->refs [r]);
+                               if (oi == -1) {
+                                       fprintf (outfile, "referenced obj %p not found in heap\n", (void*)obj->refs [r]);
+                                       continue;
+                               }
+                               ref = hs->objects_hash [oi];
+                               if (!marks [oi]) {
+                                       marks [oi] = ref->num_refs? MARK_GRAY: MARK_BLACK;
+                               }
+                       }
+                       marked_some++;
+               }
+       }
+
+       num_unmarked = 0;
+       for (i = 0; i < hs->objects_hash_size; ++i) {
+               if (hs->objects_hash [i] && !marks [i]) {
+                       num_unmarked++;
+                       fprintf (outfile, "object %p (%s) unmarked\n", (void*)hs->objects_hash [i], hs->objects_hash [i]->hklass->klass->name);
+               }
+       }
+       fprintf (outfile, "Total unmarked: %zd/%zd\n", num_unmarked, hs->objects_count);
+       g_free (marks);
+}
+
+static void
+heap_shot_free_objects (HeapShot *hs)
+{
+       uintptr_t i;
+       for (i = 0; i < hs->objects_hash_size; ++i) {
+               HeapObjectDesc *ho = hs->objects_hash [i];
+               if (ho)
+                       g_free (ho);
+       }
+       if (hs->objects_hash)
+               g_free (hs->objects_hash);
+       hs->objects_hash = NULL;
+       hs->objects_hash_size = 0;
+       hs->objects_count = 0;
+}
+
+
+struct _BackTrace {
+       BackTrace *next;
+       unsigned int hash;
+       int count;
+       int id;
+       MethodDesc *methods [1];
+};
+
+static BackTrace *backtrace_hash [HASH_SIZE];
+static BackTrace **backtraces = NULL;
+static int num_backtraces = 0;
+static int next_backtrace = 0;
+
+static int
+hash_backtrace (int count, MethodDesc **methods)
+{
+       int hash = count;
+       int i;
+       for (i = 0; i < count; ++i) {
+               hash = (hash << 5) - hash + methods [i]->method;
+       }
+       return hash;
+}
+
+static int
+compare_backtrace (BackTrace *bt, int count, MethodDesc **methods)
+{
+       int i;
+       if (bt->count != count)
+               return 0;
+       for (i = 0; i < count; ++i)
+               if (methods [i] != bt->methods [i])
+                       return 0;
+       return 1;
+}
+
+static BackTrace*
+add_backtrace (int count, MethodDesc **methods)
+{
+       int hash = hash_backtrace (count, methods);
+       int slot = (hash & 0xffff) % HASH_SIZE;
+       BackTrace *bt = backtrace_hash [slot];
+       while (bt) {
+               if (bt->hash == hash && compare_backtrace (bt, count, methods))
+                       return bt;
+               bt = bt->next;
+       }
+       bt = (BackTrace *) g_malloc (sizeof (BackTrace) + ((count - 1) * sizeof (void*)));
+       bt->next = backtrace_hash [slot];
+       backtrace_hash [slot] = bt;
+       if (next_backtrace == num_backtraces) {
+               num_backtraces *= 2;
+               if (!num_backtraces)
+                       num_backtraces = 16;
+               backtraces = (BackTrace **) g_realloc (backtraces, sizeof (void*) * num_backtraces);
+       }
+       bt->id = next_backtrace++;
+       backtraces [bt->id] = bt;
+       bt->count = count;
+       bt->hash = hash;
+       for (slot = 0; slot < count; ++slot)
+               bt->methods [slot] = methods [slot];
+
+       return bt;
+}
+
+typedef struct _MonitorDesc MonitorDesc;
+typedef struct _ThreadContext ThreadContext;
+typedef struct _DomainContext DomainContext;
+typedef struct _RemCtxContext RemCtxContext;
+
+typedef struct {
+       FILE *file;
+#if defined (HAVE_SYS_ZLIB)
+       gzFile gzfile;
+#endif
+       unsigned char *buf;
+       int size;
+       int data_version;
+       int version_major;
+       int version_minor;
+       int timer_overhead;
+       int pid;
+       int port;
+       char *args;
+       char *arch;
+       char *os;
+       uint64_t startup_time;
+       ThreadContext *threads;
+       ThreadContext *current_thread;
+       DomainContext *domains;
+       DomainContext *current_domain;
+       RemCtxContext *remctxs;
+       RemCtxContext *current_remctx;
+} ProfContext;
+
+struct _ThreadContext {
+       ThreadContext *next;
+       intptr_t thread_id;
+       char *name;
+       /* emulated stack */
+       MethodDesc **stack;
+       uint64_t *time_stack;
+       uint64_t *callee_time_stack;
+       uint64_t last_time;
+       uint64_t contention_start;
+       MonitorDesc *monitor;
+       int stack_size;
+       int stack_id;
+       HeapShot *current_heap_shot;
+       uintptr_t num_roots;
+       uintptr_t size_roots;
+       uintptr_t *roots;
+       uintptr_t *roots_extra;
+       int *roots_types;
+       uint64_t gc_start_times [3];
+};
+
+struct _DomainContext {
+       DomainContext *next;
+       intptr_t domain_id;
+       const char *friendly_name;
+};
+
+struct _RemCtxContext {
+       RemCtxContext *next;
+       intptr_t remctx_id;
+       intptr_t domain_id;
+};
+
+static void
+ensure_buffer (ProfContext *ctx, int size)
+{
+       if (ctx->size < size) {
+               ctx->buf = (unsigned char *) g_realloc (ctx->buf, size);
+               ctx->size = size;
+       }
+}
+
+static int
+load_data (ProfContext *ctx, int size)
+{
+       ensure_buffer (ctx, size);
+#if defined (HAVE_SYS_ZLIB)
+       if (ctx->gzfile) {
+               int r = gzread (ctx->gzfile, ctx->buf, size);
+               if (r == 0)
+                       return size == 0? 1: 0;
+               return r == size;
+       } else
+#endif
+       {
+               int r = fread (ctx->buf, size, 1, ctx->file);
+               if (r == 0)
+                       return size == 0? 1: 0;
+               return r;
+       }
+}
+
+static ThreadContext*
+get_thread (ProfContext *ctx, intptr_t thread_id)
+{
+       ThreadContext *thread;
+       if (ctx->current_thread && ctx->current_thread->thread_id == thread_id)
+               return ctx->current_thread;
+       thread = ctx->threads;
+       while (thread) {
+               if (thread->thread_id == thread_id) {
+                       return thread;
+               }
+               thread = thread->next;
+       }
+       thread = (ThreadContext *) g_calloc (sizeof (ThreadContext), 1);
+       thread->next = ctx->threads;
+       ctx->threads = thread;
+       thread->thread_id = thread_id;
+       thread->last_time = 0;
+       thread->stack_id = 0;
+       thread->stack_size = 32;
+       thread->stack = (MethodDesc **) g_malloc (thread->stack_size * sizeof (void*));
+       thread->time_stack = (uint64_t *) g_malloc (thread->stack_size * sizeof (uint64_t));
+       thread->callee_time_stack = (uint64_t *) g_malloc (thread->stack_size * sizeof (uint64_t));
+       return thread;
+}
+
+static DomainContext *
+get_domain (ProfContext *ctx, intptr_t domain_id)
+{
+       if (ctx->current_domain && ctx->current_domain->domain_id == domain_id)
+               return ctx->current_domain;
+
+       DomainContext *domain = ctx->domains;
+
+       while (domain) {
+               if (domain->domain_id == domain_id)
+                       return domain;
+
+               domain = domain->next;
+       }
+
+       domain = (DomainContext *) g_calloc (sizeof (DomainContext), 1);
+       domain->next = ctx->domains;
+       ctx->domains = domain;
+       domain->domain_id = domain_id;
+
+       return domain;
+}
+
+static RemCtxContext *
+get_remctx (ProfContext *ctx, intptr_t remctx_id)
+{
+       if (ctx->current_remctx && ctx->current_remctx->remctx_id == remctx_id)
+               return ctx->current_remctx;
+
+       RemCtxContext *remctx = ctx->remctxs;
+
+       while (remctx) {
+               if (remctx->remctx_id == remctx_id)
+                       return remctx;
+
+               remctx = remctx->next;
+       }
+
+       remctx = (RemCtxContext *) g_calloc (sizeof (RemCtxContext), 1);
+       remctx->next = ctx->remctxs;
+       ctx->remctxs = remctx;
+       remctx->remctx_id = remctx_id;
+
+       return remctx;
+}
+
+static ThreadContext*
+load_thread (ProfContext *ctx, intptr_t thread_id)
+{
+       ThreadContext *thread = get_thread (ctx, thread_id);
+       ctx->current_thread = thread;
+       return thread;
+}
+
+static void
+ensure_thread_stack (ThreadContext *thread)
+{
+       if (thread->stack_id == thread->stack_size) {
+               thread->stack_size *= 2;
+               thread->stack = (MethodDesc **) g_realloc (thread->stack, thread->stack_size * sizeof (void*));
+               thread->time_stack = (uint64_t *) g_realloc (thread->time_stack, thread->stack_size * sizeof (uint64_t));
+               thread->callee_time_stack = (uint64_t *) g_realloc (thread->callee_time_stack, thread->stack_size * sizeof (uint64_t));
+       }
+}
+
+static int
+add_trace_hashed (CallContext *traces, int size, BackTrace *bt, uint64_t value)
+{
+       int i;
+       unsigned int start_pos;
+       start_pos = bt->hash % size;
+       i = start_pos;
+       do {
+               if (traces [i].bt == bt) {
+                       traces [i].count += value;
+                       return 0;
+               } else if (!traces [i].bt) {
+                       traces [i].bt = bt;
+                       traces [i].count += value;
+                       return 1;
+               }
+               /* wrap around */
+               if (++i == size)
+                       i = 0;
+       } while (i != start_pos);
+       /* should not happen */
+       printf ("failed trace store\n");
+       return 0;
+}
+
+static void
+add_trace_bt (BackTrace *bt, TraceDesc *trace, uint64_t value)
+{
+       int i;
+       if (!collect_traces)
+               return;
+       if (trace->count * 2 >= trace->size) {
+               CallContext *n;
+               int old_size = trace->size;
+               trace->size *= 2;
+               if (trace->size == 0)
+                       trace->size = 4;
+               n = (CallContext *) g_calloc (sizeof (CallContext) * trace->size, 1);
+               for (i = 0; i < old_size; ++i) {
+                       if (trace->traces [i].bt)
+                               add_trace_hashed (n, trace->size, trace->traces [i].bt, trace->traces [i].count);
+               }
+               if (trace->traces)
+                       g_free (trace->traces);
+               trace->traces = n;
+       }
+       trace->count += add_trace_hashed (trace->traces, trace->size, bt, value);
+}
+
+static BackTrace*
+add_trace_thread (ThreadContext *thread, TraceDesc *trace, uint64_t value)
+{
+       BackTrace *bt;
+       int count = thread->stack_id;
+       if (!collect_traces)
+               return NULL;
+       if (count > trace_max)
+               count = trace_max;
+       bt = add_backtrace (count, thread->stack + thread->stack_id - count);
+       add_trace_bt (bt, trace, value);
+       return bt;
+}
+
+static BackTrace*
+add_trace_methods (MethodDesc **methods, int count, TraceDesc *trace, uint64_t value)
+{
+       BackTrace *bt;
+       if (!collect_traces)
+               return NULL;
+       if (count > trace_max)
+               count = trace_max;
+       bt = add_backtrace (count, methods);
+       add_trace_bt (bt, trace, value);
+       return bt;
+}
+
+static void
+thread_add_root (ThreadContext *ctx, uintptr_t obj, int root_type, uintptr_t extra_info)
+{
+       if (ctx->num_roots == ctx->size_roots) {
+               int new_size = ctx->size_roots * 2;
+               if (!new_size)
+                       new_size = 4;
+               ctx->roots = (uintptr_t *) g_realloc (ctx->roots, new_size * sizeof (uintptr_t));
+               ctx->roots_extra = (uintptr_t *) g_realloc (ctx->roots_extra, new_size * sizeof (uintptr_t));
+               ctx->roots_types = (int *) g_realloc (ctx->roots_types, new_size * sizeof (int));
+               ctx->size_roots = new_size;
+       }
+       ctx->roots_types [ctx->num_roots] = root_type;
+       ctx->roots_extra [ctx->num_roots] = extra_info;
+       ctx->roots [ctx->num_roots++] = obj;
+}
+
+static int
+compare_callc (const void *a, const void *b)
+{
+       const CallContext *A = (const CallContext *)a;
+       const CallContext *B = (const CallContext *)b;
+       if (B->count == A->count)
+               return 0;
+       if (B->count < A->count)
+               return -1;
+       return 1;
+}
+
+static void
+sort_context_array (TraceDesc* traces)
+{
+       int i, j;
+       for (i = 0, j = 0; i < traces->size; ++i) {
+               if (traces->traces [i].bt) {
+                       traces->traces [j].bt = traces->traces [i].bt;
+                       traces->traces [j].count = traces->traces [i].count;
+                       j++;
+               }
+       }
+       qsort (traces->traces, traces->count, sizeof (CallContext), compare_callc);
+}
+
+static void
+push_method (ThreadContext *thread, MethodDesc *method, uint64_t timestamp)
+{
+       ensure_thread_stack (thread);
+       thread->time_stack [thread->stack_id] = timestamp;
+       thread->callee_time_stack [thread->stack_id] = 0;
+       thread->stack [thread->stack_id++] = method;
+       method->recurse_count++;
+}
+
+static void
+pop_method (ThreadContext *thread, MethodDesc *method, uint64_t timestamp)
+{
+       method->recurse_count--;
+       if (thread->stack_id > 0 && thread->stack [thread->stack_id - 1] == method) {
+               uint64_t tdiff;
+               thread->stack_id--;
+               method->calls++;
+               if (timestamp < thread->time_stack [thread->stack_id])
+                       fprintf (outfile, "time went backwards for %s\n", method->name);
+               tdiff = timestamp - thread->time_stack [thread->stack_id];
+               if (thread->callee_time_stack [thread->stack_id] > tdiff)
+                       fprintf (outfile, "callee time bigger for %s\n", method->name);
+               method->self_time += tdiff - thread->callee_time_stack [thread->stack_id];
+               method->callee_time += thread->callee_time_stack [thread->stack_id];
+               if (thread->stack_id)
+                       thread->callee_time_stack [thread->stack_id - 1] += tdiff;
+               //fprintf (outfile, "method %s took %d\n", method->name, (int)(tdiff/1000));
+       } else {
+               fprintf (outfile, "unmatched leave at stack pos: %d for method %s\n", thread->stack_id, method->name);
+       }
+}
+
+typedef struct {
+       uint64_t total_time;
+       uint64_t max_time;
+       int count;
+} GCDesc;
+static GCDesc gc_info [3];
+static uint64_t max_heap_size;
+static uint64_t gc_object_moves;
+static int gc_resizes;
+typedef struct {
+       uint64_t created;
+       uint64_t destroyed;
+       uint64_t live;
+       uint64_t max_live;
+       TraceDesc traces;
+       TraceDesc destroy_traces;
+} HandleInfo;
+static HandleInfo handle_info [4];
+
+static const char*
+gc_event_name (int ev)
+{
+       switch (ev) {
+       case MONO_GC_EVENT_START: return "start";
+       case MONO_GC_EVENT_MARK_START: return "mark start";
+       case MONO_GC_EVENT_MARK_END: return "mark end";
+       case MONO_GC_EVENT_RECLAIM_START: return "reclaim start";
+       case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
+       case MONO_GC_EVENT_END: return "end";
+       case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
+       case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
+       case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
+       case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
+       default:
+               return "unknown";
+       }
+}
+
+static const char*
+sync_point_name (int type)
+{
+       switch (type) {
+       case SYNC_POINT_PERIODIC: return "periodic";
+       case SYNC_POINT_WORLD_STOP: return "world stop";
+       case SYNC_POINT_WORLD_START: return "world start";
+       default:
+               return "unknown";
+       }
+}
+
+static uint64_t clause_summary [MONO_EXCEPTION_CLAUSE_FAULT + 1];
+static uint64_t throw_count = 0;
+static TraceDesc exc_traces;
+
+static const char*
+clause_name (int type)
+{
+       switch (type) {
+       case MONO_EXCEPTION_CLAUSE_NONE: return "catch";
+       case MONO_EXCEPTION_CLAUSE_FILTER: return "filter";
+       case MONO_EXCEPTION_CLAUSE_FINALLY: return "finally";
+       case MONO_EXCEPTION_CLAUSE_FAULT: return "fault";
+       default: return "invalid";
+       }
+}
+
+static uint64_t monitor_contention;
+static uint64_t monitor_failed;
+static uint64_t monitor_acquired;
+
+struct _MonitorDesc {
+       MonitorDesc *next;
+       uintptr_t objid;
+       uintptr_t contentions;
+       uint64_t wait_time;
+       uint64_t max_wait_time;
+       TraceDesc traces;
+};
+
+static MonitorDesc* monitor_hash [SMALL_HASH_SIZE] = {0};
+static int num_monitors = 0;
+
+static MonitorDesc*
+lookup_monitor (uintptr_t objid)
+{
+       int slot = ((objid >> 3) & 0xffff) % SMALL_HASH_SIZE;
+       MonitorDesc *cd = monitor_hash [slot];
+       while (cd && cd->objid != objid)
+               cd = cd->next;
+       if (!cd) {
+               cd = (MonitorDesc *) g_calloc (sizeof (MonitorDesc), 1);
+               cd->objid = objid;
+               cd->next = monitor_hash [slot];
+               monitor_hash [slot] = cd;
+               num_monitors++;
+       }
+       return cd;
+}
+
+static const char*
+monitor_ev_name (int ev)
+{
+       switch (ev) {
+       case MONO_PROFILER_MONITOR_CONTENTION: return "contended";
+       case MONO_PROFILER_MONITOR_DONE: return "acquired";
+       case MONO_PROFILER_MONITOR_FAIL: return "not taken";
+       default: return "invalid";
+       }
+}
+
+static const char*
+get_handle_name (int htype)
+{
+       switch (htype) {
+       case 0: return "weak";
+       case 1: return "weaktrack";
+       case 2: return "normal";
+       case 3: return "pinned";
+       default: return "unknown";
+       }
+}
+
+static const char*
+get_root_name (int rtype)
+{
+       switch (rtype & MONO_PROFILE_GC_ROOT_TYPEMASK) {
+       case MONO_PROFILE_GC_ROOT_STACK: return "stack";
+       case MONO_PROFILE_GC_ROOT_FINALIZER: return "finalizer";
+       case MONO_PROFILE_GC_ROOT_HANDLE: return "handle";
+       case MONO_PROFILE_GC_ROOT_OTHER: return "other";
+       case MONO_PROFILE_GC_ROOT_MISC: return "misc";
+       default: return "unknown";
+       }
+}
+
+static uint64_t
+decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
+{
+       uint64_t res = 0;
+       int shift = 0;
+
+       while (1) {
+               uint8_t b = *buf++;
+               res |= (((uint64_t) (b & 0x7f)) << shift);
+
+               if (!(b & 0x80))
+                       break;
+
+               shift += 7;
+       }
+
+       *endbuf = buf;
+
+       return res;
+}
+
+static intptr_t
+decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
+{
+       uint8_t *p = buf;
+       intptr_t res = 0;
+       int shift = 0;
+
+       while (1) {
+               uint8_t b = *p;
+               p++;
+
+               res = res | (((intptr_t) (b & 0x7f)) << shift);
+               shift += 7;
+
+               if (!(b & 0x80)) {
+                       if (shift < sizeof (intptr_t) * 8 && (b & 0x40))
+                               res |= - ((intptr_t) 1 << shift);
+
+                       break;
+               }
+       }
+
+       *endbuf = p;
+
+       return res;
+}
+
+static MethodDesc**
+decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
+{
+       MethodDesc **frames;
+       int i;
+       if (ctx->data_version < 13)
+               decode_uleb128 (p, &p); /* flags */
+       int count = decode_uleb128 (p, &p);
+       if (count > *size)
+               frames = (MethodDesc **) g_malloc (count * sizeof (void*));
+       else
+               frames = sframes;
+       for (i = 0; i < count; ++i) {
+               intptr_t ptrdiff = decode_sleb128 (p, &p);
+               if (ctx->data_version > 12) {
+                       *method_base += ptrdiff;
+                       frames [i] = lookup_method (*method_base);
+               } else {
+                       frames [i] = lookup_method (ptr_base + ptrdiff);
+               }
+       }
+       *size = count;
+       *endp = p;
+       return frames;
+}
+
+static void
+tracked_creation (uintptr_t obj, ClassDesc *cd, uint64_t size, BackTrace *bt, uint64_t timestamp)
+{
+       int i;
+       for (i = 0; i < num_tracked_objects; ++i) {
+               if (tracked_objects [i] != obj)
+                       continue;
+               fprintf (outfile, "Object %p created (%s, %llu bytes) at %.3f secs.\n", (void*)obj, cd->name, (unsigned long long) size, (timestamp - startup_time)/1000000000.0);
+               if (bt && bt->count) {
+                       int k;
+                       for (k = 0; k < bt->count; ++k)
+                               fprintf (outfile, "\t%s\n", bt->methods [k]->name);
+               }
+       }
+}
+
+static void
+track_handle (uintptr_t obj, int htype, uint32_t handle, BackTrace *bt, uint64_t timestamp)
+{
+       int i;
+       for (i = 0; i < num_tracked_objects; ++i) {
+               if (tracked_objects [i] != obj)
+                       continue;
+               fprintf (outfile, "Object %p referenced from handle %u at %.3f secs.\n", (void*)obj, handle, (timestamp - startup_time) / 1000000000.0);
+               if (bt && bt->count) {
+                       int k;
+                       for (k = 0; k < bt->count; ++k)
+                               fprintf (outfile, "\t%s\n", bt->methods [k]->name);
+               }
+       }
+}
+
+static void
+track_move (uintptr_t src, uintptr_t dst)
+{
+       int i;
+       for (i = 0; i < num_tracked_objects; ++i) {
+               if (tracked_objects [i] == src)
+                       fprintf (outfile, "Object %p moved to %p\n", (void*)src, (void*)dst);
+               else if (tracked_objects [i] == dst)
+                       fprintf (outfile, "Object %p moved from %p\n", (void*)dst, (void*)src);
+       }
+}
+
+static void
+track_obj_reference (uintptr_t obj, uintptr_t parent, ClassDesc *cd)
+{
+       int i;
+       for (i = 0; i < num_tracked_objects; ++i) {
+               if (tracked_objects [i] == obj)
+                       fprintf (outfile, "Object %p referenced from %p (%s).\n", (void*)obj, (void*)parent, cd->name);
+       }
+}
+
+static void
+found_object (uintptr_t obj)
+{
+       num_tracked_objects ++;
+       tracked_objects = (uintptr_t *) g_realloc (tracked_objects, num_tracked_objects * sizeof (tracked_objects [0]));
+       tracked_objects [num_tracked_objects - 1] = obj;
+}
+
+static int num_jit_helpers = 0;
+static int jit_helpers_code_size = 0;
+
+static const char*
+code_buffer_desc (int type)
+{
+       switch (type) {
+       case MONO_PROFILER_CODE_BUFFER_METHOD:
+               return "method";
+       case MONO_PROFILER_CODE_BUFFER_METHOD_TRAMPOLINE:
+               return "method trampoline";
+       case MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE:
+               return "unbox trampoline";
+       case MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE:
+               return "imt trampoline";
+       case MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE:
+               return "generics trampoline";
+       case MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE:
+               return "specific trampoline";
+       case MONO_PROFILER_CODE_BUFFER_HELPER:
+               return "misc helper";
+       case MONO_PROFILER_CODE_BUFFER_MONITOR:
+               return "monitor/lock";
+       case MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE:
+               return "delegate invoke";
+       case MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING:
+               return "exception handling";
+       default:
+               return "unspecified";
+       }
+}
+
+typedef struct _CoverageAssembly CoverageAssembly;
+struct _CoverageAssembly {
+       char *name;
+       char *guid;
+       char *filename;
+       int number_of_methods;
+       int fully_covered;
+       int partially_covered;
+};
+
+typedef struct _CoverageClass CoverageClass;
+struct _CoverageClass {
+       char *assembly_name;
+       char *class_name;
+       int number_of_methods;
+       int fully_covered;
+       int partially_covered;
+};
+
+typedef struct _CoverageCoverage CoverageCoverage;
+struct _CoverageCoverage {
+       int method_id;
+       int offset;
+       int count;
+       int line;
+       int column;
+};
+
+typedef struct _CoverageMethod CoverageMethod;
+struct _CoverageMethod {
+       char *assembly_name;
+       char *class_name;
+       char *method_name;
+       char *method_signature;
+       char *filename;
+       int token;
+       int n_statements;
+       int method_id;
+       GPtrArray *coverage;
+};
+static GPtrArray *coverage_assemblies = NULL;
+static GPtrArray *coverage_methods = NULL;
+static GPtrArray *coverage_statements = NULL;
+static GHashTable *coverage_methods_hash = NULL;
+static GPtrArray *coverage_classes = NULL;
+static GHashTable *coverage_assembly_classes = NULL;
+
+static void
+gather_coverage_statements (void)
+{
+       for (guint i = 0; i < coverage_statements->len; i++) {
+               CoverageCoverage *coverage = (CoverageCoverage *)coverage_statements->pdata[i];
+               CoverageMethod *method = (CoverageMethod *)g_hash_table_lookup (coverage_methods_hash, GINT_TO_POINTER (coverage->method_id));
+               if (method == NULL) {
+                       fprintf (outfile, "Cannot find method with ID: %d\n", coverage->method_id);
+                       continue;
+               }
+
+               g_ptr_array_add (method->coverage, coverage);
+       }
+}
+
+static void
+coverage_add_assembly (CoverageAssembly *assembly)
+{
+       if (coverage_assemblies == NULL)
+               coverage_assemblies = g_ptr_array_new ();
+
+       g_ptr_array_add (coverage_assemblies, assembly);
+}
+
+static void
+coverage_add_method (CoverageMethod *method)
+{
+       if (coverage_methods == NULL) {
+               coverage_methods = g_ptr_array_new ();
+               coverage_methods_hash = g_hash_table_new (NULL, NULL);
+       }
+
+       g_ptr_array_add (coverage_methods, method);
+       g_hash_table_insert (coverage_methods_hash, GINT_TO_POINTER (method->method_id), method);
+}
+
+static void
+coverage_add_class (CoverageClass *klass)
+{
+       GPtrArray *classes = NULL;
+
+       if (coverage_classes == NULL) {
+               coverage_classes = g_ptr_array_new ();
+               coverage_assembly_classes = g_hash_table_new (g_str_hash, g_str_equal);
+       }
+
+       g_ptr_array_add (coverage_classes, klass);
+       classes = (GPtrArray *)g_hash_table_lookup (coverage_assembly_classes, klass->assembly_name);
+       if (classes == NULL) {
+               classes = g_ptr_array_new ();
+               g_hash_table_insert (coverage_assembly_classes, klass->assembly_name, classes);
+       }
+       g_ptr_array_add (classes, klass);
+}
+
+static void
+coverage_add_coverage (CoverageCoverage *coverage)
+{
+       if (coverage_statements == NULL)
+               coverage_statements = g_ptr_array_new ();
+
+       g_ptr_array_add (coverage_statements, coverage);
+}
+
+#define OBJ_ADDR(diff) ((obj_base + diff) << 3)
+#define LOG_TIME(base,diff) /*fprintf("outfile, time %llu + %llu near offset %d\n", base, diff, p - ctx->buf)*/
+
+
+/* Stats */
+#define BUFFER_HEADER_SIZE 48
+
+typedef struct {
+       int count, min_size, max_size, bytes;
+} EventStat;
+
+static int buffer_count;
+static EventStat stats [256];
+
+static void
+record_event_stats (int type, int size)
+{
+       ++stats [type].count;
+       if (!stats [type].min_size)
+               stats [type].min_size = size;
+       stats [type].min_size = MIN (stats [type].min_size, size);
+       stats [type].max_size = MAX (stats [type].max_size, size);
+       stats [type].bytes += size;
+}
+
+static int
+decode_buffer (ProfContext *ctx)
+{
+       unsigned char *p;
+       unsigned char *end;
+       intptr_t thread_id;
+       intptr_t ptr_base;
+       intptr_t obj_base;
+       intptr_t method_base;
+       uint64_t time_base;
+       uint64_t file_offset;
+       int len, i;
+       ThreadContext *thread;
+
+#ifdef HAVE_SYS_ZLIB
+       if (ctx->gzfile)
+               file_offset = gztell (ctx->gzfile);
+       else
+#endif
+               file_offset = ftell (ctx->file);
+       if (!load_data (ctx, 48))
+               return 0;
+       p = ctx->buf;
+       if (read_int32 (p) != BUF_ID) {
+               fprintf (outfile, "Incorrect buffer id: 0x%x\n", read_int32 (p));
+               for (i = 0; i < 48; ++i) {
+                       fprintf (outfile, "0x%x%s", p [i], i % 8?" ":"\n");
+               }
+               return 0;
+       }
+       len = read_int32 (p + 4);
+       time_base = read_int64 (p + 8);
+       ptr_base = read_int64 (p + 16);
+       obj_base = read_int64 (p + 24);
+       thread_id = read_int64 (p + 32);
+       method_base = read_int64 (p + 40);
+       if (debug)
+               fprintf (outfile, "buf: thread:%zx, len: %d, time: %llu, file offset: %llu\n", thread_id, len, (unsigned long long) time_base, (unsigned long long) file_offset);
+       thread = load_thread (ctx, thread_id);
+       if (!load_data (ctx, len))
+               return 0;
+
+       ++buffer_count;
+
+       if (!startup_time) {
+               startup_time = time_base;
+               if (use_time_filter) {
+                       time_from += startup_time;
+                       time_to += startup_time;
+               }
+       }
+       for (i = 0; i < thread->stack_id; ++i)
+               thread->stack [i]->recurse_count++;
+       p = ctx->buf;
+       end = p + len;
+       while (p < end) {
+               unsigned char *start = p;
+               unsigned char event = *p;
+               switch (*p & 0xf) {
+               case TYPE_GC: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_GC_RESIZE) {
+                               uint64_t new_size = decode_uleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc heap resized to %llu\n", (unsigned long long) new_size);
+                               gc_resizes++;
+                               if (new_size > max_heap_size)
+                                       max_heap_size = new_size;
+                       } else if (subtype == TYPE_GC_EVENT) {
+                               uint64_t ev;
+                               if (ctx->data_version > 12)
+                                       ev = *p++;
+                               else
+                                       ev = decode_uleb128 (p, &p);
+                               int gen;
+                               if (ctx->data_version > 12)
+                                       gen = *p++;
+                               else
+                                       gen = decode_uleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
+                               if (gen > 2) {
+                                       fprintf (outfile, "incorrect gc gen: %d\n", gen);
+                                       break;
+                               }
+                               if (ev == MONO_GC_EVENT_START) {
+                                       thread->gc_start_times [gen] = time_base;
+                                       gc_info [gen].count++;
+                               } else if (ev == MONO_GC_EVENT_END) {
+                                       tdiff = time_base - thread->gc_start_times [gen];
+                                       gc_info [gen].total_time += tdiff;
+                                       if (tdiff > gc_info [gen].max_time)
+                                               gc_info [gen].max_time = tdiff;
+                               }
+                       } else if (subtype == TYPE_GC_MOVE) {
+                               int j, num = decode_uleb128 (p, &p);
+                               gc_object_moves += num / 2;
+                               for (j = 0; j < num; j += 2) {
+                                       intptr_t obj1diff = decode_sleb128 (p, &p);
+                                       intptr_t obj2diff = decode_sleb128 (p, &p);
+                                       if (num_tracked_objects)
+                                               track_move (OBJ_ADDR (obj1diff), OBJ_ADDR (obj2diff));
+                                       if (debug) {
+                                               fprintf (outfile, "moved obj %p to %p\n", (void*)OBJ_ADDR (obj1diff), (void*)OBJ_ADDR (obj2diff));
+                                       }
+                               }
+                       } else if (subtype == TYPE_GC_HANDLE_CREATED || subtype == TYPE_GC_HANDLE_CREATED_BT) {
+                               int has_bt = subtype == TYPE_GC_HANDLE_CREATED_BT;
+                               int num_bt = 0;
+                               MethodDesc *sframes [8];
+                               MethodDesc **frames = sframes;
+                               int htype = decode_uleb128 (p, &p);
+                               uint32_t handle = decode_uleb128 (p, &p);
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (has_bt) {
+                                       num_bt = 8;
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
+                                       if (!frames) {
+                                               fprintf (outfile, "Cannot load backtrace\n");
+                                               return 0;
+                                       }
+                               }
+                               if (htype > 3)
+                                       return 0;
+                               if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
+                                       handle_info [htype].created++;
+                                       handle_info [htype].live++;
+                                       if (handle_info [htype].live > handle_info [htype].max_live)
+                                               handle_info [htype].max_live = handle_info [htype].live;
+                                       BackTrace *bt;
+                                       if (has_bt)
+                                               bt = add_trace_methods (frames, num_bt, &handle_info [htype].traces, 1);
+                                       else
+                                               bt = add_trace_thread (thread, &handle_info [htype].traces, 1);
+                                       if (num_tracked_objects)
+                                               track_handle (OBJ_ADDR (objdiff), htype, handle, bt, time_base);
+                               }
+                               if (debug)
+                                       fprintf (outfile, "handle (%s) %u created for object %p\n", get_handle_name (htype), handle, (void*)OBJ_ADDR (objdiff));
+                               if (frames != sframes)
+                                       g_free (frames);
+                       } else if (subtype == TYPE_GC_HANDLE_DESTROYED || subtype == TYPE_GC_HANDLE_DESTROYED_BT) {
+                               int has_bt = subtype == TYPE_GC_HANDLE_DESTROYED_BT;
+                               int num_bt = 0;
+                               MethodDesc *sframes [8];
+                               MethodDesc **frames = sframes;
+                               int htype = decode_uleb128 (p, &p);
+                               uint32_t handle = decode_uleb128 (p, &p);
+                               if (has_bt) {
+                                       num_bt = 8;
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
+                                       if (!frames) {
+                                               fprintf (outfile, "Cannot load backtrace\n");
+                                               return 0;
+                                       }
+                               }
+                               if (htype > 3)
+                                       return 0;
+                               if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
+                                       handle_info [htype].destroyed ++;
+                                       handle_info [htype].live--;
+                                       BackTrace *bt;
+                                       if (has_bt)
+                                               bt = add_trace_methods (frames, num_bt, &handle_info [htype].destroy_traces, 1);
+                                       else
+                                               bt = add_trace_thread (thread, &handle_info [htype].destroy_traces, 1);
+                                       /* TODO: track_handle_free () - would need to record and keep track of the associated object address... */
+                               }
+                               if (debug)
+                                       fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
+                               if (frames != sframes)
+                                       g_free (frames);
+                       } else if (subtype == TYPE_GC_FINALIZE_START) {
+                               // TODO: Generate a finalizer report based on these events.
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_END) {
+                               if (debug)
+                                       fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+                       } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+                       }
+                       break;
+               }
+               case TYPE_METADATA: {
+                       int subtype = *p & 0xf0;
+                       const char *load_str = subtype == TYPE_END_LOAD ? "loaded" : "unloaded";
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       int mtype = *p++;
+                       intptr_t ptrdiff = decode_sleb128 (p, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (mtype == TYPE_CLASS) {
+                               intptr_t imptrdiff = decode_sleb128 (p, &p);
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               if (debug)
+                                       fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
+                               if (subtype == TYPE_END_LOAD)
+                                       add_class (ptr_base + ptrdiff, (char*)p);
+                               while (*p) p++;
+                               p++;
+                       } else if (mtype == TYPE_IMAGE) {
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               if (debug)
+                                       fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
+                               if (subtype == TYPE_END_LOAD)
+                                       add_image (ptr_base + ptrdiff, (char*)p);
+                               while (*p) p++;
+                               p++;
+                       } else if (mtype == TYPE_ASSEMBLY) {
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               if (debug)
+                                       fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
+                               if (subtype == TYPE_END_LOAD)
+                                       add_assembly (ptr_base + ptrdiff, (char*)p);
+                               while (*p) p++;
+                               p++;
+                       } else if (mtype == TYPE_DOMAIN) {
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
+                               /* no subtype means it's a name event, rather than start/stop */
+                               if (subtype == 0)
+                                       nd->friendly_name = pstrdup ((char *) p);
+                               if (debug) {
+                                       if (subtype == 0)
+                                               fprintf (outfile, "domain %p named at %llu: %s\n", (void *) (ptr_base + ptrdiff), (unsigned long long) time_base, p);
+                                       else
+                                               fprintf (outfile, "%s thread %p at %llu\n", load_str, (void *) (ptr_base + ptrdiff), (unsigned long long) time_base);
+                               }
+                               if (subtype == 0) {
+                                       while (*p) p++;
+                                       p++;
+                               }
+                       } else if (mtype == TYPE_CONTEXT) {
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               intptr_t domaindiff = decode_sleb128 (p, &p);
+                               if (debug)
+                                       fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
+                               if (subtype == TYPE_END_LOAD)
+                                       get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
+                       } else if (mtype == TYPE_THREAD) {
+                               if (ctx->data_version < 13)
+                                       decode_uleb128 (p, &p); /* flags */
+                               ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
+                               /* no subtype means it's a name event, rather than start/stop */
+                               if (subtype == 0)
+                                       nt->name = pstrdup ((char*)p);
+                               if (debug) {
+                                       if (subtype == 0)
+                                               fprintf (outfile, "thread %p named at %llu: %s\n", (void*)(ptr_base + ptrdiff), (unsigned long long) time_base, p);
+                                       else
+                                               fprintf (outfile, "%s thread %p at %llu\n", load_str, (void *) (ptr_base + ptrdiff), (unsigned long long) time_base);
+                               }
+                               if (subtype == 0) {
+                                       while (*p) p++;
+                                       p++;
+                               }
+                       }
+                       break;
+               }
+               case TYPE_ALLOC: {
+                       int has_bt = *p & TYPE_ALLOC_BT;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       intptr_t ptrdiff = decode_sleb128 (p, &p);
+                       intptr_t objdiff = decode_sleb128 (p, &p);
+                       uint64_t len;
+                       int num_bt = 0;
+                       MethodDesc* sframes [8];
+                       MethodDesc** frames = sframes;
+                       ClassDesc *cd = lookup_class (ptr_base + ptrdiff);
+                       len = decode_uleb128 (p, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (debug)
+                               fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
+                       if (has_bt) {
+                               num_bt = 8;
+                               frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
+                               if (!frames) {
+                                       fprintf (outfile, "Cannot load backtrace\n");
+                                       return 0;
+                               }
+                       }
+                       if ((thread_filter && thread_filter == thread->thread_id) || (time_base >= time_from && time_base < time_to)) {
+                               BackTrace *bt;
+                               cd->allocs++;
+                               cd->alloc_size += len;
+                               if (has_bt)
+                                       bt = add_trace_methods (frames, num_bt, &cd->traces, len);
+                               else
+                                       bt = add_trace_thread (thread, &cd->traces, len);
+                               if (find_size && len >= find_size) {
+                                       if (!find_name || strstr (cd->name, find_name))
+                                               found_object (OBJ_ADDR (objdiff));
+                               } else if (!find_size && find_name && strstr (cd->name, find_name)) {
+                                       found_object (OBJ_ADDR (objdiff));
+                               }
+                               if (num_tracked_objects)
+                                       tracked_creation (OBJ_ADDR (objdiff), cd, len, bt, time_base);
+                       }
+                       if (frames != sframes)
+                               g_free (frames);
+                       break;
+               }
+               case TYPE_METHOD: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       int64_t ptrdiff = decode_sleb128 (p, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       method_base += ptrdiff;
+                       if (subtype == TYPE_JIT) {
+                               intptr_t codediff = decode_sleb128 (p, &p);
+                               int codelen = decode_uleb128 (p, &p);
+                               MethodDesc *jitted_method;
+                               if (debug)
+                                       fprintf (outfile, "jitted method %p (%s), size: %d, code: %p\n", (void*)(method_base), p, codelen, (void*)(ptr_base + codediff));
+                               jitted_method = add_method (method_base, (char*)p, ptr_base + codediff, codelen);
+                               if (!(time_base >= time_from && time_base < time_to))
+                                       jitted_method->ignore_jit = 1;
+                               while (*p) p++;
+                               p++;
+                       } else {
+                               MethodDesc *method;
+                               if ((thread_filter && thread_filter != thread->thread_id))
+                                       break;
+                               if (!(time_base >= time_from && time_base < time_to))
+                                       break;
+                               method = lookup_method (method_base);
+                               if (subtype == TYPE_ENTER) {
+                                       add_trace_thread (thread, &method->traces, 1);
+                                       push_method (thread, method, time_base);
+                               } else {
+                                       pop_method (thread, method, time_base);
+                               }
+                               if (debug)
+                                       fprintf (outfile, "%s method %s\n", subtype == TYPE_ENTER? "enter": subtype == TYPE_EXC_LEAVE? "exleave": "leave", method->name);
+                       }
+                       break;
+               }
+               case TYPE_HEAP: {
+                       int subtype = *p & 0xf0;
+                       if (subtype == TYPE_HEAP_OBJECT) {
+                               HeapObjectDesc *ho = NULL;
+                               int i;
+                               intptr_t objdiff;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       objdiff = decode_sleb128 (p, &p);
+                               } else
+                                       objdiff = decode_sleb128 (p + 1, &p);
+                               intptr_t ptrdiff = decode_sleb128 (p, &p);
+                               uint64_t size = decode_uleb128 (p, &p);
+                               uintptr_t num = decode_uleb128 (p, &p);
+                               uintptr_t ref_offset = 0;
+                               uintptr_t last_obj_offset = 0;
+                               ClassDesc *cd = lookup_class (ptr_base + ptrdiff);
+                               if (size) {
+                                       HeapClassDesc *hcd = add_heap_shot_class (thread->current_heap_shot, cd, size);
+                                       if (collect_traces) {
+                                               ho = alloc_heap_obj (OBJ_ADDR (objdiff), hcd, num);
+                                               add_heap_shot_obj (thread->current_heap_shot, ho);
+                                               ref_offset = 0;
+                                       }
+                               } else {
+                                       if (collect_traces)
+                                               ho = heap_shot_obj_add_refs (thread->current_heap_shot, OBJ_ADDR (objdiff), num, &ref_offset);
+                               }
+                               for (i = 0; i < num; ++i) {
+                                       /* FIXME: use object distance to measure how good
+                                        * the GC is at keeping related objects close
+                                        */
+                                       uintptr_t offset = ctx->data_version > 1? last_obj_offset + decode_uleb128 (p, &p): -1;
+                                       intptr_t obj1diff = decode_sleb128 (p, &p);
+                                       last_obj_offset = offset;
+                                       if (collect_traces)
+                                               ho->refs [ref_offset + i] = OBJ_ADDR (obj1diff);
+                                       if (num_tracked_objects)
+                                               track_obj_reference (OBJ_ADDR (obj1diff), OBJ_ADDR (objdiff), cd);
+                               }
+                               if (debug && size)
+                                       fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
+                       } else if (subtype == TYPE_HEAP_ROOT) {
+                               uintptr_t num;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       num = decode_uleb128 (p, &p);
+                               } else
+                                       num = decode_uleb128 (p + 1, &p);
+                               uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
+                               int i;
+                               for (i = 0; i < num; ++i) {
+                                       intptr_t objdiff = decode_sleb128 (p, &p);
+                                       int root_type;
+                                       if (ctx->data_version > 12)
+                                               root_type = *p++;
+                                       else
+                                               root_type = decode_uleb128 (p, &p);
+                                       /* we just discard the extra info for now */
+                                       uintptr_t extra_info = decode_uleb128 (p, &p);
+                                       if (debug)
+                                               fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type));
+                                       if (collect_traces)
+                                               thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info);
+                               }
+                       } else if (subtype == TYPE_HEAP_END) {
+                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                               LOG_TIME (time_base, tdiff);
+                               time_base += tdiff;
+                               if (debug)
+                                       fprintf (outfile, "heap shot end\n");
+                               if (collect_traces) {
+                                       HeapShot *hs = thread->current_heap_shot;
+                                       if (hs && thread->num_roots) {
+                                               /* transfer the root ownershipt to the heapshot */
+                                               hs->num_roots = thread->num_roots;
+                                               hs->roots = thread->roots;
+                                               hs->roots_extra = thread->roots_extra;
+                                               hs->roots_types = thread->roots_types;
+                                       } else {
+                                               g_free (thread->roots);
+                                               g_free (thread->roots_extra);
+                                               g_free (thread->roots_types);
+                                       }
+                                       thread->num_roots = 0;
+                                       thread->size_roots = 0;
+                                       thread->roots = NULL;
+                                       thread->roots_extra = NULL;
+                                       thread->roots_types = NULL;
+                                       heap_shot_resolve_reverse_refs (hs);
+                                       heap_shot_mark_objects (hs);
+                                       heap_shot_free_objects (hs);
+                               }
+                               thread->current_heap_shot = NULL;
+                       } else if (subtype == TYPE_HEAP_START) {
+                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                               LOG_TIME (time_base, tdiff);
+                               time_base += tdiff;
+                               if (debug)
+                                       fprintf (outfile, "heap shot start\n");
+                               thread->current_heap_shot = new_heap_shot (time_base);
+                       }
+                       break;
+               }
+               case TYPE_MONITOR: {
+                       int event = (*p >> 4) & 0x3;
+                       int has_bt = *p & TYPE_MONITOR_BT;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       intptr_t objdiff = decode_sleb128 (p, &p);
+                       MethodDesc* sframes [8];
+                       MethodDesc** frames = sframes;
+                       int record;
+                       int num_bt = 0;
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       record = (!thread_filter || thread_filter == thread->thread_id);
+                       if (!(time_base >= time_from && time_base < time_to))
+                               record = 0;
+                       if (event == MONO_PROFILER_MONITOR_CONTENTION) {
+                               MonitorDesc *mdesc = lookup_monitor (OBJ_ADDR (objdiff));
+                               if (record) {
+                                       monitor_contention++;
+                                       mdesc->contentions++;
+                                       thread->monitor = mdesc;
+                                       thread->contention_start = time_base;
+                               }
+                               if (has_bt) {
+                                       num_bt = 8;
+                                       frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
+                                       if (!frames) {
+                                               fprintf (outfile, "Cannot load backtrace\n");
+                                               return 0;
+                                       }
+                                       if (record)
+                                               add_trace_methods (frames, num_bt, &mdesc->traces, 1);
+                               } else {
+                                       if (record)
+                                               add_trace_thread (thread, &mdesc->traces, 1);
+                               }
+                       } else if (event == MONO_PROFILER_MONITOR_FAIL) {
+                               if (record) {
+                                       monitor_failed++;
+                                       if (thread->monitor && thread->contention_start) {
+                                               uint64_t wait_time = time_base - thread->contention_start;
+                                               if (wait_time > thread->monitor->max_wait_time)
+                                                       thread->monitor->max_wait_time = wait_time;
+                                               thread->monitor->wait_time += wait_time;
+                                               thread->monitor = NULL;
+                                               thread->contention_start = 0;
+                                       }
+                               }
+                       } else if (event == MONO_PROFILER_MONITOR_DONE) {
+                               if (record) {
+                                       monitor_acquired++;
+                                       if (thread->monitor && thread->contention_start) {
+                                               uint64_t wait_time = time_base - thread->contention_start;
+                                               if (wait_time > thread->monitor->max_wait_time)
+                                                       thread->monitor->max_wait_time = wait_time;
+                                               thread->monitor->wait_time += wait_time;
+                                               thread->monitor = NULL;
+                                               thread->contention_start = 0;
+                                       }
+                               }
+                       }
+                       if (debug)
+                               fprintf (outfile, "monitor %s for object %p\n", monitor_ev_name (event), (void*)OBJ_ADDR (objdiff));
+                       if (frames != sframes)
+                               g_free (frames);
+                       break;
+               }
+               case TYPE_EXCEPTION: {
+                       int subtype = *p & 0x70;
+                       int has_bt = *p & TYPE_THROW_BT;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       MethodDesc* sframes [8];
+                       MethodDesc** frames = sframes;
+                       int record;
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       record = (!thread_filter || thread_filter == thread->thread_id);
+                       if (!(time_base >= time_from && time_base < time_to))
+                               record = 0;
+                       if (subtype == TYPE_CLAUSE) {
+                               int clause_type;
+                               if (ctx->data_version > 12)
+                                       clause_type = *p++;
+                               else
+                                       clause_type = decode_uleb128 (p, &p);
+                               int clause_num = decode_uleb128 (p, &p);
+                               int64_t ptrdiff = decode_sleb128 (p, &p);
+                               method_base += ptrdiff;
+                               if (record)
+                                       clause_summary [clause_type]++;
+                               if (debug)
+                                       fprintf (outfile, "clause %s (%d) in method %s\n", clause_name (clause_type), clause_num, lookup_method (method_base)->name);
+                       } else {
+                               intptr_t objdiff = decode_sleb128 (p, &p);
+                               if (record)
+                                       throw_count++;
+                               if (has_bt) {
+                                       has_bt = 8;
+                                       frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
+                                       if (!frames) {
+                                               fprintf (outfile, "Cannot load backtrace\n");
+                                               return 0;
+                                       }
+                                       if (record)
+                                               add_trace_methods (frames, has_bt, &exc_traces, 1);
+                               } else {
+                                       if (record)
+                                               add_trace_thread (thread, &exc_traces, 1);
+                               }
+                               if (frames != sframes)
+                                       g_free (frames);
+                               if (debug)
+                                       fprintf (outfile, "throw %p\n", (void*)OBJ_ADDR (objdiff));
+                       }
+                       break;
+               }
+               case TYPE_RUNTIME: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_JITHELPER) {
+                               int type;
+                               if (ctx->data_version > 12)
+                                       type = *p++;
+                               else
+                                       type = decode_uleb128 (p, &p);
+                               intptr_t codediff = decode_sleb128 (p, &p);
+                               int codelen = decode_uleb128 (p, &p);
+                               const char *name;
+                               if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
+                                       name = (const char *)p;
+                                       while (*p) p++;
+                                               p++;
+                               } else {
+                                       name = code_buffer_desc (type);
+                               }
+                               num_jit_helpers++;
+                               jit_helpers_code_size += codelen;
+                               if (debug)
+                                       fprintf (outfile, "jit helper %s, size: %d, code: %p\n", name, codelen, (void*)(ptr_base + codediff));
+                       }
+                       break;
+               }
+               case TYPE_SAMPLE: {
+                       int subtype = *p & 0xf0;
+                       if (subtype == TYPE_SAMPLE_HIT) {
+                               int i;
+                               int sample_type;
+                               uint64_t tstamp;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       sample_type = *p++;
+                                       tstamp = time_base;
+                               } else {
+                                       sample_type = decode_uleb128 (p + 1, &p);
+                                       tstamp = decode_uleb128 (p, &p);
+                               }
+                               void *tid = (void *) thread_id;
+                               if (ctx->data_version > 10)
+                                       tid = (void *) (ptr_base + decode_sleb128 (p, &p));
+                               int count = decode_uleb128 (p, &p);
+                               for (i = 0; i < count; ++i) {
+                                       uintptr_t ip = ptr_base + decode_sleb128 (p, &p);
+                                       if ((tstamp >= time_from && tstamp < time_to))
+                                               add_stat_sample (sample_type, ip);
+                                       if (debug)
+                                               fprintf (outfile, "sample hit, type: %d at %p for thread %p\n", sample_type, (void*)ip, tid);
+                               }
+                               if (ctx->data_version > 5) {
+                                       count = decode_uleb128 (p, &p);
+                                       for (i = 0; i < count; ++i) {
+                                               MethodDesc *method;
+                                               int64_t ptrdiff = decode_sleb128 (p, &p);
+                                               method_base += ptrdiff;
+                                               method = lookup_method (method_base);
+                                               if (debug)
+                                                       fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
+                                               if (ctx->data_version < 13) {
+                                                       decode_sleb128 (p, &p); /* il offset */
+                                                       decode_sleb128 (p, &p); /* native offset */
+                                               }
+                                       }
+                               }
+                       } else if (subtype == TYPE_SAMPLE_USYM) {
+                               /* un unmanaged symbol description */
+                               uintptr_t addr;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       addr = ptr_base + decode_sleb128 (p, &p);
+                               } else
+                                       addr = ptr_base + decode_sleb128 (p + 1, &p);
+                               uintptr_t size = decode_uleb128 (p, &p);
+                               char *name;
+                               name = pstrdup ((char*)p);
+                               add_unmanaged_symbol (addr, name, size);
+                               if (debug)
+                                       fprintf (outfile, "unmanaged symbol %s at %p\n", name, (void*)addr);
+                               while (*p) p++;
+                               p++;
+                       } else if (subtype == TYPE_SAMPLE_UBIN) {
+                               /* un unmanaged binary loaded in memory */
+                               uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                               uintptr_t addr = decode_sleb128 (p, &p);
+                               uint64_t offset G_GNUC_UNUSED = decode_uleb128 (p, &p);
+                               uintptr_t size = decode_uleb128 (p, &p);
+                               char *name;
+                               LOG_TIME (time_base, tdiff);
+                               time_base += tdiff;
+                               name = pstrdup ((char*)p);
+                               add_unmanaged_binary (addr, name, size);
+                               if (debug)
+                                       fprintf (outfile, "unmanaged binary %s at %p\n", name, (void*)addr);
+                               while (*p) p++;
+                               p++;
+                       } else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
+                               uint64_t i, len;
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       len = decode_uleb128 (p, &p);
+                               } else
+                                       len = decode_uleb128 (p + 1, &p);
+                               for (i = 0; i < len; i++) {
+                                       uint64_t type, unit, variance, index;
+                                       uint64_t section = decode_uleb128 (p, &p);
+                                       char *section_str, *name;
+                                       if (section != MONO_COUNTER_PERFCOUNTERS) {
+                                               section_str = (char*) section_name (section);
+                                       } else {
+                                               section_str = pstrdup ((char*)p);
+                                               while (*p++);
+                                       }
+                                       name = pstrdup ((char*)p);
+                                       while (*p++);
+                                       if (ctx->data_version > 12) {
+                                               type = *p++;
+                                               unit = *p++;
+                                               variance = *p++;
+                                       } else {
+                                               type = decode_uleb128 (p, &p);
+                                               unit = decode_uleb128 (p, &p);
+                                               variance = decode_uleb128 (p, &p);
+                                       }
+                                       index = decode_uleb128 (p, &p);
+                                       add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
+                               }
+                       } else if (subtype == TYPE_SAMPLE_COUNTERS) {
+                               int i;
+                               CounterValue *value, *previous = NULL;
+                               CounterList *list;
+                               uint64_t timestamp; // milliseconds since startup
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                                       timestamp = (time_base - startup_time) / 1000 / 1000;
+                               } else
+                                       timestamp = decode_uleb128 (p + 1, &p);
+                               uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
+                               while (1) {
+                                       uint64_t type, index = decode_uleb128 (p, &p);
+                                       if (index == 0)
+                                               break;
+
+                                       for (list = counters; list; list = list->next) {
+                                               if (list->counter->index == (int)index) {
+                                                       previous = list->counter->values_last;
+                                                       break;
+                                               }
+                                       }
+
+                                       if (ctx->data_version > 12)
+                                               type = *p++;
+                                       else
+                                               type = decode_uleb128 (p, &p);
+
+                                       value = (CounterValue *) g_calloc (1, sizeof (CounterValue));
+                                       value->timestamp = timestamp;
+
+                                       switch (type) {
+                                       case MONO_COUNTER_INT:
+#if SIZEOF_VOID_P == 4
+                                       case MONO_COUNTER_WORD:
+#endif
+                                               value->buffer = (unsigned char *)g_malloc (sizeof (int32_t));
+                                               *(int32_t*)value->buffer = (int32_t)decode_sleb128 (p, &p) + (previous ? (*(int32_t*)previous->buffer) : 0);
+                                               break;
+                                       case MONO_COUNTER_UINT:
+                                               value->buffer = (unsigned char *) g_malloc (sizeof (uint32_t));
+                                               *(uint32_t*)value->buffer = (uint32_t)decode_uleb128 (p, &p) + (previous ? (*(uint32_t*)previous->buffer) : 0);
+                                               break;
+                                       case MONO_COUNTER_LONG:
+#if SIZEOF_VOID_P == 8
+                                       case MONO_COUNTER_WORD:
+#endif
+                                       case MONO_COUNTER_TIME_INTERVAL:
+                                               value->buffer = (unsigned char *) g_malloc (sizeof (int64_t));
+                                               *(int64_t*)value->buffer = (int64_t)decode_sleb128 (p, &p) + (previous ? (*(int64_t*)previous->buffer) : 0);
+                                               break;
+                                       case MONO_COUNTER_ULONG:
+                                               value->buffer = (unsigned char *) g_malloc (sizeof (uint64_t));
+                                               *(uint64_t*)value->buffer = (uint64_t)decode_uleb128 (p, &p) + (previous ? (*(uint64_t*)previous->buffer) : 0);
+                                               break;
+                                       case MONO_COUNTER_DOUBLE:
+                                               value->buffer = (unsigned char *) g_malloc (sizeof (double));
+#if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
+                                               for (i = 0; i < sizeof (double); i++)
+#else
+                                               for (i = sizeof (double) - 1; i >= 0; i--)
+#endif
+                                                       value->buffer[i] = *p++;
+                                               break;
+                                       case MONO_COUNTER_STRING:
+                                               if (*p++ == 0) {
+                                                       value->buffer = NULL;
+                                               } else {
+                                                       value->buffer = (unsigned char*) pstrdup ((char*)p);
+                                                       while (*p++);
+                                               }
+                                               break;
+                                       }
+                                       if (time_between >= time_from && time_between <= time_to)
+                                               add_counter_value (index, value);
+                               }
+                       } else {
+                               return 0;
+                       }
+                       break;
+               }
+               case TYPE_COVERAGE:{
+                       int subtype = *p & 0xf0;
+                       switch (subtype) {
+                       case TYPE_COVERAGE_METHOD: {
+                               CoverageMethod *method = g_new0 (CoverageMethod, 1);
+                               const char *assembly, *klass, *name, *sig, *filename;
+                               int token, n_offsets, method_id;
+
+                               p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
+                               assembly = (const char *)p; while (*p) p++; p++;
+                               klass = (const char *)p; while (*p) p++; p++;
+                               name = (const char *)p; while (*p) p++; p++;
+                               sig = (const char *)p; while (*p) p++; p++;
+                               filename = (const char *)p; while (*p) p++; p++;
+
+                               token = decode_uleb128 (p, &p);
+                               method_id = decode_uleb128 (p, &p);
+                               n_offsets = decode_uleb128 (p, &p);
+
+                               method->assembly_name = g_strdup (assembly);
+                               method->class_name = g_strdup (klass);
+                               method->method_name = g_strdup (name);
+                               method->method_signature = g_strdup (sig);
+                               method->filename = g_strdup (filename);
+                               method->token = token;
+                               method->n_statements = n_offsets;
+                               method->coverage = g_ptr_array_new ();
+                               method->method_id = method_id;
+
+                               coverage_add_method (method);
+
+                               break;
+                       }
+                       case TYPE_COVERAGE_STATEMENT: {
+                               CoverageCoverage *coverage = g_new0 (CoverageCoverage, 1);
+                               int offset, count, line, column, method_id;
+
+                               p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
+                               method_id = decode_uleb128 (p, &p);
+                               offset = decode_uleb128 (p, &p);
+                               count = decode_uleb128 (p, &p);
+                               line = decode_uleb128 (p, &p);
+                               column = decode_uleb128 (p, &p);
+
+                               coverage->method_id = method_id;
+                               coverage->offset = offset;
+                               coverage->count = count;
+                               coverage->line = line;
+                               coverage->column = column;
+
+                               coverage_add_coverage (coverage);
+                               break;
+                       }
+                       case TYPE_COVERAGE_ASSEMBLY: {
+                               CoverageAssembly *assembly = g_new0 (CoverageAssembly, 1);
+                               char *name, *guid, *filename;
+                               int number_of_methods, fully_covered, partially_covered;
+                               p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
+                               name = (char *)p; while (*p) p++; p++;
+                               guid = (char *)p; while (*p) p++; p++;
+                               filename = (char *)p; while (*p) p++; p++;
+                               number_of_methods = decode_uleb128 (p, &p);
+                               fully_covered = decode_uleb128 (p, &p);
+                               partially_covered = decode_uleb128 (p, &p);
+
+                               assembly->name = g_strdup (name);
+                               assembly->guid = g_strdup (guid);
+                               assembly->filename = g_strdup (filename);
+                               assembly->number_of_methods = number_of_methods;
+                               assembly->fully_covered = fully_covered;
+                               assembly->partially_covered = partially_covered;
+
+                               coverage_add_assembly (assembly);
+                               break;
+                       }
+                       case TYPE_COVERAGE_CLASS: {
+                               CoverageClass *klass = g_new0 (CoverageClass, 1);
+                               char *assembly_name, *class_name;
+                               int number_of_methods, fully_covered, partially_covered;
+                               p++;
+
+                               if (ctx->data_version > 12) {
+                                       uint64_t tdiff = decode_uleb128 (p, &p);
+                                       LOG_TIME (time_base, tdiff);
+                                       time_base += tdiff;
+                               }
+
+                               assembly_name = (char *)p; while (*p) p++; p++;
+                               class_name = (char *)p; while (*p) p++; p++;
+                               number_of_methods = decode_uleb128 (p, &p);
+                               fully_covered = decode_uleb128 (p, &p);
+                               partially_covered = decode_uleb128 (p, &p);
+
+                               klass->assembly_name = g_strdup (assembly_name);
+                               klass->class_name = g_strdup (class_name);
+                               klass->number_of_methods = number_of_methods;
+                               klass->fully_covered = fully_covered;
+                               klass->partially_covered = partially_covered;
+
+                               coverage_add_class (klass);
+                               break;
+                       }
+
+                       default:
+                               break;
+                       }
+                       break;
+               }
+               case TYPE_META: {
+                       int subtype = *p & 0xf0;
+                       uint64_t tdiff = decode_uleb128 (p + 1, &p);
+                       LOG_TIME (time_base, tdiff);
+                       time_base += tdiff;
+                       if (subtype == TYPE_SYNC_POINT) {
+                               int type = *p++;
+                               if (debug)
+                                       fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
+                       }
+                       break;
+               }
+               default:
+                       fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
+                       exit (1);
+               }
+               record_event_stats (event, p - start);
+       }
+       thread->last_time = time_base;
+       for (i = 0; i < thread->stack_id; ++i)
+               thread->stack [i]->recurse_count = 0;
+       return 1;
+}
+
+static int
+read_header_string (ProfContext *ctx, char **field)
+{
+       if (!load_data (ctx, 4))
+               return 0;
+
+       if (!load_data (ctx, read_int32 (ctx->buf)))
+               return 0;
+
+       *field = pstrdup ((const char *) ctx->buf);
+
+       return 1;
+}
+
+static ProfContext*
+load_file (char *name)
+{
+       unsigned char *p;
+       ProfContext *ctx = (ProfContext *) g_calloc (sizeof (ProfContext), 1);
+       if (strcmp (name, "-") == 0)
+               ctx->file = stdin;
+       else
+               ctx->file = fopen (name, "rb");
+       if (!ctx->file) {
+               printf ("Cannot open file: %s\n", name);
+               exit (1);
+       }
+#if defined (HAVE_SYS_ZLIB)
+       if (ctx->file != stdin)
+               ctx->gzfile = gzdopen (fileno (ctx->file), "rb");
+#endif
+       if (!load_data (ctx, 30))
+               return NULL;
+       p = ctx->buf;
+       if (read_int32 (p) != LOG_HEADER_ID || p [6] > LOG_DATA_VERSION)
+               return NULL;
+       ctx->version_major = p [4];
+       ctx->version_minor = p [5];
+       ctx->data_version = p [6];
+       /* reading 64 bit files on 32 bit systems not supported yet */
+       if (p [7] > sizeof (void*))
+               return NULL;
+       if (read_int32 (p + 20)) /* flags must be 0 */
+               return NULL;
+       ctx->startup_time = read_int64 (p + 8);
+       ctx->timer_overhead = read_int32 (p + 16);
+       ctx->pid = read_int32 (p + 24);
+       ctx->port = read_int16 (p + 28);
+       if (ctx->version_major >= 1) {
+               if (!read_header_string (ctx, &ctx->args))
+                       return NULL;
+               if (!read_header_string (ctx, &ctx->arch))
+                       return NULL;
+               if (!read_header_string (ctx, &ctx->os))
+                       return NULL;
+       } else {
+               if (!load_data (ctx, 2)) /* old opsys field, was never used */
+                       return NULL;
+       }
+       return ctx;
+}
+
+enum {
+       ALLOC_SORT_BYTES,
+       ALLOC_SORT_COUNT
+};
+static int alloc_sort_mode = ALLOC_SORT_BYTES;
+
+static int
+compare_class (const void *a, const void *b)
+{
+       ClassDesc *const *A = (ClassDesc *const *)a;
+       ClassDesc *const *B = (ClassDesc *const *)b;
+       uint64_t vala, valb;
+       if (alloc_sort_mode == ALLOC_SORT_BYTES) {
+               vala = (*A)->alloc_size;
+               valb = (*B)->alloc_size;
+       } else {
+               vala = (*A)->allocs;
+               valb = (*B)->allocs;
+       }
+       if (valb == vala)
+               return 0;
+       if (valb < vala)
+               return -1;
+       return 1;
+}
+
+static void
+dump_header (ProfContext *ctx)
+{
+       time_t st = ctx->startup_time / 1000;
+       char *t = ctime (&st);
+       fprintf (outfile, "\nMono log profiler data\n");
+       fprintf (outfile, "\tProfiler version: %d.%d\n", ctx->version_major, ctx->version_minor);
+       fprintf (outfile, "\tData version: %d\n", ctx->data_version);
+       if (ctx->version_major >= 1) {
+               fprintf (outfile, "\tArguments: %s\n", ctx->args);
+               fprintf (outfile, "\tArchitecture: %s\n", ctx->arch);
+               fprintf (outfile, "\tOperating system: %s\n", ctx->os);
+       }
+       fprintf (outfile, "\tMean timer overhead: %d nanoseconds\n", ctx->timer_overhead);
+       fprintf (outfile, "\tProgram startup: %s", t);
+       if (ctx->pid)
+               fprintf (outfile, "\tProgram ID: %d\n", ctx->pid);
+       if (ctx->port)
+               fprintf (outfile, "\tServer listening on: %d\n", ctx->port);
+}
+
+static void
+dump_traces (TraceDesc *traces, const char *desc)
+{
+       int j;
+       if (!show_traces)
+               return;
+       if (!traces->count)
+               return;
+       sort_context_array (traces);
+       for (j = 0; j < traces->count; ++j) {
+               int k;
+               BackTrace *bt;
+               bt = traces->traces [j].bt;
+               if (!bt->count)
+                       continue;
+               fprintf (outfile, "\t%llu %s from:\n", (unsigned long long) traces->traces [j].count, desc);
+               for (k = 0; k < bt->count; ++k)
+                       fprintf (outfile, "\t\t%s\n", bt->methods [k]->name);
+       }
+}
+
+static void
+dump_threads (ProfContext *ctx)
+{
+       ThreadContext *thread;
+       fprintf (outfile, "\nThread summary\n");
+       for (thread = ctx->threads; thread; thread = thread->next) {
+               if (thread->thread_id) {
+                       fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
+               }
+       }
+}
+
+static void
+dump_domains (ProfContext *ctx)
+{
+       fprintf (outfile, "\nDomain summary\n");
+
+       for (DomainContext *domain = ctx->domains; domain; domain = domain->next)
+               fprintf (outfile, "\tDomain: %p, friendly name: \"%s\"\n", (void *) domain->domain_id, domain->friendly_name);
+}
+
+static void
+dump_remctxs (ProfContext *ctx)
+{
+       fprintf (outfile, "\nContext summary\n");
+
+       for (RemCtxContext *remctx = ctx->remctxs; remctx; remctx = remctx->next)
+               fprintf (outfile, "\tContext: %p, domain: %p\n", (void *) remctx->remctx_id, (void *) remctx->domain_id);
+}
+
+static void
+dump_exceptions (void)
+{
+       int i;
+       fprintf (outfile, "\nException summary\n");
+       fprintf (outfile, "\tThrows: %llu\n", (unsigned long long) throw_count);
+       dump_traces (&exc_traces, "throws");
+       for (i = 0; i <= MONO_EXCEPTION_CLAUSE_FAULT; ++i) {
+               if (!clause_summary [i])
+                       continue;
+               fprintf (outfile, "\tExecuted %s clauses: %llu\n", clause_name (i), (unsigned long long) clause_summary [i]);
+       }
+}
+
+static int
+compare_monitor (const void *a, const void *b)
+{
+       MonitorDesc *const *A = (MonitorDesc *const *)a;
+       MonitorDesc *const *B = (MonitorDesc *const *)b;
+       if ((*B)->wait_time == (*A)->wait_time)
+               return 0;
+       if ((*B)->wait_time < (*A)->wait_time)
+               return -1;
+       return 1;
+}
+
+static void
+dump_monitors (void)
+{
+       MonitorDesc **monitors;
+       int i, j;
+       if (!num_monitors)
+               return;
+       monitors = (MonitorDesc **) g_malloc (sizeof (void*) * num_monitors);
+       for (i = 0, j = 0; i < SMALL_HASH_SIZE; ++i) {
+               MonitorDesc *mdesc = monitor_hash [i];
+               while (mdesc) {
+                       monitors [j++] = mdesc;
+                       mdesc = mdesc->next;
+               }
+       }
+       qsort (monitors, num_monitors, sizeof (void*), compare_monitor);
+       fprintf (outfile, "\nMonitor lock summary\n");
+       for (i = 0; i < num_monitors; ++i) {
+               MonitorDesc *mdesc = monitors [i];
+               fprintf (outfile, "\tLock object %p: %d contentions\n", (void*)mdesc->objid, (int)mdesc->contentions);
+               fprintf (outfile, "\t\t%.6f secs total wait time, %.6f max, %.6f average\n",
+                       mdesc->wait_time/1000000000.0, mdesc->max_wait_time/1000000000.0, mdesc->wait_time/1000000000.0/mdesc->contentions);
+               dump_traces (&mdesc->traces, "contentions");
+       }
+       fprintf (outfile, "\tLock contentions: %llu\n", (unsigned long long) monitor_contention);
+       fprintf (outfile, "\tLock acquired: %llu\n", (unsigned long long) monitor_acquired);
+       fprintf (outfile, "\tLock failures: %llu\n", (unsigned long long) monitor_failed);
+}
+
+static void
+dump_gcs (void)
+{
+       int i;
+       fprintf (outfile, "\nGC summary\n");
+       fprintf (outfile, "\tGC resizes: %d\n", gc_resizes);
+       fprintf (outfile, "\tMax heap size: %llu\n", (unsigned long long) max_heap_size);
+       fprintf (outfile, "\tObject moves: %llu\n", (unsigned long long) gc_object_moves);
+       for (i = 0; i < 3; ++i) {
+               if (!gc_info [i].count)
+                       continue;
+               fprintf (outfile, "\tGen%d collections: %d, max time: %lluus, total time: %lluus, average: %lluus\n",
+                       i, gc_info [i].count,
+                       (unsigned long long) (gc_info [i].max_time / 1000),
+                       (unsigned long long) (gc_info [i].total_time / 1000),
+                       (unsigned long long) (gc_info [i].total_time / gc_info [i].count / 1000));
+       }
+       for (i = 0; i < 3; ++i) {
+               if (!handle_info [i].max_live)
+                       continue;
+               fprintf (outfile, "\tGC handles %s: created: %llu, destroyed: %llu, max: %llu\n",
+                       get_handle_name (i),
+                       (unsigned long long) (handle_info [i].created),
+                       (unsigned long long) (handle_info [i].destroyed),
+                       (unsigned long long) (handle_info [i].max_live));
+               dump_traces (&handle_info [i].traces, "created");
+               dump_traces (&handle_info [i].destroy_traces, "destroyed");
+       }
+}
+
+static void
+dump_jit (void)
+{
+       int i;
+       int code_size = 0;
+       int compiled_methods = 0;
+       MethodDesc* m;
+       fprintf (outfile, "\nJIT summary\n");
+       for (i = 0; i < HASH_SIZE; ++i) {
+               m = method_hash [i];
+               for (m = method_hash [i]; m; m = m->next) {
+                       if (!m->code || m->ignore_jit)
+                               continue;
+                       compiled_methods++;
+                       code_size += m->len;
+               }
+       }
+       fprintf (outfile, "\tCompiled methods: %d\n", compiled_methods);
+       fprintf (outfile, "\tGenerated code size: %d\n", code_size);
+       fprintf (outfile, "\tJIT helpers: %d\n", num_jit_helpers);
+       fprintf (outfile, "\tJIT helpers code size: %d\n", jit_helpers_code_size);
+}
+
+static void
+dump_allocations (void)
+{
+       int i, c;
+       intptr_t allocs = 0;
+       uint64_t size = 0;
+       int header_done = 0;
+       ClassDesc **classes = (ClassDesc **) g_malloc (num_classes * sizeof (void*));
+       ClassDesc *cd;
+       c = 0;
+       for (i = 0; i < HASH_SIZE; ++i) {
+               cd = class_hash [i];
+               while (cd) {
+                       classes [c++] = cd;
+                       cd = cd->next;
+               }
+       }
+       qsort (classes, num_classes, sizeof (void*), compare_class);
+       for (i = 0; i < num_classes; ++i) {
+               cd = classes [i];
+               if (!cd->allocs)
+                       continue;
+               allocs += cd->allocs;
+               size += cd->alloc_size;
+               if (!header_done++) {
+                       fprintf (outfile, "\nAllocation summary\n");
+                       fprintf (outfile, "%10s %10s %8s Type name\n", "Bytes", "Count", "Average");
+               }
+               fprintf (outfile, "%10llu %10zd %8llu %s\n",
+                       (unsigned long long) (cd->alloc_size),
+                       cd->allocs,
+                       (unsigned long long) (cd->alloc_size / cd->allocs),
+                       cd->name);
+               dump_traces (&cd->traces, "bytes");
+       }
+       if (allocs)
+               fprintf (outfile, "Total memory allocated: %llu bytes in %zd objects\n", (unsigned long long) size, allocs);
+}
+
+enum {
+       METHOD_SORT_TOTAL,
+       METHOD_SORT_SELF,
+       METHOD_SORT_CALLS
+};
+
+static int method_sort_mode = METHOD_SORT_TOTAL;
+
+static int
+compare_method (const void *a, const void *b)
+{
+       MethodDesc *const *A = (MethodDesc *const *)a;
+       MethodDesc *const *B = (MethodDesc *const *)b;
+       uint64_t vala, valb;
+       if (method_sort_mode == METHOD_SORT_SELF) {
+               vala = (*A)->self_time;
+               valb = (*B)->self_time;
+       } else if (method_sort_mode == METHOD_SORT_CALLS) {
+               vala = (*A)->calls;
+               valb = (*B)->calls;
+       } else {
+               vala = (*A)->total_time;
+               valb = (*B)->total_time;
+       }
+       if (vala == valb)
+               return 0;
+       if (valb < vala)
+               return -1;
+       return 1;
+}
+
+static void
+dump_metadata (void)
+{
+       fprintf (outfile, "\nMetadata summary\n");
+       fprintf (outfile, "\tLoaded images: %d\n", num_images);
+       if (verbose) {
+               ImageDesc *image;
+               int i;
+               for (i = 0; i < SMALL_HASH_SIZE; ++i) {
+                       image = image_hash [i];
+                       while (image) {
+                               fprintf (outfile, "\t\t%s\n", image->filename);
+                               image = image->next;
+                       }
+               }
+       }
+       fprintf (outfile, "\tLoaded assemblies: %d\n", num_assemblies);
+       if (verbose) {
+               AssemblyDesc *assembly;
+               int i;
+               for (i = 0; i < SMALL_HASH_SIZE; ++i) {
+                       assembly = assembly_hash [i];
+                       while (assembly) {
+                               fprintf (outfile, "\t\t%s\n", assembly->asmname);
+                               assembly = assembly->next;
+                       }
+               }
+       }
+}
+
+static void
+dump_methods (void)
+{
+       int i, c;
+       uint64_t calls = 0;
+       int header_done = 0;
+       MethodDesc **methods = (MethodDesc **) g_malloc (num_methods * sizeof (void*));
+       MethodDesc *cd;
+       c = 0;
+       for (i = 0; i < HASH_SIZE; ++i) {
+               cd = method_hash [i];
+               while (cd) {
+                       cd->total_time = cd->self_time + cd->callee_time;
+                       methods [c++] = cd;
+                       cd = cd->next;
+               }
+       }
+       qsort (methods, num_methods, sizeof (void*), compare_method);
+       for (i = 0; i < num_methods; ++i) {
+               uint64_t msecs;
+               uint64_t smsecs;
+               cd = methods [i];
+               if (!cd->calls)
+                       continue;
+               calls += cd->calls;
+               msecs = cd->total_time / 1000000;
+               smsecs = (cd->total_time - cd->callee_time) / 1000000;
+               if (!msecs && !verbose)
+                       continue;
+               if (!header_done++) {
+                       fprintf (outfile, "\nMethod call summary\n");
+                       fprintf (outfile, "%8s %8s %10s Method name\n", "Total(ms)", "Self(ms)", "Calls");
+               }
+               fprintf (outfile, "%8llu %8llu %10llu %s\n",
+                       (unsigned long long) (msecs),
+                       (unsigned long long) (smsecs),
+                       (unsigned long long) (cd->calls),
+                       cd->name);
+               dump_traces (&cd->traces, "calls");
+       }
+       if (calls)
+               fprintf (outfile, "Total calls: %llu\n", (unsigned long long) calls);
+}
+
+static int
+compare_heap_class (const void *a, const void *b)
+{
+       HeapClassDesc *const *A = (HeapClassDesc *const *)a;
+       HeapClassDesc *const *B = (HeapClassDesc *const *)b;
+       uint64_t vala, valb;
+       if (alloc_sort_mode == ALLOC_SORT_BYTES) {
+               vala = (*A)->total_size;
+               valb = (*B)->total_size;
+       } else {
+               vala = (*A)->count;
+               valb = (*B)->count;
+       }
+       if (valb == vala)
+               return 0;
+       if (valb < vala)
+               return -1;
+       return 1;
+}
+
+static int
+compare_rev_class (const void *a, const void *b)
+{
+       const HeapClassRevRef *A = (const HeapClassRevRef *)a;
+       const HeapClassRevRef *B = (const HeapClassRevRef *)b;
+       if (B->count == A->count)
+               return 0;
+       if (B->count < A->count)
+               return -1;
+       return 1;
+}
+
+static void
+dump_rev_claases (HeapClassRevRef *revs, int count)
+{
+       int j;
+       if (!show_traces)
+               return;
+       if (!count)
+               return;
+       for (j = 0; j < count; ++j) {
+               HeapClassDesc *cd = revs [j].klass;
+               fprintf (outfile, "\t\t%llu references from: %s\n",
+                       (unsigned long long) (revs [j].count),
+                       cd->klass->name);
+       }
+}
+
+static void
+heap_shot_summary (HeapShot *hs, int hs_num, HeapShot *last_hs)
+{
+       uint64_t size = 0;
+       uint64_t count = 0;
+       int ccount = 0;
+       int i;
+       HeapClassDesc *cd;
+       HeapClassDesc **sorted;
+       sorted = (HeapClassDesc **) g_malloc (sizeof (void*) * hs->class_count);
+       for (i = 0; i < hs->hash_size; ++i) {
+               cd = hs->class_hash [i];
+               if (!cd)
+                       continue;
+               count += cd->count;
+               size += cd->total_size;
+               sorted [ccount++] = cd;
+       }
+       hs->sorted = sorted;
+       qsort (sorted, ccount, sizeof (void*), compare_heap_class);
+       fprintf (outfile, "\n\tHeap shot %d at %.3f secs: size: %llu, object count: %llu, class count: %d, roots: %zd\n",
+               hs_num,
+               (hs->timestamp - startup_time)/1000000000.0,
+               (unsigned long long) (size),
+               (unsigned long long) (count),
+               ccount, hs->num_roots);
+       if (!verbose && ccount > 30)
+               ccount = 30;
+       fprintf (outfile, "\t%10s %10s %8s Class name\n", "Bytes", "Count", "Average");
+       for (i = 0; i < ccount; ++i) {
+               HeapClassRevRef *rev_sorted;
+               int j, k;
+               HeapClassDesc *ocd = NULL;
+               cd = sorted [i];
+               if (last_hs)
+                       ocd = heap_class_lookup (last_hs, cd->klass);
+               fprintf (outfile, "\t%10llu %10llu %8llu %s",
+                       (unsigned long long) (cd->total_size),
+                       (unsigned long long) (cd->count),
+                       (unsigned long long) (cd->total_size / cd->count),
+                       cd->klass->name);
+               if (ocd) {
+                       int64_t bdiff = cd->total_size - ocd->total_size;
+                       int64_t cdiff = cd->count - ocd->count;
+                       fprintf (outfile, " (bytes: %+lld, count: %+lld)\n", (long long) bdiff, (long long) cdiff);
+               } else {
+                       fprintf (outfile, "\n");
+               }
+               if (!collect_traces)
+                       continue;
+               rev_sorted = (HeapClassRevRef *) g_malloc (cd->rev_count * sizeof (HeapClassRevRef));
+               k = 0;
+               for (j = 0; j < cd->rev_hash_size; ++j) {
+                       if (cd->rev_hash [j].klass)
+                               rev_sorted [k++] = cd->rev_hash [j];
+               }
+               assert (cd->rev_count == k);
+               qsort (rev_sorted, cd->rev_count, sizeof (HeapClassRevRef), compare_rev_class);
+               if (cd->root_references)
+                       fprintf (outfile, "\t\t%zd root references (%zd pinning)\n", cd->root_references, cd->pinned_references);
+               dump_rev_claases (rev_sorted, cd->rev_count);
+               g_free (rev_sorted);
+       }
+       g_free (sorted);
+}
+
+static int
+compare_heap_shots (const void *a, const void *b)
+{
+       HeapShot *const *A = (HeapShot *const *)a;
+       HeapShot *const *B = (HeapShot *const *)b;
+       if ((*B)->timestamp == (*A)->timestamp)
+               return 0;
+       if ((*B)->timestamp > (*A)->timestamp)
+               return -1;
+       return 1;
+}
+
+static void
+dump_heap_shots (void)
+{
+       HeapShot **hs_sorted;
+       HeapShot *hs;
+       HeapShot *last_hs = NULL;
+       int i;
+       if (!heap_shots)
+               return;
+       hs_sorted = (HeapShot **) g_malloc (num_heap_shots * sizeof (void*));
+       fprintf (outfile, "\nHeap shot summary\n");
+       i = 0;
+       for (hs = heap_shots; hs; hs = hs->next)
+               hs_sorted [i++] = hs;
+       qsort (hs_sorted, num_heap_shots, sizeof (void*), compare_heap_shots);
+       for (i = 0; i < num_heap_shots; ++i) {
+               hs = hs_sorted [i];
+               heap_shot_summary (hs, i, last_hs);
+               last_hs = hs;
+       }
+}
+
+/* This is a very basic escape function that escapes < > and &
+   Ideally we'd use g_markup_escape_string but that function isn't
+        available in Mono's eglib. This was written without looking at the
+        source of that function in glib. */
+static char *
+escape_string_for_xml (const char *string)
+{
+       GString *string_builder = g_string_new (NULL);
+       const char *start, *p;
+
+       start = p = string;
+       while (*p) {
+               while (*p && *p != '&' && *p != '<' && *p != '>')
+                       p++;
+
+               g_string_append_len (string_builder, start, p - start);
+
+               if (*p == '\0')
+                       break;
+
+               switch (*p) {
+               case '<':
+                       g_string_append (string_builder, "&lt;");
+                       break;
+
+               case '>':
+                       g_string_append (string_builder, "&gt;");
+                       break;
+
+               case '&':
+                       g_string_append (string_builder, "&amp;");
+                       break;
+
+               default:
+                       break;
+               }
+
+               p++;
+               start = p;
+       }
+
+       return g_string_free (string_builder, FALSE);
+}
+
+static int
+sort_assemblies (gconstpointer a, gconstpointer b)
+{
+       CoverageAssembly *assembly_a = *(CoverageAssembly **)a;
+       CoverageAssembly *assembly_b = *(CoverageAssembly **)b;
+
+       if (assembly_a->name == NULL && assembly_b->name == NULL)
+               return 0;
+       else if (assembly_a->name == NULL)
+               return -1;
+       else if (assembly_b->name == NULL)
+               return 1;
+
+       return strcmp (assembly_a->name, assembly_b->name);
+}
+
+static void
+dump_coverage (void)
+{
+       if (!coverage_methods && !coverage_assemblies)
+               return;
+
+       gather_coverage_statements ();
+       fprintf (outfile, "\nCoverage Summary:\n");
+
+       if (coverage_outfile) {
+               fprintf (coverage_outfile, "<?xml version=\"1.0\"?>\n");
+               fprintf (coverage_outfile, "<coverage version=\"0.3\">\n");
+       }
+
+       g_ptr_array_sort (coverage_assemblies, sort_assemblies);
+
+       for (guint i = 0; i < coverage_assemblies->len; i++) {
+               CoverageAssembly *assembly = (CoverageAssembly *)coverage_assemblies->pdata[i];
+               GPtrArray *classes;
+
+               if (assembly->number_of_methods != 0) {
+                       int percentage = ((assembly->fully_covered + assembly->partially_covered) * 100) / assembly->number_of_methods;
+                       fprintf (outfile, "\t%s (%s) %d%% covered (%d methods - %d covered)\n", assembly->name, assembly->filename, percentage, assembly->number_of_methods, assembly->fully_covered);
+               } else
+                       fprintf (outfile, "\t%s (%s) ?%% covered (%d methods - %d covered)\n", assembly->name, assembly->filename, assembly->number_of_methods, assembly->fully_covered);
+
+               if (coverage_outfile) {
+                       char *escaped_name, *escaped_filename;
+                       escaped_name = escape_string_for_xml (assembly->name);
+                       escaped_filename = escape_string_for_xml (assembly->filename);
+
+                       fprintf (coverage_outfile, "\t<assembly name=\"%s\" guid=\"%s\" filename=\"%s\" method-count=\"%d\" full=\"%d\" partial=\"%d\"/>\n", escaped_name, assembly->guid, escaped_filename, assembly->number_of_methods, assembly->fully_covered, assembly->partially_covered);
+
+                       g_free (escaped_name);
+                       g_free (escaped_filename);
+               }
+
+               classes = (GPtrArray *)g_hash_table_lookup (coverage_assembly_classes, assembly->name);
+               if (classes) {
+                       for (guint j = 0; j < classes->len; j++) {
+                               CoverageClass *klass = (CoverageClass *)classes->pdata [j];
+
+                               if (klass->number_of_methods > 0) {
+                                       int percentage = ((klass->fully_covered + klass->partially_covered) * 100) / klass->number_of_methods;
+                                       fprintf (outfile, "\t\t%s %d%% covered (%d methods - %d covered)\n", klass->class_name, percentage, klass->number_of_methods, klass->fully_covered);
+                               } else
+                                       fprintf (outfile, "\t\t%s ?%% covered (%d methods - %d covered)\n", klass->class_name, klass->number_of_methods, klass->fully_covered);
+
+                               if (coverage_outfile) {
+                                       char *escaped_name;
+                                       escaped_name = escape_string_for_xml (klass->class_name);
+
+                                       fprintf (coverage_outfile, "\t\t<class name=\"%s\" method-count=\"%d\" full=\"%d\" partial=\"%d\"/>\n", escaped_name, klass->number_of_methods, klass->fully_covered, klass->partially_covered);
+                                       g_free (escaped_name);
+                               }
+                       }
+               }
+       }
+
+       for (guint i = 0; i < coverage_methods->len; i++) {
+               CoverageMethod *method = (CoverageMethod *)coverage_methods->pdata [i];
+
+               if (coverage_outfile) {
+                       char *escaped_assembly, *escaped_class, *escaped_method, *escaped_sig, *escaped_filename;
+
+                       escaped_assembly = escape_string_for_xml (method->assembly_name);
+                       escaped_class = escape_string_for_xml (method->class_name);
+                       escaped_method = escape_string_for_xml (method->method_name);
+                       escaped_sig = escape_string_for_xml (method->method_signature);
+                       escaped_filename = escape_string_for_xml (method->filename);
+
+                       fprintf (coverage_outfile, "\t<method assembly=\"%s\" class=\"%s\" name=\"%s (%s)\" filename=\"%s\" token=\"%d\">\n", escaped_assembly, escaped_class, escaped_method, escaped_sig, escaped_filename, method->token);
+
+                       g_free (escaped_assembly);
+                       g_free (escaped_class);
+                       g_free (escaped_method);
+                       g_free (escaped_sig);
+                       g_free (escaped_filename);
+
+                       for (guint j = 0; j < method->coverage->len; j++) {
+                               CoverageCoverage *coverage = (CoverageCoverage *)method->coverage->pdata [j];
+                               fprintf (coverage_outfile, "\t\t<statement offset=\"%d\" counter=\"%d\" line=\"%d\" column=\"%d\"/>\n", coverage->offset, coverage->count, coverage->line, coverage->column);
+                       }
+                       fprintf (coverage_outfile, "\t</method>\n");
+               }
+       }
+
+       if (coverage_outfile) {
+               fprintf (coverage_outfile, "</coverage>\n");
+               fclose (coverage_outfile);
+               coverage_outfile = NULL;
+       }
+}
+
+#define DUMP_EVENT_STAT(EVENT,SUBTYPE) dump_event (#EVENT, #SUBTYPE, EVENT, SUBTYPE);
+
+static void
+dump_event (const char *event_name, const char *subtype_name, int event, int subtype)
+{
+       int idx = event | subtype;
+       EventStat evt = stats [idx];
+       if (!evt.count)
+               return;
+
+       fprintf (outfile, "\t%16s\t%26s\tcount %6d\tmin %3d\tmax %6d\tbytes %d\n", event_name, subtype_name, evt.count, evt.min_size, evt.max_size, evt.bytes);
+}
+
+static void
+dump_stats (void)
+{
+       fprintf (outfile, "\nMlpd statistics\n");
+       fprintf (outfile, "\tBuffer count %d\toverhead %d (%d bytes per header)\n", buffer_count, buffer_count * BUFFER_HEADER_SIZE, BUFFER_HEADER_SIZE);
+       fprintf (outfile, "\nEvent details:\n");
+
+       DUMP_EVENT_STAT (TYPE_ALLOC, TYPE_ALLOC_NO_BT);
+       DUMP_EVENT_STAT (TYPE_ALLOC, TYPE_ALLOC_BT);
+
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_EVENT);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_RESIZE);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_MOVE);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_CREATED);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_DESTROYED);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_CREATED_BT);
+       DUMP_EVENT_STAT (TYPE_GC, TYPE_GC_HANDLE_DESTROYED_BT);
+
+       DUMP_EVENT_STAT (TYPE_METADATA, TYPE_END_LOAD);
+       DUMP_EVENT_STAT (TYPE_METADATA, TYPE_END_UNLOAD);
+
+       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_LEAVE);
+       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_ENTER);
+       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_EXC_LEAVE);
+       DUMP_EVENT_STAT (TYPE_METHOD, TYPE_JIT);
+
+       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_NO_BT);
+       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_THROW_BT);
+       DUMP_EVENT_STAT (TYPE_EXCEPTION, TYPE_CLAUSE);
+
+       DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_NO_BT);
+       DUMP_EVENT_STAT (TYPE_MONITOR, TYPE_MONITOR_BT);
+
+       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_START);
+       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_END);
+       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_OBJECT);
+       DUMP_EVENT_STAT (TYPE_HEAP, TYPE_HEAP_ROOT);
+
+       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_HIT);
+       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_USYM);
+       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_UBIN);
+       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_COUNTERS_DESC);
+       DUMP_EVENT_STAT (TYPE_SAMPLE, TYPE_SAMPLE_COUNTERS);
+
+       DUMP_EVENT_STAT (TYPE_RUNTIME, TYPE_JITHELPER);
+
+       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_ASSEMBLY);
+       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
+       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
+       DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
+
+       DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
+}
+
+
+
+static void
+flush_context (ProfContext *ctx)
+{
+       ThreadContext *thread;
+       /* FIXME: sometimes there are leftovers: indagate */
+       for (thread = ctx->threads; thread; thread = thread->next) {
+               while (thread->stack_id) {
+                       if (debug)
+                               fprintf (outfile, "thread %p has %d items on stack\n", (void*)thread->thread_id, thread->stack_id);
+                       pop_method (thread, thread->stack [thread->stack_id - 1], thread->last_time);
+               }
+       }
+}
+
+static const char *reports = "header,jit,gc,sample,alloc,call,metadata,exception,monitor,thread,heapshot,counters,coverage";
+
+static const char*
+match_option (const char *p, const char *opt)
+{
+       int len = strlen (opt);
+       if (strncmp (p, opt, len) == 0) {
+               if (p [len] == ',')
+                       len++;
+               return p + len;
+       }
+       return p;
+}
+
+static int
+print_reports (ProfContext *ctx, const char *reps, int parse_only)
+{
+       const char *opt;
+       const char *p;
+       for (p = reps; *p; p = opt) {
+               if ((opt = match_option (p, "header")) != p) {
+                       if (!parse_only)
+                               dump_header (ctx);
+                       continue;
+               }
+               if ((opt = match_option (p, "thread")) != p) {
+                       if (!parse_only)
+                               dump_threads (ctx);
+                       continue;
+               }
+               if ((opt = match_option (p, "domain")) != p) {
+                       if (!parse_only)
+                               dump_domains (ctx);
+                       continue;
+               }
+               if ((opt = match_option (p, "context")) != p) {
+                       if (!parse_only)
+                               dump_remctxs (ctx);
+                       continue;
+               }
+               if ((opt = match_option (p, "gc")) != p) {
+                       if (!parse_only)
+                               dump_gcs ();
+                       continue;
+               }
+               if ((opt = match_option (p, "jit")) != p) {
+                       if (!parse_only)
+                               dump_jit ();
+                       continue;
+               }
+               if ((opt = match_option (p, "alloc")) != p) {
+                       if (!parse_only)
+                               dump_allocations ();
+                       continue;
+               }
+               if ((opt = match_option (p, "call")) != p) {
+                       if (!parse_only)
+                               dump_methods ();
+                       continue;
+               }
+               if ((opt = match_option (p, "metadata")) != p) {
+                       if (!parse_only)
+                               dump_metadata ();
+                       continue;
+               }
+               if ((opt = match_option (p, "exception")) != p) {
+                       if (!parse_only)
+                               dump_exceptions ();
+                       continue;
+               }
+               if ((opt = match_option (p, "monitor")) != p) {
+                       if (!parse_only)
+                               dump_monitors ();
+                       continue;
+               }
+               if ((opt = match_option (p, "heapshot")) != p) {
+                       if (!parse_only)
+                               dump_heap_shots ();
+                       continue;
+               }
+               if ((opt = match_option (p, "sample")) != p) {
+                       if (!parse_only)
+                               dump_samples ();
+                       continue;
+               }
+               if ((opt = match_option (p, "counters")) != p) {
+                       if (!parse_only)
+                               dump_counters ();
+                       continue;
+               }
+               if ((opt = match_option (p, "coverage")) != p) {
+                       if (!parse_only)
+                               dump_coverage ();
+                       continue;
+               }
+               if ((opt = match_option (p, "stats")) != p) {
+                       if (!parse_only)
+                               dump_stats ();
+                       continue;
+               }
+               return 0;
+       }
+       return 1;
+}
+
+static int
+add_find_spec (const char *p)
+{
+       if (p [0] == 'S' && p [1] == ':') {
+               char *vale;
+               find_size = strtoul (p + 2, &vale, 10);
+               return 1;
+       } else if (p [0] == 'T' && p [1] == ':') {
+               find_name = p + 2;
+               return 1;
+       }
+       return 0;
+}
+
+static void
+usage (void)
+{
+       printf ("Mono log profiler report version %d.%d\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR);
+       printf ("Usage: mprof-report [OPTIONS] FILENAME\n");
+       printf ("FILENAME can be '-' to read from standard input.\n");
+       printf ("Options:\n");
+       printf ("\t--help               display this help\n");
+       printf ("\t--out=FILE           write to FILE instead of stdout\n");
+       printf ("\t--traces             collect and show backtraces\n");
+       printf ("\t--maxframes=NUM      limit backtraces to NUM entries\n");
+       printf ("\t--reports=R1[,R2...] print the specified reports. Defaults are:\n");
+       printf ("\t                     %s\n", reports);
+       printf ("\t--method-sort=MODE   sort methods according to MODE: total, self, calls\n");
+       printf ("\t--alloc-sort=MODE    sort allocations according to MODE: bytes, count\n");
+       printf ("\t--counters-sort=MODE sort counters according to MODE: time, category\n");
+       printf ("\t                     only accessible in verbose mode\n");
+       printf ("\t--track=OB1[,OB2...] track what happens to objects OBJ1, O2 etc.\n");
+       printf ("\t--find=FINDSPEC      find and track objects matching FINFSPEC, where FINDSPEC is:\n");
+       printf ("\t                     S:minimum_size or T:partial_name\n");
+       printf ("\t--thread=THREADID    consider just the data for thread THREADID\n");
+       printf ("\t--time=FROM-TO       consider data FROM seconds from startup up to TO seconds\n");
+       printf ("\t--verbose            increase verbosity level\n");
+       printf ("\t--debug              display decoding debug info for mprof-report devs\n");
+       printf ("\t--coverage-out=FILE  write the coverage info to FILE as XML\n");
+}
+
+int
+main (int argc, char *argv[])
+{
+       ProfContext *ctx;
+       int i;
+       outfile = stdout;
+       for (i = 1; i < argc; ++i) {
+               if (strcmp ("--debug", argv [i]) == 0) {
+                       debug++;
+               } else if (strcmp ("--help", argv [i]) == 0) {
+                       usage ();
+                       return 0;
+               } else if (strncmp ("--alloc-sort=", argv [i], 13) == 0) {
+                       const char *val = argv [i] + 13;
+                       if (strcmp (val, "bytes") == 0) {
+                               alloc_sort_mode = ALLOC_SORT_BYTES;
+                       } else if (strcmp (val, "count") == 0) {
+                               alloc_sort_mode = ALLOC_SORT_COUNT;
+                       } else {
+                               usage ();
+                               return 1;
+                       }
+               } else if (strncmp ("--method-sort=", argv [i], 14) == 0) {
+                       const char *val = argv [i] + 14;
+                       if (strcmp (val, "total") == 0) {
+                               method_sort_mode = METHOD_SORT_TOTAL;
+                       } else if (strcmp (val, "self") == 0) {
+                               method_sort_mode = METHOD_SORT_SELF;
+                       } else if (strcmp (val, "calls") == 0) {
+                               method_sort_mode = METHOD_SORT_CALLS;
+                       } else {
+                               usage ();
+                               return 1;
+                       }
+               } else if (strncmp ("--counters-sort=", argv [i], 16) == 0) {
+                       const char *val = argv [i] + 16;
+                       if (strcmp (val, "time") == 0) {
+                               counters_sort_mode = COUNTERS_SORT_TIME;
+                       } else if (strcmp (val, "category") == 0) {
+                               counters_sort_mode = COUNTERS_SORT_CATEGORY;
+                       } else {
+                               usage ();
+                               return 1;
+                       }
+               } else if (strncmp ("--reports=", argv [i], 10) == 0) {
+                       const char *val = argv [i] + 10;
+                       if (!print_reports (NULL, val, 1)) {
+                               usage ();
+                               return 1;
+                       }
+                       reports = val;
+               } else if (strncmp ("--out=", argv [i], 6) == 0) {
+                       const char *val = argv [i] + 6;
+                       outfile = fopen (val, "w");
+                       if (!outfile) {
+                               printf ("Cannot open output file: %s\n", val);
+                               return 1;
+                       }
+               } else if (strncmp ("--maxframes=", argv [i], 12) == 0) {
+                       const char *val = argv [i] + 12;
+                       char *vale;
+                       trace_max = strtoul (val, &vale, 10);
+               } else if (strncmp ("--find=", argv [i], 7) == 0) {
+                       const char *val = argv [i] + 7;
+                       if (!add_find_spec (val)) {
+                               usage ();
+                               return 1;
+                       }
+               } else if (strncmp ("--track=", argv [i], 8) == 0) {
+                       const char *val = argv [i] + 8;
+                       char *vale;
+                       while (*val) {
+                               uintptr_t tracked_obj;
+                               if (*val == ',') {
+                                       val++;
+                                       continue;
+                               }
+                               tracked_obj = strtoul (val, &vale, 0);
+                               found_object (tracked_obj);
+                               val = vale;
+                       }
+               } else if (strncmp ("--thread=", argv [i], 9) == 0) {
+                       const char *val = argv [i] + 9;
+                       char *vale;
+                       thread_filter = strtoul (val, &vale, 0);
+               } else if (strncmp ("--time=", argv [i], 7) == 0) {
+                       char *val = pstrdup (argv [i] + 7);
+                       double from_secs, to_secs;
+                       char *top = strchr (val, '-');
+                       if (!top) {
+                               usage ();
+                               return 1;
+                       }
+                       *top++ = 0;
+                       from_secs = atof (val);
+                       to_secs = atof (top);
+                       g_free (val);
+                       if (from_secs > to_secs) {
+                               usage ();
+                               return 1;
+                       }
+                       time_from = from_secs * 1000000000;
+                       time_to = to_secs * 1000000000;
+                       use_time_filter = 1;
+               } else if (strcmp ("--verbose", argv [i]) == 0) {
+                       verbose++;
+               } else if (strcmp ("--traces", argv [i]) == 0) {
+                       show_traces = 1;
+                       collect_traces = 1;
+               } else if (strncmp ("--coverage-out=", argv [i], 15) == 0) {
+                       const char *val = argv [i] + 15;
+                       coverage_outfile = fopen (val, "w");
+                       if (!coverage_outfile) {
+                               printf ("Cannot open output file: %s\n", val);
+                               return 1;
+                       }
+               } else {
+                       break;
+               }
+       }
+       if (i >= argc) {
+               usage ();
+               return 2;
+       }
+       ctx = load_file (argv [i]);
+       if (!ctx) {
+               printf ("Not a log profiler data file (or unsupported version).\n");
+               return 1;
+       }
+       while (decode_buffer (ctx));
+       flush_context (ctx);
+       if (num_tracked_objects)
+               return 0;
+       print_reports (ctx, reports, 0);
+       return 0;
+}
diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c
deleted file mode 100644 (file)
index 17f4383..0000000
+++ /dev/null
@@ -1,5394 +0,0 @@
-/*
- * proflog.c: mono log profiler
- *
- * Authors:
- *   Paolo Molaro (lupus@ximian.com)
- *   Alex Rønne Petersen (alexrp@xamarin.com)
- *
- * Copyright 2010 Novell, Inc (http://www.novell.com)
- * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-
-#include <config.h>
-#include "../mini/jit.h"
-#include "../metadata/metadata-internals.h"
-#include <mono/metadata/profiler.h>
-#include <mono/metadata/threads.h>
-#include <mono/metadata/debug-helpers.h>
-#include <mono/metadata/mono-config.h>
-#include <mono/metadata/mono-gc.h>
-#include <mono/metadata/mono-perfcounters.h>
-#include <mono/metadata/appdomain.h>
-#include <mono/metadata/assembly.h>
-#include <mono/metadata/tokentype.h>
-#include <mono/metadata/tabledefs.h>
-#include <mono/utils/atomic.h>
-#include <mono/utils/mono-membar.h>
-#include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-counters.h>
-#include <mono/utils/mono-os-mutex.h>
-#include <mono/utils/mono-os-semaphore.h>
-#include <mono/utils/mono-conc-hashtable.h>
-#include <mono/utils/mono-linked-list-set.h>
-#include <mono/utils/lock-free-alloc.h>
-#include <mono/utils/lock-free-queue.h>
-#include <mono/utils/hazard-pointer.h>
-#include <mono/utils/mono-threads.h>
-#include <mono/utils/mono-threads-api.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <glib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SCHED_GETAFFINITY
-#include <sched.h>
-#endif
-#include <fcntl.h>
-#include <errno.h>
-#if defined(HOST_WIN32) || defined(DISABLE_SOCKETS)
-#define DISABLE_HELPER_THREAD 1
-#endif
-
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
-#ifdef HAVE_DLFCN_H
-#include <dlfcn.h>
-#endif
-#ifdef HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
-#ifdef HAVE_LINK_H
-#include <link.h>
-#endif
-
-#ifndef DISABLE_HELPER_THREAD
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/select.h>
-#endif
-
-#ifdef HOST_WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#include "utils.c"
-#include "proflog.h"
-
-#if defined (HAVE_SYS_ZLIB)
-#include <zlib.h>
-#endif
-
-#if defined(__linux__)
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#ifdef ENABLE_PERF_EVENTS
-#include <linux/perf_event.h>
-
-#define USE_PERF_EVENTS 1
-
-static int read_perf_mmap (MonoProfiler* prof, int cpu);
-#endif
-
-#endif
-
-#define BUFFER_SIZE (4096 * 16)
-
-/* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
-#define LEB128_SIZE 10
-/* Size of a value encoded as a single byte. */
-#define BYTE_SIZE 1
-/* Size in bytes of the event prefix (ID + time). */
-#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
-
-static int nocalls = 0;
-static int notraces = 0;
-static int use_zip = 0;
-static int do_report = 0;
-static int do_heap_shot = 0;
-static int max_call_depth = 100;
-static volatile int runtime_inited = 0;
-static int need_helper_thread = 0;
-static int command_port = 0;
-static int heapshot_requested = 0;
-static int sample_type = 0;
-static int sample_freq = 0;
-static int do_mono_sample = 0;
-static int in_shutdown = 0;
-static int do_debug = 0;
-static int do_counters = 0;
-static int do_coverage = 0;
-static gboolean debug_coverage = FALSE;
-static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
-static int max_allocated_sample_hits;
-
-static gint32 sample_hits;
-static gint32 sample_flushes;
-static gint32 sample_allocations;
-static gint32 buffer_allocations;
-static gint32 thread_starts;
-static gint32 thread_ends;
-static gint32 domain_loads;
-static gint32 domain_unloads;
-static gint32 context_loads;
-static gint32 context_unloads;
-static gint32 assembly_loads;
-static gint32 assembly_unloads;
-static gint32 image_loads;
-static gint32 image_unloads;
-static gint32 class_loads;
-static gint32 class_unloads;
-
-static MonoLinkedListSet profiler_thread_list;
-
-/*
- * file format:
- * [header] [buffer]*
- *
- * The file is composed by a header followed by 0 or more buffers.
- * Each buffer contains events that happened on a thread: for a given thread
- * buffers that appear later in the file are guaranteed to contain events
- * that happened later in time. Buffers from separate threads could be interleaved,
- * though.
- * Buffers are not required to be aligned.
- *
- * header format:
- * [id: 4 bytes] constant value: LOG_HEADER_ID
- * [major: 1 byte] [minor: 1 byte] major and minor version of the log profiler
- * [format: 1 byte] version of the data format for the rest of the file
- * [ptrsize: 1 byte] size in bytes of a pointer in the profiled program
- * [startup time: 8 bytes] time in milliseconds since the unix epoch when the program started
- * [timer overhead: 4 bytes] approximate overhead in nanoseconds of the timer
- * [flags: 4 bytes] file format flags, should be 0 for now
- * [pid: 4 bytes] pid of the profiled process
- * [port: 2 bytes] tcp port for server if != 0
- * [args size: 4 bytes] size of args
- * [args: string] arguments passed to the profiler
- * [arch size: 4 bytes] size of arch
- * [arch: string] architecture the profiler is running on
- * [os size: 4 bytes] size of os
- * [os: string] operating system the profiler is running on
- *
- * The multiple byte integers are in little-endian format.
- *
- * buffer format:
- * [buffer header] [event]*
- * Buffers have a fixed-size header followed by 0 or more bytes of event data.
- * Timing information and other values in the event data are usually stored
- * as uleb128 or sleb128 integers. To save space, as noted for each item below,
- * some data is represented as a difference between the actual value and
- * either the last value of the same type (like for timing information) or
- * as the difference from a value stored in a buffer header.
- *
- * For timing information the data is stored as uleb128, since timing
- * increases in a monotonic way in each thread: the value is the number of
- * nanoseconds to add to the last seen timing data in a buffer. The first value
- * in a buffer will be calculated from the time_base field in the buffer head.
- *
- * Object or heap sizes are stored as uleb128.
- * Pointer differences are stored as sleb128, instead.
- *
- * If an unexpected value is found, the rest of the buffer should be ignored,
- * as generally the later values need the former to be interpreted correctly.
- *
- * buffer header format:
- * [bufid: 4 bytes] constant value: BUF_ID
- * [len: 4 bytes] size of the data following the buffer header
- * [time_base: 8 bytes] time base in nanoseconds since an unspecified epoch
- * [ptr_base: 8 bytes] base value for pointers
- * [obj_base: 8 bytes] base value for object addresses
- * [thread id: 8 bytes] system-specific thread ID (pthread_t for example)
- * [method_base: 8 bytes] base value for MonoMethod pointers
- *
- * event format:
- * [extended info: upper 4 bits] [type: lower 4 bits]
- * [time diff: uleb128] nanoseconds since last timing
- * [data]*
- * The data that follows depends on type and the extended info.
- * Type is one of the enum values in proflog.h: TYPE_ALLOC, TYPE_GC,
- * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
- * The extended info bits are interpreted based on type, see
- * each individual event description below.
- * strings are represented as a 0-terminated utf8 sequence.
- *
- * backtrace format:
- * [num: uleb128] number of frames following
- * [frame: sleb128]* mum MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- *
- * type alloc format:
- * type: TYPE_ALLOC
- * exinfo: flags: TYPE_ALLOC_BT
- * [ptr: sleb128] class as a byte difference from ptr_base
- * [obj: sleb128] object address as a byte difference from obj_base
- * [size: uleb128] size of the object in the heap
- * If the TYPE_ALLOC_BT flag is set, a backtrace follows.
- *
- * type GC format:
- * type: TYPE_GC
- * exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
- * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
- * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
- * if exinfo == TYPE_GC_RESIZE
- *     [heap_size: uleb128] new heap size
- * if exinfo == TYPE_GC_EVENT
- *     [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
- *     [generation: byte] GC generation event refers to
- * if exinfo == TYPE_GC_MOVE
- *     [num_objects: uleb128] number of object moves that follow
- *     [objaddr: sleb128]+ num_objects object pointer differences from obj_base
- *     num is always an even number: the even items are the old
- *     addresses, the odd numbers are the respective new object addresses
- * if exinfo == TYPE_GC_HANDLE_CREATED[_BT]
- *     [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
- *     upper bits reserved as flags
- *     [handle: uleb128] GC handle value
- *     [objaddr: sleb128] object pointer differences from obj_base
- *     If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows.
- * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT]
- *     [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType)
- *     upper bits reserved as flags
- *     [handle: uleb128] GC handle value
- *     If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
- * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
- *     [object: sleb128] the object as a difference from obj_base
- *
- * type metadata format:
- * type: TYPE_METADATA
- * exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN)
- * [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
- * TYPE_THREAD, TYPE_CONTEXT
- * [pointer: sleb128] pointer of the metadata type depending on mtype
- * if mtype == TYPE_CLASS
- *     [image: sleb128] MonoImage* as a pointer difference from ptr_base
- *     [name: string] full class name
- * if mtype == TYPE_IMAGE
- *     [name: string] image file name
- * if mtype == TYPE_ASSEMBLY
- *     [name: string] assembly name
- * if mtype == TYPE_DOMAIN && exinfo == 0
- *     [name: string] domain friendly name
- * if mtype == TYPE_CONTEXT
- *     [domain: sleb128] domain id as pointer
- * if mtype == TYPE_THREAD && exinfo == 0
- *     [name: string] thread name
- *
- * type method format:
- * type: TYPE_METHOD
- * exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
- * [method: sleb128] MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- * if exinfo == TYPE_JIT
- *     [code address: sleb128] pointer to the native code as a diff from ptr_base
- *     [code size: uleb128] size of the generated code
- *     [name: string] full method name
- *
- * type exception format:
- * type: TYPE_EXCEPTION
- * exinfo: TYPE_THROW_BT flag or one of: TYPE_CLAUSE
- * if exinfo == TYPE_CLAUSE
- *     [clause type: byte] MonoExceptionEnum enum value
- *     [clause index: uleb128] index of the current clause
- *     [method: sleb128] MonoMethod* as a pointer difference from the last such
- *     pointer or the buffer method_base
- * else
- *     [object: sleb128] the exception object as a difference from obj_base
- *     if exinfo has TYPE_THROW_BT set, a backtrace follows.
- *
- * type runtime format:
- * type: TYPE_RUNTIME
- * exinfo: one of: TYPE_JITHELPER
- * if exinfo == TYPE_JITHELPER
- *     [type: byte] MonoProfilerCodeBufferType enum value
- *     [buffer address: sleb128] pointer to the native code as a diff from ptr_base
- *     [buffer size: uleb128] size of the generated code
- *     if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
- *             [name: string] buffer description name
- *
- * type monitor format:
- * type: TYPE_MONITOR
- * exinfo: TYPE_MONITOR_BT flag and one of: MONO_PROFILER_MONITOR_(CONTENTION|FAIL|DONE)
- * [object: sleb128] the lock object as a difference from obj_base
- * if exinfo.low3bits == MONO_PROFILER_MONITOR_CONTENTION
- *     If the TYPE_MONITOR_BT flag is set, a backtrace follows.
- *
- * type heap format
- * type: TYPE_HEAP
- * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
- * if exinfo == TYPE_HEAP_OBJECT
- *     [object: sleb128] the object as a difference from obj_base
- *     [class: sleb128] the object MonoClass* as a difference from ptr_base
- *     [size: uleb128] size of the object on the heap
- *     [num_refs: uleb128] number of object references
- *     each referenced objref is preceded by a uleb128 encoded offset: the
- *     first offset is from the object address and each next offset is relative
- *     to the previous one
- *     [objrefs: sleb128]+ object referenced as a difference from obj_base
- *     The same object can appear multiple times, but only the first time
- *     with size != 0: in the other cases this data will only be used to
- *     provide additional referenced objects.
- * if exinfo == TYPE_HEAP_ROOT
- *     [num_roots: uleb128] number of root references
- *     [num_gc: uleb128] number of major gcs
- *     [object: sleb128] the object as a difference from obj_base
- *     [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
- *     [extra_info: uleb128] the extra_info value
- *     object, root_type and extra_info are repeated num_roots times
- *
- * type sample format
- * type: TYPE_SAMPLE
- * exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
- * if exinfo == TYPE_SAMPLE_HIT
- *     [sample_type: byte] type of sample (SAMPLE_*)
- *     [thread: sleb128] thread id as difference from ptr_base
- *     [count: uleb128] number of following instruction addresses
- *     [ip: sleb128]* instruction pointer as difference from ptr_base
- *     [mbt_count: uleb128] number of managed backtrace frames
- *     [method: sleb128]* MonoMethod* as a pointer difference from the last such
- *     pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
- * if exinfo == TYPE_SAMPLE_USYM
- *     [address: sleb128] symbol address as a difference from ptr_base
- *     [size: uleb128] symbol size (may be 0 if unknown)
- *     [name: string] symbol name
- * if exinfo == TYPE_SAMPLE_UBIN
- *     [address: sleb128] address where binary has been loaded
- *     [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
- *     [size: uleb128] memory size
- *     [name: string] binary name
- * if exinfo == TYPE_SAMPLE_COUNTERS_DESC
- *     [len: uleb128] number of counters
- *     for i = 0 to len
- *             [section: uleb128] section of counter
- *             if section == MONO_COUNTER_PERFCOUNTERS:
- *                     [section_name: string] section name of counter
- *             [name: string] name of counter
- *             [type: byte] type of counter
- *             [unit: byte] unit of counter
- *             [variance: byte] variance of counter
- *             [index: uleb128] unique index of counter
- * if exinfo == TYPE_SAMPLE_COUNTERS
- *     while true:
- *             [index: uleb128] unique index of counter
- *             if index == 0:
- *                     break
- *             [type: byte] type of counter value
- *             if type == string:
- *                     if value == null:
- *                             [0: uleb128] 0 -> value is null
- *                     else:
- *                             [1: uleb128] 1 -> value is not null
- *                             [value: string] counter value
- *             else:
- *                     [value: uleb128/sleb128/double] counter value, can be sleb128, uleb128 or double (determined by using type)
- *
- * type coverage format
- * type: TYPE_COVERAGE
- * exinfo: one of TYPE_COVERAGE_METHOD, TYPE_COVERAGE_STATEMENT, TYPE_COVERAGE_ASSEMBLY, TYPE_COVERAGE_CLASS
- * if exinfo == TYPE_COVERAGE_METHOD
- *  [assembly: string] name of assembly
- *  [class: string] name of the class
- *  [name: string] name of the method
- *  [signature: string] the signature of the method
- *  [filename: string] the file path of the file that contains this method
- *  [token: uleb128] the method token
- *  [method_id: uleb128] an ID for this data to associate with the buffers of TYPE_COVERAGE_STATEMENTS
- *  [len: uleb128] the number of TYPE_COVERAGE_BUFFERS associated with this method
- * if exinfo == TYPE_COVERAGE_STATEMENTS
- *  [method_id: uleb128] an the TYPE_COVERAGE_METHOD buffer to associate this with
- *  [offset: uleb128] the il offset relative to the previous offset
- *  [counter: uleb128] the counter for this instruction
- *  [line: uleb128] the line of filename containing this instruction
- *  [column: uleb128] the column containing this instruction
- * if exinfo == TYPE_COVERAGE_ASSEMBLY
- *  [name: string] assembly name
- *  [guid: string] assembly GUID
- *  [filename: string] assembly filename
- *  [number_of_methods: uleb128] the number of methods in this assembly
- *  [fully_covered: uleb128] the number of fully covered methods
- *  [partially_covered: uleb128] the number of partially covered methods
- *    currently partially_covered will always be 0, and fully_covered is the
- *    number of methods that are fully and partially covered.
- * if exinfo == TYPE_COVERAGE_CLASS
- *  [name: string] assembly name
- *  [class: string] class name
- *  [number_of_methods: uleb128] the number of methods in this class
- *  [fully_covered: uleb128] the number of fully covered methods
- *  [partially_covered: uleb128] the number of partially covered methods
- *    currently partially_covered will always be 0, and fully_covered is the
- *    number of methods that are fully and partially covered.
- *
- * type meta format:
- * type: TYPE_META
- * exinfo: one of: TYPE_SYNC_POINT
- * if exinfo == TYPE_SYNC_POINT
- *     [type: byte] MonoProfilerSyncPointType enum value
- */
-
-// Pending data to be written to the log, for a single thread.
-// Threads periodically flush their own LogBuffers by calling safe_send
-typedef struct _LogBuffer LogBuffer;
-struct _LogBuffer {
-       // Next (older) LogBuffer in processing queue
-       LogBuffer *next;
-
-       uint64_t time_base;
-       uint64_t last_time;
-       uintptr_t ptr_base;
-       uintptr_t method_base;
-       uintptr_t last_method;
-       uintptr_t obj_base;
-       uintptr_t thread_id;
-
-       // Bytes allocated for this LogBuffer
-       int size;
-
-       // Start of currently unused space in buffer
-       unsigned char* cursor;
-
-       // Pointer to start-of-structure-plus-size (for convenience)
-       unsigned char* buf_end;
-
-       // Start of data in buffer. Contents follow "buffer format" described above.
-       unsigned char buf [1];
-};
-
-typedef struct {
-       MonoLinkedListSetNode node;
-
-       // The current log buffer for this thread.
-       LogBuffer *buffer;
-
-       // Methods referenced by events in `buffer`, see `MethodInfo`.
-       GPtrArray *methods;
-
-       // Current call depth for enter/leave events.
-       int call_depth;
-
-       // Indicates whether this thread is currently writing to its `buffer`.
-       int busy;
-} MonoProfilerThread;
-
-static inline void
-ign_res (int G_GNUC_UNUSED unused, ...)
-{
-}
-
-/*
- * These macros create a scope to avoid leaking the buffer returned
- * from ensure_logbuf () as it may have been invalidated by a GC
- * thread during STW. If you called init_thread () with add_to_lls =
- * FALSE, then don't use these macros.
- */
-
-#define ENTER_LOG \
-       do { \
-               buffer_lock (); \
-               g_assert (!PROF_TLS_GET ()->busy++ && "Why are we trying to write a new event while already writing one?")
-
-#define EXIT_LOG \
-               PROF_TLS_GET ()->busy--; \
-               buffer_unlock (); \
-       } while (0)
-
-static volatile gint32 buffer_rwlock_count;
-static volatile gpointer buffer_rwlock_exclusive;
-
-// Can be used recursively.
-static void
-buffer_lock (void)
-{
-       /*
-        * If the thread holding the exclusive lock tries to modify the
-        * reader count, just make it a no-op. This way, we also avoid
-        * invoking the GC safe point macros below, which could break if
-        * done from a thread that is currently the initiator of STW.
-        *
-        * In other words, we rely on the fact that the GC thread takes
-        * the exclusive lock in the gc_event () callback when the world
-        * is about to stop.
-        */
-       if (InterlockedReadPointer (&buffer_rwlock_exclusive) != (gpointer) thread_id ()) {
-               MONO_ENTER_GC_SAFE;
-
-               while (InterlockedReadPointer (&buffer_rwlock_exclusive))
-                       mono_thread_info_yield ();
-
-               InterlockedIncrement (&buffer_rwlock_count);
-
-               MONO_EXIT_GC_SAFE;
-       }
-
-       mono_memory_barrier ();
-}
-
-static void
-buffer_unlock (void)
-{
-       mono_memory_barrier ();
-
-       // See the comment in buffer_lock ().
-       if (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id ())
-               return;
-
-       g_assert (InterlockedRead (&buffer_rwlock_count) && "Why are we trying to decrement a zero reader count?");
-
-       InterlockedDecrement (&buffer_rwlock_count);
-}
-
-// Cannot be used recursively.
-static void
-buffer_lock_excl (void)
-{
-       gpointer tid = (gpointer) thread_id ();
-
-       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) != tid && "Why are we taking the exclusive lock twice?");
-
-       MONO_ENTER_GC_SAFE;
-
-       while (InterlockedCompareExchangePointer (&buffer_rwlock_exclusive, tid, 0))
-               mono_thread_info_yield ();
-
-       while (InterlockedRead (&buffer_rwlock_count))
-               mono_thread_info_yield ();
-
-       MONO_EXIT_GC_SAFE;
-
-       mono_memory_barrier ();
-}
-
-static void
-buffer_unlock_excl (void)
-{
-       mono_memory_barrier ();
-
-       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why is the exclusive lock not held?");
-       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why does another thread hold the exclusive lock?");
-       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why are there readers when the exclusive lock is held?");
-
-       InterlockedWritePointer (&buffer_rwlock_exclusive, NULL);
-}
-
-typedef struct _BinaryObject BinaryObject;
-struct _BinaryObject {
-       BinaryObject *next;
-       void *addr;
-       char *name;
-};
-
-struct _MonoProfiler {
-       FILE* file;
-#if defined (HAVE_SYS_ZLIB)
-       gzFile gzfile;
-#endif
-       char *args;
-       uint64_t startup_time;
-       int pipe_output;
-       int last_gc_gen_started;
-       int command_port;
-       int server_socket;
-       int pipes [2];
-#ifndef HOST_WIN32
-       pthread_t helper_thread;
-       pthread_t writer_thread;
-       pthread_t dumper_thread;
-#endif
-       volatile gint32 run_writer_thread;
-       MonoLockFreeAllocSizeClass writer_entry_size_class;
-       MonoLockFreeAllocator writer_entry_allocator;
-       MonoLockFreeQueue writer_queue;
-       MonoSemType writer_queue_sem;
-       MonoConcurrentHashTable *method_table;
-       mono_mutex_t method_table_mutex;
-       volatile gint32 run_dumper_thread;
-       MonoLockFreeQueue dumper_queue;
-       MonoSemType dumper_queue_sem;
-       MonoLockFreeAllocSizeClass sample_size_class;
-       MonoLockFreeAllocator sample_allocator;
-       MonoLockFreeQueue sample_reuse_queue;
-       BinaryObject *binary_objects;
-       GPtrArray *coverage_filters;
-};
-
-typedef struct {
-       MonoLockFreeQueueNode node;
-       GPtrArray *methods;
-       LogBuffer *buffer;
-} WriterQueueEntry;
-
-#define WRITER_ENTRY_BLOCK_SIZE (mono_pagesize ())
-
-typedef struct {
-       MonoMethod *method;
-       MonoJitInfo *ji;
-       uint64_t time;
-} MethodInfo;
-
-#ifdef HOST_WIN32
-
-#define PROF_TLS_SET(VAL) (TlsSetValue (profiler_tls, (VAL)))
-#define PROF_TLS_GET() ((MonoProfilerThread *) TlsGetValue (profiler_tls))
-#define PROF_TLS_INIT() (profiler_tls = TlsAlloc ())
-#define PROF_TLS_FREE() (TlsFree (profiler_tls))
-
-static DWORD profiler_tls;
-
-#elif HAVE_KW_THREAD
-
-#define PROF_TLS_SET(VAL) (profiler_tls = (VAL))
-#define PROF_TLS_GET() (profiler_tls)
-#define PROF_TLS_INIT()
-#define PROF_TLS_FREE()
-
-static __thread MonoProfilerThread *profiler_tls;
-
-#else
-
-#define PROF_TLS_SET(VAL) (pthread_setspecific (profiler_tls, (VAL)))
-#define PROF_TLS_GET() ((MonoProfilerThread *) pthread_getspecific (profiler_tls))
-#define PROF_TLS_INIT() (pthread_key_create (&profiler_tls, NULL))
-#define PROF_TLS_FREE() (pthread_key_delete (&profiler_tls))
-
-static pthread_key_t profiler_tls;
-
-#endif
-
-static char*
-pstrdup (const char *s)
-{
-       int len = strlen (s) + 1;
-       char *p = (char *)malloc (len);
-       memcpy (p, s, len);
-       return p;
-}
-
-static LogBuffer*
-create_buffer (void)
-{
-       LogBuffer* buf = (LogBuffer *)alloc_buffer (BUFFER_SIZE);
-
-       InterlockedIncrement (&buffer_allocations);
-
-       buf->size = BUFFER_SIZE;
-       buf->time_base = current_time ();
-       buf->last_time = buf->time_base;
-       buf->buf_end = (unsigned char*)buf + buf->size;
-       buf->cursor = buf->buf;
-       return buf;
-}
-
-static void
-init_buffer_state (MonoProfilerThread *thread)
-{
-       thread->buffer = create_buffer ();
-       thread->methods = NULL;
-}
-
-static void
-clear_hazard_pointers (MonoThreadHazardPointers *hp)
-{
-       mono_hazard_pointer_clear (hp, 0);
-       mono_hazard_pointer_clear (hp, 1);
-       mono_hazard_pointer_clear (hp, 2);
-}
-
-static MonoProfilerThread *
-init_thread (gboolean add_to_lls)
-{
-       MonoProfilerThread *thread = PROF_TLS_GET ();
-
-       /*
-        * Sometimes we may try to initialize a thread twice. One example is the
-        * main thread: We initialize it when setting up the profiler, but we will
-        * also get a thread_start () callback for it. Another example is when
-        * attaching new threads to the runtime: We may get a gc_alloc () callback
-        * for that thread's thread object (where we initialize it), soon followed
-        * by a thread_start () callback.
-        *
-        * These cases are harmless anyhow. Just return if we've already done the
-        * initialization work.
-        */
-       if (thread)
-               return thread;
-
-       thread = malloc (sizeof (MonoProfilerThread));
-       thread->node.key = thread_id ();
-       thread->call_depth = 0;
-       thread->busy = 0;
-
-       init_buffer_state (thread);
-
-       /*
-        * Some internal profiler threads don't need to be cleaned up
-        * by the main thread on shutdown.
-        */
-       if (add_to_lls) {
-               MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-               g_assert (mono_lls_insert (&profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?");
-               clear_hazard_pointers (hp);
-       }
-
-       PROF_TLS_SET (thread);
-
-       return thread;
-}
-
-// Only valid if init_thread () was called with add_to_lls = FALSE.
-static void
-deinit_thread (MonoProfilerThread *thread)
-{
-       free (thread);
-       PROF_TLS_SET (NULL);
-}
-
-static LogBuffer *
-ensure_logbuf_inner (LogBuffer *old, int bytes)
-{
-       if (old && old->cursor + bytes + 100 < old->buf_end)
-               return old;
-
-       LogBuffer *new_ = create_buffer ();
-       new_->next = old;
-
-       return new_;
-}
-
-// Only valid if init_thread () was called with add_to_lls = FALSE.
-static LogBuffer *
-ensure_logbuf_unsafe (int bytes)
-{
-       MonoProfilerThread *thread = PROF_TLS_GET ();
-       LogBuffer *old = thread->buffer;
-       LogBuffer *new_ = ensure_logbuf_inner (old, bytes);
-
-       if (new_ == old)
-               return old; // Still enough space.
-
-       thread->buffer = new_;
-
-       return new_;
-}
-
-/*
- * Any calls to this function should be wrapped in the ENTER_LOG and
- * EXIT_LOG macros to prevent the returned pointer from leaking
- * outside of the critical region created by the calls to buffer_lock ()
- * and buffer_unlock () that those macros insert. If the pointer leaks,
- * it can and will lead to crashes as the GC or helper thread may
- * invalidate the pointer at any time.
- *
- * Note: If you're calling from a thread that called init_thread () with
- * add_to_lls = FALSE, you should use ensure_logbuf_unsafe () and omit
- * the macros.
- */
-static LogBuffer*
-ensure_logbuf (int bytes)
-{
-       g_assert (PROF_TLS_GET ()->busy && "Why are we trying to expand our buffer without the busy flag set?");
-
-       return ensure_logbuf_unsafe (bytes);
-}
-
-static void
-emit_byte (LogBuffer *logbuffer, int value)
-{
-       logbuffer->cursor [0] = value;
-       logbuffer->cursor++;
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_value (LogBuffer *logbuffer, int value)
-{
-       encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_time (LogBuffer *logbuffer, uint64_t value)
-{
-       uint64_t tdiff = value - logbuffer->last_time;
-       //if (value < logbuffer->last_time)
-       //      printf ("time went backwards\n");
-       //if (tdiff > 1000000)
-       //      printf ("large time offset: %llu\n", tdiff);
-       encode_uleb128 (tdiff, logbuffer->cursor, &logbuffer->cursor);
-       /*if (tdiff != decode_uleb128 (p, &p))
-               printf ("incorrect encoding: %llu\n", tdiff);*/
-       logbuffer->last_time = value;
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_event_time (LogBuffer *logbuffer, int event, uint64_t time)
-{
-       emit_byte (logbuffer, event);
-       emit_time (logbuffer, time);
-}
-
-static void
-emit_event (LogBuffer *logbuffer, int event)
-{
-       emit_event_time (logbuffer, event, current_time ());
-}
-
-static void
-emit_svalue (LogBuffer *logbuffer, int64_t value)
-{
-       encode_sleb128 (value, logbuffer->cursor, &logbuffer->cursor);
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_uvalue (LogBuffer *logbuffer, uint64_t value)
-{
-       encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_ptr (LogBuffer *logbuffer, void *ptr)
-{
-       if (!logbuffer->ptr_base)
-               logbuffer->ptr_base = (uintptr_t)ptr;
-       emit_svalue (logbuffer, (intptr_t)ptr - logbuffer->ptr_base);
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_method_inner (LogBuffer *logbuffer, void *method)
-{
-       if (!logbuffer->method_base) {
-               logbuffer->method_base = (intptr_t)method;
-               logbuffer->last_method = (intptr_t)method;
-       }
-       encode_sleb128 ((intptr_t)((char*)method - (char*)logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor);
-       logbuffer->last_method = (intptr_t)method;
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-/*
-typedef struct {
-       MonoMethod *method;
-       MonoJitInfo *found;
-} MethodSearch;
-
-static void
-find_method (MonoDomain *domain, void *user_data)
-{
-       MethodSearch *search = user_data;
-
-       if (search->found)
-               return;
-
-       MonoJitInfo *ji = mono_get_jit_info_from_method (domain, search->method);
-
-       // It could be AOT'd, so we need to get it from the AOT runtime's cache.
-       if (!ji) {
-               void *ip = mono_aot_get_method (domain, search->method);
-
-               // Avoid a slow path in mono_jit_info_table_find ().
-               if (ip)
-                       ji = mono_jit_info_table_find (domain, ip);
-       }
-
-       if (ji)
-               search->found = ji;
-}
-*/
-
-static void
-register_method_local (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji)
-{
-       if (!mono_conc_hashtable_lookup (prof->method_table, method)) {
-               /*
-                * FIXME: In some cases, we crash while looking up JIT info for AOT'd methods.
-                * This usually happens for static constructors. This code is disabled for now
-                * as we don't need this info for anything critical.
-                *
-                * https://bugzilla.xamarin.com/show_bug.cgi?id=35171
-                */
-               /*
-               if (!ji) {
-                       MethodSearch search = { method, NULL };
-
-                       mono_domain_foreach (find_method, &search);
-
-                       ji = search.found;
-               }
-               */
-
-               /*
-                * FIXME: We can't always find JIT info for a generic shared method, especially
-                * if we obtained the MonoMethod during an async stack walk. For now, we deal
-                * with this by giving the generic shared method name and dummy code start/size
-                * information (i.e. zeroes).
-                */
-               //g_assert (ji);
-
-               MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo));
-
-               info->method = method;
-               info->ji = ji;
-               info->time = current_time ();
-
-               MonoProfilerThread *thread = PROF_TLS_GET ();
-               GPtrArray *arr = thread->methods ? thread->methods : (thread->methods = g_ptr_array_new ());
-               g_ptr_array_add (arr, info);
-       }
-}
-
-static void
-emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
-{
-       register_method_local (prof, method, NULL);
-       emit_method_inner (logbuffer, method);
-}
-
-static void
-emit_obj (LogBuffer *logbuffer, void *ptr)
-{
-       if (!logbuffer->obj_base)
-               logbuffer->obj_base = (uintptr_t)ptr >> 3;
-       emit_svalue (logbuffer, ((uintptr_t)ptr >> 3) - logbuffer->obj_base);
-       assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-static void
-emit_string (LogBuffer *logbuffer, const char *str, size_t size)
-{
-       size_t i = 0;
-       if (str) {
-               for (; i < size; i++) {
-                       if (str[i] == '\0')
-                               break;
-                       emit_byte (logbuffer, str [i]);
-               }
-       }
-       emit_byte (logbuffer, '\0');
-}
-
-static void
-emit_double (LogBuffer *logbuffer, double value)
-{
-       int i;
-       unsigned char buffer[8];
-       memcpy (buffer, &value, 8);
-#if G_BYTE_ORDER == G_BIG_ENDIAN
-       for (i = 7; i >= 0; i--)
-#else
-       for (i = 0; i < 8; i++)
-#endif
-               emit_byte (logbuffer, buffer[i]);
-}
-
-static char*
-write_int16 (char *buf, int32_t value)
-{
-       int i;
-       for (i = 0; i < 2; ++i) {
-               buf [i] = value;
-               value >>= 8;
-       }
-       return buf + 2;
-}
-
-static char*
-write_int32 (char *buf, int32_t value)
-{
-       int i;
-       for (i = 0; i < 4; ++i) {
-               buf [i] = value;
-               value >>= 8;
-       }
-       return buf + 4;
-}
-
-static char*
-write_int64 (char *buf, int64_t value)
-{
-       int i;
-       for (i = 0; i < 8; ++i) {
-               buf [i] = value;
-               value >>= 8;
-       }
-       return buf + 8;
-}
-
-static char *
-write_header_string (char *p, const char *str)
-{
-       size_t len = strlen (str) + 1;
-
-       p = write_int32 (p, len);
-       strcpy (p, str);
-
-       return p + len;
-}
-
-static void
-dump_header (MonoProfiler *profiler)
-{
-       const char *args = profiler->args;
-       const char *arch = mono_config_get_cpu ();
-       const char *os = mono_config_get_os ();
-
-       char *hbuf = malloc (
-               sizeof (gint32) /* header id */ +
-               sizeof (gint8) /* major version */ +
-               sizeof (gint8) /* minor version */ +
-               sizeof (gint8) /* data version */ +
-               sizeof (gint8) /* word size */ +
-               sizeof (gint64) /* startup time */ +
-               sizeof (gint32) /* timer overhead */ +
-               sizeof (gint32) /* flags */ +
-               sizeof (gint32) /* process id */ +
-               sizeof (gint16) /* command port */ +
-               sizeof (gint32) + strlen (args) + 1 /* arguments */ +
-               sizeof (gint32) + strlen (arch) + 1 /* architecture */ +
-               sizeof (gint32) + strlen (os) + 1 /* operating system */
-       );
-       char *p = hbuf;
-
-       p = write_int32 (p, LOG_HEADER_ID);
-       *p++ = LOG_VERSION_MAJOR;
-       *p++ = LOG_VERSION_MINOR;
-       *p++ = LOG_DATA_VERSION;
-       *p++ = sizeof (void *);
-       p = write_int64 (p, ((uint64_t) time (NULL)) * 1000);
-       p = write_int32 (p, get_timer_overhead ());
-       p = write_int32 (p, 0); /* flags */
-       p = write_int32 (p, process_id ());
-       p = write_int16 (p, profiler->command_port);
-       p = write_header_string (p, args);
-       p = write_header_string (p, arch);
-       p = write_header_string (p, os);
-
-#if defined (HAVE_SYS_ZLIB)
-       if (profiler->gzfile) {
-               gzwrite (profiler->gzfile, hbuf, p - hbuf);
-       } else
-#endif
-       {
-               fwrite (hbuf, p - hbuf, 1, profiler->file);
-               fflush (profiler->file);
-       }
-
-       free (hbuf);
-}
-
-static void
-send_buffer (MonoProfiler *prof, MonoProfilerThread *thread)
-{
-       WriterQueueEntry *entry = mono_lock_free_alloc (&prof->writer_entry_allocator);
-       entry->methods = thread->methods;
-       entry->buffer = thread->buffer;
-
-       mono_lock_free_queue_node_init (&entry->node, FALSE);
-
-       mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
-       mono_os_sem_post (&prof->writer_queue_sem);
-}
-
-static void
-remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_callback)
-{
-       MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
-
-       if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) {
-               LogBuffer *buffer = thread->buffer;
-
-               /*
-                * No need to take the buffer lock here as no other threads can
-                * be accessing this buffer anymore.
-                */
-
-               if (!from_callback) {
-                       /*
-                        * The thread is being cleaned up by the main thread during
-                        * shutdown. This typically happens for internal runtime
-                        * threads. We need to synthesize a thread end event.
-                        */
-
-                       buffer = ensure_logbuf_inner (buffer,
-                               EVENT_SIZE /* event */ +
-                               BYTE_SIZE /* type */ +
-                               LEB128_SIZE /* tid */
-                       );
-
-                       emit_event (buffer, TYPE_END_UNLOAD | TYPE_METADATA);
-                       emit_byte (buffer, TYPE_THREAD);
-                       emit_ptr (buffer, (void *) thread->node.key);
-               }
-
-               send_buffer (prof, thread);
-
-               mono_thread_hazardous_try_free (thread, free);
-       }
-
-       clear_hazard_pointers (hp);
-
-       if (from_callback)
-               PROF_TLS_SET (NULL);
-}
-
-static void
-dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
-{
-       char hbuf [128];
-       char *p = hbuf;
-
-       if (buf->next)
-               dump_buffer (profiler, buf->next);
-
-       p = write_int32 (p, BUF_ID);
-       p = write_int32 (p, buf->cursor - buf->buf);
-       p = write_int64 (p, buf->time_base);
-       p = write_int64 (p, buf->ptr_base);
-       p = write_int64 (p, buf->obj_base);
-       p = write_int64 (p, buf->thread_id);
-       p = write_int64 (p, buf->method_base);
-
-#if defined (HAVE_SYS_ZLIB)
-       if (profiler->gzfile) {
-               gzwrite (profiler->gzfile, hbuf, p - hbuf);
-               gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
-       } else
-#endif
-       {
-               fwrite (hbuf, p - hbuf, 1, profiler->file);
-               fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
-               fflush (profiler->file);
-       }
-
-       free_buffer (buf, buf->size);
-}
-
-static void
-dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf)
-{
-       for (LogBuffer *iter = buf; iter; iter = iter->next)
-               iter->thread_id = 0;
-
-       dump_buffer (profiler, buf);
-}
-
-static void
-process_requests (MonoProfiler *profiler)
-{
-       if (heapshot_requested)
-               mono_gc_collect (mono_gc_max_generation ());
-}
-
-static void counters_init (MonoProfiler *profiler);
-static void counters_sample (MonoProfiler *profiler, uint64_t timestamp);
-
-static void
-safe_send (MonoProfiler *profiler)
-{
-       /* We need the runtime initialized so that we have threads and hazard
-        * pointers available. Otherwise, the lock free queue will not work and
-        * there won't be a thread to process the data.
-        *
-        * While the runtime isn't initialized, we just accumulate data in the
-        * thread local buffer list.
-        */
-       if (!InterlockedRead (&runtime_inited))
-               return;
-
-       MonoProfilerThread *thread = PROF_TLS_GET ();
-
-       buffer_lock ();
-
-       send_buffer (profiler, thread);
-       init_buffer_state (thread);
-
-       buffer_unlock ();
-}
-
-static void
-send_if_needed (MonoProfiler *prof)
-{
-       if (PROF_TLS_GET ()->buffer->next)
-               safe_send (prof);
-}
-
-static void
-safe_send_threadless (MonoProfiler *prof)
-{
-       LogBuffer *buf = PROF_TLS_GET ()->buffer;
-
-       for (LogBuffer *iter = buf; iter; iter = iter->next)
-               iter->thread_id = 0;
-
-       safe_send (prof);
-}
-
-static void
-send_if_needed_threadless (MonoProfiler *prof)
-{
-       if (PROF_TLS_GET ()->buffer->next)
-               safe_send_threadless (prof);
-}
-
-// Assumes that the exclusive lock is held.
-static void
-sync_point_flush (MonoProfiler *prof)
-{
-       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
-
-       MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
-               send_buffer (prof, thread);
-               init_buffer_state (thread);
-       } MONO_LLS_FOREACH_SAFE_END
-}
-
-// Assumes that the exclusive lock is held.
-static void
-sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type)
-{
-       g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* type */
-       );
-
-       emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
-       emit_byte (logbuffer, type);
-
-       EXIT_LOG;
-
-       switch (type) {
-       case SYNC_POINT_PERIODIC:
-               safe_send_threadless (prof);
-               break;
-       case SYNC_POINT_WORLD_STOP:
-       case SYNC_POINT_WORLD_START:
-               safe_send (prof);
-               break;
-       default:
-               g_assert_not_reached ();
-               break;
-       }
-}
-
-// Assumes that the exclusive lock is held.
-static void
-sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type)
-{
-       sync_point_flush (prof);
-       sync_point_mark (prof, type);
-}
-
-static int
-gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data)
-{
-       /* account for object alignment in the heap */
-       size += 7;
-       size &= ~7;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* obj */ +
-               LEB128_SIZE /* klass */ +
-               LEB128_SIZE /* size */ +
-               LEB128_SIZE /* num */ +
-               num * (
-                       LEB128_SIZE /* offset */ +
-                       LEB128_SIZE /* ref */
-               )
-       );
-
-       emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
-       emit_obj (logbuffer, obj);
-       emit_ptr (logbuffer, klass);
-       emit_value (logbuffer, size);
-       emit_value (logbuffer, num);
-
-       uintptr_t last_offset = 0;
-
-       for (int i = 0; i < num; ++i) {
-               emit_value (logbuffer, offsets [i] - last_offset);
-               last_offset = offsets [i];
-               emit_obj (logbuffer, refs [i]);
-       }
-
-       EXIT_LOG;
-
-       return 0;
-}
-
-static unsigned int hs_mode_ms = 0;
-static unsigned int hs_mode_gc = 0;
-static unsigned int hs_mode_ondemand = 0;
-static unsigned int gc_count = 0;
-static uint64_t last_hs_time = 0;
-
-static void
-heap_walk (MonoProfiler *profiler)
-{
-       if (!do_heap_shot)
-               return;
-
-       gboolean do_walk = 0;
-       uint64_t now = current_time ();
-
-       if (hs_mode_ms && (now - last_hs_time) / 1000000 >= hs_mode_ms)
-               do_walk = TRUE;
-       else if (hs_mode_gc && (gc_count % hs_mode_gc) == 0)
-               do_walk = TRUE;
-       else if (hs_mode_ondemand)
-               do_walk = heapshot_requested;
-       else if (!hs_mode_ms && !hs_mode_gc && profiler->last_gc_gen_started == mono_gc_max_generation ())
-               do_walk = TRUE;
-
-       if (!do_walk)
-               return;
-
-       heapshot_requested = 0;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */
-       );
-
-       emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
-
-       EXIT_LOG;
-
-       mono_gc_walk_heap (0, gc_reference, NULL);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */
-       );
-
-       now = current_time ();
-
-       emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
-
-       EXIT_LOG;
-
-       last_hs_time = now;
-}
-
-static void
-gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* gc event */ +
-               BYTE_SIZE /* generation */
-       );
-
-       emit_event (logbuffer, TYPE_GC_EVENT | TYPE_GC);
-       emit_byte (logbuffer, ev);
-       emit_byte (logbuffer, generation);
-
-       EXIT_LOG;
-
-       switch (ev) {
-       case MONO_GC_EVENT_START:
-               /* to deal with nested gen1 after gen0 started */
-               profiler->last_gc_gen_started = generation;
-
-               if (generation == mono_gc_max_generation ())
-                       gc_count++;
-               break;
-       case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED:
-               /*
-                * Ensure that no thread can be in the middle of writing to
-                * a buffer when the world stops...
-                */
-               buffer_lock_excl ();
-               break;
-       case MONO_GC_EVENT_POST_STOP_WORLD:
-               /*
-                * ... So that we now have a consistent view of all buffers.
-                * This allows us to flush them. We need to do this because
-                * they may contain object allocation events that need to be
-                * committed to the log file before any object move events
-                * that will be produced during this GC.
-                */
-               sync_point (profiler, SYNC_POINT_WORLD_STOP);
-               break;
-       case MONO_GC_EVENT_PRE_START_WORLD:
-               heap_walk (profiler);
-               break;
-       case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED:
-               /*
-                * Similarly, we must now make sure that any object moves
-                * written to the GC thread's buffer are flushed. Otherwise,
-                * object allocation events for certain addresses could come
-                * after the move events that made those addresses available.
-                */
-               sync_point_mark (profiler, SYNC_POINT_WORLD_START);
-
-               /*
-                * Finally, it is safe to allow other threads to write to
-                * their buffers again.
-                */
-               buffer_unlock_excl ();
-               break;
-       default:
-               break;
-       }
-}
-
-static void
-gc_resize (MonoProfiler *profiler, int64_t new_size)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* new size */
-       );
-
-       emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
-       emit_value (logbuffer, new_size);
-
-       EXIT_LOG;
-}
-
-// If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
-#define MAX_FRAMES 32
-
-typedef struct {
-       int count;
-       MonoMethod* methods [MAX_FRAMES];
-       int32_t il_offsets [MAX_FRAMES];
-       int32_t native_offsets [MAX_FRAMES];
-} FrameData;
-
-static int num_frames = MAX_FRAMES;
-
-static mono_bool
-walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_bool managed, void* data)
-{
-       FrameData *frame = (FrameData *)data;
-       if (method && frame->count < num_frames) {
-               frame->il_offsets [frame->count] = il_offset;
-               frame->native_offsets [frame->count] = native_offset;
-               frame->methods [frame->count++] = method;
-               //printf ("In %d %s at %d (native: %d)\n", frame->count, mono_method_get_name (method), il_offset, native_offset);
-       }
-       return frame->count == num_frames;
-}
-
-/*
- * a note about stack walks: they can cause more profiler events to fire,
- * so we need to make sure they don't happen after we started emitting an
- * event, hence the collect_bt/emit_bt split.
- */
-static void
-collect_bt (FrameData *data)
-{
-       data->count = 0;
-       mono_stack_walk_no_il (walk_stack, data);
-}
-
-static void
-emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
-{
-       /* FIXME: this is actually tons of data and we should
-        * just output it the first time and use an id the next
-        */
-       if (data->count > num_frames)
-               printf ("bad num frames: %d\n", data->count);
-       emit_value (logbuffer, data->count);
-       //if (*p != data.count) {
-       //      printf ("bad num frames enc at %d: %d -> %d\n", count, data.count, *p); printf ("frames end: %p->%p\n", p, logbuffer->cursor); exit(0);}
-       while (data->count) {
-               emit_method (prof, logbuffer, data->methods [--data->count]);
-       }
-}
-
-static void
-gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
-{
-       init_thread (TRUE);
-
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
-       FrameData data;
-       uintptr_t len = mono_object_get_size (obj);
-       /* account for object alignment in the heap */
-       len += 7;
-       len &= ~7;
-
-       if (do_bt)
-               collect_bt (&data);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* klass */ +
-               LEB128_SIZE /* obj */ +
-               LEB128_SIZE /* size */ +
-               (do_bt ? (
-                       LEB128_SIZE /* count */ +
-                       data.count * (
-                               LEB128_SIZE /* method */
-                       )
-               ) : 0)
-       );
-
-       emit_event (logbuffer, do_bt | TYPE_ALLOC);
-       emit_ptr (logbuffer, klass);
-       emit_obj (logbuffer, obj);
-       emit_value (logbuffer, len);
-
-       if (do_bt)
-               emit_bt (prof, logbuffer, &data);
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-static void
-gc_moves (MonoProfiler *prof, void **objects, int num)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* num */ +
-               num * (
-                       LEB128_SIZE /* object */
-               )
-       );
-
-       emit_event (logbuffer, TYPE_GC_MOVE | TYPE_GC);
-       emit_value (logbuffer, num);
-
-       for (int i = 0; i < num; ++i)
-               emit_obj (logbuffer, objects [i]);
-
-       EXIT_LOG;
-}
-
-static void
-gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* num */ +
-               LEB128_SIZE /* collections */ +
-               num * (
-                       LEB128_SIZE /* object */ +
-                       LEB128_SIZE /* root type */ +
-                       LEB128_SIZE /* extra info */
-               )
-       );
-
-       emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
-       emit_value (logbuffer, num);
-       emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ()));
-
-       for (int i = 0; i < num; ++i) {
-               emit_obj (logbuffer, objects [i]);
-               emit_byte (logbuffer, root_types [i]);
-               emit_value (logbuffer, extra_info [i]);
-       }
-
-       EXIT_LOG;
-}
-
-static void
-gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj)
-{
-       int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces;
-       FrameData data;
-
-       if (do_bt)
-               collect_bt (&data);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* type */ +
-               LEB128_SIZE /* handle */ +
-               (op == MONO_PROFILER_GC_HANDLE_CREATED ? (
-                       LEB128_SIZE /* obj */
-               ) : 0) +
-               (do_bt ? (
-                       LEB128_SIZE /* count */ +
-                       data.count * (
-                               LEB128_SIZE /* method */
-                       )
-               ) : 0)
-       );
-
-       if (op == MONO_PROFILER_GC_HANDLE_CREATED)
-               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
-       else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED)
-               emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
-       else
-               g_assert_not_reached ();
-
-       emit_value (logbuffer, type);
-       emit_value (logbuffer, handle);
-
-       if (op == MONO_PROFILER_GC_HANDLE_CREATED)
-               emit_obj (logbuffer, obj);
-
-       if (do_bt)
-               emit_bt (prof, logbuffer, &data);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-finalize_begin (MonoProfiler *prof)
-{
-       ENTER_LOG;
-
-       LogBuffer *buf = ensure_logbuf (
-               EVENT_SIZE /* event */
-       );
-
-       emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-finalize_end (MonoProfiler *prof)
-{
-       ENTER_LOG;
-
-       LogBuffer *buf = ensure_logbuf (
-               EVENT_SIZE /* event */
-       );
-
-       emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-finalize_object_begin (MonoProfiler *prof, MonoObject *obj)
-{
-       ENTER_LOG;
-
-       LogBuffer *buf = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* obj */
-       );
-
-       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC);
-       emit_obj (buf, obj);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-finalize_object_end (MonoProfiler *prof, MonoObject *obj)
-{
-       ENTER_LOG;
-
-       LogBuffer *buf = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* obj */
-       );
-
-       emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC);
-       emit_obj (buf, obj);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static char*
-push_nesting (char *p, MonoClass *klass)
-{
-       MonoClass *nesting;
-       const char *name;
-       const char *nspace;
-       nesting = mono_class_get_nesting_type (klass);
-       if (nesting) {
-               p = push_nesting (p, nesting);
-               *p++ = '/';
-               *p = 0;
-       }
-       name = mono_class_get_name (klass);
-       nspace = mono_class_get_namespace (klass);
-       if (*nspace) {
-               strcpy (p, nspace);
-               p += strlen (nspace);
-               *p++ = '.';
-               *p = 0;
-       }
-       strcpy (p, name);
-       p += strlen (name);
-       return p;
-}
-
-static char*
-type_name (MonoClass *klass)
-{
-       char buf [1024];
-       char *p;
-       push_nesting (buf, klass);
-       p = (char *)malloc (strlen (buf) + 1);
-       strcpy (p, buf);
-       return p;
-}
-
-static void
-image_loaded (MonoProfiler *prof, MonoImage *image, int result)
-{
-       if (result != MONO_PROFILE_OK)
-               return;
-
-       const char *name = mono_image_get_filename (image);
-       int nlen = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* image */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_IMAGE);
-       emit_ptr (logbuffer, image);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&image_loads);
-}
-
-static void
-image_unloaded (MonoProfiler *prof, MonoImage *image)
-{
-       const char *name = mono_image_get_filename (image);
-       int nlen = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* image */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_IMAGE);
-       emit_ptr (logbuffer, image);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&image_unloads);
-}
-
-static void
-assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result)
-{
-       if (result != MONO_PROFILE_OK)
-               return;
-
-       char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
-       int nlen = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* assembly */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_ASSEMBLY);
-       emit_ptr (logbuffer, assembly);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       mono_free (name);
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&assembly_loads);
-}
-
-static void
-assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly)
-{
-       char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly));
-       int nlen = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* assembly */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_ASSEMBLY);
-       emit_ptr (logbuffer, assembly);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       mono_free (name);
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&assembly_unloads);
-}
-
-static void
-class_loaded (MonoProfiler *prof, MonoClass *klass, int result)
-{
-       if (result != MONO_PROFILE_OK)
-               return;
-
-       char *name;
-
-       if (InterlockedRead (&runtime_inited))
-               name = mono_type_get_name (mono_class_get_type (klass));
-       else
-               name = type_name (klass);
-
-       int nlen = strlen (name) + 1;
-       MonoImage *image = mono_class_get_image (klass);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* klass */ +
-               LEB128_SIZE /* image */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_CLASS);
-       emit_ptr (logbuffer, klass);
-       emit_ptr (logbuffer, image);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       if (runtime_inited)
-               mono_free (name);
-       else
-               g_free (name);
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&class_loads);
-}
-
-static void
-class_unloaded (MonoProfiler *prof, MonoClass *klass)
-{
-       char *name;
-
-       if (InterlockedRead (&runtime_inited))
-               name = mono_type_get_name (mono_class_get_type (klass));
-       else
-               name = type_name (klass);
-
-       int nlen = strlen (name) + 1;
-       MonoImage *image = mono_class_get_image (klass);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* klass */ +
-               LEB128_SIZE /* image */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_CLASS);
-       emit_ptr (logbuffer, klass);
-       emit_ptr (logbuffer, image);
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       if (runtime_inited)
-               mono_free (name);
-       else
-               g_free (name);
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&class_unloads);
-}
-
-#ifndef DISABLE_HELPER_THREAD
-static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method);
-#endif /* DISABLE_HELPER_THREAD */
-
-static void
-method_enter (MonoProfiler *prof, MonoMethod *method)
-{
-#ifndef DISABLE_HELPER_THREAD
-       process_method_enter_coverage (prof, method);
-#endif /* DISABLE_HELPER_THREAD */
-
-       if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) {
-               ENTER_LOG;
-
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* method */
-               );
-
-               emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
-               emit_method (prof, logbuffer, method);
-
-               EXIT_LOG;
-       }
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-static void
-method_leave (MonoProfiler *prof, MonoMethod *method)
-{
-       if (--PROF_TLS_GET ()->call_depth <= max_call_depth) {
-               ENTER_LOG;
-
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* method */
-               );
-
-               emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
-               emit_method (prof, logbuffer, method);
-
-               EXIT_LOG;
-       }
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-static void
-method_exc_leave (MonoProfiler *prof, MonoMethod *method)
-{
-       if (!nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) {
-               ENTER_LOG;
-
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* method */
-               );
-
-               emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
-               emit_method (prof, logbuffer, method);
-
-               EXIT_LOG;
-       }
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-static void
-method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int result)
-{
-       if (result != MONO_PROFILE_OK)
-               return;
-
-       register_method_local (prof, method, ji);
-
-       process_requests (prof);
-}
-
-static void
-code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data)
-{
-       char *name;
-       int nlen;
-
-       if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
-               name = (char *) data;
-               nlen = strlen (name) + 1;
-       } else {
-               name = NULL;
-               nlen = 0;
-       }
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* buffer */ +
-               LEB128_SIZE /* size */ +
-               (name ? (
-                       nlen /* name */
-               ) : 0)
-       );
-
-       emit_event (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
-       emit_byte (logbuffer, type);
-       emit_ptr (logbuffer, buffer);
-       emit_value (logbuffer, size);
-
-       if (name) {
-               memcpy (logbuffer->cursor, name, nlen);
-               logbuffer->cursor += nlen;
-       }
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-throw_exc (MonoProfiler *prof, MonoObject *object)
-{
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_THROW_BT : 0;
-       FrameData data;
-
-       if (do_bt)
-               collect_bt (&data);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* object */ +
-               (do_bt ? (
-                       LEB128_SIZE /* count */ +
-                       data.count * (
-                               LEB128_SIZE /* method */
-                       )
-               ) : 0)
-       );
-
-       emit_event (logbuffer, do_bt | TYPE_EXCEPTION);
-       emit_obj (logbuffer, object);
-
-       if (do_bt)
-               emit_bt (prof, logbuffer, &data);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* clause type */ +
-               LEB128_SIZE /* clause num */ +
-               LEB128_SIZE /* method */
-       );
-
-       emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
-       emit_byte (logbuffer, clause_type);
-       emit_value (logbuffer, clause_num);
-       emit_method (prof, logbuffer, method);
-
-       EXIT_LOG;
-
-       process_requests (prof);
-}
-
-static void
-monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEvent event)
-{
-       int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces && event == MONO_PROFILER_MONITOR_CONTENTION) ? TYPE_MONITOR_BT : 0;
-       FrameData data;
-
-       if (do_bt)
-               collect_bt (&data);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* object */ +
-               (do_bt ? (
-                       LEB128_SIZE /* count */ +
-                       data.count * (
-                               LEB128_SIZE /* method */
-                       )
-               ) : 0)
-       );
-
-       emit_event (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
-       emit_obj (logbuffer, object);
-
-       if (do_bt)
-               emit_bt (profiler, logbuffer, &data);
-
-       EXIT_LOG;
-
-       process_requests (profiler);
-}
-
-static void
-thread_start (MonoProfiler *prof, uintptr_t tid)
-{
-       init_thread (TRUE);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* tid */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_THREAD);
-       emit_ptr (logbuffer, (void*) tid);
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&thread_starts);
-}
-
-static void
-thread_end (MonoProfiler *prof, uintptr_t tid)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* tid */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_THREAD);
-       emit_ptr (logbuffer, (void*) tid);
-
-       EXIT_LOG;
-
-       // Don't process requests as the thread is detached from the runtime.
-
-       remove_thread (prof, PROF_TLS_GET (), TRUE);
-
-       InterlockedIncrement (&thread_ends);
-}
-
-static void
-domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result)
-{
-       if (result != MONO_PROFILE_OK)
-               return;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* domain id */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_DOMAIN);
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&domain_loads);
-}
-
-static void
-domain_unloaded (MonoProfiler *prof, MonoDomain *domain)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* domain id */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_DOMAIN);
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&domain_unloads);
-}
-
-static void
-domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name)
-{
-       int nlen = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* domain id */ +
-               nlen /* name */
-       );
-
-       emit_event (logbuffer, TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_DOMAIN);
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
-       memcpy (logbuffer->cursor, name, nlen);
-       logbuffer->cursor += nlen;
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-static void
-context_loaded (MonoProfiler *prof, MonoAppContext *context)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* context id */ +
-               LEB128_SIZE /* domain id */
-       );
-
-       emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_CONTEXT);
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&context_loads);
-}
-
-static void
-context_unloaded (MonoProfiler *prof, MonoAppContext *context)
-{
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* context id */ +
-               LEB128_SIZE /* domain id */
-       );
-
-       emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_CONTEXT);
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
-       emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-
-       InterlockedIncrement (&context_unloads);
-}
-
-static void
-thread_name (MonoProfiler *prof, uintptr_t tid, const char *name)
-{
-       int len = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               BYTE_SIZE /* type */ +
-               LEB128_SIZE /* tid */ +
-               len /* name */
-       );
-
-       emit_event (logbuffer, TYPE_METADATA);
-       emit_byte (logbuffer, TYPE_THREAD);
-       emit_ptr (logbuffer, (void*)tid);
-       memcpy (logbuffer->cursor, name, len);
-       logbuffer->cursor += len;
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       process_requests (prof);
-}
-
-typedef struct {
-       MonoMethod *method;
-       MonoDomain *domain;
-       void *base_address;
-       int offset;
-} AsyncFrameInfo;
-
-typedef struct {
-       MonoLockFreeQueueNode node;
-       MonoProfiler *prof;
-       uint64_t time;
-       uintptr_t tid;
-       void *ip;
-       int count;
-       AsyncFrameInfo frames [MONO_ZERO_LEN_ARRAY];
-} SampleHit;
-
-static mono_bool
-async_walk_stack (MonoMethod *method, MonoDomain *domain, void *base_address, int offset, void *data)
-{
-       SampleHit *sample = (SampleHit *) data;
-
-       if (sample->count < num_frames) {
-               int i = sample->count;
-
-               sample->frames [i].method = method;
-               sample->frames [i].domain = domain;
-               sample->frames [i].base_address = base_address;
-               sample->frames [i].offset = offset;
-
-               sample->count++;
-       }
-
-       return sample->count == num_frames;
-}
-
-#define SAMPLE_SLOT_SIZE(FRAMES) (sizeof (SampleHit) + sizeof (AsyncFrameInfo) * (FRAMES - MONO_ZERO_LEN_ARRAY))
-#define SAMPLE_BLOCK_SIZE (mono_pagesize ())
-
-static void
-enqueue_sample_hit (gpointer p)
-{
-       SampleHit *sample = p;
-
-       mono_lock_free_queue_node_unpoison (&sample->node);
-       mono_lock_free_queue_enqueue (&sample->prof->dumper_queue, &sample->node);
-       mono_os_sem_post (&sample->prof->dumper_queue_sem);
-
-       InterlockedIncrement (&sample_flushes);
-}
-
-static void
-mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
-{
-       /*
-        * Please note: We rely on the runtime loading the profiler with
-        * MONO_DL_EAGER (RTLD_NOW) so that references to runtime functions within
-        * this function (and its siblings) are resolved when the profiler is
-        * loaded. Otherwise, we would potentially invoke the dynamic linker when
-        * invoking runtime functions, which is not async-signal-safe.
-        */
-
-       if (in_shutdown)
-               return;
-
-       InterlockedIncrement (&sample_hits);
-
-       SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
-
-       if (!sample) {
-               /*
-                * If we're out of reusable sample events and we're not allowed to
-                * allocate more, we have no choice but to drop the event.
-                */
-               if (InterlockedRead (&sample_allocations) >= max_allocated_sample_hits)
-                       return;
-
-               sample = mono_lock_free_alloc (&profiler->sample_allocator);
-               sample->prof = profiler;
-               mono_lock_free_queue_node_init (&sample->node, TRUE);
-
-               InterlockedIncrement (&sample_allocations);
-       }
-
-       sample->count = 0;
-       mono_stack_walk_async_safe (&async_walk_stack, context, sample);
-
-       sample->time = current_time ();
-       sample->tid = thread_id ();
-       sample->ip = ip;
-
-       if (do_debug) {
-               int len;
-               char buf [256];
-               snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) sample->tid, (unsigned long long int) ((sample->time - profiler->startup_time) / 10000 / 100));
-               len = strlen (buf);
-               ign_res (write (2, buf, len));
-       }
-
-       mono_thread_hazardous_try_free (sample, enqueue_sample_hit);
-}
-
-static uintptr_t *code_pages = 0;
-static int num_code_pages = 0;
-static int size_code_pages = 0;
-#define CPAGE_SHIFT (9)
-#define CPAGE_SIZE (1 << CPAGE_SHIFT)
-#define CPAGE_MASK (~(CPAGE_SIZE - 1))
-#define CPAGE_ADDR(p) ((p) & CPAGE_MASK)
-
-static uintptr_t
-add_code_page (uintptr_t *hash, uintptr_t hsize, uintptr_t page)
-{
-       uintptr_t i;
-       uintptr_t start_pos;
-       start_pos = (page >> CPAGE_SHIFT) % hsize;
-       i = start_pos;
-       do {
-               if (hash [i] && CPAGE_ADDR (hash [i]) == CPAGE_ADDR (page)) {
-                       return 0;
-               } else if (!hash [i]) {
-                       hash [i] = page;
-                       return 1;
-               }
-               /* wrap around */
-               if (++i == hsize)
-                       i = 0;
-       } while (i != start_pos);
-       /* should not happen */
-       printf ("failed code page store\n");
-       return 0;
-}
-
-static void
-add_code_pointer (uintptr_t ip)
-{
-       uintptr_t i;
-       if (num_code_pages * 2 >= size_code_pages) {
-               uintptr_t *n;
-               uintptr_t old_size = size_code_pages;
-               size_code_pages *= 2;
-               if (size_code_pages == 0)
-                       size_code_pages = 16;
-               n = (uintptr_t *)calloc (sizeof (uintptr_t) * size_code_pages, 1);
-               for (i = 0; i < old_size; ++i) {
-                       if (code_pages [i])
-                               add_code_page (n, size_code_pages, code_pages [i]);
-               }
-               if (code_pages)
-                       g_free (code_pages);
-               code_pages = n;
-       }
-       num_code_pages += add_code_page (code_pages, size_code_pages, ip & CPAGE_MASK);
-}
-
-/* ELF code crashes on some systems. */
-//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
-#if 0
-static void
-dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
-{
-       int len = strlen (filename) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* load address */ +
-               LEB128_SIZE /* offset */ +
-               LEB128_SIZE /* size */ +
-               nlen /* file name */
-       );
-
-       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
-       emit_svalue (logbuffer, load_addr);
-       emit_uvalue (logbuffer, offset);
-       emit_uvalue (logbuffer, size);
-       memcpy (logbuffer->cursor, filename, len);
-       logbuffer->cursor += len;
-
-       EXIT_LOG;
-}
-#endif
-
-static void
-dump_usym (const char *name, uintptr_t value, uintptr_t size)
-{
-       int len = strlen (name) + 1;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* value */ +
-               LEB128_SIZE /* size */ +
-               len /* name */
-       );
-
-       emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
-       emit_ptr (logbuffer, (void*)value);
-       emit_value (logbuffer, size);
-       memcpy (logbuffer->cursor, name, len);
-       logbuffer->cursor += len;
-
-       EXIT_LOG;
-}
-
-/* ELF code crashes on some systems. */
-//#if defined(ELFMAG0)
-#if 0
-
-#if SIZEOF_VOID_P == 4
-#define ELF_WSIZE 32
-#else
-#define ELF_WSIZE 64
-#endif
-#ifndef ElfW
-#define ElfW(type)      _ElfW (Elf, ELF_WSIZE, type)
-#define _ElfW(e,w,t)    _ElfW_1 (e, w, _##t)
-#define _ElfW_1(e,w,t)  e##w##t
-#endif
-
-static void
-dump_elf_symbols (ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
-{
-       int i;
-       for (i = 0; i < num_symbols; ++i) {
-               const char* sym;
-               sym =  strtab + symbols [i].st_name;
-               if (!symbols [i].st_name || !symbols [i].st_size || (symbols [i].st_info & 0xf) != STT_FUNC)
-                       continue;
-               //printf ("symbol %s at %d\n", sym, symbols [i].st_value);
-               dump_usym (sym, (uintptr_t)load_addr + symbols [i].st_value, symbols [i].st_size);
-       }
-}
-
-static int
-read_elf_symbols (MonoProfiler *prof, const char *filename, void *load_addr)
-{
-       int fd, i;
-       void *data;
-       struct stat statb;
-       uint64_t file_size;
-       ElfW(Ehdr) *header;
-       ElfW(Shdr) *sheader;
-       ElfW(Shdr) *shstrtabh;
-       ElfW(Shdr) *symtabh = NULL;
-       ElfW(Shdr) *strtabh = NULL;
-       ElfW(Sym) *symbols = NULL;
-       const char *strtab;
-       int num_symbols;
-
-       fd = open (filename, O_RDONLY);
-       if (fd < 0)
-               return 0;
-       if (fstat (fd, &statb) != 0) {
-               close (fd);
-               return 0;
-       }
-       file_size = statb.st_size;
-       data = mmap (NULL, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
-       close (fd);
-       if (data == MAP_FAILED)
-               return 0;
-       header = data;
-       if (header->e_ident [EI_MAG0] != ELFMAG0 ||
-                       header->e_ident [EI_MAG1] != ELFMAG1 ||
-                       header->e_ident [EI_MAG2] != ELFMAG2 ||
-                       header->e_ident [EI_MAG3] != ELFMAG3 ) {
-               munmap (data, file_size);
-               return 0;
-       }
-       sheader = (void*)((char*)data + header->e_shoff);
-       shstrtabh = (void*)((char*)sheader + (header->e_shentsize * header->e_shstrndx));
-       strtab = (const char*)data + shstrtabh->sh_offset;
-       for (i = 0; i < header->e_shnum; ++i) {
-               //printf ("section header: %d\n", sheader->sh_type);
-               if (sheader->sh_type == SHT_SYMTAB) {
-                       symtabh = sheader;
-                       strtabh = (void*)((char*)data + header->e_shoff + sheader->sh_link * header->e_shentsize);
-                       /*printf ("symtab section header: %d, .strstr: %d\n", i, sheader->sh_link);*/
-                       break;
-               }
-               sheader = (void*)((char*)sheader + header->e_shentsize);
-       }
-       if (!symtabh || !strtabh) {
-               munmap (data, file_size);
-               return 0;
-       }
-       strtab = (const char*)data + strtabh->sh_offset;
-       num_symbols = symtabh->sh_size / symtabh->sh_entsize;
-       symbols = (void*)((char*)data + symtabh->sh_offset);
-       dump_elf_symbols (symbols, num_symbols, strtab, load_addr);
-       munmap (data, file_size);
-       return 1;
-}
-#endif
-
-/* ELF code crashes on some systems. */
-//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
-#if 0
-static int
-elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data)
-{
-       MonoProfiler *prof = data;
-       char buf [256];
-       const char *filename;
-       BinaryObject *obj;
-       char *a = (void*)info->dlpi_addr;
-       int i, num_sym;
-       ElfW(Dyn) *dyn = NULL;
-       ElfW(Sym) *symtab = NULL;
-       ElfW(Word) *hash_table = NULL;
-       ElfW(Ehdr) *header = NULL;
-       const char* strtab = NULL;
-       for (obj = prof->binary_objects; obj; obj = obj->next) {
-               if (obj->addr == a)
-                       return 0;
-       }
-       filename = info->dlpi_name;
-       if (!filename)
-               return 0;
-       if (!info->dlpi_addr && !filename [0]) {
-               int l = readlink ("/proc/self/exe", buf, sizeof (buf) - 1);
-               if (l > 0) {
-                       buf [l] = 0;
-                       filename = buf;
-               }
-       }
-       obj = g_calloc (sizeof (BinaryObject), 1);
-       obj->addr = (void*)info->dlpi_addr;
-       obj->name = pstrdup (filename);
-       obj->next = prof->binary_objects;
-       prof->binary_objects = obj;
-       //printf ("loaded file: %s at %p, segments: %d\n", filename, (void*)info->dlpi_addr, info->dlpi_phnum);
-       a = NULL;
-       for (i = 0; i < info->dlpi_phnum; ++i) {
-               //printf ("segment type %d file offset: %d, size: %d\n", info->dlpi_phdr[i].p_type, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
-               if (info->dlpi_phdr[i].p_type == PT_LOAD && !header) {
-                       header = (ElfW(Ehdr)*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
-                       if (header->e_ident [EI_MAG0] != ELFMAG0 ||
-                                       header->e_ident [EI_MAG1] != ELFMAG1 ||
-                                       header->e_ident [EI_MAG2] != ELFMAG2 ||
-                                       header->e_ident [EI_MAG3] != ELFMAG3 ) {
-                               header = NULL;
-                       }
-                       dump_ubin (filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
-               } else if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
-                       dyn = (ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
-               }
-       }
-       if (read_elf_symbols (prof, filename, (void*)info->dlpi_addr))
-               return 0;
-       if (!info->dlpi_name || !info->dlpi_name[0])
-               return 0;
-       if (!dyn)
-               return 0;
-       for (i = 0; dyn [i].d_tag != DT_NULL; ++i) {
-               if (dyn [i].d_tag == DT_SYMTAB) {
-                       if (symtab && do_debug)
-                               printf ("multiple symtabs: %d\n", i);
-                       symtab = (ElfW(Sym) *)(a + dyn [i].d_un.d_ptr);
-               } else if (dyn [i].d_tag == DT_HASH) {
-                       hash_table = (ElfW(Word) *)(a + dyn [i].d_un.d_ptr);
-               } else if (dyn [i].d_tag == DT_STRTAB) {
-                       strtab = (const char*)(a + dyn [i].d_un.d_ptr);
-               }
-       }
-       if (!hash_table)
-               return 0;
-       num_sym = hash_table [1];
-       dump_elf_symbols (symtab, num_sym, strtab, (void*)info->dlpi_addr);
-       return 0;
-}
-
-static int
-load_binaries (MonoProfiler *prof)
-{
-       dl_iterate_phdr (elf_dl_callback, prof);
-       return 1;
-}
-#else
-static int
-load_binaries (MonoProfiler *prof)
-{
-       return 0;
-}
-#endif
-
-static const char*
-symbol_for (uintptr_t code)
-{
-#ifdef HAVE_DLADDR
-       void *ip = (void*)code;
-       Dl_info di;
-       if (dladdr (ip, &di)) {
-               if (di.dli_sname)
-                       return di.dli_sname;
-       } else {
-       /*      char **names;
-               names = backtrace_symbols (&ip, 1);
-               if (names) {
-                       const char* p = names [0];
-                       g_free (names);
-                       return p;
-               }
-               */
-       }
-#endif
-       return NULL;
-}
-
-static void
-dump_unmanaged_coderefs (MonoProfiler *prof)
-{
-       int i;
-       const char* last_symbol;
-       uintptr_t addr, page_end;
-
-       if (load_binaries (prof))
-               return;
-       for (i = 0; i < size_code_pages; ++i) {
-               const char* sym;
-               if (!code_pages [i] || code_pages [i] & 1)
-                       continue;
-               last_symbol = NULL;
-               addr = CPAGE_ADDR (code_pages [i]);
-               page_end = addr + CPAGE_SIZE;
-               code_pages [i] |= 1;
-               /* we dump the symbols for the whole page */
-               for (; addr < page_end; addr += 16) {
-                       sym = symbol_for (addr);
-                       if (sym && sym == last_symbol)
-                               continue;
-                       last_symbol = sym;
-                       if (!sym)
-                               continue;
-                       dump_usym (sym, addr, 0); /* let's not guess the size */
-                       //printf ("found symbol at %p: %s\n", (void*)addr, sym);
-               }
-       }
-}
-
-static int
-mono_cpu_count (void)
-{
-#ifdef PLATFORM_ANDROID
-       /* Android tries really hard to save power by powering off CPUs on SMP phones which
-        * means the normal way to query cpu count returns a wrong value with userspace API.
-        * Instead we use /sys entries to query the actual hardware CPU count.
-        */
-       int count = 0;
-       char buffer[8] = {'\0'};
-       int present = open ("/sys/devices/system/cpu/present", O_RDONLY);
-       /* Format of the /sys entry is a cpulist of indexes which in the case
-        * of present is always of the form "0-(n-1)" when there is more than
-        * 1 core, n being the number of CPU cores in the system. Otherwise
-        * the value is simply 0
-        */
-       if (present != -1 && read (present, (char*)buffer, sizeof (buffer)) > 3)
-               count = strtol (((char*)buffer) + 2, NULL, 10);
-       if (present != -1)
-               close (present);
-       if (count > 0)
-               return count + 1;
-#endif
-
-#if defined(HOST_ARM) || defined (HOST_ARM64)
-
-       /* ARM platforms tries really hard to save power by powering off CPUs on SMP phones which
-        * means the normal way to query cpu count returns a wrong value with userspace API. */
-
-#ifdef _SC_NPROCESSORS_CONF
-       {
-               int count = sysconf (_SC_NPROCESSORS_CONF);
-               if (count > 0)
-                       return count;
-       }
-#endif
-
-#else
-
-#ifdef HAVE_SCHED_GETAFFINITY
-       {
-               cpu_set_t set;
-               if (sched_getaffinity (getpid (), sizeof (set), &set) == 0)
-                       return CPU_COUNT (&set);
-       }
-#endif
-#ifdef _SC_NPROCESSORS_ONLN
-       {
-               int count = sysconf (_SC_NPROCESSORS_ONLN);
-               if (count > 0)
-                       return count;
-       }
-#endif
-
-#endif /* defined(HOST_ARM) || defined (HOST_ARM64) */
-
-#ifdef USE_SYSCTL
-       {
-               int count;
-               int mib [2];
-               size_t len = sizeof (int);
-               mib [0] = CTL_HW;
-               mib [1] = HW_NCPU;
-               if (sysctl (mib, 2, &count, &len, NULL, 0) == 0)
-                       return count;
-       }
-#endif
-#ifdef HOST_WIN32
-       {
-               SYSTEM_INFO info;
-               GetSystemInfo (&info);
-               return info.dwNumberOfProcessors;
-       }
-#endif
-       /* FIXME: warn */
-       return 1;
-}
-
-#if USE_PERF_EVENTS
-
-typedef struct {
-       int perf_fd;
-       unsigned int prev_pos;
-       void *mmap_base;
-       struct perf_event_mmap_page *page_desc;
-} PerfData ;
-
-static PerfData *perf_data = NULL;
-static int num_perf;
-#define PERF_PAGES_SHIFT 4
-static int num_pages = 1 << PERF_PAGES_SHIFT;
-static unsigned int mmap_mask;
-
-typedef struct {
-       struct perf_event_header h;
-       uint64_t ip;
-       uint32_t pid;
-       uint32_t tid;
-       uint64_t timestamp;
-       uint64_t period;
-       uint64_t nframes;
-} PSample;
-
-static int
-perf_event_syscall (struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags)
-{
-       attr->size = PERF_ATTR_SIZE_VER0;
-       //printf ("perf attr size: %d\n", attr->size);
-#if defined(__x86_64__)
-       return syscall(/*__NR_perf_event_open*/ 298, attr, pid, cpu, group_fd, flags);
-#elif defined(__i386__)
-       return syscall(/*__NR_perf_event_open*/ 336, attr, pid, cpu, group_fd, flags);
-#elif defined(__arm__) || defined (__aarch64__)
-       return syscall(/*__NR_perf_event_open*/ 364, attr, pid, cpu, group_fd, flags);
-#else
-       return -1;
-#endif
-}
-
-static int
-setup_perf_map (PerfData *perf)
-{
-       perf->mmap_base = mmap (NULL, (num_pages + 1) * getpagesize (), PROT_READ|PROT_WRITE, MAP_SHARED, perf->perf_fd, 0);
-       if (perf->mmap_base == MAP_FAILED) {
-               if (do_debug)
-                       printf ("failed mmap\n");
-               return 0;
-       }
-       perf->page_desc = perf->mmap_base;
-       if (do_debug)
-               printf ("mmap version: %d\n", perf->page_desc->version);
-       return 1;
-}
-
-static void
-dump_perf_hits (MonoProfiler *prof, void *buf, int size)
-{
-       int count = 1;
-       int mbt_count = 0;
-       void *end = (char*)buf + size;
-       int samples = 0;
-       int pid = getpid ();
-
-       while (buf < end) {
-               PSample *s = buf;
-               if (s->h.size == 0)
-                       break;
-               if (pid != s->pid) {
-                       if (do_debug)
-                               printf ("event for different pid: %d\n", s->pid);
-                       buf = (char*)buf + s->h.size;
-                       continue;
-               }
-               /*ip = (void*)s->ip;
-               printf ("sample: %d, size: %d, ip: %p (%s), timestamp: %llu, nframes: %llu\n",
-                       s->h.type, s->h.size, ip, symbol_for (ip), s->timestamp, s->nframes);*/
-
-               ENTER_LOG;
-
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       BYTE_SIZE /* type */ +
-                       LEB128_SIZE /* tid */ +
-                       LEB128_SIZE /* count */ +
-                       count * (
-                               LEB128_SIZE /* ip */
-                       ) +
-                       LEB128_SIZE /* managed count */ +
-                       mbt_count * (
-                               LEB128_SIZE /* method */
-                       )
-               );
-
-               emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
-               emit_byte (logbuffer, sample_type);
-               /*
-                * No useful thread ID to write here, since throughout the
-                * profiler we use pthread_self () but the ID we get from
-                * perf is the kernel's thread ID.
-                */
-               emit_ptr (logbuffer, 0);
-               emit_value (logbuffer, count);
-               emit_ptr (logbuffer, (void*)(uintptr_t)s->ip);
-               /* no support here yet for the managed backtrace */
-               emit_uvalue (logbuffer, mbt_count);
-
-               EXIT_LOG;
-
-               add_code_pointer (s->ip);
-               buf = (char*)buf + s->h.size;
-               samples++;
-       }
-       if (do_debug)
-               printf ("dumped %d samples\n", samples);
-       dump_unmanaged_coderefs (prof);
-}
-
-/* read events from the ring buffer */
-static int
-read_perf_mmap (MonoProfiler* prof, int cpu)
-{
-       PerfData *perf = perf_data + cpu;
-       unsigned char *buf;
-       unsigned char *data = (unsigned char*)perf->mmap_base + getpagesize ();
-       unsigned int head = perf->page_desc->data_head;
-       int diff, size;
-       unsigned int old;
-
-       mono_memory_read_barrier ();
-
-       old = perf->prev_pos;
-       diff = head - old;
-       if (diff < 0) {
-               if (do_debug)
-                       printf ("lost mmap events: old: %d, head: %d\n", old, head);
-               old = head;
-       }
-       size = head - old;
-       if ((old & mmap_mask) + size != (head & mmap_mask)) {
-               buf = data + (old & mmap_mask);
-               size = mmap_mask + 1 - (old & mmap_mask);
-               old += size;
-               /* size bytes at buf */
-               if (do_debug)
-                       printf ("found1 bytes of events: %d\n", size);
-               dump_perf_hits (prof, buf, size);
-       }
-       buf = data + (old & mmap_mask);
-       size = head - old;
-       /* size bytes at buf */
-       if (do_debug)
-               printf ("found bytes of events: %d\n", size);
-       dump_perf_hits (prof, buf, size);
-       old += size;
-       perf->prev_pos = old;
-       perf->page_desc->data_tail = old;
-       return 0;
-}
-
-static int
-setup_perf_event_for_cpu (PerfData *perf, int cpu)
-{
-       struct perf_event_attr attr;
-       memset (&attr, 0, sizeof (attr));
-       attr.type = PERF_TYPE_HARDWARE;
-       switch (sample_type) {
-       case SAMPLE_CYCLES: attr.config = PERF_COUNT_HW_CPU_CYCLES; break;
-       case SAMPLE_INSTRUCTIONS: attr.config = PERF_COUNT_HW_INSTRUCTIONS; break;
-       case SAMPLE_CACHE_MISSES: attr.config = PERF_COUNT_HW_CACHE_MISSES; break;
-       case SAMPLE_CACHE_REFS: attr.config = PERF_COUNT_HW_CACHE_REFERENCES; break;
-       case SAMPLE_BRANCHES: attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; break;
-       case SAMPLE_BRANCH_MISSES: attr.config = PERF_COUNT_HW_BRANCH_MISSES; break;
-       default: attr.config = PERF_COUNT_HW_CPU_CYCLES; break;
-       }
-       attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD | PERF_SAMPLE_TIME;
-//     attr.sample_type |= PERF_SAMPLE_CALLCHAIN;
-       attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID;
-       attr.inherit = 1;
-       attr.freq = 1;
-       attr.sample_freq = sample_freq;
-
-       perf->perf_fd = perf_event_syscall (&attr, getpid (), cpu, -1, 0);
-       if (do_debug)
-               printf ("perf fd: %d, freq: %d, event: %llu\n", perf->perf_fd, sample_freq, attr.config);
-       if (perf->perf_fd < 0) {
-               if (perf->perf_fd == -EPERM) {
-                       fprintf (stderr, "Perf syscall denied, do \"echo 1 > /proc/sys/kernel/perf_event_paranoid\" as root to enable.\n");
-               } else {
-                       if (do_debug)
-                               perror ("open perf event");
-               }
-               return 0;
-       }
-       if (!setup_perf_map (perf)) {
-               close (perf->perf_fd);
-               perf->perf_fd = -1;
-               return 0;
-       }
-       return 1;
-}
-
-static int
-setup_perf_event (void)
-{
-       int i, count = 0;
-       mmap_mask = num_pages * getpagesize () - 1;
-       num_perf = mono_cpu_count ();
-       perf_data = g_calloc (num_perf, sizeof (PerfData));
-       for (i = 0; i < num_perf; ++i) {
-               count += setup_perf_event_for_cpu (perf_data + i, i);
-       }
-       if (count)
-               return 1;
-       g_free (perf_data);
-       perf_data = NULL;
-       return 0;
-}
-
-#endif /* USE_PERF_EVENTS */
-
-#ifndef DISABLE_HELPER_THREAD
-
-typedef struct MonoCounterAgent {
-       MonoCounter *counter;
-       // MonoCounterAgent specific data :
-       void *value;
-       size_t value_size;
-       short index;
-       short emitted;
-       struct MonoCounterAgent *next;
-} MonoCounterAgent;
-
-static MonoCounterAgent* counters;
-static gboolean counters_initialized = FALSE;
-static int counters_index = 1;
-static mono_mutex_t counters_mutex;
-
-static void
-counters_add_agent (MonoCounter *counter)
-{
-       MonoCounterAgent *agent, *item;
-
-       if (!counters_initialized)
-               return;
-
-       mono_os_mutex_lock (&counters_mutex);
-
-       for (agent = counters; agent; agent = agent->next) {
-               if (agent->counter == counter) {
-                       agent->value_size = 0;
-                       if (agent->value) {
-                               g_free (agent->value);
-                               agent->value = NULL;
-                       }
-                       mono_os_mutex_unlock (&counters_mutex);
-                       return;
-               }
-       }
-
-       agent = (MonoCounterAgent *)malloc (sizeof (MonoCounterAgent));
-       agent->counter = counter;
-       agent->value = NULL;
-       agent->value_size = 0;
-       agent->index = counters_index++;
-       agent->emitted = 0;
-       agent->next = NULL;
-
-       if (!counters) {
-               counters = agent;
-       } else {
-               item = counters;
-               while (item->next)
-                       item = item->next;
-               item->next = agent;
-       }
-
-       mono_os_mutex_unlock (&counters_mutex);
-}
-
-static mono_bool
-counters_init_foreach_callback (MonoCounter *counter, gpointer data)
-{
-       counters_add_agent (counter);
-       return TRUE;
-}
-
-static void
-counters_init (MonoProfiler *profiler)
-{
-       assert (!counters_initialized);
-
-       mono_os_mutex_init (&counters_mutex);
-
-       counters_initialized = TRUE;
-
-       mono_counters_on_register (&counters_add_agent);
-       mono_counters_foreach (counters_init_foreach_callback, NULL);
-}
-
-static void
-counters_emit (MonoProfiler *profiler)
-{
-       MonoCounterAgent *agent;
-       int len = 0;
-       int size =
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* len */
-       ;
-
-       if (!counters_initialized)
-               return;
-
-       mono_os_mutex_lock (&counters_mutex);
-
-       for (agent = counters; agent; agent = agent->next) {
-               if (agent->emitted)
-                       continue;
-
-               size +=
-                       LEB128_SIZE /* section */ +
-                       strlen (mono_counter_get_name (agent->counter)) + 1 /* name */ +
-                       BYTE_SIZE /* type */ +
-                       BYTE_SIZE /* unit */ +
-                       BYTE_SIZE /* variance */ +
-                       LEB128_SIZE /* index */
-               ;
-
-               len += 1;
-       }
-
-       if (!len) {
-               mono_os_mutex_unlock (&counters_mutex);
-               return;
-       }
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (size);
-
-       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
-       emit_value (logbuffer, len);
-
-       for (agent = counters; agent; agent = agent->next) {
-               const char *name;
-
-               if (agent->emitted)
-                       continue;
-
-               name = mono_counter_get_name (agent->counter);
-               emit_value (logbuffer, mono_counter_get_section (agent->counter));
-               emit_string (logbuffer, name, strlen (name) + 1);
-               emit_byte (logbuffer, mono_counter_get_type (agent->counter));
-               emit_byte (logbuffer, mono_counter_get_unit (agent->counter));
-               emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
-               emit_value (logbuffer, agent->index);
-
-               agent->emitted = 1;
-       }
-
-       EXIT_LOG;
-
-       mono_os_mutex_unlock (&counters_mutex);
-}
-
-static void
-counters_sample (MonoProfiler *profiler, uint64_t timestamp)
-{
-       MonoCounterAgent *agent;
-       MonoCounter *counter;
-       int type;
-       int buffer_size;
-       void *buffer;
-       int size;
-
-       if (!counters_initialized)
-               return;
-
-       counters_emit (profiler);
-
-       buffer_size = 8;
-       buffer = g_calloc (1, buffer_size);
-
-       mono_os_mutex_lock (&counters_mutex);
-
-       size =
-               EVENT_SIZE /* event */
-       ;
-
-       for (agent = counters; agent; agent = agent->next) {
-               size +=
-                       LEB128_SIZE /* index */ +
-                       BYTE_SIZE /* type */ +
-                       mono_counter_get_size (agent->counter) /* value */
-               ;
-       }
-
-       size +=
-               LEB128_SIZE /* stop marker */
-       ;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (size);
-
-       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
-
-       for (agent = counters; agent; agent = agent->next) {
-               size_t size;
-
-               counter = agent->counter;
-
-               size = mono_counter_get_size (counter);
-               if (size < 0) {
-                       continue; // FIXME error
-               } else if (size > buffer_size) {
-                       buffer_size = size;
-                       buffer = g_realloc (buffer, buffer_size);
-               }
-
-               memset (buffer, 0, buffer_size);
-
-               if (mono_counters_sample (counter, buffer, size) < 0)
-                       continue; // FIXME error
-
-               type = mono_counter_get_type (counter);
-
-               if (!agent->value) {
-                       agent->value = g_calloc (1, size);
-                       agent->value_size = size;
-               } else {
-                       if (type == MONO_COUNTER_STRING) {
-                               if (strcmp (agent->value, buffer) == 0)
-                                       continue;
-                       } else {
-                               if (agent->value_size == size && memcmp (agent->value, buffer, size) == 0)
-                                       continue;
-                       }
-               }
-
-               emit_uvalue (logbuffer, agent->index);
-               emit_byte (logbuffer, type);
-               switch (type) {
-               case MONO_COUNTER_INT:
-#if SIZEOF_VOID_P == 4
-               case MONO_COUNTER_WORD:
-#endif
-                       emit_svalue (logbuffer, *(int*)buffer - *(int*)agent->value);
-                       break;
-               case MONO_COUNTER_UINT:
-                       emit_uvalue (logbuffer, *(guint*)buffer - *(guint*)agent->value);
-                       break;
-               case MONO_COUNTER_TIME_INTERVAL:
-               case MONO_COUNTER_LONG:
-#if SIZEOF_VOID_P == 8
-               case MONO_COUNTER_WORD:
-#endif
-                       emit_svalue (logbuffer, *(gint64*)buffer - *(gint64*)agent->value);
-                       break;
-               case MONO_COUNTER_ULONG:
-                       emit_uvalue (logbuffer, *(guint64*)buffer - *(guint64*)agent->value);
-                       break;
-               case MONO_COUNTER_DOUBLE:
-                       emit_double (logbuffer, *(double*)buffer);
-                       break;
-               case MONO_COUNTER_STRING:
-                       if (size == 0) {
-                               emit_byte (logbuffer, 0);
-                       } else {
-                               emit_byte (logbuffer, 1);
-                               emit_string (logbuffer, (char*)buffer, size);
-                       }
-                       break;
-               default:
-                       assert (0);
-               }
-
-               if (type == MONO_COUNTER_STRING && size > agent->value_size) {
-                       agent->value = g_realloc (agent->value, size);
-                       agent->value_size = size;
-               }
-
-               if (size > 0)
-                       memcpy (agent->value, buffer, size);
-       }
-       g_free (buffer);
-
-       emit_value (logbuffer, 0);
-
-       EXIT_LOG;
-
-       mono_os_mutex_unlock (&counters_mutex);
-}
-
-typedef struct _PerfCounterAgent PerfCounterAgent;
-struct _PerfCounterAgent {
-       PerfCounterAgent *next;
-       int index;
-       char *category_name;
-       char *name;
-       int type;
-       gint64 value;
-       guint8 emitted;
-       guint8 updated;
-       guint8 deleted;
-};
-
-static PerfCounterAgent *perfcounters = NULL;
-
-static void
-perfcounters_emit (MonoProfiler *profiler)
-{
-       PerfCounterAgent *pcagent;
-       int len = 0;
-       int size =
-               EVENT_SIZE /* event */ +
-               LEB128_SIZE /* len */
-       ;
-
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
-               if (pcagent->emitted)
-                       continue;
-
-               size +=
-                       LEB128_SIZE /* section */ +
-                       strlen (pcagent->category_name) + 1 /* category name */ +
-                       strlen (pcagent->name) + 1 /* name */ +
-                       BYTE_SIZE /* type */ +
-                       BYTE_SIZE /* unit */ +
-                       BYTE_SIZE /* variance */ +
-                       LEB128_SIZE /* index */
-               ;
-
-               len += 1;
-       }
-
-       if (!len)
-               return;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (size);
-
-       emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
-       emit_value (logbuffer, len);
-
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
-               if (pcagent->emitted)
-                       continue;
-
-               emit_value (logbuffer, MONO_COUNTER_PERFCOUNTERS);
-               emit_string (logbuffer, pcagent->category_name, strlen (pcagent->category_name) + 1);
-               emit_string (logbuffer, pcagent->name, strlen (pcagent->name) + 1);
-               emit_byte (logbuffer, MONO_COUNTER_LONG);
-               emit_byte (logbuffer, MONO_COUNTER_RAW);
-               emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
-               emit_value (logbuffer, pcagent->index);
-
-               pcagent->emitted = 1;
-       }
-
-       EXIT_LOG;
-}
-
-static gboolean
-perfcounters_foreach (char *category_name, char *name, unsigned char type, gint64 value, gpointer user_data)
-{
-       PerfCounterAgent *pcagent;
-
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
-               if (strcmp (pcagent->category_name, category_name) != 0 || strcmp (pcagent->name, name) != 0)
-                       continue;
-               if (pcagent->value == value)
-                       return TRUE;
-
-               pcagent->value = value;
-               pcagent->updated = 1;
-               pcagent->deleted = 0;
-               return TRUE;
-       }
-
-       pcagent = g_new0 (PerfCounterAgent, 1);
-       pcagent->next = perfcounters;
-       pcagent->index = counters_index++;
-       pcagent->category_name = g_strdup (category_name);
-       pcagent->name = g_strdup (name);
-       pcagent->type = (int) type;
-       pcagent->value = value;
-       pcagent->emitted = 0;
-       pcagent->updated = 1;
-       pcagent->deleted = 0;
-
-       perfcounters = pcagent;
-
-       return TRUE;
-}
-
-static void
-perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
-{
-       PerfCounterAgent *pcagent;
-       int size;
-
-       if (!counters_initialized)
-               return;
-
-       mono_os_mutex_lock (&counters_mutex);
-
-       /* mark all perfcounters as deleted, foreach will unmark them as necessary */
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next)
-               pcagent->deleted = 1;
-
-       mono_perfcounter_foreach (perfcounters_foreach, perfcounters);
-
-       perfcounters_emit (profiler);
-
-       size =
-               EVENT_SIZE /* event */
-       ;
-
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
-               if (pcagent->deleted || !pcagent->updated)
-                       continue;
-
-               size +=
-                       LEB128_SIZE /* index */ +
-                       BYTE_SIZE /* type */ +
-                       LEB128_SIZE /* value */
-               ;
-       }
-
-       size +=
-               LEB128_SIZE /* stop marker */
-       ;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (size);
-
-       emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
-
-       for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
-               if (pcagent->deleted || !pcagent->updated)
-                       continue;
-               emit_uvalue (logbuffer, pcagent->index);
-               emit_byte (logbuffer, MONO_COUNTER_LONG);
-               emit_svalue (logbuffer, pcagent->value);
-
-               pcagent->updated = 0;
-       }
-
-       emit_value (logbuffer, 0);
-
-       EXIT_LOG;
-
-       mono_os_mutex_unlock (&counters_mutex);
-}
-
-static void
-counters_and_perfcounters_sample (MonoProfiler *prof)
-{
-       uint64_t now = current_time ();
-
-       counters_sample (prof, now);
-       perfcounters_sample (prof, now);
-}
-
-#define COVERAGE_DEBUG(x) if (debug_coverage) {x}
-static mono_mutex_t coverage_mutex;
-static MonoConcurrentHashTable *coverage_methods = NULL;
-static MonoConcurrentHashTable *coverage_assemblies = NULL;
-static MonoConcurrentHashTable *coverage_classes = NULL;
-
-static MonoConcurrentHashTable *filtered_classes = NULL;
-static MonoConcurrentHashTable *entered_methods = NULL;
-static MonoConcurrentHashTable *image_to_methods = NULL;
-static MonoConcurrentHashTable *suppressed_assemblies = NULL;
-static gboolean coverage_initialized = FALSE;
-
-static GPtrArray *coverage_data = NULL;
-static int previous_offset = 0;
-
-typedef struct {
-       MonoLockFreeQueueNode node;
-       MonoMethod *method;
-} MethodNode;
-
-typedef struct {
-       int offset;
-       int counter;
-       char *filename;
-       int line;
-       int column;
-} CoverageEntry;
-
-static void
-free_coverage_entry (gpointer data, gpointer userdata)
-{
-       CoverageEntry *entry = (CoverageEntry *)data;
-       g_free (entry->filename);
-       g_free (entry);
-}
-
-static void
-obtain_coverage_for_method (MonoProfiler *prof, const MonoProfileCoverageEntry *entry)
-{
-       int offset = entry->iloffset - previous_offset;
-       CoverageEntry *e = g_new (CoverageEntry, 1);
-
-       previous_offset = entry->iloffset;
-
-       e->offset = offset;
-       e->counter = entry->counter;
-       e->filename = g_strdup(entry->filename ? entry->filename : "");
-       e->line = entry->line;
-       e->column = entry->col;
-
-       g_ptr_array_add (coverage_data, e);
-}
-
-static char *
-parse_generic_type_names(char *name)
-{
-       char *new_name, *ret;
-       int within_generic_declaration = 0, generic_members = 1;
-
-       if (name == NULL || *name == '\0')
-               return g_strdup ("");
-
-       if (!(ret = new_name = (char *)calloc (strlen (name) * 4 + 1, sizeof (char))))
-               return NULL;
-
-       do {
-               switch (*name) {
-                       case '<':
-                               within_generic_declaration = 1;
-                               break;
-
-                       case '>':
-                               within_generic_declaration = 0;
-
-                               if (*(name - 1) != '<') {
-                                       *new_name++ = '`';
-                                       *new_name++ = '0' + generic_members;
-                               } else {
-                                       memcpy (new_name, "&lt;&gt;", 8);
-                                       new_name += 8;
-                               }
-
-                               generic_members = 0;
-                               break;
-
-                       case ',':
-                               generic_members++;
-                               break;
-
-                       default:
-                               if (!within_generic_declaration)
-                                       *new_name++ = *name;
-
-                               break;
-               }
-       } while (*name++);
-
-       return ret;
-}
-
-static int method_id;
-static void
-build_method_buffer (gpointer key, gpointer value, gpointer userdata)
-{
-       MonoMethod *method = (MonoMethod *)value;
-       MonoProfiler *prof = (MonoProfiler *)userdata;
-       MonoClass *klass;
-       MonoImage *image;
-       char *class_name;
-       const char *image_name, *method_name, *sig, *first_filename;
-       guint i;
-
-       previous_offset = 0;
-       coverage_data = g_ptr_array_new ();
-
-       mono_profiler_coverage_get (prof, method, obtain_coverage_for_method);
-
-       klass = mono_method_get_class (method);
-       image = mono_class_get_image (klass);
-       image_name = mono_image_get_name (image);
-
-       sig = mono_signature_get_desc (mono_method_signature (method), TRUE);
-       class_name = parse_generic_type_names (mono_type_get_name (mono_class_get_type (klass)));
-       method_name = mono_method_get_name (method);
-
-       if (coverage_data->len != 0) {
-               CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[0];
-               first_filename = entry->filename ? entry->filename : "";
-       } else
-               first_filename = "";
-
-       image_name = image_name ? image_name : "";
-       sig = sig ? sig : "";
-       method_name = method_name ? method_name : "";
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               strlen (image_name) + 1 /* image name */ +
-               strlen (class_name) + 1 /* class name */ +
-               strlen (method_name) + 1 /* method name */ +
-               strlen (sig) + 1 /* signature */ +
-               strlen (first_filename) + 1 /* first file name */ +
-               LEB128_SIZE /* token */ +
-               LEB128_SIZE /* method id */ +
-               LEB128_SIZE /* entries */
-       );
-
-       emit_event (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
-       emit_string (logbuffer, image_name, strlen (image_name) + 1);
-       emit_string (logbuffer, class_name, strlen (class_name) + 1);
-       emit_string (logbuffer, method_name, strlen (method_name) + 1);
-       emit_string (logbuffer, sig, strlen (sig) + 1);
-       emit_string (logbuffer, first_filename, strlen (first_filename) + 1);
-
-       emit_uvalue (logbuffer, mono_method_get_token (method));
-       emit_uvalue (logbuffer, method_id);
-       emit_value (logbuffer, coverage_data->len);
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       for (i = 0; i < coverage_data->len; i++) {
-               CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
-
-               ENTER_LOG;
-
-               LogBuffer *logbuffer = ensure_logbuf (
-                       EVENT_SIZE /* event */ +
-                       LEB128_SIZE /* method id */ +
-                       LEB128_SIZE /* offset */ +
-                       LEB128_SIZE /* counter */ +
-                       LEB128_SIZE /* line */ +
-                       LEB128_SIZE /* column */
-               );
-
-               emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
-               emit_uvalue (logbuffer, method_id);
-               emit_uvalue (logbuffer, entry->offset);
-               emit_uvalue (logbuffer, entry->counter);
-               emit_uvalue (logbuffer, entry->line);
-               emit_uvalue (logbuffer, entry->column);
-
-               EXIT_LOG;
-
-               send_if_needed (prof);
-       }
-
-       method_id++;
-
-       g_free (class_name);
-
-       g_ptr_array_foreach (coverage_data, free_coverage_entry, NULL);
-       g_ptr_array_free (coverage_data, TRUE);
-       coverage_data = NULL;
-}
-
-/* This empties the queue */
-static guint
-count_queue (MonoLockFreeQueue *queue)
-{
-       MonoLockFreeQueueNode *node;
-       guint count = 0;
-
-       while ((node = mono_lock_free_queue_dequeue (queue))) {
-               count++;
-               mono_thread_hazardous_try_free (node, free);
-       }
-
-       return count;
-}
-
-static void
-build_class_buffer (gpointer key, gpointer value, gpointer userdata)
-{
-       MonoClass *klass = (MonoClass *)key;
-       MonoLockFreeQueue *class_methods = (MonoLockFreeQueue *)value;
-       MonoProfiler *prof = (MonoProfiler *)userdata;
-       MonoImage *image;
-       char *class_name;
-       const char *assembly_name;
-       int number_of_methods, partially_covered;
-       guint fully_covered;
-
-       image = mono_class_get_image (klass);
-       assembly_name = mono_image_get_name (image);
-       class_name = mono_type_get_name (mono_class_get_type (klass));
-
-       assembly_name = assembly_name ? assembly_name : "";
-       number_of_methods = mono_class_num_methods (klass);
-       fully_covered = count_queue (class_methods);
-       /* We don't handle partial covered yet */
-       partially_covered = 0;
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               strlen (assembly_name) + 1 /* assembly name */ +
-               strlen (class_name) + 1 /* class name */ +
-               LEB128_SIZE /* no. methods */ +
-               LEB128_SIZE /* fully covered */ +
-               LEB128_SIZE /* partially covered */
-       );
-
-       emit_event (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
-       emit_string (logbuffer, assembly_name, strlen (assembly_name) + 1);
-       emit_string (logbuffer, class_name, strlen (class_name) + 1);
-       emit_uvalue (logbuffer, number_of_methods);
-       emit_uvalue (logbuffer, fully_covered);
-       emit_uvalue (logbuffer, partially_covered);
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-
-       g_free (class_name);
-}
-
-static void
-get_coverage_for_image (MonoImage *image, int *number_of_methods, guint *fully_covered, int *partially_covered)
-{
-       MonoLockFreeQueue *image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
-
-       *number_of_methods = mono_image_get_table_rows (image, MONO_TABLE_METHOD);
-       if (image_methods)
-               *fully_covered = count_queue (image_methods);
-       else
-               *fully_covered = 0;
-
-       // FIXME: We don't handle partially covered yet.
-       *partially_covered = 0;
-}
-
-static void
-build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
-{
-       MonoAssembly *assembly = (MonoAssembly *)value;
-       MonoProfiler *prof = (MonoProfiler *)userdata;
-       MonoImage *image = mono_assembly_get_image (assembly);
-       const char *name, *guid, *filename;
-       int number_of_methods = 0, partially_covered = 0;
-       guint fully_covered = 0;
-
-       name = mono_image_get_name (image);
-       guid = mono_image_get_guid (image);
-       filename = mono_image_get_filename (image);
-
-       name = name ? name : "";
-       guid = guid ? guid : "";
-       filename = filename ? filename : "";
-
-       get_coverage_for_image (image, &number_of_methods, &fully_covered, &partially_covered);
-
-       ENTER_LOG;
-
-       LogBuffer *logbuffer = ensure_logbuf (
-               EVENT_SIZE /* event */ +
-               strlen (name) + 1 /* name */ +
-               strlen (guid) + 1 /* guid */ +
-               strlen (filename) + 1 /* file name */ +
-               LEB128_SIZE /* no. methods */ +
-               LEB128_SIZE /* fully covered */ +
-               LEB128_SIZE /* partially covered */
-       );
-
-       emit_event (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
-       emit_string (logbuffer, name, strlen (name) + 1);
-       emit_string (logbuffer, guid, strlen (guid) + 1);
-       emit_string (logbuffer, filename, strlen (filename) + 1);
-       emit_uvalue (logbuffer, number_of_methods);
-       emit_uvalue (logbuffer, fully_covered);
-       emit_uvalue (logbuffer, partially_covered);
-
-       EXIT_LOG;
-
-       send_if_needed (prof);
-}
-
-static void
-dump_coverage (MonoProfiler *prof)
-{
-       if (!coverage_initialized)
-               return;
-
-       COVERAGE_DEBUG(fprintf (stderr, "Coverage: Started dump\n");)
-       method_id = 0;
-
-       mono_os_mutex_lock (&coverage_mutex);
-       mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, prof);
-       mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, prof);
-       mono_conc_hashtable_foreach (coverage_methods, build_method_buffer, prof);
-       mono_os_mutex_unlock (&coverage_mutex);
-
-       COVERAGE_DEBUG(fprintf (stderr, "Coverage: Finished dump\n");)
-}
-
-static void
-process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method)
-{
-       MonoClass *klass;
-       MonoImage *image;
-
-       if (!coverage_initialized)
-               return;
-
-       klass = mono_method_get_class (method);
-       image = mono_class_get_image (klass);
-
-       if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)))
-               return;
-
-       mono_os_mutex_lock (&coverage_mutex);
-       mono_conc_hashtable_insert (entered_methods, method, method);
-       mono_os_mutex_unlock (&coverage_mutex);
-}
-
-static MonoLockFreeQueueNode *
-create_method_node (MonoMethod *method)
-{
-       MethodNode *node = (MethodNode *)g_malloc (sizeof (MethodNode));
-       mono_lock_free_queue_node_init ((MonoLockFreeQueueNode *) node, FALSE);
-       node->method = method;
-
-       return (MonoLockFreeQueueNode *) node;
-}
-
-static gboolean
-coverage_filter (MonoProfiler *prof, MonoMethod *method)
-{
-       MonoError error;
-       MonoClass *klass;
-       MonoImage *image;
-       MonoAssembly *assembly;
-       MonoMethodHeader *header;
-       guint32 iflags, flags, code_size;
-       char *fqn, *classname;
-       gboolean has_positive, found;
-       MonoLockFreeQueue *image_methods, *class_methods;
-       MonoLockFreeQueueNode *node;
-
-       if (!coverage_initialized)
-               return FALSE;
-
-       COVERAGE_DEBUG(fprintf (stderr, "Coverage filter for %s\n", mono_method_get_name (method));)
-
-       flags = mono_method_get_flags (method, &iflags);
-       if ((iflags & 0x1000 /*METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL*/) ||
-           (flags & 0x2000 /*METHOD_ATTRIBUTE_PINVOKE_IMPL*/)) {
-               COVERAGE_DEBUG(fprintf (stderr, "   Internal call or pinvoke - ignoring\n");)
-               return FALSE;
-       }
-
-       // Don't need to do anything else if we're already tracking this method
-       if (mono_conc_hashtable_lookup (coverage_methods, method)) {
-               COVERAGE_DEBUG(fprintf (stderr, "   Already tracking\n");)
-               return TRUE;
-       }
-
-       klass = mono_method_get_class (method);
-       image = mono_class_get_image (klass);
-
-       // Don't handle coverage for the core assemblies
-       if (mono_conc_hashtable_lookup (suppressed_assemblies, (gpointer) mono_image_get_name (image)) != NULL)
-               return FALSE;
-
-       if (prof->coverage_filters) {
-               /* Check already filtered classes first */
-               if (mono_conc_hashtable_lookup (filtered_classes, klass)) {
-                       COVERAGE_DEBUG(fprintf (stderr, "   Already filtered\n");)
-                       return FALSE;
-               }
-
-               classname = mono_type_get_name (mono_class_get_type (klass));
-
-               fqn = g_strdup_printf ("[%s]%s", mono_image_get_name (image), classname);
-
-               COVERAGE_DEBUG(fprintf (stderr, "   Looking for %s in filter\n", fqn);)
-               // Check positive filters first
-               has_positive = FALSE;
-               found = FALSE;
-               for (guint i = 0; i < prof->coverage_filters->len; ++i) {
-                       char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
-
-                       if (filter [0] == '+') {
-                               filter = &filter [1];
-
-                               COVERAGE_DEBUG(fprintf (stderr, "   Checking against +%s ...", filter);)
-
-                               if (strstr (fqn, filter) != NULL) {
-                                       COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
-                                       found = TRUE;
-                               } else
-                                       COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
-
-                               has_positive = TRUE;
-                       }
-               }
-
-               if (has_positive && !found) {
-                       COVERAGE_DEBUG(fprintf (stderr, "   Positive match was not found\n");)
-
-                       mono_os_mutex_lock (&coverage_mutex);
-                       mono_conc_hashtable_insert (filtered_classes, klass, klass);
-                       mono_os_mutex_unlock (&coverage_mutex);
-                       g_free (fqn);
-                       g_free (classname);
-
-                       return FALSE;
-               }
-
-               for (guint i = 0; i < prof->coverage_filters->len; ++i) {
-                       // FIXME: Is substring search sufficient?
-                       char *filter = (char *)g_ptr_array_index (prof->coverage_filters, i);
-                       if (filter [0] == '+')
-                               continue;
-
-                       // Skip '-'
-                       filter = &filter [1];
-                       COVERAGE_DEBUG(fprintf (stderr, "   Checking against -%s ...", filter);)
-
-                       if (strstr (fqn, filter) != NULL) {
-                               COVERAGE_DEBUG(fprintf (stderr, "matched\n");)
-
-                               mono_os_mutex_lock (&coverage_mutex);
-                               mono_conc_hashtable_insert (filtered_classes, klass, klass);
-                               mono_os_mutex_unlock (&coverage_mutex);
-                               g_free (fqn);
-                               g_free (classname);
-
-                               return FALSE;
-                       } else
-                               COVERAGE_DEBUG(fprintf (stderr, "no match\n");)
-
-               }
-
-               g_free (fqn);
-               g_free (classname);
-       }
-
-       COVERAGE_DEBUG(fprintf (stderr, "   Handling coverage for %s\n", mono_method_get_name (method));)
-       header = mono_method_get_header_checked (method, &error);
-       mono_error_cleanup (&error);
-
-       mono_method_header_get_code (header, &code_size, NULL);
-
-       assembly = mono_image_get_assembly (image);
-
-       // Need to keep the assemblies around for as long as they are kept in the hashtable
-       // Nunit, for example, has a habit of unloading them before the coverage statistics are
-       // generated causing a crash. See https://bugzilla.xamarin.com/show_bug.cgi?id=39325
-       mono_assembly_addref (assembly);
-
-       mono_os_mutex_lock (&coverage_mutex);
-       mono_conc_hashtable_insert (coverage_methods, method, method);
-       mono_conc_hashtable_insert (coverage_assemblies, assembly, assembly);
-       mono_os_mutex_unlock (&coverage_mutex);
-
-       image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image);
-
-       if (image_methods == NULL) {
-               image_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue));
-               mono_lock_free_queue_init (image_methods);
-               mono_os_mutex_lock (&coverage_mutex);
-               mono_conc_hashtable_insert (image_to_methods, image, image_methods);
-               mono_os_mutex_unlock (&coverage_mutex);
-       }
-
-       node = create_method_node (method);
-       mono_lock_free_queue_enqueue (image_methods, node);
-
-       class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (coverage_classes, klass);
-
-       if (class_methods == NULL) {
-               class_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue));
-               mono_lock_free_queue_init (class_methods);
-               mono_os_mutex_lock (&coverage_mutex);
-               mono_conc_hashtable_insert (coverage_classes, klass, class_methods);
-               mono_os_mutex_unlock (&coverage_mutex);
-       }
-
-       node = create_method_node (method);
-       mono_lock_free_queue_enqueue (class_methods, node);
-
-       return TRUE;
-}
-
-#define LINE_BUFFER_SIZE 4096
-/* Max file limit of 128KB */
-#define MAX_FILE_SIZE 128 * 1024
-static char *
-get_file_content (FILE *stream)
-{
-       char *buffer;
-       ssize_t bytes_read;
-       long filesize;
-       int res, offset = 0;
-
-       res = fseek (stream, 0, SEEK_END);
-       if (res < 0)
-         return NULL;
-
-       filesize = ftell (stream);
-       if (filesize < 0)
-         return NULL;
-
-       res = fseek (stream, 0, SEEK_SET);
-       if (res < 0)
-         return NULL;
-
-       if (filesize > MAX_FILE_SIZE)
-         return NULL;
-
-       buffer = (char *)g_malloc ((filesize + 1) * sizeof (char));
-       while ((bytes_read = fread (buffer + offset, 1, LINE_BUFFER_SIZE, stream)) > 0)
-               offset += bytes_read;
-
-       /* NULL terminate our buffer */
-       buffer[filesize] = '\0';
-       return buffer;
-}
-
-static char *
-get_next_line (char *contents, char **next_start)
-{
-       char *p = contents;
-
-       if (p == NULL || *p == '\0') {
-               *next_start = NULL;
-               return NULL;
-       }
-
-       while (*p != '\n' && *p != '\0')
-               p++;
-
-       if (*p == '\n') {
-               *p = '\0';
-               *next_start = p + 1;
-       } else
-               *next_start = NULL;
-
-       return contents;
-}
-
-static void
-init_suppressed_assemblies (void)
-{
-       char *content;
-       char *line;
-       FILE *sa_file;
-
-       suppressed_assemblies = mono_conc_hashtable_new (g_str_hash, g_str_equal);
-       sa_file = fopen (SUPPRESSION_DIR "/mono-profiler-log.suppression", "r");
-       if (sa_file == NULL)
-               return;
-
-       /* Don't need to free @content as it is referred to by the lines stored in @suppressed_assemblies */
-       content = get_file_content (sa_file);
-       if (content == NULL) {
-               g_error ("mono-profiler-log.suppression is greater than 128kb - aborting\n");
-       }
-
-       while ((line = get_next_line (content, &content))) {
-               line = g_strchomp (g_strchug (line));
-               /* No locking needed as we're doing initialization */
-               mono_conc_hashtable_insert (suppressed_assemblies, line, line);
-       }
-
-       fclose (sa_file);
-}
-
-#endif /* DISABLE_HELPER_THREAD */
-
-static void
-coverage_init (MonoProfiler *prof)
-{
-#ifndef DISABLE_HELPER_THREAD
-       assert (!coverage_initialized);
-
-       COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");)
-
-       mono_os_mutex_init (&coverage_mutex);
-       coverage_methods = mono_conc_hashtable_new (NULL, NULL);
-       coverage_assemblies = mono_conc_hashtable_new (NULL, NULL);
-       coverage_classes = mono_conc_hashtable_new (NULL, NULL);
-       filtered_classes = mono_conc_hashtable_new (NULL, NULL);
-       entered_methods = mono_conc_hashtable_new (NULL, NULL);
-       image_to_methods = mono_conc_hashtable_new (NULL, NULL);
-       init_suppressed_assemblies ();
-
-       coverage_initialized = TRUE;
-#endif /* DISABLE_HELPER_THREAD */
-}
-
-static void
-unref_coverage_assemblies (gpointer key, gpointer value, gpointer userdata)
-{
-       MonoAssembly *assembly = (MonoAssembly *)value;
-       mono_assembly_close (assembly);
-}
-
-static void
-free_sample_hit (gpointer p)
-{
-       mono_lock_free_free (p, SAMPLE_BLOCK_SIZE);
-}
-
-static void
-cleanup_reusable_samples (MonoProfiler *prof)
-{
-       SampleHit *sample;
-
-       while ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->sample_reuse_queue)))
-               mono_thread_hazardous_try_free (sample, free_sample_hit);
-}
-
-static void
-log_shutdown (MonoProfiler *prof)
-{
-       void *res;
-
-       in_shutdown = 1;
-#ifndef DISABLE_HELPER_THREAD
-       counters_and_perfcounters_sample (prof);
-
-       dump_coverage (prof);
-
-       if (prof->command_port) {
-               char c = 1;
-               ign_res (write (prof->pipes [1], &c, 1));
-               pthread_join (prof->helper_thread, &res);
-       }
-#endif
-#if USE_PERF_EVENTS
-       if (perf_data) {
-               int i;
-               for (i = 0; i < num_perf; ++i)
-                       read_perf_mmap (prof, i);
-       }
-#endif
-
-       /*
-        * Ensure that we empty the LLS completely, even if some nodes are
-        * not immediately removed upon calling mono_lls_remove (), by
-        * iterating until the head is NULL.
-        */
-       while (profiler_thread_list.head) {
-               MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
-                       remove_thread (prof, thread, FALSE);
-               } MONO_LLS_FOREACH_SAFE_END
-       }
-
-       InterlockedWrite (&prof->run_dumper_thread, 0);
-       mono_os_sem_post (&prof->dumper_queue_sem);
-       pthread_join (prof->dumper_thread, &res);
-       mono_os_sem_destroy (&prof->dumper_queue_sem);
-
-       InterlockedWrite (&prof->run_writer_thread, 0);
-       mono_os_sem_post (&prof->writer_queue_sem);
-       pthread_join (prof->writer_thread, &res);
-       mono_os_sem_destroy (&prof->writer_queue_sem);
-
-       cleanup_reusable_samples (prof);
-
-       /*
-        * Pump the entire hazard free queue to make sure that anything we allocated
-        * in the profiler will be freed. If we don't do this, the runtime could get
-        * around to freeing some items after the profiler has been unloaded, which
-        * would mean calling into functions in the profiler library, leading to a
-        * crash.
-        */
-       mono_thread_hazardous_try_free_all ();
-
-       g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why is the reader count still non-zero?");
-       g_assert (!InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why does someone still hold the exclusive lock?");
-
-#if defined (HAVE_SYS_ZLIB)
-       if (prof->gzfile)
-               gzclose (prof->gzfile);
-#endif
-       if (prof->pipe_output)
-               pclose (prof->file);
-       else
-               fclose (prof->file);
-
-       mono_conc_hashtable_destroy (prof->method_table);
-       mono_os_mutex_destroy (&prof->method_table_mutex);
-
-       if (coverage_initialized) {
-               mono_os_mutex_lock (&coverage_mutex);
-               mono_conc_hashtable_foreach (coverage_assemblies, unref_coverage_assemblies, prof);
-               mono_os_mutex_unlock (&coverage_mutex);
-
-               mono_conc_hashtable_destroy (coverage_methods);
-               mono_conc_hashtable_destroy (coverage_assemblies);
-               mono_conc_hashtable_destroy (coverage_classes);
-               mono_conc_hashtable_destroy (filtered_classes);
-
-               mono_conc_hashtable_destroy (entered_methods);
-               mono_conc_hashtable_destroy (image_to_methods);
-               mono_conc_hashtable_destroy (suppressed_assemblies);
-               mono_os_mutex_destroy (&coverage_mutex);
-       }
-
-       PROF_TLS_FREE ();
-
-       g_free (prof->args);
-       g_free (prof);
-}
-
-static char*
-new_filename (const char* filename)
-{
-       time_t t = time (NULL);
-       int pid = process_id ();
-       char pid_buf [16];
-       char time_buf [16];
-       char *res, *d;
-       const char *p;
-       int count_dates = 0;
-       int count_pids = 0;
-       int s_date, s_pid;
-       struct tm *ts;
-       for (p = filename; *p; p++) {
-               if (*p != '%')
-                       continue;
-               p++;
-               if (*p == 't')
-                       count_dates++;
-               else if (*p == 'p')
-                       count_pids++;
-               else if (*p == 0)
-                       break;
-       }
-       if (!count_dates && !count_pids)
-               return pstrdup (filename);
-       snprintf (pid_buf, sizeof (pid_buf), "%d", pid);
-       ts = gmtime (&t);
-       snprintf (time_buf, sizeof (time_buf), "%d%02d%02d%02d%02d%02d",
-               1900 + ts->tm_year, 1 + ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec);
-       s_date = strlen (time_buf);
-       s_pid = strlen (pid_buf);
-       d = res = (char *)malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids);
-       for (p = filename; *p; p++) {
-               if (*p != '%') {
-                       *d++ = *p;
-                       continue;
-               }
-               p++;
-               if (*p == 't') {
-                       strcpy (d, time_buf);
-                       d += s_date;
-                       continue;
-               } else if (*p == 'p') {
-                       strcpy (d, pid_buf);
-                       d += s_pid;
-                       continue;
-               } else if (*p == '%') {
-                       *d++ = '%';
-                       continue;
-               } else if (*p == 0)
-                       break;
-               *d++ = '%';
-               *d++ = *p;
-       }
-       *d = 0;
-       return res;
-}
-
-//this is exposed by the JIT, but it's not meant to be a supported API for now.
-extern void mono_threads_attach_tools_thread (void);
-
-#ifndef DISABLE_HELPER_THREAD
-
-static void*
-helper_thread (void* arg)
-{
-       MonoProfiler* prof = (MonoProfiler *)arg;
-       int command_socket;
-       int len;
-       char buf [64];
-
-       mono_threads_attach_tools_thread ();
-       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
-
-       init_thread (FALSE);
-
-       //fprintf (stderr, "Server listening\n");
-       command_socket = -1;
-       while (1) {
-               fd_set rfds;
-               struct timeval tv;
-               int max_fd = -1;
-               FD_ZERO (&rfds);
-               FD_SET (prof->server_socket, &rfds);
-               max_fd = prof->server_socket;
-               FD_SET (prof->pipes [0], &rfds);
-               if (max_fd < prof->pipes [0])
-                       max_fd = prof->pipes [0];
-               if (command_socket >= 0) {
-                       FD_SET (command_socket, &rfds);
-                       if (max_fd < command_socket)
-                               max_fd = command_socket;
-               }
-#if USE_PERF_EVENTS
-               if (perf_data) {
-                       int i;
-                       for ( i = 0; i < num_perf; ++i) {
-                               if (perf_data [i].perf_fd < 0)
-                                       continue;
-                               FD_SET (perf_data [i].perf_fd, &rfds);
-                               if (max_fd < perf_data [i].perf_fd)
-                                       max_fd = perf_data [i].perf_fd;
-                       }
-               }
-#endif
-
-               counters_and_perfcounters_sample (prof);
-
-               buffer_lock_excl ();
-
-               sync_point (prof, SYNC_POINT_PERIODIC);
-
-               buffer_unlock_excl ();
-
-               tv.tv_sec = 1;
-               tv.tv_usec = 0;
-               len = select (max_fd + 1, &rfds, NULL, NULL, &tv);
-
-               if (len < 0) {
-                       if (errno == EINTR)
-                               continue;
-
-                       g_warning ("Error in proflog server: %s", strerror (errno));
-                       return NULL;
-               }
-
-               if (FD_ISSET (prof->pipes [0], &rfds)) {
-                       char c;
-                       read (prof->pipes [0], &c, 1);
-                       if (do_debug)
-                               fprintf (stderr, "helper shutdown\n");
-#if USE_PERF_EVENTS
-                       if (perf_data) {
-                               int i;
-                               for ( i = 0; i < num_perf; ++i) {
-                                       if (perf_data [i].perf_fd < 0)
-                                               continue;
-                                       if (FD_ISSET (perf_data [i].perf_fd, &rfds))
-                                               read_perf_mmap (prof, i);
-                               }
-                       }
-#endif
-                       safe_send_threadless (prof);
-                       return NULL;
-               }
-#if USE_PERF_EVENTS
-               if (perf_data) {
-                       int i;
-                       for ( i = 0; i < num_perf; ++i) {
-                               if (perf_data [i].perf_fd < 0)
-                                       continue;
-                               if (FD_ISSET (perf_data [i].perf_fd, &rfds)) {
-                                       read_perf_mmap (prof, i);
-                                       send_if_needed_threadless (prof);
-                               }
-                       }
-               }
-#endif
-               if (command_socket >= 0 && FD_ISSET (command_socket, &rfds)) {
-                       len = read (command_socket, buf, sizeof (buf) - 1);
-                       if (len < 0)
-                               continue;
-                       if (len == 0) {
-                               close (command_socket);
-                               command_socket = -1;
-                               continue;
-                       }
-                       buf [len] = 0;
-                       if (strcmp (buf, "heapshot\n") == 0 && hs_mode_ondemand) {
-                               // Rely on the finalization callbacks invoking process_requests ().
-                               heapshot_requested = 1;
-                               mono_gc_finalize_notify ();
-                       }
-                       continue;
-               }
-               if (!FD_ISSET (prof->server_socket, &rfds)) {
-                       continue;
-               }
-               command_socket = accept (prof->server_socket, NULL, NULL);
-               if (command_socket < 0)
-                       continue;
-               //fprintf (stderr, "Accepted connection\n");
-       }
-
-       mono_thread_info_detach ();
-
-       return NULL;
-}
-
-static int
-start_helper_thread (MonoProfiler* prof)
-{
-       struct sockaddr_in server_address;
-       int r;
-       socklen_t slen;
-       if (pipe (prof->pipes) < 0) {
-               fprintf (stderr, "Cannot create pipe\n");
-               return 0;
-       }
-       prof->server_socket = socket (PF_INET, SOCK_STREAM, 0);
-       if (prof->server_socket < 0) {
-               fprintf (stderr, "Cannot create server socket\n");
-               return 0;
-       }
-       memset (&server_address, 0, sizeof (server_address));
-       server_address.sin_family = AF_INET;
-       server_address.sin_addr.s_addr = INADDR_ANY;
-       server_address.sin_port = htons (prof->command_port);
-       if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) < 0) {
-               fprintf (stderr, "Cannot bind server socket, port: %d: %s\n", prof->command_port, strerror (errno));
-               close (prof->server_socket);
-               return 0;
-       }
-       if (listen (prof->server_socket, 1) < 0) {
-               fprintf (stderr, "Cannot listen server socket\n");
-               close (prof->server_socket);
-               return 0;
-       }
-       slen = sizeof (server_address);
-       if (getsockname (prof->server_socket, (struct sockaddr *)&server_address, &slen) == 0) {
-               prof->command_port = ntohs (server_address.sin_port);
-               /*fprintf (stderr, "Assigned server port: %d\n", prof->command_port);*/
-       }
-
-       r = pthread_create (&prof->helper_thread, NULL, helper_thread, prof);
-       if (r) {
-               close (prof->server_socket);
-               return 0;
-       }
-       return 1;
-}
-#endif
-
-static void
-free_writer_entry (gpointer p)
-{
-       mono_lock_free_free (p, WRITER_ENTRY_BLOCK_SIZE);
-}
-
-static gboolean
-handle_writer_queue_entry (MonoProfiler *prof)
-{
-       WriterQueueEntry *entry;
-
-       if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
-               if (!entry->methods)
-                       goto no_methods;
-
-               LogBuffer *buf = NULL;
-
-               /*
-                * Encode the method events in a temporary log buffer that we
-                * flush to disk before the main buffer, ensuring that all
-                * methods have metadata emitted before they're referenced.
-                *
-                * We use a 'proper' thread-local buffer for this as opposed
-                * to allocating and freeing a buffer by hand because the call
-                * to mono_method_full_name () below may trigger class load
-                * events when it retrieves the signature of the method. So a
-                * thread-local buffer needs to exist when such events occur.
-                */
-               for (guint i = 0; i < entry->methods->len; i++) {
-                       MethodInfo *info = (MethodInfo *) g_ptr_array_index (entry->methods, i);
-
-                       if (mono_conc_hashtable_lookup (prof->method_table, info->method))
-                               goto free_info; // This method already has metadata emitted.
-
-                       /*
-                        * Other threads use this hash table to get a general
-                        * idea of whether a method has already been emitted to
-                        * the stream. Due to the way we add to this table, it
-                        * can easily happen that multiple threads queue up the
-                        * same methods, but that's OK since eventually all
-                        * methods will be in this table and the thread-local
-                        * method lists will just be empty for the rest of the
-                        * app's lifetime.
-                        */
-                       mono_os_mutex_lock (&prof->method_table_mutex);
-                       mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
-                       mono_os_mutex_unlock (&prof->method_table_mutex);
-
-                       char *name = mono_method_full_name (info->method, 1);
-                       int nlen = strlen (name) + 1;
-                       void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
-                       int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
-
-                       buf = ensure_logbuf_unsafe (
-                               EVENT_SIZE /* event */ +
-                               LEB128_SIZE /* method */ +
-                               LEB128_SIZE /* start */ +
-                               LEB128_SIZE /* size */ +
-                               nlen /* name */
-                       );
-
-                       emit_event_time (buf, TYPE_JIT | TYPE_METHOD, info->time);
-                       emit_method_inner (buf, info->method);
-                       emit_ptr (buf, cstart);
-                       emit_value (buf, csize);
-
-                       memcpy (buf->cursor, name, nlen);
-                       buf->cursor += nlen;
-
-                       mono_free (name);
-
-               free_info:
-                       g_free (info);
-               }
-
-               g_ptr_array_free (entry->methods, TRUE);
-
-               if (buf) {
-                       dump_buffer_threadless (prof, buf);
-                       init_buffer_state (PROF_TLS_GET ());
-               }
-
-       no_methods:
-               dump_buffer (prof, entry->buffer);
-
-               mono_thread_hazardous_try_free (entry, free_writer_entry);
-
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-static void *
-writer_thread (void *arg)
-{
-       MonoProfiler *prof = (MonoProfiler *)arg;
-
-       mono_threads_attach_tools_thread ();
-       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler writer");
-
-       dump_header (prof);
-
-       MonoProfilerThread *thread = init_thread (FALSE);
-
-       while (InterlockedRead (&prof->run_writer_thread)) {
-               mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
-               handle_writer_queue_entry (prof);
-       }
-
-       /* Drain any remaining entries on shutdown. */
-       while (handle_writer_queue_entry (prof));
-
-       free_buffer (thread->buffer, thread->buffer->size);
-       deinit_thread (thread);
-
-       mono_thread_info_detach ();
-
-       return NULL;
-}
-
-static int
-start_writer_thread (MonoProfiler* prof)
-{
-       InterlockedWrite (&prof->run_writer_thread, 1);
-
-       return !pthread_create (&prof->writer_thread, NULL, writer_thread, prof);
-}
-
-static void
-reuse_sample_hit (gpointer p)
-{
-       SampleHit *sample = p;
-
-       mono_lock_free_queue_node_unpoison (&sample->node);
-       mono_lock_free_queue_enqueue (&sample->prof->sample_reuse_queue, &sample->node);
-}
-
-static gboolean
-handle_dumper_queue_entry (MonoProfiler *prof)
-{
-       SampleHit *sample;
-
-       if ((sample = (SampleHit *) mono_lock_free_queue_dequeue (&prof->dumper_queue))) {
-               for (int i = 0; i < sample->count; ++i) {
-                       MonoMethod *method = sample->frames [i].method;
-                       MonoDomain *domain = sample->frames [i].domain;
-                       void *address = sample->frames [i].base_address;
-
-                       if (!method) {
-                               g_assert (domain && "What happened to the domain pointer?");
-                               g_assert (address && "What happened to the instruction pointer?");
-
-                               MonoJitInfo *ji = mono_jit_info_table_find (domain, (char *) address);
-
-                               if (ji)
-                                       sample->frames [i].method = mono_jit_info_get_method (ji);
-                       }
-               }
-
-               LogBuffer *logbuffer = ensure_logbuf_unsafe (
-                       EVENT_SIZE /* event */ +
-                       BYTE_SIZE /* type */ +
-                       LEB128_SIZE /* tid */ +
-                       LEB128_SIZE /* count */ +
-                       1 * (
-                               LEB128_SIZE /* ip */
-                       ) +
-                       LEB128_SIZE /* managed count */ +
-                       sample->count * (
-                               LEB128_SIZE /* method */
-                       )
-               );
-
-               emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time);
-               emit_byte (logbuffer, sample_type);
-               emit_ptr (logbuffer, (void *) sample->tid);
-               emit_value (logbuffer, 1);
-
-               // TODO: Actual native unwinding.
-               for (int i = 0; i < 1; ++i) {
-                       emit_ptr (logbuffer, sample->ip);
-                       add_code_pointer ((uintptr_t) sample->ip);
-               }
-
-               /* new in data version 6 */
-               emit_uvalue (logbuffer, sample->count);
-
-               for (int i = 0; i < sample->count; ++i)
-                       emit_method (prof, logbuffer, sample->frames [i].method);
-
-               mono_thread_hazardous_try_free (sample, reuse_sample_hit);
-
-               dump_unmanaged_coderefs (prof);
-
-               send_if_needed_threadless (prof);
-       }
-
-       return FALSE;
-}
-
-static void *
-dumper_thread (void *arg)
-{
-       MonoProfiler *prof = (MonoProfiler *)arg;
-
-       mono_threads_attach_tools_thread ();
-       mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
-
-       MonoProfilerThread *thread = init_thread (FALSE);
-
-       while (InterlockedRead (&prof->run_dumper_thread)) {
-               mono_os_sem_wait (&prof->dumper_queue_sem, MONO_SEM_FLAGS_NONE);
-               handle_dumper_queue_entry (prof);
-       }
-
-       /* Drain any remaining entries on shutdown. */
-       while (handle_dumper_queue_entry (prof));
-
-       safe_send_threadless (prof);
-       deinit_thread (thread);
-
-       mono_thread_info_detach ();
-
-       return NULL;
-}
-
-static int
-start_dumper_thread (MonoProfiler* prof)
-{
-       InterlockedWrite (&prof->run_dumper_thread, 1);
-
-       return !pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof);
-}
-
-static void
-runtime_initialized (MonoProfiler *profiler)
-{
-       InterlockedWrite (&runtime_inited, 1);
-
-#ifndef DISABLE_HELPER_THREAD
-       if (hs_mode_ondemand || need_helper_thread) {
-               if (!start_helper_thread (profiler))
-                       profiler->command_port = 0;
-       }
-#endif
-
-       start_writer_thread (profiler);
-       start_dumper_thread (profiler);
-
-       mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
-       mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
-       mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
-       mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
-       mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
-       mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
-       mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
-       mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
-       mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
-       mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
-       mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
-       mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
-       mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
-       mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
-       mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
-       mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
-
-#ifndef DISABLE_HELPER_THREAD
-       counters_init (profiler);
-       counters_sample (profiler, 0);
-#endif
-       /* ensure the main thread data and startup are available soon */
-       safe_send (profiler);
-}
-
-static MonoProfiler*
-create_profiler (const char *args, const char *filename, GPtrArray *filters)
-{
-       MonoProfiler *prof;
-       char *nf;
-       int force_delete = 0;
-       prof = (MonoProfiler *)calloc (1, sizeof (MonoProfiler));
-
-       prof->args = pstrdup (args);
-       prof->command_port = command_port;
-       if (filename && *filename == '-') {
-               force_delete = 1;
-               filename++;
-       }
-       if (!filename) {
-               if (do_report)
-                       filename = "|mprof-report -";
-               else
-                       filename = "output.mlpd";
-               nf = (char*)filename;
-       } else {
-               nf = new_filename (filename);
-               if (do_report) {
-                       int s = strlen (nf) + 32;
-                       char *p = (char *)malloc (s);
-                       snprintf (p, s, "|mprof-report '--out=%s' -", nf);
-                       g_free (nf);
-                       nf = p;
-               }
-       }
-       if (*nf == '|') {
-               prof->file = popen (nf + 1, "w");
-               prof->pipe_output = 1;
-       } else if (*nf == '#') {
-               int fd = strtol (nf + 1, NULL, 10);
-               prof->file = fdopen (fd, "a");
-       } else {
-               if (force_delete)
-                       unlink (nf);
-               prof->file = fopen (nf, "wb");
-       }
-       if (!prof->file) {
-               fprintf (stderr, "Cannot create profiler output: %s\n", nf);
-               exit (1);
-       }
-#if defined (HAVE_SYS_ZLIB)
-       if (use_zip)
-               prof->gzfile = gzdopen (fileno (prof->file), "wb");
-#endif
-#if USE_PERF_EVENTS
-       if (sample_type && sample_freq && !do_mono_sample)
-               need_helper_thread = setup_perf_event ();
-       if (!perf_data) {
-               /* FIXME: warn if different freq or sample type */
-               do_mono_sample = 1;
-       }
-#endif
-       if (do_mono_sample) {
-               need_helper_thread = 1;
-       }
-       if (do_counters && !need_helper_thread) {
-               need_helper_thread = 1;
-       }
-
-       /*
-        * If you hit this assert while increasing MAX_FRAMES, you need to increase
-        * SAMPLE_BLOCK_SIZE as well.
-        */
-       g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE));
-
-       // FIXME: We should free this stuff too.
-       mono_lock_free_allocator_init_size_class (&prof->sample_size_class, SAMPLE_SLOT_SIZE (num_frames), SAMPLE_BLOCK_SIZE);
-       mono_lock_free_allocator_init_allocator (&prof->sample_allocator, &prof->sample_size_class, MONO_MEM_ACCOUNT_PROFILER);
-
-       mono_lock_free_queue_init (&prof->sample_reuse_queue);
-
-#ifdef DISABLE_HELPER_THREAD
-       if (hs_mode_ondemand)
-               fprintf (stderr, "Ondemand heapshot unavailable on this arch.\n");
-
-       if (do_coverage)
-               fprintf (stderr, "Coverage unavailable on this arch.\n");
-
-#endif
-
-       g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
-
-       // FIXME: We should free this stuff too.
-       mono_lock_free_allocator_init_size_class (&prof->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
-       mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER);
-
-       mono_lock_free_queue_init (&prof->writer_queue);
-       mono_os_sem_init (&prof->writer_queue_sem, 0);
-
-       mono_lock_free_queue_init (&prof->dumper_queue);
-       mono_os_sem_init (&prof->dumper_queue_sem, 0);
-
-       mono_os_mutex_init (&prof->method_table_mutex);
-       prof->method_table = mono_conc_hashtable_new (NULL, NULL);
-
-       if (do_coverage)
-               coverage_init (prof);
-       prof->coverage_filters = filters;
-
-       prof->startup_time = current_time ();
-       return prof;
-}
-
-static void
-usage (int do_exit)
-{
-       printf ("Log profiler version %d.%d (format: %d)\n", LOG_VERSION_MAJOR, LOG_VERSION_MINOR, LOG_DATA_VERSION);
-       printf ("Usage: mono --profile=log[:OPTION1[,OPTION2...]] program.exe\n");
-       printf ("Options:\n");
-       printf ("\thelp                 show this usage info\n");
-       printf ("\t[no]alloc            enable/disable recording allocation info\n");
-       printf ("\t[no]calls            enable/disable recording enter/leave method events\n");
-       printf ("\theapshot[=MODE]      record heap shot info (by default at each major collection)\n");
-       printf ("\t                     MODE: every XXms milliseconds, every YYgc collections, ondemand\n");
-       printf ("\tcounters             sample counters every 1s\n");
-       printf ("\tsample[=TYPE]        use statistical sampling mode (by default cycles/100)\n");
-       printf ("\t                     TYPE: cycles,instr,cacherefs,cachemiss,branches,branchmiss\n");
-       printf ("\t                     TYPE can be followed by /FREQUENCY\n");
-       printf ("\ttime=fast            use a faster (but more inaccurate) timer\n");
-       printf ("\tmaxframes=NUM        collect up to NUM stack frames\n");
-       printf ("\tcalldepth=NUM        ignore method events for call chain depth bigger than NUM\n");
-       printf ("\toutput=FILENAME      write the data to file FILENAME (-FILENAME to overwrite)\n");
-       printf ("\toutput=|PROGRAM      write the data to the stdin of PROGRAM\n");
-       printf ("\t                     %%t is subtituted with date and time, %%p with the pid\n");
-       printf ("\treport               create a report instead of writing the raw data to a file\n");
-       printf ("\tzip                  compress the output data\n");
-       printf ("\tport=PORTNUM         use PORTNUM for the listening command server\n");
-       printf ("\tcoverage             enable collection of code coverage data\n");
-       printf ("\tcovfilter=ASSEMBLY   add an assembly to the code coverage filters\n");
-       printf ("\t                     add a + to include the assembly or a - to exclude it\n");
-       printf ("\t                     filter=-mscorlib\n");
-       printf ("\tcovfilter-file=FILE  use FILE to generate the list of assemblies to be filtered\n");
-       if (do_exit)
-               exit (1);
-}
-
-static const char*
-match_option (const char* p, const char *opt, char **rval)
-{
-       int len = strlen (opt);
-       if (strncmp (p, opt, len) == 0) {
-               if (rval) {
-                       if (p [len] == '=' && p [len + 1]) {
-                               const char *opt = p + len + 1;
-                               const char *end = strchr (opt, ',');
-                               char *val;
-                               int l;
-                               if (end == NULL) {
-                                       l = strlen (opt);
-                               } else {
-                                       l = end - opt;
-                               }
-                               val = (char *)malloc (l + 1);
-                               memcpy (val, opt, l);
-                               val [l] = 0;
-                               *rval = val;
-                               return opt + l;
-                       }
-                       if (p [len] == 0 || p [len] == ',') {
-                               *rval = NULL;
-                               return p + len + (p [len] == ',');
-                       }
-                       usage (1);
-               } else {
-                       if (p [len] == 0)
-                               return p + len;
-                       if (p [len] == ',')
-                               return p + len + 1;
-               }
-       }
-       return p;
-}
-
-typedef struct {
-       const char *name;
-       int sample_mode;
-} SampleMode;
-
-static const SampleMode sample_modes [] = {
-       {"cycles", SAMPLE_CYCLES},
-       {"instr", SAMPLE_INSTRUCTIONS},
-       {"cachemiss", SAMPLE_CACHE_MISSES},
-       {"cacherefs", SAMPLE_CACHE_REFS},
-       {"branches", SAMPLE_BRANCHES},
-       {"branchmiss", SAMPLE_BRANCH_MISSES},
-       {NULL, 0}
-};
-
-static void
-set_sample_mode (char* val, int allow_empty)
-{
-       char *end;
-       char *maybe_freq = NULL;
-       unsigned int count;
-       const SampleMode *smode = sample_modes;
-#ifndef USE_PERF_EVENTS
-       do_mono_sample = 1;
-#endif
-       if (allow_empty && !val) {
-               sample_type = SAMPLE_CYCLES;
-               sample_freq = 100;
-               return;
-       }
-       if (strcmp (val, "mono") == 0) {
-               do_mono_sample = 1;
-               sample_type = SAMPLE_CYCLES;
-               g_free (val);
-               return;
-       }
-       for (smode = sample_modes; smode->name; smode++) {
-               int l = strlen (smode->name);
-               if (strncmp (val, smode->name, l) == 0) {
-                       sample_type = smode->sample_mode;
-                       maybe_freq = val + l;
-                       break;
-               }
-       }
-       if (!smode->name)
-               usage (1);
-       if (*maybe_freq == '/') {
-               count = strtoul (maybe_freq + 1, &end, 10);
-               if (maybe_freq + 1 == end)
-                       usage (1);
-               sample_freq = count;
-       } else if (*maybe_freq != 0) {
-               usage (1);
-       } else {
-               sample_freq = 100;
-       }
-       g_free (val);
-}
-
-static void
-set_hsmode (char* val, int allow_empty)
-{
-       char *end;
-       unsigned int count;
-       if (allow_empty && !val)
-               return;
-       if (strcmp (val, "ondemand") == 0) {
-               hs_mode_ondemand = 1;
-               g_free (val);
-               return;
-       }
-       count = strtoul (val, &end, 10);
-       if (val == end)
-               usage (1);
-       if (strcmp (end, "ms") == 0)
-               hs_mode_ms = count;
-       else if (strcmp (end, "gc") == 0)
-               hs_mode_gc = count;
-       else
-               usage (1);
-       g_free (val);
-}
-
-/*
- * declaration to silence the compiler: this is the entry point that
- * mono will load from the shared library and call.
- */
-extern void
-mono_profiler_startup (const char *desc);
-
-extern void
-mono_profiler_startup_log (const char *desc);
-
-/*
- * this is the entry point that will be used when the profiler
- * is embedded inside the main executable.
- */
-void
-mono_profiler_startup_log (const char *desc)
-{
-       mono_profiler_startup (desc);
-}
-
-void
-mono_profiler_startup (const char *desc)
-{
-       MonoProfiler *prof;
-       GPtrArray *filters = NULL;
-       char *filename = NULL;
-       const char *p;
-       const char *opt;
-       int fast_time = 0;
-       int calls_enabled = 0;
-       int allocs_enabled = 0;
-       int only_counters = 0;
-       int only_coverage = 0;
-       int events = MONO_PROFILE_GC|MONO_PROFILE_ALLOCATIONS|
-               MONO_PROFILE_GC_MOVES|MONO_PROFILE_CLASS_EVENTS|MONO_PROFILE_THREADS|
-               MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS|
-               MONO_PROFILE_MONITOR_EVENTS|MONO_PROFILE_MODULE_EVENTS|MONO_PROFILE_GC_ROOTS|
-               MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
-               MONO_PROFILE_ASSEMBLY_EVENTS|MONO_PROFILE_GC_FINALIZATION;
-
-       max_allocated_sample_hits = mono_cpu_count () * 1000;
-
-       p = desc;
-       if (strncmp (p, "log", 3))
-               usage (1);
-       p += 3;
-       if (*p == ':')
-               p++;
-       for (; *p; p = opt) {
-               char *val;
-               if (*p == ',') {
-                       opt = p + 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "help", NULL)) != p) {
-                       usage (0);
-                       continue;
-               }
-               if ((opt = match_option (p, "calls", NULL)) != p) {
-                       calls_enabled = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "nocalls", NULL)) != p) {
-                       events &= ~MONO_PROFILE_ENTER_LEAVE;
-                       nocalls = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "alloc", NULL)) != p) {
-                       allocs_enabled = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "noalloc", NULL)) != p) {
-                       events &= ~MONO_PROFILE_ALLOCATIONS;
-                       continue;
-               }
-               if ((opt = match_option (p, "time", &val)) != p) {
-                       if (strcmp (val, "fast") == 0)
-                               fast_time = 1;
-                       else if (strcmp (val, "null") == 0)
-                               fast_time = 2;
-                       else
-                               usage (1);
-                       g_free (val);
-                       continue;
-               }
-               if ((opt = match_option (p, "report", NULL)) != p) {
-                       do_report = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "debug", NULL)) != p) {
-                       do_debug = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "sampling-real", NULL)) != p) {
-                       sampling_mode = MONO_PROFILER_STAT_MODE_REAL;
-                       continue;
-               }
-               if ((opt = match_option (p, "sampling-process", NULL)) != p) {
-                       sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
-                       continue;
-               }
-               if ((opt = match_option (p, "heapshot", &val)) != p) {
-                       events &= ~MONO_PROFILE_ALLOCATIONS;
-                       events &= ~MONO_PROFILE_ENTER_LEAVE;
-                       nocalls = 1;
-                       do_heap_shot = 1;
-                       set_hsmode (val, 1);
-                       continue;
-               }
-               if ((opt = match_option (p, "sample", &val)) != p) {
-                       events &= ~MONO_PROFILE_ALLOCATIONS;
-                       events &= ~MONO_PROFILE_ENTER_LEAVE;
-                       nocalls = 1;
-                       set_sample_mode (val, 1);
-                       continue;
-               }
-               if ((opt = match_option (p, "hsmode", &val)) != p) {
-                       fprintf (stderr, "The hsmode profiler option is obsolete, use heapshot=MODE.\n");
-                       set_hsmode (val, 0);
-                       continue;
-               }
-               if ((opt = match_option (p, "zip", NULL)) != p) {
-                       use_zip = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "output", &val)) != p) {
-                       filename = val;
-                       continue;
-               }
-               if ((opt = match_option (p, "port", &val)) != p) {
-                       char *end;
-                       command_port = strtoul (val, &end, 10);
-                       g_free (val);
-                       continue;
-               }
-               if ((opt = match_option (p, "maxframes", &val)) != p) {
-                       char *end;
-                       num_frames = strtoul (val, &end, 10);
-                       if (num_frames > MAX_FRAMES)
-                               num_frames = MAX_FRAMES;
-                       g_free (val);
-                       notraces = num_frames == 0;
-                       continue;
-               }
-               if ((opt = match_option (p, "maxsamples", &val)) != p) {
-                       char *end;
-                       max_allocated_sample_hits = strtoul (val, &end, 10);
-                       if (!max_allocated_sample_hits)
-                               max_allocated_sample_hits = G_MAXINT32;
-                       g_free (val);
-                       continue;
-               }
-               if ((opt = match_option (p, "calldepth", &val)) != p) {
-                       char *end;
-                       max_call_depth = strtoul (val, &end, 10);
-                       g_free (val);
-                       continue;
-               }
-               if ((opt = match_option (p, "counters", NULL)) != p) {
-                       do_counters = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "countersonly", NULL)) != p) {
-                       only_counters = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "coverage", NULL)) != p) {
-                       do_coverage = 1;
-                       events |= MONO_PROFILE_ENTER_LEAVE;
-                       debug_coverage = (g_getenv ("MONO_PROFILER_DEBUG_COVERAGE") != NULL);
-                       continue;
-               }
-               if ((opt = match_option (p, "onlycoverage", NULL)) != p) {
-                       only_coverage = 1;
-                       continue;
-               }
-               if ((opt = match_option (p, "covfilter-file", &val)) != p) {
-                       FILE *filter_file;
-                       char *line, *content;
-
-                       if (filters == NULL)
-                               filters = g_ptr_array_new ();
-
-                       filter_file = fopen (val, "r");
-                       if (filter_file == NULL) {
-                               fprintf (stderr, "Unable to open %s\n", val);
-                               exit (0);
-                       }
-
-                       /* Don't need to free content as it is referred to by the lines stored in @filters */
-                       content = get_file_content (filter_file);
-                       if (content == NULL)
-                               fprintf (stderr, "WARNING: %s is greater than 128kb - ignoring\n", val);
-
-                       while ((line = get_next_line (content, &content)))
-                               g_ptr_array_add (filters, g_strchug (g_strchomp (line)));
-
-                       fclose (filter_file);
-                       continue;
-               }
-               if ((opt = match_option (p, "covfilter", &val)) != p) {
-                       if (filters == NULL)
-                               filters = g_ptr_array_new ();
-
-                       g_ptr_array_add (filters, val);
-                       continue;
-               }
-               if (opt == p) {
-                       usage (0);
-                       exit (0);
-               }
-       }
-       if (calls_enabled) {
-               events |= MONO_PROFILE_ENTER_LEAVE;
-               nocalls = 0;
-       }
-       if (allocs_enabled)
-               events |= MONO_PROFILE_ALLOCATIONS;
-       if (only_counters)
-               events = 0;
-       if (only_coverage)
-               events = MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE;
-
-       utils_init (fast_time);
-
-       PROF_TLS_INIT ();
-
-       prof = create_profiler (desc, filename, filters);
-       if (!prof) {
-               PROF_TLS_FREE ();
-               return;
-       }
-
-       mono_lls_init (&profiler_thread_list, NULL);
-
-       init_thread (TRUE);
-
-       mono_profiler_install (prof, log_shutdown);
-       mono_profiler_install_gc (gc_event, gc_resize);
-       mono_profiler_install_allocation (gc_alloc);
-       mono_profiler_install_gc_moves (gc_moves);
-       mono_profiler_install_gc_roots (gc_handle, gc_roots);
-       mono_profiler_install_gc_finalize (finalize_begin, finalize_object_begin, finalize_object_end, finalize_end);
-       mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL);
-       mono_profiler_install_appdomain_name (domain_name);
-       mono_profiler_install_context (context_loaded, context_unloaded);
-       mono_profiler_install_class (NULL, class_loaded, class_unloaded, NULL);
-       mono_profiler_install_module (NULL, image_loaded, image_unloaded, NULL);
-       mono_profiler_install_assembly (NULL, assembly_loaded, assembly_unloaded, NULL);
-       mono_profiler_install_thread (thread_start, thread_end);
-       mono_profiler_install_thread_name (thread_name);
-       mono_profiler_install_enter_leave (method_enter, method_leave);
-       mono_profiler_install_jit_end (method_jitted);
-       mono_profiler_install_code_buffer_new (code_buffer_new);
-       mono_profiler_install_exception (throw_exc, method_exc_leave, clause_exc);
-       mono_profiler_install_monitor (monitor_event);
-       mono_profiler_install_runtime_initialized (runtime_initialized);
-       if (do_coverage)
-               mono_profiler_install_coverage_filter (coverage_filter);
-
-       if (do_mono_sample && sample_type == SAMPLE_CYCLES && sample_freq && !only_counters) {
-               events |= MONO_PROFILE_STATISTICAL;
-               mono_profiler_set_statistical_mode (sampling_mode, sample_freq);
-               mono_profiler_install_statistical (mono_sample_hit);
-       }
-
-       mono_profiler_set_events ((MonoProfileFlags)events);
-}
diff --git a/mono/profiler/proflog.h b/mono/profiler/proflog.h
deleted file mode 100644 (file)
index 5649d8b..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#ifndef __MONO_PROFLOG_H__
-#define __MONO_PROFLOG_H__
-
-#define BUF_ID 0x4D504C01
-#define LOG_HEADER_ID 0x4D505A01
-#define LOG_VERSION_MAJOR 1
-#define LOG_VERSION_MINOR 0
-#define LOG_DATA_VERSION 13
-/*
- * Changes in major/minor versions:
- * version 1.0: removed sysid field from header
- *              added args, arch, os fields to header
- *
- * Changes in data versions:
- * version 2: added offsets in heap walk
- * version 3: added GC roots
- * version 4: added sample/statistical profiling
- * version 5: added counters sampling
- * version 6: added optional backtrace in sampling info
- * version 8: added TYPE_RUNTIME and JIT helpers/trampolines
- * version 9: added MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING
- * version 10: added TYPE_COVERAGE
- * version 11: added thread ID to TYPE_SAMPLE_HIT
-               added more load/unload events
-                   unload for class
-                   unload for image
-                   load/unload for appdomain
-                   load/unload for contexts
-                   load/unload/name for assemblies
-               removed TYPE_LOAD_ERR flag (profiler never generated it, now removed from the format itself)
-               added TYPE_GC_HANDLE_{CREATED,DESTROYED}_BT
-               TYPE_JIT events are no longer guaranteed to have code start/size info (can be zero)
- * version 12: added MONO_COUNTER_PROFILER
- * version 13: added MONO_GC_EVENT_{PRE_STOP_WORLD_LOCKED,POST_START_WORLD_UNLOCKED}
-               added TYPE_META + TYPE_SYNC_POINT
-               removed il and native offset in TYPE_SAMPLE_HIT
-               methods in backtraces are now encoded as proper method pointers
-               removed flags in backtrace format
-               removed flags in metadata events
-               changed the following fields to a single byte rather than leb128
-                   TYPE_GC_EVENT: event_type, generation
-                   TYPE_HEAP_ROOT: root_type
-                   TYPE_JITHELPER: type
-                   TYPE_SAMPLE_HIT: sample_type
-                   TYPE_CLAUSE: clause_type
-                   TYPE_SAMPLE_COUNTERS_DESC: type, unit, variance
-                   TYPE_SAMPLE_COUNTERS: type
-               added time fields to all events that were missing one
-                   TYPE_HEAP_OBJECT
-                   TYPE_HEAP_ROOT
-                   TYPE_SAMPLE_USYM
-                   TYPE_SAMPLE_COUNTERS_DESC
-                   TYPE_COVERAGE_METHOD
-                   TYPE_COVERAGE_STATEMENT
-                   TYPE_COVERAGE_CLASS
-                   TYPE_COVERAGE_ASSEMBLY
-               moved the time field in TYPE_SAMPLE_HIT to right after the event byte, now encoded as a regular time field
-               changed the time field in TYPE_SAMPLE_COUNTERS to be encoded as a regular time field (in nanoseconds)
-               added TYPE_GC_FINALIZE_{START,END,OBJECT_START,OBJECT_END}
- */
-
-enum {
-       TYPE_ALLOC,
-       TYPE_GC,
-       TYPE_METADATA,
-       TYPE_METHOD,
-       TYPE_EXCEPTION,
-       TYPE_MONITOR,
-       TYPE_HEAP,
-       TYPE_SAMPLE,
-       TYPE_RUNTIME,
-       TYPE_COVERAGE,
-       TYPE_META,
-       /* extended type for TYPE_HEAP */
-       TYPE_HEAP_START  = 0 << 4,
-       TYPE_HEAP_END    = 1 << 4,
-       TYPE_HEAP_OBJECT = 2 << 4,
-       TYPE_HEAP_ROOT   = 3 << 4,
-       /* extended type for TYPE_METADATA */
-       TYPE_END_LOAD     = 2 << 4,
-       TYPE_END_UNLOAD   = 4 << 4,
-       /* extended type for TYPE_GC */
-       TYPE_GC_EVENT  = 1 << 4,
-       TYPE_GC_RESIZE = 2 << 4,
-       TYPE_GC_MOVE   = 3 << 4,
-       TYPE_GC_HANDLE_CREATED      = 4 << 4,
-       TYPE_GC_HANDLE_DESTROYED    = 5 << 4,
-       TYPE_GC_HANDLE_CREATED_BT   = 6 << 4,
-       TYPE_GC_HANDLE_DESTROYED_BT = 7 << 4,
-       TYPE_GC_FINALIZE_START = 8 << 4,
-       TYPE_GC_FINALIZE_END = 9 << 4,
-       TYPE_GC_FINALIZE_OBJECT_START = 10 << 4,
-       TYPE_GC_FINALIZE_OBJECT_END = 11 << 4,
-       /* extended type for TYPE_METHOD */
-       TYPE_LEAVE     = 1 << 4,
-       TYPE_ENTER     = 2 << 4,
-       TYPE_EXC_LEAVE = 3 << 4,
-       TYPE_JIT       = 4 << 4,
-       /* extended type for TYPE_EXCEPTION */
-       TYPE_THROW_NO_BT = 0 << 7,
-       TYPE_THROW_BT    = 1 << 7,
-       TYPE_CLAUSE      = 1 << 4,
-       /* extended type for TYPE_ALLOC */
-       TYPE_ALLOC_NO_BT  = 0 << 4,
-       TYPE_ALLOC_BT     = 1 << 4,
-       /* extended type for TYPE_MONITOR */
-       TYPE_MONITOR_NO_BT  = 0 << 7,
-       TYPE_MONITOR_BT     = 1 << 7,
-       /* extended type for TYPE_SAMPLE */
-       TYPE_SAMPLE_HIT           = 0 << 4,
-       TYPE_SAMPLE_USYM          = 1 << 4,
-       TYPE_SAMPLE_UBIN          = 2 << 4,
-       TYPE_SAMPLE_COUNTERS_DESC = 3 << 4,
-       TYPE_SAMPLE_COUNTERS      = 4 << 4,
-       /* extended type for TYPE_RUNTIME */
-       TYPE_JITHELPER = 1 << 4,
-       /* extended type for TYPE_COVERAGE */
-       TYPE_COVERAGE_ASSEMBLY = 0 << 4,
-       TYPE_COVERAGE_METHOD   = 1 << 4,
-       TYPE_COVERAGE_STATEMENT = 2 << 4,
-       TYPE_COVERAGE_CLASS = 3 << 4,
-       /* extended type for TYPE_META */
-       TYPE_SYNC_POINT = 0 << 4,
-       TYPE_END
-};
-
-enum {
-       /* metadata type byte for TYPE_METADATA */
-       TYPE_CLASS    = 1,
-       TYPE_IMAGE    = 2,
-       TYPE_ASSEMBLY = 3,
-       TYPE_DOMAIN   = 4,
-       TYPE_THREAD   = 5,
-       TYPE_CONTEXT  = 6,
-};
-
-typedef enum {
-       SYNC_POINT_PERIODIC,
-       SYNC_POINT_WORLD_STOP,
-       SYNC_POINT_WORLD_START
-} MonoProfilerSyncPointType;
-
-// Sampling sources
-// Unless you have compiled with --enable-perf-events, only SAMPLE_CYCLES is available
-enum {
-       SAMPLE_CYCLES = 1,
-       SAMPLE_INSTRUCTIONS,
-       SAMPLE_CACHE_MISSES,
-       SAMPLE_CACHE_REFS,
-       SAMPLE_BRANCHES,
-       SAMPLE_BRANCH_MISSES,
-       SAMPLE_LAST
-};
-
-#endif /* __MONO_PROFLOG_H__ */
diff --git a/mono/profiler/utils.c b/mono/profiler/utils.c
deleted file mode 100644 (file)
index cfa7589..0000000
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * utils.c: log profiler and reporter utils
- *
- * We have here the minimal needed portability functions: we can't depend
- * on the ones provided by the runtime, since they are internal and,
- * especially mprof-report is an external program.
- * Note also that we don't take a glib/eglib dependency here for mostly
- * the same reason (but also because we need tight control in the profiler
- * over memory allocation, which needs to work with the world stopped).
- *
- * Author:
- *   Paolo Molaro (lupus@ximian.com)
- *
- * Copyright 2010 Novell, Inc (http://www.novell.com)
- * Licensed under the MIT license. See LICENSE file in the project root for full license information.
- */
-#include "utils.h"
-#include <stdlib.h>
-#include <time.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#ifdef HOST_WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
-#include <sched.h>
-#endif
-#include <glib.h>
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-
-#if defined(__APPLE__)
-#include <mach/mach_time.h>  
-#include <stdio.h> 
-
-static mach_timebase_info_data_t timebase_info;
-#endif
-
-#ifndef MAP_ANONYMOUS
-#define MAP_ANONYMOUS MAP_ANON
-#endif
-
-#define TICKS_PER_SEC 1000000000LL
-
-#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU)
-#define HAVE_RDTSC 1
-#endif
-
-typedef struct {
-       unsigned int timer_count;
-       int last_cpu;
-       uint64_t last_rdtsc;
-       uint64_t last_time;
-} TlsData;
-
-#ifdef HOST_WIN32
-static int tls_data;
-#define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) TlsGetValue (tls_data); if (tls == NULL) { tls = (TlsData *) g_calloc (sizeof (TlsData), 1); TlsSetValue (tls_data, tls); }
-#define TLS_INIT(x) x = TlsAlloc()
-#elif HAVE_KW_THREAD
-static __thread TlsData tls_data;
-#define DECL_TLS_DATA TlsData *tls = &tls_data
-#define TLS_INIT(x)
-#else
-static pthread_key_t tls_data;
-#define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) pthread_getspecific (tls_data); if (tls == NULL) { tls = (TlsData *) g_calloc (sizeof (TlsData), 1); pthread_setspecific (tls_data, tls); }
-#define TLS_INIT(x) pthread_key_create(&x, NULL)
-#endif
-
-#ifdef HOST_WIN32
-static CRITICAL_SECTION log_lock;
-static LARGE_INTEGER pcounter_freq;
-#else
-static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-static int timer_overhead = 0;
-static uint64_t time_inc = 0;
-typedef uint64_t (*TimeFunc)(void);
-
-static TimeFunc time_func;
-
-static uint64_t
-clock_time (void)
-{
-#if defined(__APPLE__)
-       uint64_t time = mach_absolute_time ();
-       
-       time *= timebase_info.numer;
-       time /= timebase_info.denom;
-
-       return time;
-#elif defined(HOST_WIN32)
-       LARGE_INTEGER value;
-       QueryPerformanceCounter (&value);
-       return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart;
-#elif defined(CLOCK_MONOTONIC)
-       struct timespec tspec;
-       clock_gettime (CLOCK_MONOTONIC, &tspec);
-       return ((uint64_t)tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec);
-#else
-       struct timeval tv;
-       gettimeofday (&tv, NULL);
-       return ((uint64_t)tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000);
-#endif
-}
-
-/* must be power of two */
-#define TIME_ADJ 8
-
-static uint64_t
-fast_current_time (void)
-{
-       DECL_TLS_DATA;
-       if (tls->timer_count++ & (TIME_ADJ - 1)) {
-               tls->last_time += time_inc;
-               return tls->last_time;
-       }
-       tls->last_time = clock_time ();
-       return tls->last_time;
-}
-
-#if HAVE_RDTSC
-
-#define rdtsc(low,high) \
-       __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
-
-static uint64_t
-safe_rdtsc (int *cpu)
-{
-       unsigned int low, high;
-       int c1 = sched_getcpu ();
-       int c2;
-       rdtsc (low, high);
-       c2 = sched_getcpu ();
-       if (c1 != c2) {
-               *cpu = -1;
-               return 0;
-       }
-       *cpu = c1;
-       return (((uint64_t) high) << 32) + (uint64_t)low;
-}
-
-static double cpu_freq;
-
-static int 
-have_rdtsc (void) {
-       char buf[256];
-       int have_freq = 0;
-       int have_flag = 0;
-       float val;
-       FILE *cpuinfo;
-       int cpu = sched_getcpu ();
-
-       if (cpu < 0)
-               return 0;
-
-       if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
-               return 0;
-       while (fgets (buf, sizeof(buf), cpuinfo)) {
-               if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
-                       /*printf ("got mh: %f\n", val);*/
-                       have_freq = 1;
-                       cpu_freq = val * 1000000;
-               }
-               if (strncmp (buf, "flags :", 5) == 0) {
-                       if (strstr (buf, "constant_tsc")) {
-                               have_flag = 1;
-                               /*printf ("have tsc\n");*/
-                       }
-               }
-       }
-       fclose (cpuinfo);
-       return have_flag? have_freq: 0;
-}
-
-static uint64_t
-rdtsc_current_time (void)
-{
-       DECL_TLS_DATA;
-       if (tls->timer_count++ & (TIME_ADJ*8 - 1)) {
-               int cpu;
-               uint64_t tsc = safe_rdtsc (&cpu);
-               if (cpu != -1 && cpu == tls->last_cpu) {
-                       int64_t diff = tsc - tls->last_rdtsc;
-                       uint64_t nsecs;
-                       if (diff > 0) {
-                               nsecs = (double)diff/cpu_freq;
-                               //printf ("%llu cycles: %llu nsecs\n", diff, nsecs);
-                               return tls->last_time + nsecs;
-                       } else {
-                               printf ("tsc went backwards\n");
-                       }
-               } else {
-                       //printf ("wrong cpu: %d\n", cpu);
-               }
-       }
-       tls->last_time = clock_time ();
-       tls->last_rdtsc = safe_rdtsc (&tls->last_cpu);
-       return tls->last_time;
-}
-#else
-#define have_rdtsc() 0
-#define rdtsc_current_time fast_current_time
-#endif
-
-static uint64_t
-null_time (void)
-{
-       static uint64_t timer = 0;
-       return timer++;
-}
-
-void
-utils_init (int fast_time)
-{
-       int i;
-       uint64_t time_start, time_end;
-       TLS_INIT (tls_data);
-#ifdef HOST_WIN32
-       InitializeCriticalSection (&log_lock);
-       QueryPerformanceFrequency (&pcounter_freq);
-#endif
-#if defined (__APPLE__)
-       mach_timebase_info (&timebase_info);
-#endif
-
-       if (fast_time > 1) {
-               time_func = null_time;
-       } else if (fast_time) {
-               uint64_t timea;
-               uint64_t timeb;
-               clock_time ();
-               timea = clock_time ();
-               timeb = clock_time ();
-               time_inc = (timeb - timea) / TIME_ADJ;
-               /*printf ("time inc: %llu, timea: %llu, timeb: %llu, diff: %llu\n", time_inc, timea, timeb, timec-timeb);*/
-               if (have_rdtsc ())
-                       time_func = rdtsc_current_time;
-               else
-                       time_func = fast_current_time;
-       } else {
-               time_func = clock_time;
-       }
-       time_start = time_func ();
-       for (i = 0; i < 256; ++i)
-               time_func ();
-       time_end = time_func ();
-       timer_overhead = (time_end - time_start) / 256;
-}
-
-int
-get_timer_overhead (void)
-{
-       return timer_overhead;
-}
-
-uint64_t
-current_time (void)
-{
-       return time_func ();
-}
-
-void*
-alloc_buffer (int size)
-{
-       void *ptr;
-#ifdef HOST_WIN32
-       ptr = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE);
-       return ptr;
-#else
-       ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-       if (ptr == MAP_FAILED)
-               return NULL;
-       return ptr;
-#endif
-}
-
-void
-free_buffer (void *buf, int size)
-{
-#ifdef HOST_WIN32
-       VirtualFree (buf, 0, MEM_RELEASE);
-#else
-       munmap (buf, size);
-#endif
-}
-
-void
-take_lock (void)
-{
-#ifdef HOST_WIN32
-       EnterCriticalSection (&log_lock);
-#else
-       pthread_mutex_lock (&log_lock);
-#endif
-}
-
-void
-release_lock (void)
-{
-#ifdef HOST_WIN32
-       LeaveCriticalSection (&log_lock);
-#else
-       pthread_mutex_unlock (&log_lock);
-#endif
-}
-
-void
-encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf)
-{
-       uint8_t *p = buf;
-
-       do {
-               uint8_t b = value & 0x7f;
-               value >>= 7;
-               if (value != 0) /* more bytes to come */
-                       b |= 0x80;
-               *p ++ = b;
-       } while (value);
-
-       *endbuf = p;
-}
-
-void
-encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf)
-{
-       int more = 1;
-       int negative = (value < 0);
-       unsigned int size = sizeof (intptr_t) * 8;
-       uint8_t byte;
-       uint8_t *p = buf;
-
-       while (more) {
-               byte = value & 0x7f;
-               value >>= 7;
-               /* the following is unnecessary if the
-                * implementation of >>= uses an arithmetic rather
-                * than logical shift for a signed left operand
-                */
-               if (negative)
-                       /* sign extend */
-                       value |= - ((intptr_t)1 <<(size - 7));
-               /* sign bit of byte is second high order bit (0x40) */
-               if ((value == 0 && !(byte & 0x40)) ||
-                       (value == -1 && (byte & 0x40)))
-                       more = 0;
-               else
-                       byte |= 0x80;
-               *p ++= byte;
-       }
-
-       *endbuf = p;
-}
-
-uint64_t
-decode_uleb128 (uint8_t *buf, uint8_t **endbuf)
-{
-       uint64_t res = 0;
-       int shift = 0;
-
-       while (1) {
-               uint8_t b = *buf++;
-
-               res |= (((uint64_t)(b & 0x7f)) << shift);
-               if (!(b & 0x80))
-                       break;
-               shift += 7;
-       }
-
-       *endbuf = buf;
-
-       return res;
-}
-
-intptr_t
-decode_sleb128 (uint8_t *buf, uint8_t **endbuf)
-{
-       uint8_t *p = buf;
-       intptr_t res = 0;
-       int shift = 0;
-
-       while (1) {
-               uint8_t b = *p;
-               p ++;
-
-               res = res | (((intptr_t)(b & 0x7f)) << shift);
-               shift += 7;
-               if (!(b & 0x80)) {
-                       if (shift < sizeof (intptr_t) * 8 && (b & 0x40))
-                               res |= - ((intptr_t)1 << shift);
-                       break;
-               }
-       }
-
-       *endbuf = p;
-
-       return res;
-}
-
-uintptr_t
-thread_id (void)
-{
-#ifdef HOST_WIN32
-       return (uintptr_t)GetCurrentThreadId ();
-#else
-       return (uintptr_t)pthread_self ();
-#endif
-}
-
-uintptr_t
-process_id (void)
-{
-#ifdef HOST_WIN32
-       return GetCurrentProcessId ();
-#else
-       return (uintptr_t)getpid ();
-#endif
-}
-
diff --git a/mono/profiler/utils.h b/mono/profiler/utils.h
deleted file mode 100644 (file)
index 3af56d2..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __MONO_MPLOG_UTILS_H__
-#define __MONO_MPLOG_UTILS_H__
-
-#include "config.h"
-#include "mono/utils/mono-publib.h"
-
-void utils_init (int fast_time);
-int get_timer_overhead (void);
-uint64_t current_time (void);
-void* alloc_buffer (int size);
-void free_buffer (void *buf, int size);
-void take_lock (void);
-void release_lock (void);
-uintptr_t thread_id (void);
-uintptr_t process_id (void);
-
-void encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf);
-void encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf);
-uint64_t decode_uleb128 (uint8_t *buf, uint8_t **endbuf);
-intptr_t decode_sleb128 (uint8_t *buf, uint8_t **endbuf);
-
-
-#endif /* __MONO_MPLOG_UTILS_H__ */
-
index 74c5c02a0278355074ab21273d63831791da11af..44ddf94b24dad9e505796d536d2d0c6f99417e14 100644 (file)
@@ -58,6 +58,11 @@ sgen_object_layout_dump (FILE *out)
        fprintf (out, "ref-array %lu\n", count_ref_array);
        fprintf (out, "vtype-array %lu\n", count_vtype_array);
 }
+#else
 
+#ifdef _MSC_VER
+// Quiet Visual Studio linker warning, LNK4221, in cases when this source file intentional ends up empty.
+void __mono_win32_sgen_layout_stats_quiet_lnk4221(void) {}
 #endif
+#endif /* SGEN_OBJECT_LAYOUT_STATISTICS */
 #endif
index 16af9f66a7a56143f92ae0e5edaef17a50b4a803..e112be0fa16e46960bfafae3f5572c7bbd08bfb0 100644 (file)
@@ -15,15 +15,10 @@ class Driver
        {
                return new Thread (() => {
                        /* Exit bypassing completely the runtime */
-                       try {
-                               pthread_exit (IntPtr.Zero);
-                       } catch (EntryPointNotFoundException) {
-                       }
-
-                       try {
-                               ExitThread (IntPtr.Zero);
-                       } catch (EntryPointNotFoundException) {
-                       }
+                       if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX)
+                           pthread_exit (IntPtr.Zero);
+                       else
+                           ExitThread (IntPtr.Zero);
                });
        }
 
index 70d550d95c239b6b6d5ce5d868f31633a590c7d1..9501307fc1dd29f5c8c3c26baa9073c3b5856bf5 100644 (file)
@@ -27,8 +27,8 @@
 #define __MONO_LOCKFREEALLOC_H__
 
 #include <glib.h>
-
-#include "lock-free-queue.h"
+#include <mono/utils/lock-free-queue.h>
+#include <mono/utils/mono-mmap.h>
 
 typedef struct {
        MonoLockFreeQueue partial;
index 1f4f889904500d13befec05cd6944c83de19d698..8a044e50d31a2eb15cc4bb2a56a2266db85644b6 100644 (file)
@@ -281,12 +281,6 @@ typedef SSIZE_T ssize_t;
 #define MONO_LLVM_INTERNAL 
 #endif
 
-#if HAVE_DEPRECATED
-#define MONO_DEPRECATED __attribute__ ((deprecated))
-#else
-#define MONO_DEPRECATED 
-#endif
-
 #ifdef __GNUC__
 #define MONO_ALWAYS_INLINE __attribute__((always_inline))
 #elif defined(_MSC_VER)
index 9f59ce1ea821df2fa3dd849edd89d8e3a8b8aee7..c4bfe620f98edd116b07884e10c0f9b5ecae0922 100644 (file)
@@ -291,7 +291,12 @@ typedef HANDLE MonoSemType;
 static inline void
 mono_os_sem_init (MonoSemType *sem, int value)
 {
+#if G_HAVE_API_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT)
        *sem = CreateSemaphore (NULL, value, 0x7FFFFFFF, NULL);
+#else
+       *sem = CreateSemaphoreEx (NULL, value, 0x7FFFFFFF, NULL, 0, SEMAPHORE_ALL_ACCESS);
+#endif
+
        if (G_UNLIKELY (*sem == NULL))
                g_error ("%s: CreateSemaphore failed with error %d", __func__, GetLastError ());
 }
index 89d4fb68b7590a565057dd42d4ca1844ac571340..e2614388ce96038ff74ab94e56bea381c128ee23 100644 (file)
@@ -116,6 +116,15 @@ mono_set_allocator_vtable (MonoAllocatorVTable* vtable);
 #define MONO_RT_EXTERNAL_ONLY
 #endif /* MONO_INSIDE_RUNTIME */
 
+#ifdef __GNUC__
+#define _MONO_DEPRECATED __attribute__ ((deprecated))
+#elif defined (_MSC_VER)
+#define _MONO_DEPRECATED __declspec (deprecated)
+#else
+#define _MONO_DEPRECATED
+#endif
+
+#define MONO_DEPRECATED MONO_API MONO_RT_EXTERNAL_ONLY _MONO_DEPRECATED
 
 MONO_END_DECLS
 
index 9e6ebe712c2c446ba607190f6d4fb8d14c477c62..7d656132b5908b35b491f4c439eefa66c83cd243 100644 (file)
@@ -288,6 +288,14 @@ mono_native_thread_set_name (MonoNativeThreadId tid, const char *name)
 #endif
 }
 
+gboolean
+mono_native_thread_join (MonoNativeThreadId tid)
+{
+       void *res;
+
+       return !pthread_join (tid, &res);
+}
+
 void
 mono_threads_platform_set_exited (gpointer handle)
 {
index 7beb557fc70ef3661f0c5b7e0ed7705dd97708b1..5d6774ed4d7ea1c051365f841939c9d407dcec22 100644 (file)
@@ -187,6 +187,21 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg)
        return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL;
 }
 
+gboolean
+mono_native_thread_join (MonoNativeThreadId tid)
+{
+       HANDLE handle;
+
+       if (!(handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid)))
+               return FALSE;
+
+       DWORD res = WaitForSingleObject (handle, INFINITE);
+
+       CloseHandle (handle);
+
+       return res != WAIT_FAILED;
+}
+
 #if HAVE_DECL___READFSDWORD==0
 static MONO_ALWAYS_INLINE unsigned long long
 __readfsdword (unsigned long offset)
index 5e31607c176eb466536b4a38db672d4efcd54e0d..72f90e38157111c857703ab676bda8cb7ba12162 100644 (file)
@@ -531,15 +531,18 @@ void mono_threads_coop_end_global_suspend (void);
 MONO_API MonoNativeThreadId
 mono_native_thread_id_get (void);
 
-gboolean
+MONO_API gboolean
 mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2);
 
-gboolean
+MONO_API gboolean
 mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg);
 
 MONO_API void
 mono_native_thread_set_name (MonoNativeThreadId tid, const char *name);
 
+MONO_API gboolean
+mono_native_thread_join (MonoNativeThreadId tid);
+
 /*Mach specific internals */
 void mono_threads_init_dead_letter (void);
 void mono_threads_install_dead_letter (void);
index a036cf1f8dbc283329b0c3c07ec21baf97d9f750..a22d2a91ff418265354bc59c8043ba1a16403891 100644 (file)
@@ -2,6 +2,7 @@
 /al
 /al1
 /al2
+/btls-cert-sync
 /caspol
 /cert-sync
 /cert2spc
index 4447e30939f9a727a9952fea1f950c5570fd201b..3174ec4c3fa0308aa18ed717a3e714e9eafce8c3 100644 (file)
@@ -73,6 +73,7 @@ scripts_4_0 = \
        prj2make$(SCRIPT_SUFFIX)                \
        soapsuds$(SCRIPT_SUFFIX)                \
        caspol$(SCRIPT_SUFFIX)                  \
+       btls-cert-sync$(SCRIPT_SUFFIX)          \
        cert-sync$(SCRIPT_SUFFIX)               \
        cert2spc$(SCRIPT_SUFFIX)                \
        certmgr$(SCRIPT_SUFFIX)                 \
index 059ae97cff2cbe200a06713ff7f16c9b49ab1e63..ab17183b1b0bf0a8d5cfc1565fbd926becb336bb 100755 (executable)
@@ -55,11 +55,6 @@ fi
 if [[ ${CI_TAGS} == *'monolite'* ]]; then make get-monolite-latest; fi
 
 ${TESTCMD} --label=make --timeout=300m --fatal make -j4 -w V=1
-if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]];
-    then
-    exit 0
-    # we don't run the test suite on Windows PRs, we just ensure the build succeeds, so end here
-fi
 
 if [[ ${CI_TAGS} == *'acceptance-tests'* ]];
     then
index bffda6b73f7191f1673b4e3123ca9c18b95589ea..17a154768a1a950c05a644b10d7c75bfb8966647 100755 (executable)
@@ -9,41 +9,44 @@ ${TESTCMD} --label=verify --timeout=15m make -w -C runtime mcs-compileall
 ${TESTCMD} --label=profiler --timeout=30m make -w -C mono/profiler -k check
 ${TESTCMD} --label=compiler --timeout=30m make -w -C mcs/tests run-test
 ${TESTCMD} --label=compiler-errors --timeout=30m make -w -C mcs/errors run-test
-${TESTCMD} --label=System --timeout=10m make -w -C mcs/class/System run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System --skip; else ${TESTCMD} --label=System --timeout=10m make -w -C mcs/class/System run-test; fi
 ${TESTCMD} --label=System.XML --timeout=5m make -w -C mcs/class/System.XML run-test
 ${TESTCMD} --label=Mono.Security --timeout=5m make -w -C mcs/class/Mono.Security run-test
-${TESTCMD} --label=System.Security --timeout=5m make -w -C mcs/class/System.Security run-test;
-${TESTCMD} --label=System.Drawing --timeout=5m make -w -C mcs/class/System.Drawing run-test
-if [[ ${label} == osx-* ]]
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Security --skip; else ${TESTCMD} --label=System.Security --timeout=5m make -w -C mcs/class/System.Security run-test; fi
+if [[ ${label} == w* ]]
+then ${TESTCMD} --label=System.Drawing --skip;
+else ${TESTCMD} --label=System.Drawing --timeout=5m make -w -C mcs/class/System.Drawing run-test
+fi
+if [[ ${label} == osx-* ]] || [[ ${label} == w* ]]
 then ${TESTCMD} --label=Windows.Forms --skip;
 else ${TESTCMD} --label=Windows.Forms --timeout=5m make -w -C mcs/class/System.Windows.Forms run-test
 fi
 ${TESTCMD} --label=System.Data --timeout=5m make -w -C mcs/class/System.Data run-test
 ${TESTCMD} --label=System.Data.OracleClient --timeout=5m make -w -C mcs/class/System.Data.OracleClient run-test;
 ${TESTCMD} --label=System.Design --timeout=5m make -w -C mcs/class/System.Design run-test;
-${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test
-${TESTCMD} --label=System.Web --timeout=30m make -w -C mcs/class/System.Web run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Mono.Posix --skip; else ${TESTCMD} --label=Mono.Posix --timeout=5m make -w -C mcs/class/Mono.Posix run-test; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Web --skip; else ${TESTCMD} --label=System.Web --timeout=30m make -w -C mcs/class/System.Web run-test; fi
 ${TESTCMD} --label=System.Web.Services --timeout=5m make -w -C mcs/class/System.Web.Services run-test
 ${TESTCMD} --label=System.Runtime.SFS --timeout=5m make -w -C mcs/class/System.Runtime.Serialization.Formatters.Soap run-test;
-${TESTCMD} --label=System.Runtime.Remoting --timeout=5m make -w -C mcs/class/System.Runtime.Remoting run-test;
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Runtime.Remoting --skip; else ${TESTCMD} --label=System.Runtime.Remoting --timeout=5m make -w -C mcs/class/System.Runtime.Remoting run-test; fi
 ${TESTCMD} --label=Cscompmgd --timeout=5m make -w -C mcs/class/Cscompmgd run-test;
 ${TESTCMD} --label=Commons.Xml.Relaxng --timeout=5m make -w -C mcs/class/Commons.Xml.Relaxng run-test;
-${TESTCMD} --label=System.ServiceProcess --timeout=5m make -w -C mcs/class/System.ServiceProcess run-test;
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.ServiceProcess --skip; else ${TESTCMD} --label=System.ServiceProcess --timeout=5m make -w -C mcs/class/System.ServiceProcess run-test; fi
 ${TESTCMD} --label=I18N.CJK --timeout=5m make -w -C mcs/class/I18N/CJK run-test
 ${TESTCMD} --label=I18N.West --timeout=5m make -w -C mcs/class/I18N/West run-test
 ${TESTCMD} --label=I18N.MidEast --timeout=5m make -w -C mcs/class/I18N/MidEast run-test
 ${TESTCMD} --label=System.DirectoryServices --timeout=5m make -w -C mcs/class/System.DirectoryServices run-test
-${TESTCMD} --label=Microsoft.Build.Engine --timeout=5m make -w -C mcs/class/Microsoft.Build.Engine run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Engine --skip; else ${TESTCMD} --label=Microsoft.Build.Engine --timeout=5m make -w -C mcs/class/Microsoft.Build.Engine run-test; fi
 ${TESTCMD} --label=Microsoft.Build.Framework --timeout=5m make -w -C mcs/class/Microsoft.Build.Framework run-test
-${TESTCMD} --label=Microsoft.Build.Tasks --timeout=5m make -w -C mcs/class/Microsoft.Build.Tasks run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Tasks --skip; else ${TESTCMD} --label=Microsoft.Build.Tasks --timeout=5m make -w -C mcs/class/Microsoft.Build.Tasks run-test; fi
 ${TESTCMD} --label=Microsoft.Build.Utilities --timeout=5m make -w -C mcs/class/Microsoft.Build.Utilities run-test
 ${TESTCMD} --label=Mono.C5 --timeout=5m make -w -C mcs/class/Mono.C5 run-test
 ${TESTCMD} --label=Mono.Tasklets --timeout=5m make -w -C mcs/class/Mono.Tasklets run-test
 ${TESTCMD} --label=System.Configuration --timeout=5m make -w -C mcs/class/System.Configuration run-test
 ${TESTCMD} --label=System.Transactions --timeout=5m make -w -C mcs/class/System.Transactions run-test
-${TESTCMD} --label=System.Web.Extensions --timeout=5m make -w -C mcs/class/System.Web.Extensions run-test
-${TESTCMD} --label=System.Core --timeout=15m make -w -C mcs/class/System.Core run-test
-${TESTCMD} --label=symbolicate --timeout=60m make -w -C mcs/tools/mono-symbolicate check
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Web.Extensions --skip; else ${TESTCMD} --label=System.Web.Extensions --timeout=5m make -w -C mcs/class/System.Web.Extensions run-test; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Core --skip; else ${TESTCMD} --label=System.Core --timeout=15m make -w -C mcs/class/System.Core run-test; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=symbolicate --skip; else ${TESTCMD} --label=symbolicate --timeout=60m make -w -C mcs/tools/mono-symbolicate check; fi
 ${TESTCMD} --label=System.Xml.Linq --timeout=5m make -w -C mcs/class/System.Xml.Linq run-test
 ${TESTCMD} --label=System.Data.DSE --timeout=5m make -w -C mcs/class/System.Data.DataSetExtensions run-test
 ${TESTCMD} --label=System.Web.Abstractions --timeout=5m make -w -C mcs/class/System.Web.Abstractions run-test
@@ -57,9 +60,9 @@ ${TESTCMD} --label=System.ComponentModel.DataAnnotations --timeout=5m make -w -C
 ${TESTCMD} --label=Mono.CodeContracts --timeout=5m make -w -C mcs/class/Mono.CodeContracts run-test
 ${TESTCMD} --label=System.Runtime.Caching --timeout=5m make -w -C mcs/class/System.Runtime.Caching run-test
 ${TESTCMD} --label=System.Data.Services --timeout=5m make -w -C mcs/class/System.Data.Services run-test
-${TESTCMD} --label=System.Web.DynamicData --timeout=5m make -w -C mcs/class/System.Web.DynamicData run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=System.Web.DynamicData --skip; else ${TESTCMD} --label=System.Web.DynamicData --timeout=5m make -w -C mcs/class/System.Web.DynamicData run-test; fi
 ${TESTCMD} --label=Mono.CSharp --timeout=5m make -w -C mcs/class/Mono.CSharp run-test
-${TESTCMD} --label=WindowsBase --timeout=5m make -w -C mcs/class/WindowsBase run-test
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=WindowsBase --skip; else ${TESTCMD} --label=WindowsBase --timeout=5m make -w -C mcs/class/WindowsBase run-test; fi
 ${TESTCMD} --label=System.Numerics --timeout=5m make -w -C mcs/class/System.Numerics run-test
 ${TESTCMD} --label=System.Runtime.DurableInstancing --timeout=5m make -w -C mcs/class/System.Runtime.DurableInstancing run-test
 ${TESTCMD} --label=System.ServiceModel.Discovery --timeout=5m make -w -C mcs/class/System.ServiceModel.Discovery run-test
@@ -68,17 +71,17 @@ ${TESTCMD} --label=System.Net.Http --timeout=5m make -w -C mcs/class/System.Net.
 ${TESTCMD} --label=System.Json --timeout=5m make -w -C mcs/class/System.Json run-test
 ${TESTCMD} --label=System.Threading.Tasks.Dataflow --timeout=5m make -w -C mcs/class/System.Threading.Tasks.Dataflow run-test
 ${TESTCMD} --label=Mono.Debugger.Soft --timeout=5m make -w -C mcs/class/Mono.Debugger.Soft run-test
-${TESTCMD} --label=Microsoft.Build --timeout=5m make -w -C mcs/class/Microsoft.Build run-test
-${TESTCMD} --label=monodoc --timeout=10m make -w -C mcs/tools/mdoc run-test
-${TESTCMD} --label=Microsoft.Build-12 --timeout=10m make -w -C mcs/class/Microsoft.Build run-test PROFILE=xbuild_12
-${TESTCMD} --label=Microsoft.Build.Engine-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Engine run-test PROFILE=xbuild_12
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build --skip; else ${TESTCMD} --label=Microsoft.Build --timeout=5m make -w -C mcs/class/Microsoft.Build run-test; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=monodoc --skip; else ${TESTCMD} --label=monodoc --timeout=10m make -w -C mcs/tools/mdoc run-test; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build-12 --skip; else ${TESTCMD} --label=Microsoft.Build-12 --timeout=10m make -w -C mcs/class/Microsoft.Build run-test PROFILE=xbuild_12; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Engine-12 --skip; else ${TESTCMD} --label=Microsoft.Build.Engine-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Engine run-test PROFILE=xbuild_12; fi
 ${TESTCMD} --label=Microsoft.Build.Framework-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Framework run-test PROFILE=xbuild_12
-${TESTCMD} --label=Microsoft.Build.Tasks-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Tasks run-test PROFILE=xbuild_12
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Tasks-12 --skip; else ${TESTCMD} --label=Microsoft.Build.Tasks-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Tasks run-test PROFILE=xbuild_12; fi
 ${TESTCMD} --label=Microsoft.Build.Utilities-12 --timeout=60m make -w -C mcs/class/Microsoft.Build.Utilities run-test PROFILE=xbuild_12
-${TESTCMD} --label=Microsoft.Build-14 --timeout=60m make -w -C mcs/class/Microsoft.Build run-test PROFILE=xbuild_14
-${TESTCMD} --label=Microsoft.Build.Engine-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Engine run-test PROFILE=xbuild_14
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build-14 --skip; else ${TESTCMD} --label=Microsoft.Build-14 --timeout=60m make -w -C mcs/class/Microsoft.Build run-test PROFILE=xbuild_14; fi
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Engine-14 --skip; else ${TESTCMD} --label=Microsoft.Build.Engine-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Engine run-test PROFILE=xbuild_14; fi
 ${TESTCMD} --label=Microsoft.Build.Framework-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Framework run-test PROFILE=xbuild_14
-${TESTCMD} --label=Microsoft.Build.Tasks-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Tasks run-test PROFILE=xbuild_14
+if [[ -n "${ghprbPullId}" ]] && [[ ${label} == w* ]]; then ${TESTCMD} --label=Microsoft.Build.Tasks-14 --skip; else ${TESTCMD} --label=Microsoft.Build.Tasks-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Tasks run-test PROFILE=xbuild_14; fi
 ${TESTCMD} --label=Microsoft.Build.Utilities-14 --timeout=60m make -w -C mcs/class/Microsoft.Build.Utilities run-test PROFILE=xbuild_14
 if [[ ${label} == osx-* ]]
 then ${TESTCMD} --label=ms-test-suite --timeout=15m make -w -C acceptance-tests check-ms-test-suite
index 52d6f1668003d6eb79373b94101697d66f0f8bfa..05f5015611ec91e07ef669e6eb671ff84a830339 100755 (executable)
@@ -2,4 +2,4 @@
 
 export TESTCMD=`dirname "${BASH_SOURCE[0]}"`/run-step.sh
 
-${TESTCMD} --label=check-profiler-stress --timeout=20h make -C acceptance-tests check-profiler-stress
+${TESTCMD} --label=check-profiler-stress --timeout=24h make -C acceptance-tests check-profiler-stress