public ExecutionTracer(TranslationCPU cpu, string file, Format format)
        {
            cache       = new LRUCache <uint, Antmicro.Renode.Peripherals.CPU.Disassembler.DisassemblyResult?>(CacheSize);
            this.file   = file;
            this.format = format;
            AttachedCPU = cpu;

            if ((AttachedCPU.Architecture == "riscv" || AttachedCPU.Architecture == "riscv64") && format != Format.Disassembly)
            {
                tryDisassembleInstruction = TryDisassembleRiscVInstruction;
            }
            else
            {
                tryDisassembleInstruction = AttachedCPU.Disassembler.TryDisassembleInstruction;
            }

            try
            {
                // truncate the file
                File.WriteAllText(file, string.Empty);
            }
            catch (Exception e)
            {
                throw new RecoverableException($"There was an error when preparing the execution trace output file {file}: {e.Message}");
            }

            AttachedCPU.SetHookAtBlockEnd(HandleBlockEndHook);
        }
        public static void EnableExecutionTracing(this TranslationCPU @this, string file, ExecutionTracer.Format format)
        {
            var tracer = new ExecutionTracer(@this, file, format);

            // we keep it as external to dispose/flush on quit
            EmulationManager.Instance.CurrentEmulation.ExternalsManager.AddExternal(tracer, $"executionTracer-{@this.GetName()}");

            tracer.Start();
        }
        public static void DisableExecutionTracing(this TranslationCPU @this)
        {
            var em      = EmulationManager.Instance.CurrentEmulation.ExternalsManager;
            var tracers = em.GetExternalsOfType <ExecutionTracer>().Where(t => t.AttachedCPU == @this).ToList();

            foreach (var tracer in tracers)
            {
                tracer.Stop();
                em.RemoveExternal(tracer);
            }
        }