1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
5 using System
.Collections
.Generic
;
8 using System
.Runtime
.InteropServices
;
9 using System
.Diagnostics
;
10 using System
.Text
.RegularExpressions
;
12 namespace LuaRemoteDebugger
14 public abstract class SymbolsManager
16 Dictionary
<UInt32
, CallStackItem
> symbolCache
= new Dictionary
<UInt32
, CallStackItem
>();
18 public List
<CallStackItem
> GetSymbolNamesFromAddresses(List
<UInt32
> addresses
)
20 // Get a list of addresses that need to be resolved
21 List
<UInt32
> uncachedAddresses
= addresses
.FindAll(x
=> !symbolCache
.ContainsKey(x
));
22 if (uncachedAddresses
.Count
> 0)
24 // Resolve uncached addresses
25 List
<CallStackItem
> items
= new List
<CallStackItem
>(GetSymbolNamesFromAddressesInternal(uncachedAddresses
));
26 Debug
.Assert(items
.Count
== uncachedAddresses
.Count
);
27 for (int i
= 0; i
< items
.Count
; ++i
)
29 symbolCache
[uncachedAddresses
[i
]] = items
[i
];
33 List
<CallStackItem
> results
= new List
<CallStackItem
>();
34 foreach (UInt32 address
in addresses
)
36 results
.Add(symbolCache
[address
]);
41 protected abstract List
<CallStackItem
> GetSymbolNamesFromAddressesInternal(List
<UInt32
> addresses
);
44 public class XboxSymbolsManager
: SymbolsManager
46 private List
<XboxSymbolResolver
> symbolResolvers
= new List
<XboxSymbolResolver
>();
48 public void AddModuleInformation(string path
, uint baseAddress
, uint size
, Guid guid
, uint age
)
52 IDiaSession diaSession
;
53 DiaSourceClass diaSource
= new DiaSourceClass();
54 diaSource
.loadAndValidateDataFromPdb(path
, ref guid
, 0, age
);
55 diaSource
.openSession(out diaSession
);
56 diaSession
.loadAddress
= baseAddress
;
58 XboxSymbolResolver symbolResolver
= new XboxSymbolResolver(diaSession
, size
);
59 symbolResolvers
.Add(symbolResolver
);
61 Marshal
.ReleaseComObject(diaSource
);
63 catch (System
.Runtime
.InteropServices
.COMException ex
)
65 switch ((UInt32
)ex
.ErrorCode
)
67 // look in dia.h for error codes
69 Console
.WriteLine("Couldn't find pdb: " + path
);
72 Console
.WriteLine("Signature invalid for: " + path
);
75 Console
.WriteLine("Unknown pdb load error for: " + path
+ ", errorcode: " + ex
.ErrorCode
);
81 protected override List
<CallStackItem
> GetSymbolNamesFromAddressesInternal(List
<UInt32
> addresses
)
83 List
<CallStackItem
> items
= new List
<CallStackItem
>();
84 foreach (UInt32 address
in addresses
)
87 foreach (XboxSymbolResolver symbolResolver
in symbolResolvers
)
89 if (symbolResolver
.AddressIsInRange(address
))
92 items
.Add(symbolResolver
.GetSymbolNameFromAddress(address
));
97 CallStackItem result
= new CallStackItem();
98 result
.Description
= "<symbol 0x" + Convert
.ToString(address
, 16) + " not found>";
106 public class XboxSymbolResolver
: IDisposable
111 public XboxSymbolResolver(IDiaSession session
, UInt32 size
)
113 this.session
= session
;
117 ~
XboxSymbolResolver()
122 public bool AddressIsInRange(UInt32 address
)
124 return (session
.loadAddress
<= address
) && (address
< session
.loadAddress
+ size
);
127 public CallStackItem
GetSymbolNameFromAddress(UInt32 address
)
129 CallStackItem result
= new CallStackItem();
130 if (AddressIsInRange(address
))
132 IDiaSymbol diaSymbol
;
133 session
.findSymbolByVA(address
, SymTagEnum
.SymTagFunction
, out diaSymbol
);
135 result
.Description
= diaSymbol
.name
+ "()";
137 IDiaEnumLineNumbers lineNumbers
;
138 session
.findLinesByVA(address
, 4, out lineNumbers
);
140 IDiaLineNumber lineNum
;
142 lineNumbers
.Next(1, out lineNum
, out celt
);
146 string baseFilename
= lineNum
.sourceFile
.fileName
.Substring(lineNum
.sourceFile
.fileName
.LastIndexOf('\\') + 1);
147 result
.Source
= baseFilename
;
148 result
.Line
= (int)lineNum
.lineNumber
;
153 result
.Description
= "<address out of range>";
158 #region IDisposable Members
160 public void Dispose()
163 GC
.SuppressFinalize(this);
166 protected virtual void Dispose(bool disposing
)
170 // free the state of any contained objects
171 // we don't contain any other objects!
176 Marshal
.ReleaseComObject(session
);
184 public class Ps3SymbolsManager
: SymbolsManager
189 public Ps3SymbolsManager(string ps3BinPath
, string selfPath
)
191 this.ps3BinPath
= ps3BinPath
;
192 this.selfPath
= selfPath
;
195 protected override List
<CallStackItem
> GetSymbolNamesFromAddressesInternal(List
<UInt32
> addresses
)
197 string arguments
= selfPath
+ " --addr2line=";
198 for (int i
= 0; i
< addresses
.Count
; ++i
)
202 arguments
+= addresses
[i
].ToString();
205 // Start the child process.
206 Process p
= new Process();
207 p
.StartInfo
.UseShellExecute
= false;
208 p
.StartInfo
.CreateNoWindow
= true;
209 p
.StartInfo
.RedirectStandardOutput
= true;
210 p
.StartInfo
.FileName
= ps3BinPath
;
211 p
.StartInfo
.Arguments
= arguments
;
213 string output
= p
.StandardOutput
.ReadToEnd();
216 // output looks something like this:
217 // Address: 0x010C8FF4
218 // Directory: E:/perforce/depot/dev/c3/Code/CryEngine/CryScriptSystem/LuaRemoteDebug
219 // File Name: LuaRemoteDebug.cpp
221 // Symbol: CLuaRemoteDebug::SendLuaState(lua_Debug*)
222 // Address: 0x010CA180
223 // Directory: E:/perforce/depot/dev/c3/Code/CryEngine/CryScriptSystem/LuaRemoteDebug
224 // File Name: LuaRemoteDebug.cpp
226 // Symbol: CLuaRemoteDebug::OnNotificationNetworkReceive(void const*, unsigned int)
229 string[] lines
= output
.Split('\n');
231 List
<CallStackItem
> items
= new List
<CallStackItem
>();
233 CallStackItem item
= new CallStackItem();
234 bool foundAddress
= false;
235 foreach (string line
in lines
)
237 if (line
.StartsWith("Address:"))
239 // The addresses should be returned in the order we requested them
245 item
= new CallStackItem();
247 else if (line
.StartsWith("File Name:"))
249 item
.Source
= line
.Substring(line
.IndexOf(':') + 1).Trim();
251 else if (line
.StartsWith("Line Number:"))
253 int.TryParse(line
.Substring(line
.IndexOf(':') + 1).Trim(), out item
.Line
);
255 else if (line
.StartsWith("Symbol:"))
257 item
.Description
= line
.Substring(line
.IndexOf(':') + 1).Trim();
265 if (items
.Count
!= addresses
.Count
)
267 // Something went wrong! Just return not found symbols
269 foreach (UInt32 address
in addresses
)
271 item
= new CallStackItem();
272 item
.Description
= "<symbol 0x" + Convert
.ToString(address
, 16) + " not found>";