!B (Sandbox) (CE-21795) Importing models with multisubmaterials via fbx switches...
[CRYENGINE.git] / Code / Tools / LuaRemoteDebugger / LuaRemoteDebugger / SymbolsManager.cs
blobee98567dacdfad9fd6ae00e4c4955dc1fd1eb982
1 // Copyright 2001-2019 Crytek GmbH / Crytek Group. All rights reserved.
3 using Dia2Lib;
4 using System;
5 using System.Collections.Generic;
6 using System.Linq;
7 using System.Text;
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];
32 // Return results
33 List<CallStackItem> results = new List<CallStackItem>();
34 foreach (UInt32 address in addresses)
36 results.Add(symbolCache[address]);
38 return results;
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)
50 try
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
68 case 0x806D0005:
69 Console.WriteLine("Couldn't find pdb: " + path);
70 break;
71 case 0x806D0006:
72 Console.WriteLine("Signature invalid for: " + path);
73 break;
74 default:
75 Console.WriteLine("Unknown pdb load error for: " + path + ", errorcode: " + ex.ErrorCode);
76 break;
81 protected override List<CallStackItem> GetSymbolNamesFromAddressesInternal(List<UInt32> addresses)
83 List<CallStackItem> items = new List<CallStackItem>();
84 foreach (UInt32 address in addresses)
86 bool found = false;
87 foreach (XboxSymbolResolver symbolResolver in symbolResolvers)
89 if (symbolResolver.AddressIsInRange(address))
91 found = true;
92 items.Add(symbolResolver.GetSymbolNameFromAddress(address));
95 if (!found)
97 CallStackItem result = new CallStackItem();
98 result.Description = "<symbol 0x" + Convert.ToString(address, 16) + " not found>";
99 items.Add(result);
102 return items;
106 public class XboxSymbolResolver : IDisposable
108 IDiaSession session;
109 UInt32 size;
111 public XboxSymbolResolver(IDiaSession session, UInt32 size)
113 this.session = session;
114 this.size = size;
117 ~XboxSymbolResolver()
119 Dispose(false);
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;
141 uint celt;
142 lineNumbers.Next(1, out lineNum, out celt);
144 if (celt == 1)
146 string baseFilename = lineNum.sourceFile.fileName.Substring(lineNum.sourceFile.fileName.LastIndexOf('\\') + 1);
147 result.Source = baseFilename;
148 result.Line = (int)lineNum.lineNumber;
151 else
153 result.Description = "<address out of range>";
155 return result;
158 #region IDisposable Members
160 public void Dispose()
162 Dispose(true);
163 GC.SuppressFinalize(this);
166 protected virtual void Dispose(bool disposing)
168 if (disposing)
170 // free the state of any contained objects
171 // we don't contain any other objects!
173 // free my own state
174 if (session != null)
176 Marshal.ReleaseComObject(session);
177 session = null;
181 #endregion
184 public class Ps3SymbolsManager : SymbolsManager
186 string ps3BinPath;
187 string selfPath;
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)
200 if (i > 0)
201 arguments += ",";
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;
212 p.Start();
213 string output = p.StandardOutput.ReadToEnd();
214 p.WaitForExit();
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
220 // Line Number: 571
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
225 // Line Number: 315
226 // Symbol: CLuaRemoteDebug::OnNotificationNetworkReceive(void const*, unsigned int)
227 // etc...
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
240 if (foundAddress)
242 items.Add(item);
244 foundAddress = true;
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();
260 if (foundAddress)
262 items.Add(item);
265 if (items.Count != addresses.Count)
267 // Something went wrong! Just return not found symbols
268 items.Clear();
269 foreach (UInt32 address in addresses)
271 item = new CallStackItem();
272 item.Description = "<symbol 0x" + Convert.ToString(address, 16) + " not found>";
273 items.Add(item);
277 return items;