Esempio n. 1
0
        void RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None)
        {
            string          outputFile           = null;
            CompilerResults decompiledOutputFile = null;

            try {
                outputFile = Tester.AssembleIL(Path.Combine(TestCasePath, testFileName), asmOptions);
                string decompiledCodeFile = Tester.DecompileCSharp(outputFile, Tester.GetSettings(options));
                decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options);

                Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile);

                Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile));
                Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly));
            } finally {
                if (decompiledOutputFile != null)
                {
                    decompiledOutputFile.TempFiles.Delete();
                }
            }
        }
Esempio n. 2
0
        public static string Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions)
        {
            if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler))
            {
                using (var peFileStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read))
                    using (var peFile = new PEFile(sourceFileName, peFileStream))
                        using (var writer = new StringWriter()) {
                            var metadata = peFile.Metadata;
                            var output   = new PlainTextOutput(writer);
                            ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
                            rd.AssemblyResolver       = new UniversalAssemblyResolver(sourceFileName, true, null);
                            rd.DetectControlStructure = false;
                            rd.WriteAssemblyReferences(metadata);
                            if (metadata.IsAssembly)
                            {
                                rd.WriteAssemblyHeader(peFile);
                            }
                            output.WriteLine();
                            rd.WriteModuleHeader(peFile, skipMVID: true);
                            output.WriteLine();
                            rd.WriteModuleContents(peFile);

                            File.WriteAllText(outputFile, ReplacePrivImplDetails(writer.ToString()));
                        }
                return(outputFile);
            }

            string ildasmPath = SdkUtility.GetSdkPath("ildasm.exe");

            ProcessStartInfo info = new ProcessStartInfo(ildasmPath);

            info.Arguments              = $"/nobar /utf8 /out=\"{outputFile}\" \"{sourceFileName}\"";
            info.RedirectStandardError  = true;
            info.RedirectStandardOutput = true;
            info.UseShellExecute        = false;

            Process process = Process.Start(info);

            var outputTask = process.StandardOutput.ReadToEndAsync();
            var errorTask  = process.StandardError.ReadToEndAsync();

            Task.WaitAll(outputTask, errorTask);
            process.WaitForExit();

            Console.WriteLine("output: " + outputTask.Result);
            Console.WriteLine("errors: " + errorTask.Result);

            // Unlike the .imagebase directive (which is a fixed value when compiling with /deterministic),
            // the image base comment still varies... ildasm putting a random number here?
            string il = File.ReadAllText(outputFile);

            il = Regex.Replace(il, @"^// Image base: 0x[0-9A-F]+\r?\n", "", RegexOptions.Multiline);
            // and while we're at it, also remove the MVID
            il = Regex.Replace(il, @"^// MVID: \{[0-9A-F-]+\}\r?\n", "", RegexOptions.Multiline);
            // and the ildasm version info (varies from system to system)
            il = Regex.Replace(il, @"^// +Microsoft .* Disassembler\. +Version.*\r?\n", "", RegexOptions.Multiline);
            // copyright header "All rights reserved" is dependent on system language
            il = Regex.Replace(il, @"^// +Copyright .* Microsoft.*\r?\n", "", RegexOptions.Multiline);
            // filename may contain full path
            il = Regex.Replace(il, @"^// WARNING: Created Win32 resource file.*\r?\n", "", RegexOptions.Multiline);
            il = ReplacePrivImplDetails(il);
            File.WriteAllText(outputFile, il);

            return(outputFile);
        }
Esempio n. 3
0
 void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null)
 {
     Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings);
 }
Esempio n. 4
0
        public static async Task <string> Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions)
        {
            if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler))
            {
                using (var peFileStream = new FileStream(sourceFileName, FileMode.Open, FileAccess.Read))
                    using (var peFile = new PEFile(sourceFileName, peFileStream))
                        using (var writer = new StringWriter())
                        {
                            var metadata = peFile.Metadata;
                            var output   = new PlainTextOutput(writer);
                            ReflectionDisassembler rd = new ReflectionDisassembler(output, CancellationToken.None);
                            rd.AssemblyResolver       = new UniversalAssemblyResolver(sourceFileName, true, null);
                            rd.DetectControlStructure = false;
                            rd.WriteAssemblyReferences(metadata);
                            if (metadata.IsAssembly)
                            {
                                rd.WriteAssemblyHeader(peFile);
                            }
                            output.WriteLine();
                            rd.WriteModuleHeader(peFile, skipMVID: true);
                            output.WriteLine();
                            rd.WriteModuleContents(peFile);

                            File.WriteAllText(outputFile, ReplacePrivImplDetails(writer.ToString()));
                        }
                return(outputFile);
            }

            string ildasmPath = Path.Combine(
                Path.GetDirectoryName(typeof(Tester).Assembly.Location),
                "ildasm.exe");

            var command = Cli.Wrap(ildasmPath)
                          .WithArguments($"/utf8 /out=\"{outputFile}\" \"{sourceFileName}\"")
                          .WithValidation(CommandResultValidation.None);

            var result = await command.ExecuteBufferedAsync().ConfigureAwait(false);

            Console.WriteLine("output: " + result.StandardOutput);
            Console.WriteLine("errors: " + result.StandardError);
            Assert.AreEqual(0, result.ExitCode, "ildasm failed");

            // Unlike the .imagebase directive (which is a fixed value when compiling with /deterministic),
            // the image base comment still varies... ildasm putting a random number here?
            string il = File.ReadAllText(outputFile);

            il = Regex.Replace(il, @"^// Image base: 0x[0-9A-F]+\r?\n", "", RegexOptions.Multiline);
            // and while we're at it, also remove the MVID
            il = Regex.Replace(il, @"^// MVID: \{[0-9A-F-]+\}\r?\n", "", RegexOptions.Multiline);
            // and the ildasm version info (varies from system to system)
            il = Regex.Replace(il, @"^// +Microsoft .* Disassembler\. +Version.*\r?\n", "", RegexOptions.Multiline);
            // copyright header "All rights reserved" is dependent on system language
            il = Regex.Replace(il, @"^// +Copyright .* Microsoft.*\r?\n", "", RegexOptions.Multiline);
            // filename may contain full path
            il = Regex.Replace(il, @"^// WARNING: Created Win32 resource file.*\r?\n", "", RegexOptions.Multiline);
            il = ReplacePrivImplDetails(il);
            File.WriteAllText(outputFile, il);

            return(outputFile);
        }
        public void CreateNewBlock_WithScript_ReturnsBlockTemplate()
        {
            this.ExecuteWithConsensusOptions(new PosConsensusOptions(), () =>
            {
                var chain = GenerateChainWithHeight(5, this.network, this.key);
                this.dateTimeProvider.Setup(d => d.GetAdjustedTimeAsUnixTimestamp())
                .Returns(new DateTime(2017, 1, 7, 0, 0, 1, DateTimeKind.Utc).ToUnixTimestamp());
                var transaction = CreateTransaction(this.network, this.key, 5, new Money(400 * 1000 * 1000), new Key(), new uint256(124124));
                var txFee       = new Money(1000);
                SetupTxMempool(chain, this.network.Consensus.Options as PosConsensusOptions, txFee, transaction);

                var assemblerOptions = new AssemblerOptions()
                {
                    IsProofOfStake = true
                };

                this.stakeValidator.Setup(s => s.GetNextTargetRequired(this.stakeChain.Object, chain.Tip, this.network.Consensus, true))
                .Returns(new Target(new uint256(1123123123)))
                .Verifiable();

                var posBlockAssembler = new PosBlockAssembler(this.consensusLoop.Object, this.network, new MempoolSchedulerLock(), this.txMempool.Object,
                                                              this.dateTimeProvider.Object, this.stakeChain.Object, this.stakeValidator.Object, chain.Tip, this.LoggerFactory.Object, assemblerOptions);

                var blockTemplate = posBlockAssembler.CreateNewBlock(this.key.ScriptPubKey);

                Assert.Null(blockTemplate.CoinbaseCommitment);
                Assert.Equal(new Money(1000), blockTemplate.TotalFee);
                Assert.Equal(2, blockTemplate.TxSigOpsCost.Count);
                Assert.Equal(-1, blockTemplate.TxSigOpsCost[0]);
                Assert.Equal(2, blockTemplate.TxSigOpsCost[1]);
                Assert.Equal(2, blockTemplate.VTxFees.Count);
                Assert.Equal(new Money(-1000), blockTemplate.VTxFees[0]);
                Assert.Equal(new Money(1000), blockTemplate.VTxFees[1]);
                Assert.Equal(2, blockTemplate.Block.Transactions.Count);
                Assert.Equal(536870912, blockTemplate.Block.Header.Version);

                Assert.Equal(2, blockTemplate.Block.Transactions.Count);

                var resultingTransaction = blockTemplate.Block.Transactions[0];
                Assert.Equal((uint)new DateTime(2017, 1, 7, 0, 0, 1, DateTimeKind.Utc).ToUnixTimestamp(), resultingTransaction.Time);
                Assert.NotEmpty(resultingTransaction.Inputs);
                Assert.NotEmpty(resultingTransaction.Outputs);
                Assert.True(resultingTransaction.IsCoinBase);
                Assert.False(resultingTransaction.IsCoinStake);
                Assert.Equal(TxIn.CreateCoinbase(6).ScriptSig, resultingTransaction.Inputs[0].ScriptSig);
                Assert.Equal(new Money(0), resultingTransaction.TotalOut);
                Assert.Equal(new Script(), resultingTransaction.Outputs[0].ScriptPubKey);
                Assert.Equal(new Money(0), resultingTransaction.Outputs[0].Value);

                resultingTransaction = blockTemplate.Block.Transactions[1];
                Assert.NotEmpty(resultingTransaction.Inputs);
                Assert.NotEmpty(resultingTransaction.Outputs);
                Assert.False(resultingTransaction.IsCoinBase);
                Assert.False(resultingTransaction.IsCoinStake);
                Assert.Equal(new Money(400 * 1000 * 1000), resultingTransaction.TotalOut);
                Assert.Equal(transaction.Inputs[0].PrevOut.Hash, resultingTransaction.Inputs[0].PrevOut.Hash);
                Assert.Equal(transaction.Inputs[0].ScriptSig, transaction.Inputs[0].ScriptSig);

                Assert.Equal(transaction.Outputs[0].ScriptPubKey, resultingTransaction.Outputs[0].ScriptPubKey);
                Assert.Equal(new Money(400 * 1000 * 1000), resultingTransaction.Outputs[0].Value);
            });
        }
        /// <summary>
        /// Compiles the specified Visua Studio document.
        /// </summary>
        /// <param name="itemPath">VS document item path</param>
        /// <param name="options">Assembler options to use</param>
        /// <returns>True, if compilation is successful; otherwise, false</returns>
        public async Task <AssemblerOutput> CompileDocument(string itemPath,
                                                            AssemblerOptions options)
        {
            var       addToProject = SpectNetPackage.Default.Options.StoreGeneratedZ80Files;
            var       zxbOptions   = PrepareZxbOptions(itemPath, addToProject);
            var       output       = new AssemblerOutput(new SourceFileItem(itemPath), options?.UseCaseSensitiveSymbols ?? false);
            var       runner       = new ZxbRunner(SpectNetPackage.Default.Options.ZxbPath);
            ZxbResult result;

            try
            {
                result = await runner.RunAsync(zxbOptions, true);
            }
            catch (Exception ex)
            {
                output.Errors.Clear();
                output.Errors.Add(new AssemblerErrorInfo("ZXB", "", 1, 0, ex.Message));
                return(output);
            }
            if (result.ExitCode != 0)
            {
                // --- Compile error - stop here
                output.Errors.Clear();
                output.Errors.AddRange(result.Errors);
                return(output);
            }

            // --- Add the generated file to the project
            if (addToProject)
            {
                var zxBasItem =
                    SpectNetPackage.Default.ActiveProject.ZxBasicProjectItems.FirstOrDefault(pi =>
                                                                                             pi.Filename == itemPath)?.DteProjectItem;
                if (SpectNetPackage.Default.Options.NestGeneratedZ80Files && zxBasItem != null)
                {
                    var newItem = zxBasItem.ProjectItems.AddFromFile(zxbOptions.OutputFilename);
                    newItem.Properties.Item("DependentUpon").Value = zxBasItem.Name;
                }
                else
                {
                    SpectNetPackage.Default.ActiveRoot.ProjectItems.AddFromFile(zxbOptions.OutputFilename);
                }
            }

            var asmContents = File.ReadAllText(zxbOptions.OutputFilename);

            ZxBasicNamespacePreprocessor preProc = new ZxBasicNamespacePreprocessor(asmContents);

            asmContents = "\t.zxbasic\r\n" + preProc.ProcessContent();
            var hasHeapSizeLabel = Regex.Match(asmContents, "ZXBASIC_HEAP_SIZE\\s+EQU");

            if (!hasHeapSizeLabel.Success)
            {
                // --- HACK: Take care that "ZXBASIC_HEAP_SIZE EQU" is added to the assembly file
                asmContents = Regex.Replace(asmContents, "ZXBASIC_USER_DATA_END\\s+EQU\\s+ZXBASIC_MEM_HEAP",
                                            "ZXBASIC_USER_DATA_END EQU ZXBASIC_USER_DATA");
            }
            File.WriteAllText(zxbOptions.OutputFilename, asmContents);

            // --- Second pass, compile the assembly file
            var compiler = new Z80Assembler();

            if (_traceMessageHandler != null)
            {
                compiler.AssemblerMessageCreated += _traceMessageHandler;
            }
            compiler.AssemblerMessageCreated += OnAssemblerMessage;
            try
            {
                output           = compiler.CompileFile(zxbOptions.OutputFilename, options);
                output.ModelType = SpectrumModelType.Spectrum48;
            }
            finally
            {
                if (_traceMessageHandler != null)
                {
                    compiler.AssemblerMessageCreated -= _traceMessageHandler;
                }
                compiler.AssemblerMessageCreated -= OnAssemblerMessage;
            }
            return(output);
        }
        /// <summary>
        /// Task for assembling one individual file.
        /// </summary>
        /// <param name="inputFile">The input file to assemble.</param>
        /// <param name="logger">The logging implementation to log errors/info to.</param>
        /// <param name="options">The options to use while assembling.</param>
        /// <returns>True if the assembler could successfully generate code for the file; otherwise returns false.</returns>
        public AssemblerResult AssembleFile(string inputFile, string outputFile, ILogger logger, AssemblerOptions options)
        {
            var result = new AssemblerResult();

            logger.Log(LogLevel.Info, "Invoking assembler for file " + inputFile);
            try
            {
                bool furtherProcessingNeeded = true;
                if (File.Exists(inputFile) &&
                    File.Exists(outputFile))
                {
                    DateTime inputFileWriteTime  = File.GetLastWriteTimeUtc(inputFile);
                    DateTime outputFileWriteTime = File.GetLastWriteTimeUtc(outputFile);
                    if (outputFileWriteTime > inputFileWriteTime)
                    {
                        logger.Log(LogLevel.Info, "Nothing to do for file " + inputFile);
                        furtherProcessingNeeded = false;
                    }
                }

                if (furtherProcessingNeeded)
                {
                    using (var reader = new StreamReader(File.OpenRead(inputFile)))
                    {
                        var symTable = new SymbolTable();

                        // build the symbol table
                        var instructionProcFac = new InstructionProcessorFactory(symTable);
                        var symTableBuilder    = new SymbolTableBuilder(logger, instructionProcFac);
                        symTableBuilder.GenerateSymbolTableForSegment(reader, SegmentType.Data, symTable);
                        symTableBuilder.GenerateSymbolTableForSegment(reader, SegmentType.Text, symTable);

                        // use the symbol table to generate code with references resolved.
                        var objFile = new BasicObjectFile(inputFile, symTable);

                        var codeGenerator = new CodeGenerator(logger, symTable, instructionProcFac);
                        codeGenerator.GenerateCode(inputFile, reader, objFile);

                        if (!objFile.TextElements.Any())
                        {
                            logger.Log(LogLevel.Warning, "No .text segment to assemble. Stop.");
                            result.OperationSuccessful = false;
                        }
                        else
                        {
                            // write the object file out.
                            var writerFac            = new ObjectFileWriterFactory();
                            IObjectFileWriter writer = writerFac.GetWriterForOutputFile(outputFile);
                            writer.WriteObjectFile(outputFile, objFile);
                        }
                    }
                }
            }
            catch (AggregateAssemblyError ex)
            {
                foreach (AssemblyException asEx in ex.AssemblyErrors)
                {
                    logger.Log(LogLevel.Critical, "In file \"" + inputFile + "\" (line " + asEx.LineNumber + "):\n\t");
                    logger.Log(LogLevel.Critical, asEx.Message);
                    result.AddUserAssemblyError(asEx);
                }
            }
            catch (Exception ex)
            {
                logger.Log(LogLevel.Critical, ex.StackTrace);
                logger.Log(LogLevel.Critical, ex.Message);
                if (ex.InnerException != null)
                {
                    logger.Log(LogLevel.Critical, ex.InnerException.StackTrace);
                    logger.Log(LogLevel.Critical, ex.InnerException.Message);
                }
                result.AddInternalAssemblerError(ex);
            }

            return(result);
        }
Esempio n. 8
0
        async Task RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None)
        {
            string          outputFile           = null;
            CompilerResults decompiledOutputFile = null;

            try
            {
                options   |= CompilerOptions.UseTestRunner;
                outputFile = await Tester.AssembleIL(Path.Combine(TestCasePath, testFileName), asmOptions).ConfigureAwait(false);

                string decompiledCodeFile = await Tester.DecompileCSharp(outputFile, Tester.GetSettings(options)).ConfigureAwait(false);

                decompiledOutputFile = await Tester.CompileCSharp(decompiledCodeFile, options).ConfigureAwait(false);

                await Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile, (options & CompilerOptions.UseTestRunner) != 0, (options & CompilerOptions.Force32Bit) != 0).ConfigureAwait(false);

                Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile));
                Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly));
            }
            finally
            {
                if (decompiledOutputFile != null)
                {
                    decompiledOutputFile.DeleteTempFiles();
                }
            }
        }