From 950011c90fe28fe9edd8ebe0d0a771f6adcff7a1 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sun, 25 Feb 2018 22:14:58 -0300
Subject: [PATCH] Added initial support for function names from symbol table on
 the cpu with tracing, fix wrong ImageEnd on executables with MOD0, fix issue
 on the CPU on input elimination for instruction with more than one register
 store

---
 ChocolArm64/AThread.cs                        |  6 +-
 ChocolArm64/ATranslator.cs                    | 82 ++++++++++++++-----
 ChocolArm64/Decoder/ADecoder.cs               |  7 +-
 ChocolArm64/Events/ACpuTraceEventArgs.cs      | 17 ++++
 ChocolArm64/Events/AInstExceptionEventArgs.cs | 14 ++++
 .../AInstUndefinedEventArgs.cs}               |  6 +-
 ChocolArm64/Instruction/AInstEmitCsel.cs      |  5 +-
 ChocolArm64/State/AInstExceptEventArgs.cs     | 14 ----
 ChocolArm64/State/AThreadState.cs             | 13 +--
 ChocolArm64/Translation/AILBarrier.cs         |  7 ++
 ChocolArm64/Translation/AILBlock.cs           | 27 ++++--
 ChocolArm64/Translation/AILEmitterCtx.cs      | 10 ++-
 ChocolArm64/Translation/AILOpCodeLoad.cs      |  6 +-
 ChocolArm64/Translation/AILOpCodeStore.cs     |  4 +-
 ChocolArm64/Translation/ALocalAlloc.cs        |  8 +-
 Ryujinx.Core/Loaders/ElfSym.cs                |  9 +-
 Ryujinx.Core/Loaders/Executable.cs            | 30 +++++--
 Ryujinx.Core/OsHle/Process.cs                 | 39 ++++++++-
 Ryujinx.Core/OsHle/Svc/SvcHandler.cs          |  3 +-
 Ryujinx.Tests/Cpu/CpuTest.cs                  |  3 +-
 20 files changed, 217 insertions(+), 93 deletions(-)
 create mode 100644 ChocolArm64/Events/ACpuTraceEventArgs.cs
 create mode 100644 ChocolArm64/Events/AInstExceptionEventArgs.cs
 rename ChocolArm64/{State/AInstUndEventArgs.cs => Events/AInstUndefinedEventArgs.cs} (60%)
 delete mode 100644 ChocolArm64/State/AInstExceptEventArgs.cs
 create mode 100644 ChocolArm64/Translation/AILBarrier.cs

diff --git a/ChocolArm64/AThread.cs b/ChocolArm64/AThread.cs
index 5c0322894..6e018db68 100644
--- a/ChocolArm64/AThread.cs
+++ b/ChocolArm64/AThread.cs
@@ -28,14 +28,14 @@ namespace ChocolArm64
 
         private object ExecuteLock;
 
-        public AThread(AMemory Memory, ThreadPriority Priority, long EntryPoint)
+        public AThread(ATranslator Translator, AMemory Memory, ThreadPriority Priority, long EntryPoint)
         {
+            this.Translator = Translator;
             this.Memory     = Memory;
             this.Priority   = Priority;
             this.EntryPoint = EntryPoint;
 
             ThreadState = new AThreadState();
-            Translator  = new ATranslator(this);
             ExecuteLock = new object();
         }
 
@@ -55,7 +55,7 @@ namespace ChocolArm64
 
             Work = new Thread(delegate()
             {
-                Translator.ExecuteSubroutine(EntryPoint);
+                Translator.ExecuteSubroutine(this, EntryPoint);
 
                 Memory.RemoveMonitor(ThreadId);
 
diff --git a/ChocolArm64/ATranslator.cs b/ChocolArm64/ATranslator.cs
index 96bbc89ea..2daf7bbc9 100644
--- a/ChocolArm64/ATranslator.cs
+++ b/ChocolArm64/ATranslator.cs
@@ -1,47 +1,70 @@
 using ChocolArm64.Decoder;
+using ChocolArm64.Events;
 using ChocolArm64.Instruction;
+using ChocolArm64.Memory;
 using ChocolArm64.Translation;
+using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Reflection.Emit;
 
 namespace ChocolArm64
 {
-    class ATranslator
+    public class ATranslator
     {
-        public AThread Thread { get; private set; }
+        private ConcurrentDictionary<long, ATranslatedSub> CachedSubs;
 
-        private Dictionary<long, ATranslatedSub> CachedSubs;
+        private ConcurrentDictionary<long, string> SymbolTable;
+
+        public event EventHandler<ACpuTraceEventArgs> CpuTrace;
+
+        public bool EnableCpuTrace { get; set; }
 
         private bool KeepRunning;
 
-        public ATranslator(AThread Parent)
+        public ATranslator(IReadOnlyDictionary<long, string> SymbolTable = null)
         {
-            this.Thread = Parent;
+            CachedSubs = new ConcurrentDictionary<long, ATranslatedSub>();
 
-            CachedSubs = new Dictionary<long, ATranslatedSub>();
+            if (SymbolTable != null)
+            {
+                this.SymbolTable = new ConcurrentDictionary<long, string>(SymbolTable);
+            }
+            else
+            {
+                this.SymbolTable = new ConcurrentDictionary<long, string>();
+            }
 
             KeepRunning = true;
         }
 
         public void StopExecution() => KeepRunning = false;
 
-        public void ExecuteSubroutine(long Position)
+        public void ExecuteSubroutine(AThread Thread, long Position)
         {
             do
             {
-                if (CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) && !Sub.NeedsReJit)
+                if (EnableCpuTrace)
                 {
-                    Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
+                    if (!SymbolTable.TryGetValue(Position, out string SubName))
+                    {
+                        SubName = string.Empty;
+                    }
+
+                    CpuTrace?.Invoke(this, new ACpuTraceEventArgs(Position, SubName));
                 }
-                else
+
+                if (!CachedSubs.TryGetValue(Position, out ATranslatedSub Sub) || Sub.NeedsReJit)
                 {
-                    Position = TranslateSubroutine(Position).Execute(Thread.ThreadState, Thread.Memory);
+                    Sub = TranslateSubroutine(Thread.Memory, Position);
                 }
+
+                Position = Sub.Execute(Thread.ThreadState, Thread.Memory);
             }
             while (Position != 0 && KeepRunning);
         }
 
-        public bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
+        internal bool TryGetCachedSub(AOpCode OpCode, out ATranslatedSub Sub)
         {
             if (OpCode.Emitter != AInstEmit.Bl)
             {
@@ -53,24 +76,29 @@ namespace ChocolArm64
             return TryGetCachedSub(((AOpCodeBImmAl)OpCode).Imm, out Sub);
         }
 
-        public bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
+        internal bool TryGetCachedSub(long Position, out ATranslatedSub Sub)
         {
             return CachedSubs.TryGetValue(Position, out Sub);
         }
 
-        public bool HasCachedSub(long Position)
+        internal bool HasCachedSub(long Position)
         {
             return CachedSubs.ContainsKey(Position);
         }
 
-        private ATranslatedSub TranslateSubroutine(long Position)
+        private ATranslatedSub TranslateSubroutine(AMemory Memory, long Position)
         {
-            (ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Position);
+            (ABlock[] Graph, ABlock Root) Cfg = ADecoder.DecodeSubroutine(this, Memory, Position);
+
+            string SubName = SymbolTable.GetOrAdd(Position, $"Sub{Position:x16}");
+
+            PropagateName(Cfg.Graph, SubName);
 
             AILEmitterCtx Context = new AILEmitterCtx(
                 this,
                 Cfg.Graph,
-                Cfg.Root);
+                Cfg.Root,
+                SubName);
 
             if (Context.CurrBlock.Position != Position)
             {
@@ -95,12 +123,24 @@ namespace ChocolArm64
 
             ATranslatedSub Subroutine = Context.GetSubroutine();
 
-            if (!CachedSubs.TryAdd(Position, Subroutine))
-            {
-                CachedSubs[Position] = Subroutine;
-            }
+            CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
 
             return Subroutine;
         }
+
+        private void PropagateName(ABlock[] Graph, string Name)
+        {
+            foreach (ABlock Block in Graph)
+            {
+                AOpCode LastOp = Block.GetLastOp();
+
+                if (LastOp != null &&
+                   (LastOp.Emitter == AInstEmit.Bl ||
+                    LastOp.Emitter == AInstEmit.Blr))
+                {
+                    SymbolTable.TryAdd(LastOp.Position + 4, Name);
+                }
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/ChocolArm64/Decoder/ADecoder.cs b/ChocolArm64/Decoder/ADecoder.cs
index a3f44e470..443022903 100644
--- a/ChocolArm64/Decoder/ADecoder.cs
+++ b/ChocolArm64/Decoder/ADecoder.cs
@@ -18,7 +18,10 @@ namespace ChocolArm64.Decoder
             OpActivators = new ConcurrentDictionary<Type, OpActivator>();
         }
 
-        public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(ATranslator Translator, long Start)
+        public static (ABlock[] Graph, ABlock Root) DecodeSubroutine(
+            ATranslator Translator,
+            AMemory     Memory,
+            long        Start)
         {
             Dictionary<long, ABlock> Visited    = new Dictionary<long, ABlock>();
             Dictionary<long, ABlock> VisitedEnd = new Dictionary<long, ABlock>();
@@ -45,7 +48,7 @@ namespace ChocolArm64.Decoder
             {
                 ABlock Current = Blocks.Dequeue();
 
-                FillBlock(Translator.Thread.Memory, Current);
+                FillBlock(Memory, Current);
 
                 //Set child blocks. "Branch" is the block the branch instruction
                 //points to (when taken), "Next" is the block at the next address,
diff --git a/ChocolArm64/Events/ACpuTraceEventArgs.cs b/ChocolArm64/Events/ACpuTraceEventArgs.cs
new file mode 100644
index 000000000..fedf3865b
--- /dev/null
+++ b/ChocolArm64/Events/ACpuTraceEventArgs.cs
@@ -0,0 +1,17 @@
+using System;
+
+namespace ChocolArm64.Events
+{
+    public class ACpuTraceEventArgs : EventArgs
+    {
+        public long Position { get; private set; }
+
+        public string SubName { get; private set; }
+
+        public ACpuTraceEventArgs(long Position, string SubName)
+        {
+            this.Position = Position;
+            this.SubName  = SubName;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ChocolArm64/Events/AInstExceptionEventArgs.cs b/ChocolArm64/Events/AInstExceptionEventArgs.cs
new file mode 100644
index 000000000..34f90c8ee
--- /dev/null
+++ b/ChocolArm64/Events/AInstExceptionEventArgs.cs
@@ -0,0 +1,14 @@
+using System;
+
+namespace ChocolArm64.Events
+{
+    public class AInstExceptionEventArgs : EventArgs
+    {
+        public int Id { get; private set; }
+
+        public AInstExceptionEventArgs(int Id)
+        {
+            this.Id = Id;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ChocolArm64/State/AInstUndEventArgs.cs b/ChocolArm64/Events/AInstUndefinedEventArgs.cs
similarity index 60%
rename from ChocolArm64/State/AInstUndEventArgs.cs
rename to ChocolArm64/Events/AInstUndefinedEventArgs.cs
index 53de65a33..cdc1728bd 100644
--- a/ChocolArm64/State/AInstUndEventArgs.cs
+++ b/ChocolArm64/Events/AInstUndefinedEventArgs.cs
@@ -1,13 +1,13 @@
 using System;
 
-namespace ChocolArm64.State
+namespace ChocolArm64.Events
 {
-    public class AInstUndEventArgs : EventArgs
+    public class AInstUndefinedEventArgs : EventArgs
     {
         public long Position  { get; private set; }
         public int  RawOpCode { get; private set; }
 
-        public AInstUndEventArgs(long Position, int RawOpCode)
+        public AInstUndefinedEventArgs(long Position, int RawOpCode)
         {
             this.Position  = Position;
             this.RawOpCode = RawOpCode;
diff --git a/ChocolArm64/Instruction/AInstEmitCsel.cs b/ChocolArm64/Instruction/AInstEmitCsel.cs
index 330809806..218767524 100644
--- a/ChocolArm64/Instruction/AInstEmitCsel.cs
+++ b/ChocolArm64/Instruction/AInstEmitCsel.cs
@@ -44,16 +44,15 @@ namespace ChocolArm64.Instruction
                 Context.Emit(OpCodes.Neg);
             }
 
-            Context.EmitStintzr(Op.Rd);
-
             Context.Emit(OpCodes.Br_S, LblEnd);
 
             Context.MarkLabel(LblTrue);
 
             Context.EmitLdintzr(Op.Rn);
-            Context.EmitStintzr(Op.Rd);
 
             Context.MarkLabel(LblEnd);
+
+            Context.EmitStintzr(Op.Rd);
         }
     }
 }
\ No newline at end of file
diff --git a/ChocolArm64/State/AInstExceptEventArgs.cs b/ChocolArm64/State/AInstExceptEventArgs.cs
deleted file mode 100644
index f2ee039b6..000000000
--- a/ChocolArm64/State/AInstExceptEventArgs.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System;
-
-namespace ChocolArm64.State
-{
-    public class AInstExceptEventArgs : EventArgs
-    {
-        public int Id { get; private set; }
-
-        public AInstExceptEventArgs(int Id)
-        {
-            this.Id = Id;
-        }
-    }
-}
\ No newline at end of file
diff --git a/ChocolArm64/State/AThreadState.cs b/ChocolArm64/State/AThreadState.cs
index cdab4034e..2d988a653 100644
--- a/ChocolArm64/State/AThreadState.cs
+++ b/ChocolArm64/State/AThreadState.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Events;
 using System;
 
 namespace ChocolArm64.State
@@ -42,23 +43,23 @@ namespace ChocolArm64.State
 
         public long CntpctEl0 => Environment.TickCount * TicksPerMS;
 
-        public event EventHandler<AInstExceptEventArgs> Break;
-        public event EventHandler<AInstExceptEventArgs> SvcCall;
-        public event EventHandler<AInstUndEventArgs>    Undefined;
+        public event EventHandler<AInstExceptionEventArgs> Break;
+        public event EventHandler<AInstExceptionEventArgs> SvcCall;
+        public event EventHandler<AInstUndefinedEventArgs> Undefined;
 
         internal void OnBreak(int Imm)
         {
-            Break?.Invoke(this, new AInstExceptEventArgs(Imm));
+            Break?.Invoke(this, new AInstExceptionEventArgs(Imm));
         }
 
         internal void OnSvcCall(int Imm)
         {
-            SvcCall?.Invoke(this, new AInstExceptEventArgs(Imm));
+            SvcCall?.Invoke(this, new AInstExceptionEventArgs(Imm));
         }
 
         internal void OnUndefined(long Position, int RawOpCode)
         {
-            Undefined?.Invoke(this, new AInstUndEventArgs(Position, RawOpCode));
+            Undefined?.Invoke(this, new AInstUndefinedEventArgs(Position, RawOpCode));
         }
     }
 }
\ No newline at end of file
diff --git a/ChocolArm64/Translation/AILBarrier.cs b/ChocolArm64/Translation/AILBarrier.cs
new file mode 100644
index 000000000..25b08de31
--- /dev/null
+++ b/ChocolArm64/Translation/AILBarrier.cs
@@ -0,0 +1,7 @@
+namespace ChocolArm64.Translation
+{
+    struct AILBarrier : IAILEmit
+    {
+        public void Emit(AILEmitter Context) { }
+    }
+}
\ No newline at end of file
diff --git a/ChocolArm64/Translation/AILBlock.cs b/ChocolArm64/Translation/AILBlock.cs
index bed195aaf..e580e09c9 100644
--- a/ChocolArm64/Translation/AILBlock.cs
+++ b/ChocolArm64/Translation/AILBlock.cs
@@ -4,11 +4,13 @@ namespace ChocolArm64.Translation
 {
     class AILBlock : IAILEmit
     {
-        public long IntInputs  { get; private set; }
-        public long IntOutputs { get; private set; }
+        public long IntInputs    { get; private set; }
+        public long IntOutputs   { get; private set; }
+        public long IntAwOutputs { get; private set; }
 
-        public long VecInputs  { get; private set; }
-        public long VecOutputs { get; private set; }
+        public long VecInputs    { get; private set; }
+        public long VecOutputs   { get; private set; }
+        public long VecAwOutputs { get; private set; }
 
         public bool HasStateStore { get; private set; }
 
@@ -24,13 +26,22 @@ namespace ChocolArm64.Translation
 
         public void Add(IAILEmit ILEmitter)
         {
-            if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index))
+            if (ILEmitter is AILBarrier)
+            {
+                //Those barriers are used to separate the groups of CIL
+                //opcodes emitted by each ARM instruction.
+                //We can only consider the new outputs for doing input elimination
+                //after all the CIL opcodes used by the instruction being emitted.
+                IntAwOutputs = IntOutputs;
+                VecAwOutputs = VecOutputs;
+            }
+            else if (ILEmitter is AILOpCodeLoad Ld && AILEmitter.IsRegIndex(Ld.Index))
             {
                 switch (Ld.IoType)
                 {
-                    case AIoType.Flag:   IntInputs |= ((1L << Ld.Index) << 32) & ~IntOutputs; break;
-                    case AIoType.Int:    IntInputs |=  (1L << Ld.Index)        & ~IntOutputs; break;
-                    case AIoType.Vector: VecInputs |=  (1L << Ld.Index)        & ~VecOutputs; break;
+                    case AIoType.Flag:   IntInputs |= ((1L << Ld.Index) << 32) & ~IntAwOutputs; break;
+                    case AIoType.Int:    IntInputs |=  (1L << Ld.Index)        & ~IntAwOutputs; break;
+                    case AIoType.Vector: VecInputs |=  (1L << Ld.Index)        & ~VecAwOutputs; break;
                 }
             }
             else if (ILEmitter is AILOpCodeStore St)
diff --git a/ChocolArm64/Translation/AILEmitterCtx.cs b/ChocolArm64/Translation/AILEmitterCtx.cs
index 9199eddc6..ffcfa851a 100644
--- a/ChocolArm64/Translation/AILEmitterCtx.cs
+++ b/ChocolArm64/Translation/AILEmitterCtx.cs
@@ -39,14 +39,16 @@ namespace ChocolArm64.Translation
         private const int Tmp4Index = -4;
         private const int Tmp5Index = -5;
 
-        public AILEmitterCtx(ATranslator Translator, ABlock[] Graph, ABlock Root)
+        public AILEmitterCtx(
+            ATranslator Translator,
+            ABlock[]    Graph,
+            ABlock      Root,
+            string      SubName)
         {
             this.Translator = Translator;
             this.Graph      = Graph;
             this.Root       = Root;
 
-            string SubName = $"Sub{Root.Position:X16}";
-
             Labels = new Dictionary<long, AILLabel>();
 
             Emitter = new AILEmitter(Graph, Root, SubName);
@@ -92,6 +94,8 @@ namespace ChocolArm64.Translation
             }
 
             CurrOp.Emitter(this);
+
+            ILBlock.Add(new AILBarrier());
         }
 
         public bool TryOptEmitSubroutineCall()
diff --git a/ChocolArm64/Translation/AILOpCodeLoad.cs b/ChocolArm64/Translation/AILOpCodeLoad.cs
index 7cb431e2d..d60ce539f 100644
--- a/ChocolArm64/Translation/AILOpCodeLoad.cs
+++ b/ChocolArm64/Translation/AILOpCodeLoad.cs
@@ -11,12 +11,10 @@ namespace ChocolArm64.Translation
 
         public ARegisterSize RegisterSize { get; private set; }
 
-        public AILOpCodeLoad(int Index, AIoType IoType) : this(Index, IoType, ARegisterSize.Int64) { }
-
-        public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize)
+        public AILOpCodeLoad(int Index, AIoType IoType, ARegisterSize RegisterSize = 0)
         {
-            this.IoType       = IoType;
             this.Index        = Index;
+            this.IoType       = IoType;
             this.RegisterSize = RegisterSize;
         }
 
diff --git a/ChocolArm64/Translation/AILOpCodeStore.cs b/ChocolArm64/Translation/AILOpCodeStore.cs
index c4ea53aba..a0feb4377 100644
--- a/ChocolArm64/Translation/AILOpCodeStore.cs
+++ b/ChocolArm64/Translation/AILOpCodeStore.cs
@@ -11,10 +11,10 @@ namespace ChocolArm64.Translation
 
         public ARegisterSize RegisterSize { get; private set; }
 
-        public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = ARegisterSize.Int64)
+        public AILOpCodeStore(int Index, AIoType IoType, ARegisterSize RegisterSize = 0)
         {
-            this.IoType       = IoType;
             this.Index        = Index;
+            this.IoType       = IoType;
             this.RegisterSize = RegisterSize;
         }
 
diff --git a/ChocolArm64/Translation/ALocalAlloc.cs b/ChocolArm64/Translation/ALocalAlloc.cs
index 0661ddc8d..f23af9c76 100644
--- a/ChocolArm64/Translation/ALocalAlloc.cs
+++ b/ChocolArm64/Translation/ALocalAlloc.cs
@@ -67,7 +67,7 @@ namespace ChocolArm64.Translation
             public long VecOutputs;
         }
 
-        private const int MaxOptGraphLength = 120;
+        private const int MaxOptGraphLength = 55;
 
         public ALocalAlloc(AILBlock[] Graph, AILBlock Root)
         {
@@ -149,11 +149,7 @@ namespace ChocolArm64.Translation
 
                     if (RetTarget)
                     {
-                        BlkIO.Entry      = Block;
-                        BlkIO.IntInputs  = 0;
-                        BlkIO.VecInputs  = 0;
-                        BlkIO.IntOutputs = 0;
-                        BlkIO.VecOutputs = 0;
+                        BlkIO.Entry = Block;
                     }
                     else
                     {
diff --git a/Ryujinx.Core/Loaders/ElfSym.cs b/Ryujinx.Core/Loaders/ElfSym.cs
index 35a45500a..89e7c61f6 100644
--- a/Ryujinx.Core/Loaders/ElfSym.cs
+++ b/Ryujinx.Core/Loaders/ElfSym.cs
@@ -16,17 +16,15 @@ namespace Ryujinx.Core.Loaders
             Binding == ElfSymBinding.STB_GLOBAL ||
             Binding == ElfSymBinding.STB_WEAK;
 
-        public int  SHIdx    { get; private set; }
-        public long ValueAbs { get; private set; }
-        public long Value    { get; private set; }
-        public long Size     { get; private set; }
+        public int  SHIdx { get; private set; }
+        public long Value { get; private set; }
+        public long Size  { get; private set; }
 
         public ElfSym(
             string Name,
             int    Info, 
             int    Other,
             int    SHIdx,
-            long   ImageBase,
             long   Value,
             long   Size)
         {
@@ -35,7 +33,6 @@ namespace Ryujinx.Core.Loaders
             this.Binding    = (ElfSymBinding)(Info >> 4);
             this.Visibility = (ElfSymVisibility)Other;
             this.SHIdx      = SHIdx;
-            this.ValueAbs   = Value + ImageBase;
             this.Value      = Value;
             this.Size       = Size;
         }
diff --git a/Ryujinx.Core/Loaders/Executable.cs b/Ryujinx.Core/Loaders/Executable.cs
index e26608389..c6770c7b3 100644
--- a/Ryujinx.Core/Loaders/Executable.cs
+++ b/Ryujinx.Core/Loaders/Executable.cs
@@ -9,13 +9,21 @@ namespace Ryujinx.Core.Loaders
     {
         private AMemory Memory;
 
-        private ElfDyn[] Dynamic;
+        private List<ElfDyn> Dynamic;
+
+        private Dictionary<long, string> m_SymbolTable;
+
+        public IReadOnlyDictionary<long, string> SymbolTable => m_SymbolTable;
 
         public long ImageBase { get; private set; }
         public long ImageEnd  { get; private set; }
 
         public Executable(IExecutable Exe, AMemory Memory, long ImageBase)
         {
+            Dynamic = new List<ElfDyn>();
+
+            m_SymbolTable = new Dictionary<long, string>();
+
             this.Memory    = Memory;
             this.ImageBase = ImageBase;
             this.ImageEnd  = ImageBase;
@@ -48,9 +56,7 @@ namespace Ryujinx.Core.Loaders
 
             MapBss(BssStartOffset, BssEndOffset - BssStartOffset);
 
-            ImageEnd = BssEndOffset;
-
-            List<ElfDyn> Dynamic = new List<ElfDyn>();
+            ImageEnd = ImageBase + BssEndOffset;
 
             while (true)
             {
@@ -69,7 +75,19 @@ namespace Ryujinx.Core.Loaders
                 Dynamic.Add(new ElfDyn(Tag, Value));
             }
 
-            this.Dynamic = Dynamic.ToArray();
+            long StrTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_STRTAB);
+            long SymTblAddr = ImageBase + GetFirstValue(ElfDynTag.DT_SYMTAB);
+
+            long SymEntSize = GetFirstValue(ElfDynTag.DT_SYMENT);
+
+            while ((ulong)SymTblAddr < (ulong)StrTblAddr)
+            {
+                ElfSym Sym = GetSymbol(SymTblAddr, StrTblAddr);
+
+                m_SymbolTable.TryAdd(Sym.Value, Sym.Name);
+
+                SymTblAddr += SymEntSize;
+            }
         }
 
         private void WriteData(
@@ -135,7 +153,7 @@ namespace Ryujinx.Core.Loaders
                 Name += (char)Chr;
             }
 
-            return new ElfSym(Name, Info, Other, SHIdx, ImageBase, Value, Size);
+            return new ElfSym(Name, Info, Other, SHIdx, Value, Size);
         }
 
         private long GetFirstValue(ElfDynTag Tag)
diff --git a/Ryujinx.Core/OsHle/Process.cs b/Ryujinx.Core/OsHle/Process.cs
index 3e265ed34..60e71ee99 100644
--- a/Ryujinx.Core/OsHle/Process.cs
+++ b/Ryujinx.Core/OsHle/Process.cs
@@ -1,6 +1,6 @@
 using ChocolArm64;
+using ChocolArm64.Events;
 using ChocolArm64.Memory;
-using ChocolArm64.State;
 using Ryujinx.Core.Loaders;
 using Ryujinx.Core.Loaders.Executables;
 using Ryujinx.Core.OsHle.Exceptions;
@@ -24,6 +24,8 @@ namespace Ryujinx.Core.OsHle
 
         private Switch Ns;
 
+        private ATranslator Translator;
+
         public int ProcessId { get; private set; }
 
         public AMemory Memory { get; private set; }
@@ -171,7 +173,7 @@ namespace Ryujinx.Core.OsHle
                 ThreadPrio = ThreadPriority.Lowest;
             }
 
-            AThread Thread = new AThread(Memory, ThreadPrio, EntryPoint);
+            AThread Thread = new AThread(GetTranslator(), Memory, ThreadPrio, EntryPoint);
 
             HThread ThreadHnd = new HThread(Thread, ProcessorId, Priority);
 
@@ -201,16 +203,45 @@ namespace Ryujinx.Core.OsHle
             return Handle;
         }
 
-        private void BreakHandler(object sender, AInstExceptEventArgs e)
+        private void BreakHandler(object sender, AInstExceptionEventArgs e)
         {
             throw new GuestBrokeExecutionException();
         }
 
-        private void UndefinedHandler(object sender, AInstUndEventArgs e)
+        private void UndefinedHandler(object sender, AInstUndefinedEventArgs e)
         {
             throw new UndefinedInstructionException(e.Position, e.RawOpCode);
         }
 
+        private ATranslator GetTranslator()
+        {
+            if (Translator == null)
+            {
+                Dictionary<long, string> SymbolTable = new Dictionary<long, string>();
+
+                foreach (Executable Exe in Executables)
+                {
+                    foreach (KeyValuePair<long, string> KV in Exe.SymbolTable)
+                    {                        
+                        SymbolTable.Add(Exe.ImageBase + KV.Key, KV.Value);
+                    }
+                }
+
+                Translator = new ATranslator(SymbolTable);
+
+                
+
+                Translator.CpuTrace += CpuTraceHandler;
+            }
+
+            return Translator;
+        }
+
+        private void CpuTraceHandler(object sender, ACpuTraceEventArgs e)
+        {
+            Logging.Info($"Executing at 0x{e.Position:x16} {e.SubName}");
+        }
+
         private int GetFreeTlsSlot(AThread Thread)
         {
             for (int Index = 1; Index < TotalTlsSlots; Index++)
diff --git a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
index c5b6da04b..ec53f47ff 100644
--- a/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
+++ b/Ryujinx.Core/OsHle/Svc/SvcHandler.cs
@@ -1,3 +1,4 @@
+using ChocolArm64.Events;
 using ChocolArm64.Memory;
 using ChocolArm64.State;
 using System;
@@ -62,7 +63,7 @@ namespace Ryujinx.Core.OsHle.Svc
             Rng = new Random();
         }
 
-        public void SvcCall(object sender, AInstExceptEventArgs e)
+        public void SvcCall(object sender, AInstExceptionEventArgs e)
         {
             AThreadState ThreadState = (AThreadState)sender;
 
diff --git a/Ryujinx.Tests/Cpu/CpuTest.cs b/Ryujinx.Tests/Cpu/CpuTest.cs
index 7af2d55d0..bf9d90e33 100644
--- a/Ryujinx.Tests/Cpu/CpuTest.cs
+++ b/Ryujinx.Tests/Cpu/CpuTest.cs
@@ -30,10 +30,11 @@ namespace Ryujinx.Tests.Cpu
             EntryPoint = Position;
 
             Ram = Marshal.AllocHGlobal((IntPtr)AMemoryMgr.RamSize);
+            ATranslator Translator = new ATranslator();
             Allocator = new AMemoryAlloc();
             Memory = new AMemory(Ram, Allocator);
             Memory.Manager.MapPhys(Position, Size, 2, AMemoryPerm.Read | AMemoryPerm.Write | AMemoryPerm.Execute);
-            Thread = new AThread(Memory, ThreadPriority.Normal, EntryPoint);
+            Thread = new AThread(Translator, Memory, ThreadPriority.Normal, EntryPoint);
         }
 
         [TearDown]