.\" Logging .\" .\" $Header$ .bp .NH THE LOGGING MACHINE. .PP Since messages and warnings provided by \fBint\fP include source code file names and line numbers, they alone often suffice to identify the error. If, however, the necessity arises, much more extensive debugging information can be obtained by activating the the Logging Machine. This Logging Machine, which monitors all actions of the EM machine, is the subject of this chapter. .NH 2 Implementation. .PP When inspecting the source code of \fBint\fP, many lines in the following format will show up: .DS LOG(("@<\fIletter\fP><\fIdigit\fP> message", args)); .DE or .DS LOG(("\ <\fIletter\fP><\fIdigit\fP> message", args)); .DE The double parentheses are needed, because \fILOG()\fP is declared as a define, and has a printf-like argument structure. .PP The <\fIletter\fP> classifies the log message and corresponds to an entry in the \fIlogmask\fP, which holds a threshold for each class of messages. The following classes exist: .TS tab(@); l l l. \(bu A\-Z@the flow of instructions: @A: array @B: branch @C: convert @F: floating point arithmetic @I: integer arithmetic @L: load @M: miscellaneous @P: procedure call @R: pointer arithmetic @S: store @T: compare @U: unsigned arithmetic @X: logical @Y: sets @Z: increment/decrement/zero \(bu d@stack dumping. \(bu g@gda & heap manipulation. \(bu s@stack manipulation. \(bu r@reading the loadfile. \(bu q@floating point calculations during reading the loadfile. \(bu x@the instruction count, contents and file position. \(bu m@monitor calls. \(bu p@procedure calls and returns. \(bu t@traps. \(bu w@warnings. .TE .LP When the interpreter reaches a LOG(()) statement it scans its first argument; if \fIletter\fP occurs in the logmask, and if \fIdigit\fP is lower or equal to the threshold in the logmask, the message is given. Depending on the first character, the message will be preceded by a position indication (with the @) or will be printed as is (with the space). The \fIletter\fP is determines the message class and the \fIdigit\fP is used to distinguish various levels of logging, with a lower digit indicating a more important message. We will call the <\fIletter\fP><\fIdigit\fP> combination the \fBid\fP of the logging. .LP In general, the lower the \fIdigit\fP following the \fIletter\fP, the more important the message. E.g. m5 reports about unsuccessful monitor calls only, m9 also reports about successful monitors (which are obviously less interesting). New logging messages can be added to the source code on places you think relevant. .LP Reasonable settings for the logmask are: .TS tab(@); l l l. @A\-Z9d4twx9@advised setting when trouble shooting (default). @A\-Zx9@shows the flow of instructions & global information. @pm9@shows the procedure & monitor calls. @tw9@shows warning & trap information. .TE .PP An EM interpreter without a Logging Machine can be obtained by undefining the macro \fICHECKING\fP in the file \fIchecking.h\fP. .NH 2 Controlling the Logging machine. .PP The actions of the Logging Machine are controlled by a set of internal variables (one of which is the log mask). These variables can be set through assignments on the command line, as explained int the manual page \fIint.1\fP, q.v. Since there are a great many logging statements in the program, of which only a few will be executed in any call of the interpreter, it is important to be able to decide quickly if a given \fIid\fP has to be checked at all. To this end all logging statements are guarded (in the #define) by a test for the boolean variable \fIlogging\fP. This variable will only be set if the command line assignments show the potential need for logging (\fImust_log\fP) and the instruction count (\fIinr\fP) is at least equal to \fIlog_start\fP (which derives from the parameter \fBLOG\fP). .LP The log mask can be set by the assignment .DS "LOGMASK=\fIlogstring\fP" .DE which sets the current logmask to \fIlogstring\fP. A logstring has the following form: .DS [ [ \fIletter\fP | \fIletter\fP \- \fIletter\fP ]+ \fIdigit\fP ]+ .DE E.g. LOGMASK=A\-D8x9R7c0hi4 will print all messages belonging to loggings with \fBid\fPs: \fIA0..A8,B0..B8,C0..C8,D0..D8,x0..x9,R0..R7,c0,h0..h4,i0..i4\fP. .PP The logging variable STOP can be used to prevent run-away logging past the point where the user expects an error to occur. STOP=\fInr\fP will stop the interpreter after instruction number \fInr\fP. .PP To simplify the use of the logging machine, a number of abbreviations have been defined. E.g., AT=\fInr\fP can be thought of as an abbreviation of LOG=\fInr\-1\fP STOP=\fInr+1\fP; this causes three stack dumps, one before the suspect instruction, one on it and one after it; then the interpreter stops. .PP Logging results will appear in a special logging file (default: \fIint.log\fP). .NH 2 Dumps. .PP There are three routines available to examine the memory contents: .TS tab(@); l l l. @\fIstd_all()\fP@dumps the contents of the stack (\fId1\fP or \fId2\fP must be in the logmask). @\fIgdad_all()\fP@dumps the contents of the gda (\fI+1\fP must be in the logmask). @\fIhpd_all()\fP@dumps the contents of the heap (\fI*1\fP must be in the logmask). .TE .LP These routines can be used everywhere in the program to examine the contents of memory. The internal variables allow the gda and heap to be dumped only once (according to the corresponding internal variable). The stack is dumped after each instruction if the log mask contains d1 or d2; d2 gives a full formatted dump, d1 produces a listing of the Return Status Blocks only. An attempt is made to format the stack correctly, based on the shadow bytes, which identify the Return Status Block. .LP Remember to set the correct \fBid\fP in the LOGMASK, and to give LOG the correct value. If dumping is needed before the first instruction, then LOG must be set to 0. .LP The dumps of the global data area and the heap are controlled internally by the id-s +1 and *1 resp.; the corresponding logmask entries are set automatically by setting the GDA and HEAP variables. .NH 2 Forking. .PP As mentioned earlier, a call to \fIfork()\fP, causes an image of the current program to start running. To prevent a messy logfile, the child process gets its own logfile (and message file, tally file, etc.). These logfiles are distinguished from the parent logfile by the a postfix, e.g., \fIlogfile_1\fP for the first child, \fIlogfile_2\fP for the second child, \fIlogfile_1_2\fP for the second child of the first child, etc. .br \fINote\fP: the implementation of this feature is shaky; it works for the log file but should also work for other files and for the names of the logging variables.