appB 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. .\" A simple tutorial
  2. .\"
  3. .\" $Id$
  4. .\"
  5. .bp
  6. .DS
  7. APPENDIX B
  8. .DE
  9. .SH
  10. How to use the interpreter
  11. .PP
  12. The interpreter is not normally used for the debugging of programs under
  13. construction. Its primary application is as a verification tool for almost
  14. completed programs. Although the proper operation of the interpreter is
  15. obviously a black art, this chapter tries to provide some guidelines.
  16. .LP
  17. For the sake of the argument, the source language is assumed to be C, but most
  18. hints apply equally well to other languages supported by ACK.
  19. .sp
  20. .LP
  21. .I "Initial measures"
  22. .PP
  23. Start with a test case of trivial size; to be on the safe side, reckon with a
  24. time dilatation factor of about 500, i.e., a second grows into 10 minutes.
  25. (The interpreter takes 0.5 msec to do one EM instruction on a Sun 3/50).
  26. Fortunately many trivial test cases are much shorter than one second.
  27. .PP
  28. Compile the program into an \fIe.out\fP, the EM machine version of a
  29. \fIa.out\fP, by calling \fIem22\fP (for 2-byte integers and 2-byte pointers),
  30. \fIem24\fP (for 2 and 4) or \fIem44\fP (for 4 and 4) as seems appropriate;
  31. if in doubt, use \fIem44\fP. These compilers can be found in the ACK
  32. \fIbin\fP directory, and should be used instead of \fIacc\fP (or normal
  33. .UX
  34. \fIcc\fP). Alternatively, \fIacc \-memNN\fP can be used instead of
  35. \fIemNN\fP.
  36. .LP
  37. If a C program consists of more than one file, as it usually does, there is
  38. a small problem. The \fIacc\fP and \fIcc\fP compilers generate .o files,
  39. whereas the \fIemNN\fP compilers generate .m files as object files.
  40. A simple technique to avoid the problem is to call
  41. .DS
  42. em44 *.c
  43. .DE
  44. if possible. If not, the following hack on the \fIMakefile\fP generally works.
  45. .IP \-
  46. Make sure the \fIMakefile\fP is reasonably clean and complete: all calls to
  47. the compiler are through \fI$(CC)\fP, \fICFLAGS\fP is used properly and all
  48. dependencies are specified.
  49. .IP \-
  50. Add the following lines to the \fIMakefile\fP (possibly permanently):
  51. .DS
  52. \&.SUFFIXES: .o
  53. \&.c.o:
  54. \& $(CC) \-c $(CFLAGS) $<
  55. .DE
  56. .IP \-
  57. Set CC to \fIem44 \-.c\fP (for example). Make sure CFLAGS includes
  58. the \-O option; this yields a speed-up of about 15 %.
  59. .IP \-
  60. Change all .o to .m (or .k if the \-O option is not used).
  61. .IP \-
  62. If necessary, change \fIa.out\fP to \fIe.out\fP.
  63. .PP
  64. With these changes, \fImake\fP will produce an EM object;
  65. \fIesize\fP can be used to verify that it is indeed an EM object and obtain some
  66. statistics. Then call the interpreter:
  67. .DS
  68. int <EM-object-file> [ parameters ]
  69. .DE
  70. where the parameters are the normal parameters of the program. This should
  71. work exactly like the original program, though slower. It reads from the
  72. terminal if the original does, it opens and closes files like the original and
  73. it accepts interrupts.
  74. .sp
  75. .LP
  76. .I "Interpreting the results"
  77. .PP
  78. Now there are several possibilities.
  79. .PP
  80. It does all this. Great! This means the program
  81. does not do very uncouth things. Now
  82. read the file \fIint.mess\fP to see if any messages were generated. If there
  83. are none, the program did not really run (perhaps the original cc \fIa.out\fP
  84. got called instead?) Normally there is at least a termination message like
  85. .DS
  86. (Message): program exits with status 0 at "awa.p", line 64, INR = 4124
  87. .DE
  88. This says that the program terminated through an exit(0) on line 64 of the
  89. file \fIawa.p\fP after 4124 EM instructions.
  90. If this is the only message it is time to move to a bigger test case.
  91. .PP
  92. On the other hand, the program may come to a grinding halt with an error
  93. message.
  94. All messages (errors and warnings) have a format in which the sequence
  95. .DS
  96. "<file name>", line <ln#>
  97. .DE
  98. occurs, which is the same sequence many compilers produce for their error
  99. messages. Consequently, the \fIint.mess\fP file can be processed as any
  100. compiler message output.
  101. .PP
  102. One such message can be
  103. .DS
  104. (Fatal error) a.em: trap "Addressing non existent memory" not caught at "a.c", line 2, INR = 16
  105. .DE
  106. produced by the abysmal program
  107. .DS
  108. main() {
  109. *(int*)200000 = 1;
  110. }
  111. .DE
  112. .LP
  113. Often the effects are more subtle, however. The program
  114. .DS
  115. main() {
  116. int *a, b = 777;
  117. b = *a;
  118. }
  119. .DE
  120. produces the following five warnings (in far less than a second):
  121. .DS
  122. (Warning 47, #1): Local data pointer expected at "t.c", line 4, INR = 17
  123. (Warning 61, cont.): Actual memory is undefined at "t.c", line 4, INR = 17
  124. (Warning 102, #1): Returned function result too small at "<unknown>", line 0, INR = 21
  125. (Warning 43, #1): Local integer expected at "exit.c", line 11, INR = 34
  126. (Warning 61, cont.): Actual memory is undefined at "exit.c", line 11, INR = 34
  127. .DE
  128. The one about the function result looks the most frightening,
  129. but is the most easily solved:
  130. \fImain\fP is a function returning an int, so the start-up routine expects a
  131. (four-byte) integer but gets an empty (zero-byte) return area.
  132. .LP
  133. \fINote\fP: The experts are divided about this. The traditional school holds
  134. that \fImain\fP is an int function and its result is the return code; this
  135. leaves them with two ways of supplying a return code: one as the parameter
  136. of \fIexit()\fP and one as the result
  137. of \fImain\fP. The modern school (Berkeley 4.2 etc.) claims that
  138. return codes are supplied exclusively
  139. by \fIexit()\fP, and they have an \fIexit(0)\fP in
  140. the start-up routine, just after the call to \fImain()\fP; leaving \fImain()\fP
  141. through the bottom implies successful termination.
  142. .LP
  143. We shall satisfy both groups by
  144. .DS
  145. main() {
  146. int *a, b = 777;
  147. b = *a;
  148. exit(0);
  149. }
  150. .DE
  151. This results in
  152. .DS
  153. (Warning 47, #1): Local data pointer expected at "t.c", line 4, INR = 17
  154. (Warning 61, cont.): Actual memory is undefined at "t.c", line 4, INR = 17
  155. (Message): program exits with status 0 at "exit.c", line 11, INR = 33
  156. .DE
  157. which is pretty clear as it stands.
  158. .sp
  159. .LP
  160. .I "Using stack dumps"
  161. .PP
  162. Let's, for the sake of argument
  163. and to avoid the fierce realism of 10000-line programs, assume that the above
  164. still does not give enough information.
  165. Since the error occurred in EM instruction number 17, we should like to see
  166. more information around that moment. Call the interpreter again, now with the
  167. shell variable AT set at 17:
  168. .DS
  169. int AT=17 t.em
  170. .DE
  171. (The interpreter has a number of internal variables that can be set by
  172. assignments on the command line, like with \fImake\fP.)
  173. This gives a file called \fIint.log\fP containing the
  174. stack dump of 150 lines presented at the end of this chapter.
  175. .PP
  176. Since dumping is a subfacility of logging in the interpreter, the formats of
  177. the lines are
  178. the same. If a line starts with an @, it will contain a file-name/line-number
  179. indication; the next two characters are the subject and the log
  180. level. Then comes the information, preceded by a space. The text contains
  181. three stack dumps, one before the offending instruction, one at it, and one
  182. after it; then the interpreter stops. All kinds of other dumps can be
  183. obtained, but this is default.
  184. .PP
  185. For each instruction we have, in order:
  186. .IP \-
  187. an @x9 line, giving the position in the program,
  188. .IP \-
  189. the messages, warnings and errors from the instruction as it is being executed,
  190. .IP \-
  191. dump(s), as requested.
  192. .PP
  193. The first two lines mean that at line 4 in file \fIt.c\fP the interpreter
  194. performed its 16-th instruction, with the Program Counter at 30 pointing at
  195. opcode 180 in the text segment; the instruction was an LOL (LOad Local)
  196. with the operand \-4 derived from the opcode. It copies the local at offset
  197. \-4 to the top of the stack. The effect can be seen from the subsequent stack
  198. dump, where the undefined word at addresses 2147483568 to ...571 (the variable
  199. \fIa\fP) has been copied to the top of the stack at 2147483560 (copying
  200. undefined values does not generate a warning).
  201. Since we used the \fIem44\fP compiler, all pointers and ints in our dump are
  202. 4 bytes long.
  203. So a variable at address X in reality extends from address X to X+3.
  204. .br
  205. Note that this is not the offending instruction; this stack dump represents
  206. the situation just before the error.
  207. .PP
  208. The stack consists of a sequence of frames, each containing data followed by
  209. a Return Status Block resulting from a call; the last frame ends in
  210. top-of-stack. The first frame represents the stack when the program starts,
  211. through a call to the start-up routine. This routine prepares the second
  212. stack frame with the actual parameters to \fImain()\fP:
  213. \fIargc\fP at 2147483596, \fIargv\fP at 2147483600 and \fIenviron\fP at
  214. 2147483604.
  215. .LP
  216. The RSB line shows that the call to \fImain()\fP was made from procedure 0
  217. which has 0 locals, with PC at
  218. 16, an LB of 2147483608 and file name and line number still unknown.
  219. The \fIcode\fP in the RSB tells how this RSB was made; possible values are STP
  220. (start-up), CAL, RTT (returnable trap) and NRT (non-returnable trap).
  221. .PP
  222. The next frame shows the local variable(s) of \fImain()\fP; there are two of
  223. them, the pointer \fIa\fP at 2147483568, which is undefined, and variable
  224. \fIb\fP at 2147483564, which has the value 777. Then comes a copy of \fIa\fP,
  225. just made by the LOL instruction, at 2147483560. The following line shows that
  226. the Function Return Area (which does not reside at the end of the stack, but
  227. just happens to be printed here) has size 0 and is presently undefined.
  228. The stack dump ends
  229. by showing that the Actuals Base is at 2147483596 (pointing at \fIargc\fP), the
  230. Locals Base at 2147483572 (pointing just above the local \fIa\fP), the Stack
  231. Pointer at 2147483560 (pointing at the undefined pointer), the line count is 4
  232. and the file name is "t.c".
  233. .LP
  234. (Notice that there is one more stack frame than one would probably expect, the
  235. one above the start-up routine.)
  236. .LP
  237. The Function Return Area
  238. could have a size larger than 0 and still be undefined, for
  239. example when an instruction that does not preserve the contents of the FRA has
  240. just been executed; likewise the FRA could have size 0 and be defined
  241. nevertheless, for example just after a RET 0 instruction.
  242. .PP
  243. All this has set the scene for the distaster which is about to strike in the
  244. next instruction. This is indeed a LOI (LOad Indirect) of size 4, opcode 169;
  245. it causes the message
  246. .DS
  247. warning: Local data pointer expected [stack.c: 242]
  248. .DE
  249. and its continuation
  250. .DS
  251. warning cont.: Actual memory is undefined
  252. .DE
  253. (detected in the interpreter file \fIstack.c\fP at line 242; this can be
  254. useful for sorting out dubious semantics). We see that the effect, as shown in
  255. the third frame of this stack dump (at instruction number 17) is somewhat
  256. unexpected: the LOI has fetched the value 4 and stacked it. The reason is
  257. that, unfortunately, undefinedness is not transitive in the interpreter. When
  258. an undefined value is used in an operation (other than copying) a warning is
  259. given, but thereafter the value is treated as if it were zero. So, after the
  260. warning a normal null pointer remains, which is then used to pick up the value
  261. at location 0. This is the place where the EM machine stores its current line
  262. number, which is presently 4.
  263. .PP
  264. The third stack dump shows the final effect: the value 4 has been unstacked
  265. and copied to variable \fIb\fP at 2147483564 through an STL (STore Local)
  266. instruction.
  267. .PP
  268. Since this form of logging dumps the stack only, the log file is relatively
  269. small as dumps go.
  270. Nevertheless, a useful excerpt can be obtained with the command
  271. .DS
  272. grep 'd1' int.log
  273. .DE
  274. This extracts the Return Status Block lines from the log, thus producing three
  275. traces of calls, one for each instruction in the log:
  276. .DS
  277. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  278. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  279. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483560, HP = 848, LIN = 4, FIL = "t.c"
  280. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  281. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  282. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483560, HP = 848, LIN = 4, FIL = "t.c"
  283. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  284. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  285. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483564, HP = 848, LIN = 4, FIL = "t.c"
  286. .DE
  287. Theoretically, the pertinent trace is the middle one, but in practice all three
  288. are equal. In the present case there isn't much to trace, but in real programs
  289. the trace can be useful.
  290. .sp
  291. .LP
  292. .I "Errors in libraries"
  293. .PP
  294. Since libraries are generally compiled with suppression of line number and
  295. file name information, the line number and file name in the interpreter will
  296. not be updated when it enters a library routine. Consequently, all messages
  297. generated by interpreting library routines will seem to originate from the
  298. line of the call. This is especially true for the routine malloc(), which,
  299. from the nature of its business, often contains dubitable code.
  300. .PP
  301. A usual message is:
  302. .DS
  303. (Warning 43, #1): Local integer expected at "buff.c", line 18, INR = 266
  304. (Warning 64, cont.): Actual memory contains a data pointer at "buff.c", line 18, INR = 266
  305. .DE
  306. and indeed at line 18 of the file buff.c we find:
  307. .DS
  308. buff = malloc(buff_size = BFSIZE);
  309. .DE
  310. This problem can be avoided by using a specially compiled version of the
  311. library that contains the correct LIN and FIL instructions, or, less
  312. elegantly, by including the source code of the library routines in the
  313. program; in the latter case, one has to be sure to have them all.
  314. .sp
  315. .LP
  316. .I "Unavoidable messages"
  317. .br
  318. Some messages produced by the logging are almost unavoidable; sometimes the
  319. writer of a library routine is forced to take liberties with the semantics of
  320. EM.
  321. .LP
  322. Examples from C include the memory allocation routines.
  323. For efficiency reasons, one bit of an pointer in the administration is used as
  324. a flag; setting, clearing and reading this bit requires bitwise operations on
  325. pointers, which gives the above messages.
  326. Realloc causes a problem in that it may have to copy the originally allocated
  327. area to a different place; this area may contain uninitialised bytes.
  328. .bp
  329. .DS
  330. .ft CW
  331. @x9 "t.c", line 4, INR = 16, PC = 30 OPCODE = 180
  332. @L6 "t.c", line 4, INR = 16, DoLOLm(-4)
  333. d2
  334. d2 . . STACK_DUMP[4/4] . . INR = 16 . . STACK_DUMP . .
  335. d2 ----------------------------------------------------------------
  336. d2 ADDRESS BYTE ITEM VALUE SHADOW
  337. d2 2147483643 0 (Dp)
  338. d2 2147483642 0 (Dp)
  339. d2 2147483641 0 (Dp)
  340. d2 2147483640 40 [ 40] (Dp)
  341. d2 2147483639 0 (Dp)
  342. d2 2147483638 0 (Dp)
  343. d2 2147483637 3 (Dp)
  344. d2 2147483636 64 [ 832] (Dp)
  345. d2 2147483635 0 (In)
  346. d2 2147483634 0 (In)
  347. d2 2147483633 0 (In)
  348. d2 2147483632 1 [ 1] (In)
  349. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  350. d2
  351. d2 ADDRESS BYTE ITEM VALUE SHADOW
  352. d2 2147483607 0 (Dp)
  353. d2 2147483606 0 (Dp)
  354. d2 2147483605 0 (Dp)
  355. d2 2147483604 40 [ 40] (Dp)
  356. d2 2147483603 0 (Dp)
  357. d2 2147483602 0 (Dp)
  358. d2 2147483601 3 (Dp)
  359. d2 2147483600 64 [ 832] (Dp)
  360. d2 2147483599 0 (In)
  361. d2 2147483598 0 (In)
  362. d2 2147483597 0 (In)
  363. d2 2147483596 1 [ 1] (In)
  364. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  365. d2
  366. d2 ADDRESS BYTE ITEM VALUE SHADOW
  367. d2 2147483571 undef
  368. d2 | | | | | |
  369. d2 2147483568 undef (1 word)
  370. d2 2147483567 0 (In)
  371. d2 2147483566 0 (In)
  372. d2 2147483565 3 (In)
  373. d2 2147483564 9 [ 777] (In)
  374. d2 2147483563 undef
  375. d2 | | | | | |
  376. d2 2147483560 undef (1 word)
  377. d2 FRA: size = 0, undefined
  378. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483560, HP = 848, \e
  379. LIN = 4, FIL = "t.c"
  380. d2 ----------------------------------------------------------------
  381. d2
  382. @x9 "t.c", line 4, INR = 17, PC = 31 OPCODE = 169
  383. @w1 "t.c", line 4, INR = 17, warning: Local data pointer expected [stack.c: 242]
  384. @w1 "t.c", line 4, INR = 17, warning cont.: Actual memory is undefined
  385. @L6 "t.c", line 4, INR = 17, DoLOIm(4)
  386. d2
  387. d2 . . STACK_DUMP[4/4] . . INR = 17 . . STACK_DUMP . .
  388. d2 ----------------------------------------------------------------
  389. d2 ADDRESS BYTE ITEM VALUE SHADOW
  390. d2 2147483643 0 (Dp)
  391. d2 2147483642 0 (Dp)
  392. d2 2147483641 0 (Dp)
  393. d2 2147483640 40 [ 40] (Dp)
  394. d2 2147483639 0 (Dp)
  395. d2 2147483638 0 (Dp)
  396. d2 2147483637 3 (Dp)
  397. d2 2147483636 64 [ 832] (Dp)
  398. d2 2147483635 0 (In)
  399. d2 2147483634 0 (In)
  400. d2 2147483633 0 (In)
  401. d2 2147483632 1 [ 1] (In)
  402. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  403. d2
  404. d2 ADDRESS BYTE ITEM VALUE SHADOW
  405. d2 2147483607 0 (Dp)
  406. d2 2147483606 0 (Dp)
  407. d2 2147483605 0 (Dp)
  408. d2 2147483604 40 [ 40] (Dp)
  409. d2 2147483603 0 (Dp)
  410. d2 2147483602 0 (Dp)
  411. d2 2147483601 3 (Dp)
  412. d2 2147483600 64 [ 832] (Dp)
  413. d2 2147483599 0 (In)
  414. d2 2147483598 0 (In)
  415. d2 2147483597 0 (In)
  416. d2 2147483596 1 [ 1] (In)
  417. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  418. d2
  419. d2 ADDRESS BYTE ITEM VALUE SHADOW
  420. d2 2147483571 undef
  421. d2 | | | | | |
  422. d2 2147483568 undef (1 word)
  423. d2 2147483567 0 (In)
  424. d2 2147483566 0 (In)
  425. d2 2147483565 3 (In)
  426. d2 2147483564 9 [ 777] (In)
  427. d2 2147483563 0 (In)
  428. d2 2147483562 0 (In)
  429. d2 2147483561 0 (In)
  430. d2 2147483560 4 [ 4] (In)
  431. d2 FRA: size = 0, undefined
  432. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483560, HP = 848, \e
  433. LIN = 4, FIL = "t.c"
  434. d2 ----------------------------------------------------------------
  435. d2
  436. @x9 "t.c", line 4, INR = 18, PC = 32 OPCODE = 229
  437. @S6 "t.c", line 4, INR = 18, DoSTLm(-8)
  438. d2
  439. d2 . . STACK_DUMP[4/4] . . INR = 18 . . STACK_DUMP . .
  440. d2 ----------------------------------------------------------------
  441. d2 ADDRESS BYTE ITEM VALUE SHADOW
  442. d2 2147483643 0 (Dp)
  443. d2 2147483642 0 (Dp)
  444. d2 2147483641 0 (Dp)
  445. d2 2147483640 40 [ 40] (Dp)
  446. d2 2147483639 0 (Dp)
  447. d2 2147483638 0 (Dp)
  448. d2 2147483637 3 (Dp)
  449. d2 2147483636 64 [ 832] (Dp)
  450. d2 2147483635 0 (In)
  451. d2 2147483634 0 (In)
  452. d2 2147483633 0 (In)
  453. d2 2147483632 1 [ 1] (In)
  454. d1 >> RSB: code = STP, PI = uninit, PC = 0, LB = 2147483644, LIN = 0, FIL = NULL
  455. d2
  456. d2 ADDRESS BYTE ITEM VALUE SHADOW
  457. d2 2147483607 0 (Dp)
  458. d2 2147483606 0 (Dp)
  459. d2 2147483605 0 (Dp)
  460. d2 2147483604 40 [ 40] (Dp)
  461. d2 2147483603 0 (Dp)
  462. d2 2147483602 0 (Dp)
  463. d2 2147483601 3 (Dp)
  464. d2 2147483600 64 [ 832] (Dp)
  465. d2 2147483599 0 (In)
  466. d2 2147483598 0 (In)
  467. d2 2147483597 0 (In)
  468. d2 2147483596 1 [ 1] (In)
  469. d1 >> RSB: code = CAL, PI = (0,0), PC = 16, LB = 2147483608, LIN = 0, FIL = NULL
  470. d2
  471. d2 ADDRESS BYTE ITEM VALUE SHADOW
  472. d2 2147483571 undef
  473. d2 | | | | | |
  474. d2 2147483568 undef (1 word)
  475. d2 2147483567 0 (In)
  476. d2 2147483566 0 (In)
  477. d2 2147483565 0 (In)
  478. d2 2147483564 4 [ 4] (In)
  479. d2 FRA: size = 0, undefined
  480. d1 >> AB = 2147483596, LB = 2147483572, SP = 2147483564, HP = 848, \e
  481. LIN = 4, FIL = "t.c"
  482. d2 ----------------------------------------------------------------
  483. d2
  484. .DE