Aucune description
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

BurstDisassembler.cs 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. #if UNITY_EDITOR || BURST_INTERNAL
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. namespace Unity.Burst.Editor
  6. {
  7. /// <summary>
  8. /// Disassembler for Intel and ARM
  9. /// </summary>
  10. internal partial class BurstDisassembler
  11. {
  12. private readonly Dictionary<int, string> _fileName;
  13. private readonly Dictionary<int, string[]> _fileList;
  14. private readonly List<AsmToken> _tokens;
  15. private static readonly StringSlice FileDirective = new StringSlice(".file");
  16. private static readonly StringSlice CVFileDirective = new StringSlice(".cv_file");
  17. private static readonly StringSlice LocDirective = new StringSlice(".loc");
  18. private static readonly StringSlice CVLocDirective = new StringSlice(".cv_loc");
  19. // This is used to aligned instructions and there operands so they look like this
  20. //
  21. // mulps x,x,x
  22. // shufbps x,x,x
  23. //
  24. // instead of
  25. //
  26. // mulps x,x,x
  27. // shufbps x,x,x
  28. //
  29. // Notice if instruction name is longer than this no alignment will be done.
  30. private const int InstructionAlignment = 10;
  31. // Colors used for the tokens
  32. // TODO: Make this configurable via some editor settings?
  33. private const string DarkColorLineDirective = "#FFFF00";
  34. private const string DarkColorDirective = "#CCCCCC";
  35. private const string DarkColorIdentifier = "#d4d4d4";
  36. private const string DarkColorQualifier = "#DCDCAA";
  37. private const string DarkColorInstruction = "#4EC9B0";
  38. private const string DarkColorInstructionSIMD = "#C586C0";
  39. private const string DarkColorRegister = "#d7ba7d";
  40. private const string DarkColorNumber = "#9cdcfe";
  41. private const string DarkColorString = "#ce9178";
  42. private const string DarkColorComment = "#6A9955";
  43. private const string LightColorLineDirective = "#888800";
  44. private const string LightColorDirective = "#444444";
  45. private const string LightColorIdentifier = "#1c1c1c";
  46. private const string LightColorQualifier = "#267f99";
  47. private const string LightColorInstruction = "#0451a5";
  48. private const string LightColorInstructionSIMD = "#0000ff";
  49. private const string LightColorRegister = "#811f3f";
  50. private const string LightColorNumber = "#007ACC";
  51. private const string LightColorString = "#a31515";
  52. private const string LightColorComment = "#008000";
  53. private string ColorLineDirective;
  54. private string ColorDirective;
  55. private string ColorIdentifier;
  56. private string ColorQualifier;
  57. private string ColorInstruction;
  58. private string ColorInstructionSIMD;
  59. private string ColorRegister;
  60. private string ColorNumber;
  61. private string ColorString;
  62. private string ColorComment;
  63. public BurstDisassembler()
  64. {
  65. _fileName= new Dictionary<int, string>();
  66. _fileList=new Dictionary<int, string[]>();
  67. _tokens = new List<AsmToken>();
  68. }
  69. public enum AsmKind
  70. {
  71. Intel,
  72. ARM,
  73. Wasm,
  74. LLVMIR
  75. }
  76. public string Process(string input, AsmKind asmKind, bool useDarkSkin = true, bool useSyntaxColouring = true)
  77. {
  78. UseSkin(useDarkSkin);
  79. #if BURST_INTERNAL
  80. return ProcessImpl(input, asmKind, useSyntaxColouring);
  81. #else
  82. try
  83. {
  84. return ProcessImpl(input, asmKind, useSyntaxColouring);
  85. }
  86. catch (Exception ex)
  87. {
  88. UnityEngine.Debug.Log($"Error while trying to disassemble the input: {ex}");
  89. }
  90. // in case of an error, return the input as-is at least
  91. return input;
  92. #endif
  93. }
  94. private void UseSkin(bool useDarkSkin)
  95. {
  96. if (useDarkSkin)
  97. {
  98. ColorLineDirective = DarkColorLineDirective;
  99. ColorDirective = DarkColorDirective;
  100. ColorIdentifier = DarkColorIdentifier;
  101. ColorQualifier = DarkColorQualifier;
  102. ColorInstruction = DarkColorInstruction;
  103. ColorInstructionSIMD = DarkColorInstructionSIMD;
  104. ColorRegister = DarkColorRegister;
  105. ColorNumber = DarkColorNumber;
  106. ColorString = DarkColorString;
  107. ColorComment = DarkColorComment;
  108. }
  109. else
  110. {
  111. ColorLineDirective = LightColorLineDirective;
  112. ColorDirective = LightColorDirective;
  113. ColorIdentifier = LightColorIdentifier;
  114. ColorQualifier = LightColorQualifier;
  115. ColorInstruction = LightColorInstruction;
  116. ColorInstructionSIMD = LightColorInstructionSIMD;
  117. ColorRegister = LightColorRegister;
  118. ColorNumber = LightColorNumber;
  119. ColorString = LightColorString;
  120. ColorComment = LightColorComment;
  121. }
  122. }
  123. private void AlignInstruction(StringBuilder output, int instructionLength, AsmKind asmKind)
  124. {
  125. // Only support Intel for now
  126. if (instructionLength >= InstructionAlignment || asmKind != AsmKind.Intel)
  127. return;
  128. output.Append(' ', InstructionAlignment - instructionLength);
  129. }
  130. private string ProcessImpl(string input, AsmKind asmKind, bool colourize = true)
  131. {
  132. _fileList.Clear();
  133. _fileName.Clear();
  134. _tokens.Clear();
  135. AsmTokenKindProvider asmTokenProvider = default;
  136. switch (asmKind)
  137. {
  138. case AsmKind.Intel:
  139. asmTokenProvider = (AsmTokenKindProvider)X86AsmTokenKindProvider.Instance;
  140. break;
  141. case AsmKind.ARM:
  142. asmTokenProvider = (AsmTokenKindProvider)ARM64AsmTokenKindProvider.Instance;
  143. break;
  144. case AsmKind.Wasm:
  145. asmTokenProvider = (AsmTokenKindProvider)WasmAsmTokenKindProvider.Instance;
  146. break;
  147. case AsmKind.LLVMIR:
  148. asmTokenProvider = (AsmTokenKindProvider)LLVMIRAsmTokenKindProvider.Instance;
  149. break;
  150. }
  151. var tokenizer = new AsmTokenizer(input, asmKind, asmTokenProvider);
  152. // Adjust token size
  153. var pseudoTokenSizeMax = input.Length / 7;
  154. if (pseudoTokenSizeMax > _tokens.Capacity)
  155. {
  156. _tokens.Capacity = pseudoTokenSizeMax;
  157. }
  158. // Read all tokens
  159. while (tokenizer.TryGetNextToken(out var nextToken))
  160. {
  161. _tokens.Add(nextToken);
  162. }
  163. // Process all tokens
  164. var output = new StringBuilder();
  165. for (int i = 0; i < _tokens.Count; i++)
  166. {
  167. var token = _tokens[i];
  168. var slice = token.Slice(input);
  169. if (token.Kind == AsmTokenKind.Directive && i + 1 < _tokens.Count)
  170. {
  171. if (slice == FileDirective || slice == CVFileDirective)
  172. {
  173. // File is followed by an index and a string or just a string with an implied index = 0
  174. i++;
  175. int index = 0;
  176. SkipSpaces(_tokens, ref i);
  177. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
  178. {
  179. var numberAsStr = _tokens[i].ToString(input);
  180. index = int.Parse(numberAsStr);
  181. i++;
  182. }
  183. SkipSpaces(_tokens, ref i);
  184. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.String)
  185. {
  186. var filename = _tokens[i].ToString(input).Trim('"');
  187. string[] fileLines;
  188. try
  189. {
  190. fileLines = System.IO.File.ReadAllLines(filename);
  191. }
  192. catch
  193. {
  194. fileLines = null;
  195. }
  196. _fileName.Add(index, filename);
  197. _fileList.Add(index, fileLines);
  198. }
  199. continue;
  200. }
  201. if (slice == LocDirective || slice == CVLocDirective)
  202. {
  203. // .loc {fileno} {lineno} [column] [options] -
  204. // .cv_loc funcid fileno lineno [column]
  205. int fileno = 0;
  206. int colno = 0;
  207. int lineno = 0; // NB 0 indicates no information given
  208. i++;
  209. SkipSpaces(_tokens, ref i);
  210. if (slice == CVLocDirective)
  211. {
  212. // silently consume function id
  213. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
  214. {
  215. i++;
  216. }
  217. SkipSpaces(_tokens, ref i);
  218. }
  219. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
  220. {
  221. var numberAsStr = _tokens[i].ToString(input);
  222. fileno = int.Parse(numberAsStr);
  223. i++;
  224. }
  225. SkipSpaces(_tokens, ref i);
  226. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
  227. {
  228. var numberAsStr = _tokens[i].ToString(input);
  229. lineno = int.Parse(numberAsStr);
  230. i++;
  231. }
  232. SkipSpaces(_tokens, ref i);
  233. if (i < _tokens.Count && _tokens[i].Kind == AsmTokenKind.Number)
  234. {
  235. var numberAsStr = _tokens[i].ToString(input);
  236. colno = int.Parse(numberAsStr);
  237. i++;
  238. }
  239. // Skip until end of line
  240. for (; i < _tokens.Count; i++)
  241. {
  242. var tokenToSkip = _tokens[i];
  243. if (tokenToSkip.Kind == AsmTokenKind.NewLine)
  244. {
  245. break;
  246. }
  247. }
  248. // If the file number is 0, skip the line
  249. if (fileno == 0)
  250. {
  251. }
  252. // If the line number is 0, then we can update the file tracking, but still not output a line
  253. else if (lineno == 0)
  254. {
  255. if (colourize) output.Append("<color=").Append(ColorLineDirective).Append(">");
  256. output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno]));
  257. if (colourize) output.Append("</color>");
  258. output.Append("\n");
  259. }
  260. // We have a source line and number -- can we load file and extract this line?
  261. else
  262. {
  263. if (_fileList.ContainsKey(fileno) && _fileList[fileno] != null && lineno - 1 < _fileList[fileno].Length)
  264. {
  265. if (colourize) output.Append("<color=").Append(ColorLineDirective).Append(">");
  266. output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno])).Append("(").Append(lineno).Append(", ").Append(colno + 1).Append(")").Append(_fileList[fileno][lineno - 1]);
  267. if (colourize) output.Append("</color>");
  268. output.Append("\n");
  269. }
  270. else
  271. {
  272. if (colourize) output.Append("<color=").Append(ColorLineDirective).Append($">");
  273. output.Append("=== ").Append(System.IO.Path.GetFileName(_fileName[fileno])).Append("(").Append(lineno).Append(", ").Append(colno + 1).Append(")");
  274. if (colourize) output.Append("</color>");
  275. output.Append("\n");
  276. }
  277. }
  278. continue;
  279. }
  280. }
  281. if (colourize)
  282. {
  283. switch (token.Kind)
  284. {
  285. case AsmTokenKind.Directive:
  286. output.Append("<color=").Append(ColorDirective).Append(">");
  287. output.Append(input, slice.Position, slice.Length);
  288. output.Append("</color>");
  289. break;
  290. case AsmTokenKind.Identifier:
  291. output.Append("<color=").Append(ColorIdentifier).Append(">");
  292. output.Append(input, slice.Position, slice.Length);
  293. output.Append("</color>");
  294. break;
  295. case AsmTokenKind.Qualifier:
  296. output.Append("<color=").Append(ColorQualifier).Append(">");
  297. output.Append(input, slice.Position, slice.Length);
  298. output.Append("</color>");
  299. break;
  300. case AsmTokenKind.Instruction:
  301. output.Append("<color=").Append(ColorInstruction).Append(">");
  302. output.Append(input, slice.Position, slice.Length);
  303. output.Append("</color>");
  304. AlignInstruction(output, slice.Length, asmKind);
  305. break;
  306. case AsmTokenKind.InstructionSIMD:
  307. output.Append("<color=").Append(ColorInstructionSIMD).Append(">");
  308. output.Append(input, slice.Position, slice.Length);
  309. output.Append("</color>");
  310. AlignInstruction(output, slice.Length, asmKind);
  311. break;
  312. case AsmTokenKind.Register:
  313. output.Append("<color=").Append(ColorRegister).Append(">");
  314. output.Append(input, slice.Position, slice.Length);
  315. output.Append("</color>");
  316. break;
  317. case AsmTokenKind.Number:
  318. output.Append("<color=").Append(ColorNumber).Append(">");
  319. output.Append(input, slice.Position, slice.Length);
  320. output.Append("</color>");
  321. break;
  322. case AsmTokenKind.String:
  323. output.Append("<color=").Append(ColorString).Append(">");
  324. output.Append(input, slice.Position, slice.Length);
  325. output.Append("</color>");
  326. break;
  327. case AsmTokenKind.Comment:
  328. output.Append("<color=").Append(ColorComment).Append(">");
  329. output.Append(input, slice.Position, slice.Length);
  330. output.Append("</color>");
  331. break;
  332. default:
  333. output.Append(input, slice.Position, slice.Length);
  334. break;
  335. }
  336. }
  337. else
  338. {
  339. output.Append(input, slice.Position, slice.Length);
  340. }
  341. }
  342. return output.ToString();
  343. }
  344. private static void SkipSpaces(List<AsmToken> tokens, ref int i)
  345. {
  346. for(; i < tokens.Count; i++)
  347. {
  348. var kind = tokens[i].Kind;
  349. if (kind != AsmTokenKind.Misc)
  350. {
  351. return;
  352. }
  353. }
  354. }
  355. }
  356. }
  357. #endif