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(); } } }
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); }
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); }
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); }
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(); } } }