FoxDisassembler.Mod 9.3 KB

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