1 // 2 // Copyright (c) 2010-2023 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 8 using System; 9 using System.IO; 10 using System.IO.Compression; 11 using Antmicro.Renode.Exceptions; 12 using Antmicro.Renode.Logging; 13 using Antmicro.Renode.Peripherals.CPU.Disassembler; 14 using Antmicro.Renode.Utilities; 15 16 namespace Antmicro.Renode.Peripherals.CPU 17 { 18 public abstract class TraceWriter : IDisposable 19 { TraceWriter(TranslationCPU cpu, string path, TraceFormat format, bool compress)20 public TraceWriter(TranslationCPU cpu, string path, TraceFormat format, bool compress) 21 { 22 AttachedCPU = cpu; 23 this.format = format; 24 25 try 26 { 27 stream = File.Open(path, FileMode.CreateNew); 28 if(compress) 29 { 30 stream = new GZipStream(stream, CompressionLevel.Fastest); 31 } 32 } 33 catch(Exception e) 34 { 35 throw new RecoverableException($"There was an error when preparing the execution trace output file {path}: {e.Message}"); 36 } 37 } 38 Write(ExecutionTracer.Block block)39 public abstract void Write(ExecutionTracer.Block block); 40 WriteHeader()41 public virtual void WriteHeader() { } 42 FlushBuffer()43 public virtual void FlushBuffer() { } 44 45 public TranslationCPU AttachedCPU { get; } 46 Dispose()47 public void Dispose() => Dispose(true); 48 Dispose(bool disposing)49 protected virtual void Dispose(bool disposing) 50 { 51 if(disposed) 52 { 53 return; 54 } 55 56 if(disposing) 57 { 58 FlushBuffer(); 59 stream?.Dispose(); 60 } 61 disposed = true; 62 } 63 TryReadAndDisassembleInstruction(ulong pc, uint flags, out DisassemblyResult result)64 protected bool TryReadAndDisassembleInstruction(ulong pc, uint flags, out DisassemblyResult result) 65 { 66 // here we read only 4-bytes as it should cover most cases 67 var key = AttachedCPU.Bus.ReadDoubleWord(pc, context: AttachedCPU); 68 if(!disassemblyCache.TryGetValue(key, out result)) 69 { 70 // here we are prepared for longer opcodes 71 var mem = AttachedCPU.Bus.ReadBytes(pc, MaxOpcodeBytes, context: AttachedCPU); 72 if(!AttachedCPU.Disassembler.TryDisassembleInstruction(pc, mem, flags, out result)) 73 { 74 result = new DisassemblyResult(); 75 // mark this as an invalid opcode 76 disassemblyCache.Add(key, result); 77 } 78 else 79 { 80 if(result.OpcodeSize <= 4) 81 { 82 disassemblyCache.Add(key, result); 83 } 84 } 85 } 86 87 if(result.OpcodeSize == 0) 88 { 89 AttachedCPU.Log(LogLevel.Warning, "ExecutionTracer: couldn't disassemble opcode at PC 0x{0:X}", pc); 90 return false; 91 } 92 93 result.PC = pc; 94 return true; 95 } 96 97 protected readonly TraceFormat format; 98 protected readonly Stream stream; 99 protected LRUCache<uint, Disassembler.DisassemblyResult> disassemblyCache; 100 101 protected const int MaxOpcodeBytes = 16; 102 103 private bool disposed; 104 } 105 } 106