FoxDisassembler.Mod 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. MODULE FoxDisassembler; (** AUTHOR ""; PURPOSE ""; *)
  2. IMPORT Streams, ObjectFile, Scanner := FoxScanner, Basic := FoxBasic, BitSets, D := Debugging, Files, Commands;
  3. CONST Trace = TRUE;
  4. TYPE
  5. Block*= POINTER TO RECORD (ObjectFile.Section)
  6. to-: LONGINT;
  7. next-: Block;
  8. END;
  9. Disassembler* = OBJECT
  10. VAR
  11. first, block: Block; w: Streams.Writer; stringWriter: Streams.StringWriter; code,data: BitSets.BitSet; codeUnit, dataUnit: LONGINT;
  12. codeDisplacement-, dataDisplacement: LONGINT;
  13. PROCEDURE & Init*(w: Streams.Writer);
  14. BEGIN SELF.w := w; NEW(stringWriter, 256);
  15. codeDisplacement := 0; dataDisplacement := 0;
  16. END Init;
  17. PROCEDURE GetLogFile*(CONST binaryFileName: ARRAY OF CHAR): Files.File;
  18. VAR fileName,extension: Files.FileName;
  19. BEGIN
  20. Files.SplitExtension(binaryFileName, fileName, extension);
  21. Files.JoinExtension(fileName, "log", fileName);
  22. RETURN Files.Old(fileName)
  23. END GetLogFile;
  24. PROCEDURE BlockHeader(block: Block);
  25. VAR name: ObjectFile.SectionName; offset: LONGINT;
  26. BEGIN
  27. Basic.SegmentedNameToString(block.identifier.name, name);
  28. w.String("-------- "); w.Char(Scanner.TAB);
  29. IF ObjectFile.IsCode(block.type) THEN w.String("code");
  30. ELSE w.String("data");
  31. END;
  32. w.Char(Scanner.TAB);
  33. w.String(name);
  34. w.String(" @");
  35. w.Hex(block.alignment,-8); (*w.String("-"); w.Hex(block.to+offset,-8);*)
  36. w.String(" ---");
  37. w.Ln;
  38. END BlockHeader;
  39. PROCEDURE WriteReference*(adr: LONGINT; isCode: BOOLEAN; w: Streams.Writer);
  40. VAR b: Block; name: ObjectFile.SectionName; offset: LONGINT;
  41. BEGIN
  42. w.String(" --> "); w.Hex(adr+codeDisplacement,-8);
  43. b := first; IF b = NIL THEN RETURN END;
  44. IF isCode THEN offset := codeDisplacement ELSE offset := dataDisplacement END;
  45. WHILE (b # NIL) & ((adr < b.alignment-offset) OR (adr > b.to - offset) OR (ObjectFile.IsCode(b.type)#isCode)) DO
  46. b := b.next;
  47. END;
  48. IF (b # NIL) & (b # block) THEN
  49. Basic.SegmentedNameToString(b.identifier.name, name);
  50. w.String(" [");
  51. w.String(name);
  52. IF adr # b.alignment THEN
  53. w.String("+"); w.Int(adr-b.alignment,1)
  54. END;
  55. w.String("]");
  56. END;
  57. END WriteReference;
  58. PROCEDURE DisassembleInstruction*(bitset: BitSets.BitSet; VAR adrInUnits: LONGINT; maxInstructionSize: LONGINT; w: Streams.Writer);
  59. BEGIN
  60. END DisassembleInstruction;
  61. PROCEDURE DisassembleBlock(from, to: LONGINT);
  62. VAR adr, prevadr, max, digit,value: LONGINT; string: ARRAY 256 OF CHAR;
  63. BEGIN
  64. IF code = NIL THEN RETURN END;
  65. adr := from;
  66. max := MIN(to+1, code.GetSize() DIV codeUnit);
  67. WHILE adr < max DO
  68. (* adr *)
  69. w.Hex(adr+codeDisplacement,-8); w.String(": ");
  70. prevadr := adr;
  71. DisassembleInstruction(code, adr, max-adr, stringWriter);
  72. IF prevadr = adr THEN w.String("decoder error: address must increase"); w.Ln; RETURN END;
  73. stringWriter.Update;
  74. stringWriter.Get(string);
  75. (* value *)
  76. WHILE prevadr < adr DO
  77. value := code.GetBits(prevadr*codeUnit, codeUnit);
  78. w.Hex(value,-((codeUnit-1) DIV 4 +1)); w.String(" ");
  79. INC(prevadr);
  80. END;
  81. (* instruction string *)
  82. w.Char(Scanner.TAB); w.String(string); w.Ln;
  83. END;
  84. END DisassembleBlock;
  85. PROCEDURE DataBlock(from, to: LONGINT);
  86. VAR adr,width,max,value: LONGINT;
  87. BEGIN
  88. IF data = NIL THEN RETURN END;
  89. adr := from;
  90. max := MIN(to+1, data.GetSize() DIV dataUnit);
  91. WHILE adr < max DO
  92. w.Hex(adr+dataDisplacement,-8); w.String(": ");
  93. width := 8;
  94. WHILE (adr < max) & (width > 0) DO
  95. value := data.GetBits(adr*dataUnit, dataUnit);
  96. w.Hex(value,-((dataUnit-1) DIV 4 +1)); w.String(" ");
  97. INC(adr); DEC(width);
  98. END;
  99. w.Ln;
  100. END;
  101. END DataBlock;
  102. PROCEDURE ParseLogFile*(file: Files.File): Block;
  103. VAR reader: Files.Reader; newline: BOOLEAN; sectionName: ObjectFile.SectionName; scanner: Scanner.AssemblerScanner;
  104. symbol: Scanner.Symbol; b: BOOLEAN; block: Block; first: Block; last: Block;
  105. PROCEDURE GetNextSymbol;
  106. VAR b: BOOLEAN;
  107. BEGIN b := scanner.GetNextSymbol(symbol)
  108. END GetNextSymbol;
  109. PROCEDURE ExpectToken(token: LONGINT): BOOLEAN;
  110. BEGIN IF symbol.token = token THEN GetNextSymbol; RETURN TRUE ELSE RETURN FALSE END;
  111. END ExpectToken;
  112. PROCEDURE ExpectIdentifier(VAR name: ARRAY OF CHAR): BOOLEAN;
  113. BEGIN
  114. IF (symbol.token = Scanner.Identifier) THEN COPY(symbol.identifierString,name); GetNextSymbol; RETURN TRUE
  115. ELSE RETURN FALSE
  116. END;
  117. END ExpectIdentifier;
  118. PROCEDURE ExpectThisIdentifier(CONST name: ARRAY OF CHAR): BOOLEAN;
  119. BEGIN
  120. IF (symbol.token = Scanner.Identifier) & (symbol.identifierString = name) THEN GetNextSymbol; RETURN TRUE
  121. ELSE RETURN FALSE
  122. END;
  123. END ExpectThisIdentifier;
  124. PROCEDURE ExpectNumber(VAR int: LONGINT):BOOLEAN;
  125. BEGIN
  126. IF (symbol.token = Scanner.Number) THEN
  127. int := SHORT(symbol.hugeint); GetNextSymbol; RETURN TRUE
  128. ELSE RETURN FALSE
  129. END;
  130. END ExpectNumber;
  131. PROCEDURE ParseLine(): Block;
  132. VAR from,to: LONGINT; block: Block; displacement: LONGINT;
  133. BEGIN
  134. block := NIL;
  135. IF ExpectNumber(from) & ExpectToken(Scanner.Colon) THEN
  136. IF ExpectThisIdentifier("code") & ExpectIdentifier(sectionName) & ExpectThisIdentifier("to") & ExpectNumber(to) THEN
  137. NEW(block); block.type := ObjectFile.Code; Basic.ToSegmentedName(sectionName, block.identifier.name); block.alignment := from; block.fixed := TRUE; block.to := to;
  138. ELSIF ExpectThisIdentifier("data") & ExpectIdentifier(sectionName) & ExpectThisIdentifier("to") & ExpectNumber(to) THEN
  139. NEW(block); block.type := ObjectFile.Data; Basic.ToSegmentedName(sectionName, block.identifier.name); block.alignment := from; block.fixed := TRUE; block.to := to;
  140. END;
  141. ELSIF ExpectThisIdentifier("code") & ExpectThisIdentifier("displacement") & ExpectNumber(displacement) THEN
  142. codeDisplacement := displacement; dataDisplacement := displacement
  143. ELSIF ExpectThisIdentifier("data") & ExpectThisIdentifier("displacement") & ExpectNumber(displacement) THEN
  144. dataDisplacement := displacement;
  145. ELSE scanner.SkipToEndOfLine; GetNextSymbol; scanner.ResetError;
  146. END;
  147. IF (block # NIL) & Trace THEN
  148. D.String("found section ");
  149. D.String(sectionName);
  150. IF ObjectFile.IsCode(block.type) THEN D.String(" (code) ") ELSE D.String(" (data) ") END;
  151. D.Int(block.alignment,1); D.String(" "); D.Int(block.to,1);
  152. D.Ln;
  153. END;
  154. RETURN block
  155. END ParseLine;
  156. BEGIN
  157. first := NIL; last := NIL;
  158. IF file = NIL THEN RETURN NIL END;
  159. NEW(reader, file, 0);
  160. scanner := Scanner.NewAssemblerScanner("",reader,0,NIL);
  161. b := scanner.GetNextSymbol(symbol);
  162. REPEAT
  163. block := ParseLine();
  164. IF block # NIL THEN
  165. IF first = NIL THEN first := block; last := block ELSE last.next := block; last := block END;
  166. END;
  167. GetNextSymbol
  168. UNTIL symbol.token = Scanner.EndOfText;
  169. RETURN first;
  170. END ParseLogFile;
  171. PROCEDURE Disassemble*(code, data: BitSets.BitSet; codeUnit, dataUnit: LONGINT; logFile: Files.File; address: ADDRESS);
  172. BEGIN
  173. SELF.code := code;SELF.data := data; SELF.codeUnit := codeUnit; SELF.dataUnit := dataUnit;
  174. first := ParseLogFile(logFile); block := first;
  175. IF block = NIL THEN
  176. w.String("------ code ------"); w.Ln;
  177. DisassembleBlock(0, MAX(LONGINT)-1);
  178. IF code # data THEN
  179. w.String("------ data ------"); w.Ln;
  180. DataBlock(0, MAX(LONGINT)-1);
  181. END;
  182. ELSE
  183. WHILE block # NIL DO
  184. IF (address = 0) OR (block.alignment <= address) & (block.to > address) THEN
  185. BlockHeader(block);
  186. IF ObjectFile.IsCode(block.type) & (code # NIL) THEN
  187. DisassembleBlock(block.alignment-codeDisplacement, block.to-codeDisplacement);
  188. ELSE
  189. DataBlock(block.alignment-dataDisplacement, block.to-dataDisplacement);
  190. END;
  191. END;
  192. block := block.next
  193. END;
  194. END;
  195. END Disassemble;
  196. PROCEDURE SetDisplacements*(code, data: LONGINT);
  197. BEGIN
  198. codeDisplacement := code;
  199. dataDisplacement := data;
  200. END SetDisplacements;
  201. END Disassembler;
  202. PROCEDURE FindPC*(context: Commands.Context);
  203. VAR file: Files.File; logFile: Files.FileName; adr,maxadr: LONGINT; disassembler: Disassembler; block, found: Block; name: ObjectFile.SectionName;
  204. BEGIN
  205. IF context.arg.GetString(logFile) & context.arg.GetInteger(adr, TRUE) THEN
  206. file := Files.Old(logFile);
  207. IF file = NIL THEN Files.JoinExtension(logFile,".log",logFile); file := Files.Old(logFile) END;
  208. IF file = NIL THEN
  209. context.error.String("file not found "); context.error.String(logFile); context.error.Ln
  210. ELSE
  211. NEW(disassembler, context.out);
  212. maxadr := 0;
  213. block := disassembler.ParseLogFile(file);
  214. WHILE (block # NIL ) DO
  215. IF (block.alignment < adr) & (block.alignment > maxadr) & ObjectFile.IsCode(block.type) THEN
  216. found := block;
  217. maxadr := block.alignment
  218. END;
  219. block := block.next
  220. END;
  221. Basic.SegmentedNameToString(found.identifier.name, name);
  222. context.out.String(name); context.out.String(":"); context.out.Int(adr-found.alignment,1); context.out.Ln;
  223. END;
  224. END;
  225. END FindPC;
  226. (*
  227. PROCEDURE Test*(context: Commands.Context);
  228. VAR filename: Files.FileName; name: ObjectFile.SectionName; block: Block;
  229. BEGIN
  230. IF context.arg.GetString(filename) THEN
  231. file := Files.Old(filename);
  232. IF file = NIL THEN (* error *) HALT(100) END;
  233. block := ParseLogFile(filename);
  234. WHILE block # NIL DO
  235. Basic.SegmentedNameToString(block.identifier.name, name);
  236. context.out.String(name); context.out.String(" at "); context.out.Int(block.alignment,1); context.out.Ln;
  237. block := block.next;
  238. END;
  239. END;
  240. END Test;
  241. *)
  242. END FoxDisassembler.
  243. SystemTools.FreeDownTo FoxDisassembler ~
  244. FoxDisassembler.Test ins.log ~