Skeleton support for resolving symbols

This commit is contained in:
x1nixmzeng 2018-01-06 18:27:39 +00:00
parent d822b23562
commit d3e5c0644d
7 changed files with 146 additions and 33 deletions

View File

@ -63,6 +63,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DebuggerSymbols\Kernel\KernelSymbolProvider.cs" />
<Compile Include="Debugger\Debugger.cs" />
<Compile Include="Debugger\DebuggerEventInterfaces.cs" />
<Compile Include="Debugger\DebuggerInstance.cs" />

View File

@ -41,6 +41,7 @@ namespace CxbxDebugger
List<IDebuggerExceptionEvents> ExceptionEvents = new List<IDebuggerExceptionEvents>();
DebuggerSymbolServer SymbolSrv;
KernelProvider KernelSymbolProvider;
private void Init()
{
@ -48,6 +49,9 @@ namespace CxbxDebugger
SymbolSrv = new DebuggerSymbolServer();
KernelSymbolProvider = new KernelProvider();
SymbolSrv.RegisterProvider(KernelSymbolProvider);
RegisterEventInterfaces(this);
}
@ -115,19 +119,20 @@ namespace CxbxDebugger
}
static string CxbxDebuggerPrefix = "CxbxDebugger! ";
static string KernelImportPrefix = "KernelImport_";
public void OnDebugOutput(string Message)
{
if (Message.StartsWith(CxbxDebuggerPrefix))
{
string Payload = Message.Substring(CxbxDebuggerPrefix.Length);
if (Payload.StartsWith("IoCreateFile@"))
if (Payload.StartsWith(KernelImportPrefix))
{
Payload = Payload.Substring("IoCreateFile@".Length);
// TODO: Something with payload
KernelSymbolProvider.AddKernelSymbolFromMessage(Payload);
}
else
{
// TODO Ensure this
SetupHLECacheProvider(Payload);
}
}
@ -482,6 +487,16 @@ namespace CxbxDebugger
}
}
public DebuggerSymbol ResolveSymbol(uint Address)
{
return SymbolSrv.FindSymbol(Address);
}
public DebuggerSymbol ResolveSymbol(IntPtr Address)
{
return SymbolSrv.FindSymbol((uint)Address);
}
public void RegisterEventInterfaces(object EventClass)
{
IDebuggerGeneralEvents GeneralListener = EventClass as IDebuggerGeneralEvents;

View File

@ -7,31 +7,50 @@ namespace CxbxDebugger
{
public class DebuggerSymbolServer
{
List<DebuggerSymbolProvider> Providers = new List<DebuggerSymbolProvider>();
public DebuggerSymbolServer() { }
public DebuggerSymbolResult ResolveAddress(uint Address)
List<DebuggerSymbolProviderBase> Providers = new List<DebuggerSymbolProviderBase>();
public DebuggerSymbol FindSymbol(uint Address)
{
DebuggerSymbolResult Result = new DebuggerSymbolResult();
if (Providers.Count == 0)
return null;
foreach (DebuggerSymbolProvider SymbolProvider in Providers)
DebuggerSymbol BestResult = null;
// Find the first provider who can give a symbol for this address
int ProviderIndex = 0;
do
{
Result = SymbolProvider.ResolveAddress(Address);
if (Result.Success)
BestResult = Providers[ProviderIndex].FindSymbolFromAddress(Address);
if (BestResult != null)
break;
}
while (ProviderIndex < Providers.Count);
return Result;
// Try to find another symbol which is closer to the given address
// TODO Investigate adding symbol size metadata this can just check if Address is within a given range
for (int i = ProviderIndex + 1; i < Providers.Count; ++i)
{
DebuggerSymbol OtherResult = Providers[i].FindSymbolFromAddress(Address);
if (OtherResult == null)
continue;
if(OtherResult.AddrBegin < BestResult.AddrBegin )
{
BestResult = OtherResult;
}
}
return BestResult;
}
public void RegisterProvider(DebuggerSymbolProvider Provider)
public void RegisterProvider(DebuggerSymbolProviderBase Provider)
{
Providers.Add(Provider);
}
public void UnregisterProvider(DebuggerSymbolProvider Provider)
public void UnregisterProvider(DebuggerSymbolProviderBase Provider)
{
Providers.Remove(Provider);
}

View File

@ -1,15 +1,51 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System.Collections;
using System.Collections.Generic;
namespace CxbxDebugger
{
public class DebuggerSymbolResult
public class DebuggerSymbol
{
public bool Success { get; set; } = false;
public string Name { get; set; } = "";
public uint AddrBegin { get; set; } = 0;
public uint AddrEnd { get; set; } = 0;
}
public abstract class DebuggerSymbolProvider
public class DebuggerSymbolProviderBase
{
public virtual DebuggerSymbolResult ResolveAddress(uint Address) { return new DebuggerSymbolResult(); }
// Stored in a map so the addresses are sorted
Dictionary<uint, DebuggerSymbol> Symbols = new Dictionary<uint, DebuggerSymbol>();
protected void AddSymbol(DebuggerSymbol Symbol)
{
Symbols.Add(Symbol.AddrBegin, Symbol);
}
protected void RemoveSymbol(DebuggerSymbol Symbol)
{
Symbols.Remove(Symbol.AddrBegin);
}
// TODO Find an inbuilt lower bound method
public DebuggerSymbol FindSymbolFromAddress(uint Address)
{
uint BestAddr = 0;
foreach (uint SymbolAddr in Symbols.Keys)
{
if (SymbolAddr > Address)
break;
BestAddr = SymbolAddr;
}
if (!Symbols.ContainsKey(BestAddr))
return null;
return Symbols[BestAddr];
}
}
}

View File

@ -1,26 +1,32 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
using System.Collections.Generic;
using System.IO;
namespace CxbxDebugger
{
public class HLECacheProvider : DebuggerSymbolProvider
public class HLECacheProvider : DebuggerSymbolProviderBase
{
HLECacheFile CacheFile;
public bool Load(string FileName)
{
CacheFile = new HLECacheFile();
return CacheFile.Load(FileName);
}
if (!File.Exists(FileName))
return false;
public override DebuggerSymbolResult ResolveAddress(uint Address)
{
var SymbolResult = new DebuggerSymbolResult();
HLECacheFile CacheFile = new HLECacheFile();
if (!CacheFile.Load(FileName))
return false;
// TODO: Resolve me
SymbolResult.Success = false;
foreach(KeyValuePair<uint, string> Item in CacheFile.AddressMap)
{
DebuggerSymbol NewSymbol = new DebuggerSymbol();
NewSymbol.Name = Item.Value;
NewSymbol.AddrBegin = Item.Key;
return SymbolResult;
AddSymbol(NewSymbol);
}
return true;
}
}
}

View File

@ -0,0 +1,25 @@
// Written by x1nixmzeng for the Cxbx-Reloaded project
//
namespace CxbxDebugger
{
public class KernelProvider : DebuggerSymbolProviderBase
{
public void AddKernelSymbolFromMessage(string Message)
{
var Parts = Message.Split('@');
if( Parts.Length == 2 )
{
uint Address = 0;
if( uint.TryParse(Parts[1], out Address) )
{
DebuggerSymbol NewSymbol = new DebuggerSymbol();
NewSymbol.Name = Parts[0];
NewSymbol.AddrBegin = Address;
AddSymbol(NewSymbol);
}
}
}
}
}

View File

@ -260,6 +260,9 @@ namespace CxbxDebugger
public void OnAccessViolation()
{
frm.DebugEvent("Access violation exception occured");
// Already suspended at this point, so we can rebuild the callstack list
frm.PopulateThreadList(frm.cbThreads.Items);
}
}
@ -297,9 +300,17 @@ namespace CxbxDebugger
var Callstack = DebugThreads[Index].CallstackCache;
foreach(DebuggerStackFrame StackFrame in Callstack.StackFrames)
{
// TODO Resolve symbol names
string FrameString = string.Format("{0:X8} {1:X8}", (uint)StackFrame.Base, (uint)StackFrame.PC);
// Try to resolve the symbol name
var Symbol = DebuggerInst.ResolveSymbol(StackFrame.Base);
if( Symbol != null)
{
uint Offset = Symbol.AddrBegin - (uint)StackFrame.Base;
FrameString = string.Format("{0} + 0x{1:X}", Symbol.Name, Offset);
}
lbRegisters.Items.Add(FrameString);
}
}