═══ 1. Dynamic Trace Customizer(TRCUST) ═══ ═══ 1.1. Description ═══ OS/2 provides a mechanism by which developers may dynamically apply tracepoints in their module at run time. This method eliminates all overhead of tracing when tracing is disabled. It also allows the developer to add tracepoints without modifying source code. This reduces the possibility that adding a tracepoint will induce errors into one's code. OS/2 needs a binary file, for each module being dynamically traced, which defines the tracepoints for the module. The Trace Customizer(TRCUST) converts tracepoint definitions from a trace source file(TSF) into dynamic tracepoints for the trace definition file(TDF), and into formatting rules in the trace format file(TFF). Definitions .TSF An ASCII file created by a developer which defines all dynamic tracepoints for a given module. TRCUST currently allows at most only one major code per TSF. .TDF A binary file, created by TRCUST, using the .TSF file as input. This file defines all tracepoints in the module in a manner acceptable to OS/2. This is used by the Trace Utility, TRACE. .TFF A binary file also created by TRCUST using the .TSF file. This file defines how all tracepoints will be formatted. This is used by the Trace Formatter, TRACEFMT. major code A byte value used to identify the module being traced. TRCUST allows at most only one major code per TSF. minor code A word value used to uniquely identify each tracepoint. GROUP A value used to identify this tracepoint with tracepoints of the same category. Examples are MEM for memory management and PM for Presentation Manager. For an example of uses of groups, see the online help for the TRACE command. TYPE A value used to associate a subset of dynamic trace events within a module. Examples are PRE for pre-invocation, POST for post-invocation and API for API calls within a module. For an explanation and examples of uses of types, see the online help for the trace command. ═══ 1.2. Overview ═══ ═══ 1.2.1. File Naming and Location ═══ The TDF file name is the same as the module to be traced, but has a file extension of "TDF". The TFF has a name of the form "TRC00xx.TFF" where xx is the major code, e.g. a module with major code 0xC2 will generate a TFF with the name "TRC00C2.TFF". This naming convention is used to allow TRACEFMT to dynamically generate the TFF name given only the major code. TRCUST can be invoked to process a TSF or to combine several TFF files into a single TFF. For processing a TSF, TRCUST is given the name of a TSF, and optionally: o the desired name of the resulting TDF o the MAP file name o the error message level TRCUST will store the TSF tracepoint formatting specifications in the TFF file and if the tracepoint specified was not for a static tracepoint, the TSF tracepoint definition will be converted into the format required by the Trace Utility and stored in the TDF file. On errors, TRCUST will display appropriate messages, skip any tracepoint with errors in its definition, and continue processing the next tracepoint definition. For combining TFF files that use the same major code, TRCUST is given the name of the file containing the TFF filenames to combine and the name of the file to contain the combined trace format statements. TRCUST will issue an error message and abort processing under the following conditions: o the TSF cannot be opened o when combining TFF files, if any TFF input files cannot be read or if all TFF input files do not use the same major code o when defining dynamic tracepoints, if the executable module to contain the tracepoints cannot be read o the TDF, or TFF files cannot be written to o an error in the header definition in the TSF o a missing ending quote in the TSF Note: TRCUST always returns 0 so that, when invoking it from a makefile, processing of the rest of the makefile can continue if TRCUST aborts. Combine TFF files when several modules that use dynamic tracing use the same major code. The Trace Formatter can only use one TFF file per major code to get formatting information from. After the TSF file for each module is run through TRCUST to produce a TDF and TFF file, TRCUST can be invoked again, this time using the combine TFF files option and a file that only contains the paths to all the TFF files using the same major code. TRCUST will read all the TFF files. If all TFF files don't use the same major code, TRCUST will issue an error message and abort. TRCUST will read each trace format record from the TFF files and write them(in ascending order according to minor code) to the destination TFF file given. ═══ 1.2.2. Invoking the Trace Customizer ═══ The Trace Customizer is a protect mode only program and must therefore be run under OS/2. TRCUST may be invoked to combine TFF files or to process a TSF. The syntax for combining TFF files is as follows: [d:][path]TRCUST [d:][path]tffsource /C=[d:][path]tffdest [/Wn] where: TRCUST is the name of the Trace Customizer program. A drive and path may optionally be specified to explicitly define the location of the Trace Customizer program, otherwise the program is searched for in the current directory, followed by looking along the path defined by the PATH environment variable. [d:][path]tffsource is the name of a file containing fully qualified(including extensions) pathnames of TFF files to combine. Each TFF file must use the same major code and each filename in the tffsource file is separated by white space. This will combine all TFF files for the same major code into a single TFF file. If duplicate minor code format definitions are found, the first format definition for the minor code remains valid, the duplicates are discarded and a warning message is issued. If no path is provided the tffsource file is searched for in the current directory, followed by using the current value of DPATH. [d:][path]tffdest is the name of the trace format destination file to store the combined trace format definitions. /Wn (optional) is the level of error messages to be displayed, where n can be 0, 1, or 2. The possible message levels are shown below along with the messages that each displays: 0 fatal and severe messages 1 fatal, severe, and error messages 2 all (fatal, severe, error, and warning) messages A message level of 2 is the default. An example of a tffsource file for using the combine TFF files option of TRCUST is: \DRV6\SRC\PM\TRC00C2.TFF \DRV6\SRC\DM2\TRC00C2.TFF \DRV6\SRC\DOSCALLS\TRC00C2.TFF \DRV6\SRC\KB\TRC00C2.TFF To invoke TRCUST to combine TFF files using the above file as input(assume filename is \DRV6\SRC\TR\TFF00C2) and output the combined format statements into file \DRV6\SRC\TR\TRC00C2.TFF is: TRCUST \DRV6\SRC\TR\TFF00C2 /C=\DRV6\SRC\TR\TRC00C2.TFF The syntax for processing a TSF file is as follows: [d:][path]TRCUST [d:][path]tsf [[d:][path]tdf] [/M=mapfile] [/Wn] where: TRCUST is the name of the Trace Customizer program. A drive and path may optionally be specified to explicitly define the location of the Trace Customizer program, otherwise the program is searched for in the current directory, followed by looking along the path defined by the PATH environment variable. [d:][path]tsf is the name of the trace source file. If no file extension is provided then an extension of TSF is assumed. If no path is provided the trace source file is searched for in the current directory, followed by using the current value of DPATH. [d:][path]tdf (optional) is the name of the trace definition file to store the dynamic tracepoint definitions. If not specified, the TSF filename is used with an extension of TDF. If no file extension is provided then an extension of TDF is assumed. /M=mapfile (optional) defines mapfile as the MAP file for this module. The name may be qualified by a drive/directory, otherwise it will be searched for in the current directory followed by the path specified by the DPATH environment variable. If specified as an option, the MAP file must exist and the filename extension must be MAP or TRCUST will abort processing. The mapfile will only be used if a symbol is not found in the symbolic debug information stored in the executable module. /Wn (optional) is the level of error messages to be displayed, where n can be 0, 1, or 2. The possible message levels are shown below along with the messages that each displays: 0 fatal and severe messages 1 fatal, severe, and error messages 2 all (fatal, severe, error, and warning) messages A message level of 2 is the default. ═══ 1.2.3. Symbolic Debug Support ═══ ═══ 1.2.3.1. Source Level Symbolic Support ═══ If the module has been compiled and linked with the debug options: 1. /Ti on the C/Set2 language compiler for C source files 2. /CO on the link command then the Trace Customizer can look into the module to extract symbolic information. In this case addresses may be specified symbolically. Note that not all source files must be C language, although only public labels from assembler routines will be found in the symbolic information. You may specify filename and line number, a local variable name or a global variable name when using C routines. All symbolic names are case sensitive when the source was compiled with debug options, but if linking in a C language program that was not compiled with debug options, all symbolic names are case sensitive and begin with an underscore "_" character unless the name is declared with the Pascal calling conventions, in which case the underscore is omitted but the symbolic name is capitalized. ═══ 1.2.3.2. MAP File Support ═══ The Trace Customizer can also use the symbolic information in the MAP file produced by the linker. All public symbols will be listed with their offsets in the module being traced. This is not as complete a support as offered by the debug compile option for C language source files, but it does allow entry points, public labels and global data to be referenced symbolically within the TSF. Note that the use of a MAP file is NOT language dependent. Note: When using a MAP file, if the symbolic name is a C language entry point, it will be case sensitive and begin with an underscore "_" character unless it is declared with the Pascal naming convention, in which case the underscore is omitted and the name is capitalized. If the name is not from C language source file, the name is case sensitive. ═══ 1.2.3.3. Building a Module ═══ To trace only public procedures, you only need your MAP file that was generated by linking your module. To trace local variables in C language routines, compile the C programs with the debug option and assemble the ASM routines with public symbols. Link all the OBJs together with the debug option(/CO) and run TRCUST on the executable module. You can now strip the debug information from the executable file by either relinking the OBJs without the debug option or by using a tool to delete the debug information from the executable module file. ═══ 1.2.4. TDF and TFF File Usage ═══ The TDF, and TFF files produced by TRCUST are used in the following way: ┌─────────┐ │ .TSF │ └────┬────┘ V ┌──────┴──────┐ │ TRCUST Util │ └──────┬──────┘ ┌────────────────────────────┤ V │ ┌────┴────┐ ┌────┴────┐ │ .TDF │ │ .TFF │ └────┬────┘ └────┬────┘ │ │ ┌──────┴──────┐ │ │ TRACE util │ │ └─────────────┘ │ │ │ ┌───────┴───────┐ V │tracepoints set│ │ └───────────────┘ │ ┌───────────────┐ │ │ tracepoint hit│ │ └───────┬───────┘ │ │ │ ┌───────┴───────┐ │ │ OS/2 kernel │ │ └───────┬───────┘ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ┌───────┴───────┐ ┌──────┴──────┐ │ trace buffer │────────────>│TRACEFMT util│ └───────────────┘ └──────┬──────┘ │ ┌──────┴──────┐ │ formatted │ │trace records│ └─────────────┘ How TRCUST fits into the system Totraceamoduledothefollowing : 1. Define the tracepoints and data to be traced in the TSF. 2. Invoke the Trace Customizer using the TSF as input. This produces two files, a TDF and a TFF. 3. Put the TDF file in the same directory the module to trace resides, put the TFF file in a directory accessible by TRACEFMT. It is suggested that all TFF files reside in the same subdirectory, an example directory could be \OS2\SYSTEM\TRACE. 4. Invoke the OS/2 TRACE command using the name of the TDF instead of the major code value. This activates the tracepoints, causing the trace data to be saved in the system trace buffer. 5. The OS/2 TRACE command can be used to turn tracing off at any time. 6. To display the contents of the trace buffer, invoke the OS/2 TRACEFMT command. TRACEFMT uses the major code to determine the TFF file and uses the formatting string corresponding to the minor code value to format the data in the RAS trace buffer and output it to the screen, file or printer. ═══ 1.2.5. Symbols and Abbreviations Used in the Document ═══ [...] denotes optional items. [... | ... | ...] denotes a list of optional items, zero or more of which may be chosen. {... | ... | ...} denotes a list of items of which ONE must be chosen. item... denotes that item is repeated zero or more times. statement,..... denotes this example is incomplete. nnn is a number in the range 0-255 inclusive. nnnnn is a number in the range 0-65535 inclusive. All numbers and values can be entered in decimal form or in C hexadecimal form (0x....). ═══ 1.3. Trace Source File ═══ This section details the statements that can appear within a trace source file. Examples are given of TRACE statements. ═══ 1.3.1. TSF Format ═══ The layout of a trace source file is: ┌────────────────────────┐ │ Header │ ├────────────────────────┤ │ Type List Definition │ │ (optional) │ ├────────────────────────┤ │ Group List Definition │ │ (optional) │ ├────────────────────────┤ │ │ │ │ │ Tracepoint Definitions │ │ │ │ │ └────────────────────────┘ Layout of a trace source file Notes : o Comments may be freely inserted anywhere in the trace source file. A comment is identified by a ; or by using C syntax comments anywhere in the file. A C comment has start and end delimiters, namely /* and */. C type comments may span lines, and may be nested. o Below are sample TSF files. See Sample Trace Source Files for more examples. ; Sample trace source file depicting dynamic tracing for OS calls compiled ; with 32-bit addressing MODNAME = doscall1.dll MAJOR = 100 /* this is decimal, would be 0x64 if specified hex */ MAXDATALENGTH = 200 /* max bytes logged per tracepoint is 200 */ TYPELIST NAME=PRE,ID=1, NAME=SYS,ID=0x40, NAME=API,ID=128, /* decimal, if hex would be 0x80 */ NAME=POST,ID=0x8000 GROUPLIST NAME=MEM,ID=2, NAME=FS,ID=0x5, NAME=MOU,ID=13, NAME=DOS,ID=0x2B /* would be 43 if decimal */ TRACE MINOR=0x0001, TP=.DosOpen, /* Pre-invocation tracing on DosOpen */ TYPE=(PRE,API), GROUP=DOS, DESC="(OS) DosOpen Pre-Invocation", FMT="Major = %X Minor = %Y", FMT=" EAX = %D", FMT=" FileName = %P%S", REGS=(EAX), ASCIIZ32=(.FileName,DIRECT,128) TRACE MINOR=0x7001, /* Puts tracept on code at line 28 */ /* of file dosopen1.c. Debug */ TP=@dosopen1.c,28, /* info is needed to use this. */ TYPE=(API), GROUP=DOS, DESC="(OS) CheckParm After Createhandle", FMT=" New handle = %P%W", MEM32=(.handle,DIRECT,2) TRACE MINOR=0x8001, /* Post-invocation tracing at */ TP=.DosOpenC,RETEP, /* procedure DosOpenC return point. */ TYPE=(API,POST), /* Debug info is needed to use */ GROUP=DOS, /* this type of tracepoint. */ DESC="(OS) DosOpenC Post-Invocation", FMT=" Return Code = %P%W", FMT=" Variable Rec= %P%U", MEM32=(.retcode,DIRECT,2), /* The following will log a variable length structure. The */ /* second field in the structure is the length of the */ /* record(position var_struct+2). This LEN parameter must*/ /* immediately precede the memory specification defining */ /* the variable length record. */ LEN=(var_struct+2,DIRECT), MEM32=(.var_struct,DIRECT,LEN) ═══ 1.3.2. TSF Header ═══ This defines common information for the module to be traced. The format is: MODNAME = [d:][path]Name MAJOR = nnn [ MAXDATALENGTH = nnnn ] where: d: is the drive containing the module. If not specified the current drive is used. path is the path to the module. If not specified the current path is used. Name is the name of the executable module to be traced. If an extension is not specified and the Name is not OS2KRNL, an extension of DLL is appended to Name. MAJOR=nnn defines the major trace ID allocated to this module. It may be in the range 1 to 255 decimal or specified 0x1 to 0xFF hex. The default value is 1. The major trace ID is part of the data placed in the trace buffer when a tracepoint is executed. Only one major code is permitted per module. Note: OS/2 currently only supports major codes 0x1 - 0x00FF. MAXDATALENGTH=nnnn (optional) defines the maximum amount of data that a single tracepoint call will insert into the trace buffer. The length may be in the range 20 to 512 decimal or specified 0x14 to 0x200 hex. The default value is 512. This limit on the amount of data to trace is to avoid yielding the processor when doing dynamic tracing. ═══ 1.3.3. Typelist Definition ═══ This defines the optional typelist event IDs. For more description and examples of event types see the online help for the trace command. The format is: TYPELIST NAME=TypeName,ID=TypeValue, [NAME=TypeName,ID=TypeValue,]... where: NAME=Typename defines a 1-8 byte character string used to reference the TypeValue in the tracepoint definitions. All TypeNames and GroupNames within a TSF must be unique. ID=TypeValue defines a bit value of the form 2**y where y in range 0 to 15, permitting a maximum of 16 types to be defined in a single TSF. This can be decimal or specified 0xnnnn for hex. An example TYPELIST definition follows: TYPELIST NAME=PRE,ID=1, NAME=SYS,ID=0x40, NAME=API,ID=128, NAME=POST,ID=0x8000,..... ═══ 1.3.4. Grouplist Definition ═══ This defines the optional grouplist IDs. For more description and examples of groups see the online help for the trace command. The format is: GROUPLIST NAME=GroupName,ID=GroupValue, [NAME=GroupName,ID=GroupValue,]... where: NAME=GroupName defines a 1-8 byte character string used to reference the GroupValue in the tracepoint definitions. There are a maximum of 48 GroupNames allowed in a TSF file. All TypeNames and GroupNames within a TSF must be unique. ID=GroupValue defines a word value in the range 1 to 65535 decimal or 0x1 to 0xFFFF hex. An example GROUPLIST definition follows: GROUPLIST NAME=MEM,ID=2, NAME=FS,ID=0x5, NAME=MOU,ID=13,..... ═══ 1.3.5. Tracepoint Definitions ═══ The tracepoint address and the data to be traced are specified by the TRACE statement. There are a maximum of 65535 tracepoints permitted in a trace source file. The format of the TRACE statement is: TRACE [MINOR=minorcode,] TP={@STATIC,|@filename,linenum,|.name[{+|-}offs][,RETEP]}, [OPCODE=0xnn,] [TYPE=(typename[,typename...]),] [GROUP=groupnam,] [DESC="Tracepoint description",] [FMT="Formatting string",]... [LEN=(length_spec,flag),] [DATA_STMT,]... The TRACE keyword delimits a tracepoint definition statement. The definition is considered complete when the next TRACE keyword is encountered or the end of file is reached. There is one TRACE statement for each tracepoint. LEN is used to log variable length records. A DATA_STMT must immediately follow the LEN statement. LEN will give the location of a one word field containing the number of bytes to log for the following DATA_STMT. ═══ 1.3.5.1. MINOR Keyword ═══ The MINOR parameter is an optional keyword parameter. If it is specified in the first tracepoint definition, it must be specified in every tracepoint definition. If it is not specified in the first tracepoint definition, it cannot be specified in any of the subsequent tracepoint definitions. It should be coded as: MINOR=nnnnn, where: nnnnn is a decimal number from 1 to 65535 or a hex number from 0x1 to 0xFFFF. This represents the minor code for the tracepoint, which must be unique for the major code specified for this module. When tracepoints with duplicate minor codes are encountered, the first is saved and the rest are discarded, and an error message is issued. If minor codes are not specified in the TSF, TRCUST sequentially provides them, starting with 1, for each tracepoint definition it encounters. ═══ 1.3.5.2. TP Keyword ═══ The TP parameter is a required keyword parameter. If TP is specified more than once for a single tracepoint definition, the tracepoint is discarded. TP has three mutually exclusive definitions which can be coded as: TP=@STATIC, where: STATIC defines this tracepoint entry to be used only for creating a trace format statement for the TFF file. No tracepoint definition is created for the TDF, and the only other TRACE parameters that will be used are DESC, MINOR and FMT. This is used to create trace formatting information for static tracepoints. If the TSF contains only @STATIC directives, no TDF files are created. TP=@filename,linenum, where: filename is an ASCII string specifying the name(including extension) of a source filename used in creating the module. The source filename is stored in the debug information contained in the executable module, so debug information must exist to use this parameter. The filename is not case sensitive. linenum is a decimal number specifying the line number in the given source file name to place the tracepoint. Note: Debug information must exist to use this option. The statement at the given source linenum may have been rearranged during compiler optimization, so the developer must use this with caution. If the linenum is not found in the debug information, the tracepoint is applied at the next linenum defined in the debug information and a warning message is issued to the user. An example to apply a tracepoint to line 35 of file stubfile.c is: TRACE MINOR=0x700A, /* puts tracepoint on code at line */ TP=@stubfile.c,35,..... /* 35 of source file stubfile.c */ TP=.name[{+|-}offs][,RETEP], where: name is a public label or an entry point name of a procedure to be traced. The "." preceding name is required. Name must be found in the debug information in the module or name must be a public symbol as found in the MAP file. If debug information is used, the address of this tracepoint will be immediately following the prologue of the procedure. If MAP information is used, this address points to the opcode at the given label. If the procedure was compiled with debug support, Name is case sensitive. If not, C language functions will be case sensitive and begin with an underscore "_" character unless the function is declared with the Pascal calling convention, in which case the underscore is omitted and the name is capitalized. offs (optional) is a decimal(specified as nnnnnnnn) or hex(specified as 0xnnnnnnnn) offset from the entry point address. RETEP (optional) specifies that the tracepoint will be inserted at the return address corresponding to this entry point. This is just before the procedure epilogue is executed and at this point the procedure's automatic data is still addressable from register (E)BP and the return code (if any) is set up in (E)AX. The module must include information supplied by the debug compile option (see Symbolic Debug Support), meaning that the source language must have been C, otherwise an error message will be generated and this tracepoint discarded. When the RETEP is used, the name must be a valid entry point to a procedure. Note: For ASM functions to accomplish tracing, a label must be made public to have a tracepoint applied. Therefore, to accomplish "POST" tracing, a label must be made public at the return statement. Partial examples of Pre/Post tracing of DosOpen follows: TRACE MINOR=0x0001, TP=.DosOpen,..... /* Pre-invocation tracing */ TRACE MINOR=0x8001, TP=.DosOpen,RETEP,..... /* Post-invocation tracing */ Note: It is not possible to set dynamic tracepoints on the following machine instructions: 0x9C PUSHF 0xCC INT 3 0xCD INT n 0xCE INTO 0x62 BOUND 0x69 IMUL 0x6B IMUL 0xF6 DIV, IDIV, MUL, IMUL, NEG, NOT, TEST (immediate) 0xF7 DIV, IDIV, MUL, IMUL, NEG, NOT, TEST (immediate) TRCUST gives an error for these opcodes and the tracepoint is rejected. Note: In all cases, two tracepoints cannot be applied at the same address. ═══ 1.3.5.3. OPCODE Keyword ═══ The OPCODE parameter is an optional keyword parameter. OPCODE=0xnn, where: nn is the expected one byte hex opcode to be found at the tracepoint address and TRCUST verifies the value with that in the module. The opcode of the instruction being traced must be the same as this value or an error message is issued and the tracepoint is rejected. This may be used to verify the opcode expected at the address specified by the TP parameter. This may be useful when using TP = @filename,linenum to ensure the requested instruction is traced. ═══ 1.3.5.4. TYPE Keyword ═══ The TYPE parameter is an optional keyword parameter that defines the event types of this tracepoint. For more description and examples of event types see the online help for the trace command. TYPE=(typename[,typename...]), where: typename is an ASCII string specifying the type of this tracepoint. The typename symbol must have been previously defined by the TYPELIST statement. If an invalid typename is given, the tracepoint will be discarded and a message issued. The final type value is obtained by logically combining each type name value using the OR operator. If TYPE is omitted, the trace statement will have a typevalue of 0. ═══ 1.3.5.5. GROUP Keyword ═══ The GROUP parameter is an optional keyword parameter that defines the group this tracepoint belongs to. For more description and examples of groups see the online help for the trace command. GROUP=groupnam, where: groupnam is an ASCII string specifying which group this tracepoint belongs. The groupname symbol must have been previously defined by the GROUPLIST statement. If an invalid groupname is given, the tracepoint will be discarded and a message issued. If GROUP is omitted, the trace statement will have a groupvalue of 0. ═══ 1.3.5.6. DESC Keyword ═══ The DESC parameter is used to produce a description for the tracepoint that is output as the first line of formatted data. It should include the entry point name of the procedure being traced and whether this is an entry or return point. The descriptive string is enclosed in double quotes as for a C language string. The DESC parameter is required if any FMT specifications are present. The recommended formats for such strings are as follows: DESC="name Pre-Invocation", DESC="name Post-Invocation", where: name is the system component(in parentheses) followed by the entry point name of the procedure. Pre-Invocation identifies this tracepoint as an entry point, i.e. before the function has been executed. Post-Invocation identifies this tracepoint as a return point from the function. The words Pre-Invocation and Post-Invocation are not mandatory, merely recommendations to be compatible with the base OS/2 tracepoints, when formatted. If a tracepoint is inserted in the middle of a procedure it will be appropriate to use different wording. The Trace Customizer does not check the wording. An example of pre-invocation and post-invocation tracepoints follow: TRACE MINOR=0x0001, TP=.DosOpen, DESC="(OS) DosOpen Pre-Invocation",..... TRACE MINOR=0x8001, TP=.DosOpen,RETEP, DESC="(OS) DosOpen Post-Invocation",..... ═══ 1.3.5.7. FMT Keyword ═══ The optional FMT parameter is used to produce the formatting string for the trace data. The developer should use these to control formatting the output produced by the Trace Formatter. Each FMT keyword causes CR/LF to be appended to the format string. The formatting string is similar to a C library printf string specification. It consists of ASCII characters and formatting controls enclosed in double quotes as for a C language string. Each formatting primitive describes the format of the data in the trace buffer at the formatting position and must match the data stored in the trace buffer by the data statements described later. See Formatting Trace Data for a description of how the data is stored in the trace buffer and subsequently formatted. The formatting controls are as follows: %Innn Ignore nnn number of bytes in the trace buffer. This tells the Trace Formatter to skip over the next nnn bytes in the current trace record. This could be used for example to skip over unimportant data, traced as a block, and only output the data of interest. When using this control, nnn represents an ASCII decimal number and must be followed by a space. statement: FMT = "ignore ten bytes %I10 here", FMT = " and two more %I2 here", generates: ignore ten bytes here and two more here %P Process the data prefix bytes associated with the trace data. This tells the Trace Formatter that the next bytes in the trace record are the prefix or header bytes for data logged by the dynamic tracing mechanism. This is required to precede any format control describing data logged from memory. Do not use this before data that was logged from a register and never use with static tracepoints. See Formatting Trace Data for a description of how the data is stored in the trace buffer and the use of this control. statements: FMT="memory byte = %P%B", generates: memory byte = C2 %B Output a byte of data. statement: FMT = "memory byte = %P%B" generates: memory byte = 01 %W Output a word of data. statement: FMT = "register word = %W" generates: register word = 0001 statement: FMT = "memory word = %P%W" generates: memory word = 0001 %D Output a double word of data. statement: FMT = "double word EAX = %D" generates: double word EAX = 0000 4B2C statement: FMT = "double memory word = %P%D" generates: double memory word = 0000 4B2C %F Output a Flat (0:32 bit) address. statement: FMT = "flat address EAX = %F" generates: flat address EAX = 00004B2C %Q Output a quad word of data. statement: FMT = "quad word from regs EAX and EBX = %Q" generates: quad word from regs EAX and EBX = 00004B2C 00000001 %A Output a segmented(16:16 bit) address. statement: FMT = "segmented address in SS:SP = %A" generates: segmented address in SS:SP = 00B7:0001 statement: FMT = "segmented address in memory = %P%A" generates: segmented address in memory = 00B7:0001 %R Repeat the following format control for the rest of the memory that was logged. This is used for formatting variable length records. Use this in place of the prefix parameter %P to log the rest of the record in the format specified following the repeat code. statement: FMT = "log a variable number of words from memory = %R%W" generates: log a variable number of words from memory = 0001 0004 %S Output an ASCIIZ string. The prefix formatting control should always precede this for dynamic tracepoints because the data was logged from memory. Note: If the tracepoint is static, then %P should not be used because the string is terminated with a null byte. statement: FMT = "string = %P%S" generates: string = c:\os2\os2.ini %U Format the remainder of the trace record as a sequence of bytes. This will output the remaining of the traced data, including any prefix bytes. statement: FMT = "garbage = %U" generates: garbage = 00 00 00 03 c2 c1 c4 ff 04 00 09 c0 18 %X Output the major event code. statement: FMT = "major code = %X" generates: major code = 00C2 %Y Output the minor event code. statement: FMT = "minor code = %Y" generates: minor code = 0081 Note: To avoid conflicts with source file control information, all formatting specifications can be in upper or lower case. Also, prefix format specifications may be combined with data format specifications. For example, the following create the same format controls in the TFF: FMT = "%P%W here" FMT = "%p%w here" FMT = " %P %W here" ═══ 1.3.5.8. LEN Keyword ═══ The LEN parameter is an optional keyword parameter that defines the length of the variable length record that will follow in the next MEM or MEM32 statement. LEN=(length_spec,flag), where: length_spec is an address specification that points to the one word length field of the next memory specification. This format can be symbolic_name+nnnnnnnn where symbolic_name is a symbolic memory location and nnnnnnnn is the offset from that symbolic address. The length_spec can also be Flat Register Form or Segment Register Form. flag is a mandatory parameter that identifies the level of indirection to be used on the length_spec. It is one of: D[IRECT] I[NDIRECT][*[{+|-}iiiiiiii]]... DIRECT implies that the length_spec specifies a memory location that contains the length of the variable length record. INDIRECT means that the length_spec contains an address and is dereferenced to obtain the memory location. The optional asterisks denote the level of indirection, one for each level. The indirect offsets iiiiiiii are added to or subtracted from the value found at the given level of indirection. The following are example LEN statements followed by the memory statement whose length they describe. TRACE MINOR=....., /* Symbol vrecord is a record whose first field is a one */ /* word value that is the total length of the entire */ /* variable length record. */ LEN=(vrecord,DIRECT), MEM=(.vrecord,DIRECT,LEN), /* Symbol vrec_ptr is a pointer to a variable length record */ /* and vend_ptr is a pointer to the end of the same record. */ /* The second field(10 bytes from end of record) is total */ /* length of the variable length record. */ LEN=(vend_ptr,INDIRECT*-10), MEM=(.vrec_ptr,INDIRECT,LEN), /* Symbol vrec_ptr is a pointer to a variable length record.*/ /* The second field(2 bytes from beginning of record) is */ /* total length of the variable length record. */ LEN=(vrec_ptr,INDIRECT*+2), MEM=(.vrec_ptr,INDIRECT,LEN), /* Symbol ind_ptr is a pointer to a structure. The third */ /* field in the structure(6 bytes from beginning) is a */ /* pointer to a variable record. The fourth field in the */ /* variable length record(8 bytes from beginning) is the */ /* total length of this variable length record. */ LEN=(ind_ptr,INDIRECT*+6*+8), MEM=(.ind_ptr,INDIRECT*+6*,LEN), /* If DS:DI contains the address of ind_ptr, to perform */ /* the above logging, the statements would be: */ LEN=(RDS+DI,INDIRECT*+6*+8), MEM=(RDS+DI,INDIRECT*+6*,LEN) ═══ 1.3.5.9. DATA_STMT ═══ There are three types of data that may be traced as part of the optional DATA_STMT section of the TRACE statement. Registers Memory ASCIIZ strings More than one keyword is permitted in a tracepoint definition. The order of the statements defines the order in which the data is inserted into the trace buffer. The combined amount of data to be traced for a single tracepoint cannot exceed MAXDATALENGTH. If TRCUST determines that the maximum data size might be exceeded, a warning message is issued but the tracepoint definition will remain valid. The keywords for tracing the three types of data are REGS, MEM32, MEM, ASCIIZ32, and ASCIIZ. The REGS keyword identifies which registers are to be recorded in the trace buffer. The MEM32 keyword is used to record sections of memory in the trace buffer. Access to this memory location is through 32-bit flat addresses from functions compiled using 32-bit addressing. Several MEM32 parameters may be coded at any one tracepoint if several different memory areas are to be traced. The MEM keyword is also used to record sections of memory in the trace buffer, but access to this memory is through a segment:offset pair. This is used for functions compiled using 16-bit addressing with segment registers. Several MEM parameters may be coded at any one tracepoint if several different memory areas are to be traced. The ASCIIZ32 keyword is used to record an ASCIIZ string in the trace buffer. This is a special form of the MEM32 keyword and there may be more than one ASCIIZ32 parameter coded for a single tracepoint. The ASCIIZ keyword is used to record an ASCIIZ string in the trace buffer. This is a special form of the MEM keyword and there may be more than one ASCIIZ parameter coded for a single tracepoint. ═══ 1.3.5.10. REGS Keyword ═══ This is coded as: REGS=(register[,register]...), where: register is one of the following to support OS/2 versions 1.1 and 1.2: CS,DS,SS,ES,AX,BX,CX,DX,SP,BP,SI,DI,IP,FLAGS with the addition of the following to support OS/2 version 2.0: EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI,EFLAGS,EIP,FS,GS or the symbolic name of a C language variable declared with the register storage-class specifier as: .symbolic_name The same register may appear multiple times in the register list. It will be traced as many times as it appears. Extended registers(E) are 32 bits and logged as two words. All other registers are 16 bits and logged as one word. Note: To log a C language variable declared with the register storage class, debug information must exist and the variable name is case sensitive. When formatting the data logged from a register variable, remember that there are no memory prefix bytes put into the log buffer. Example of the REGS statement follows: /* Given the following declaration in a C language source file: */ register int ret_code; /* To log registers AX, CX and the register variable ret_code: */ TRACE MINOR=..... REGS=(AX,CX,.ret_code), FMT="AX=%W CX=%W ret_code=%W" ═══ 1.3.5.11. MEM32 Keyword ═══ This is used to log memory in a function compiled using 32-bit flat addressing and is coded as: MEM32=(address_spec,flag,{length|LEN}), where: address_spec is a flat memory address specification as described in Address Specification. flag is a mandatory parameter that identifies the level of indirection to be used on the address. It is one of: D[IRECT] I[NDIRECT][*[{+|-}iiiiiiii]]... IS DIRECT implies that the address specifies a memory location to be saved in the trace buffer. INDIRECT means that the address contains a flat address and is dereferenced to obtain the memory location. The optional asterisks denote the level of indirection, one for each level. The indirect offsets iiiiiiii are added to or subtracted from the value found at the given level of indirection. IS(Indirect Segmented) means that the address contains a segmented address that is dereferenced to obtain the memory location. length is the number of bytes at the memory location to be saved in the trace buffer. If length is too big, a warning message will be given, and length will be set to MAXDATALENGTH. If length is 0 an error message will be given, and this tracepoint will be ignored. LEN specifies that this is a variable length record to log and the length was specified by the preceding LEN statement. If there was no preceding LEN statement, this tracepoint is rejected. Either length or LEN must be specified, but not both. Example of the MEM32 statement follows: TRACE MINOR=..... /* To log retcode enter the following: */ MEM32=(.retcode,DIRECT,2), /* s_ptr is a pointer to a structure, log it for 4 bytes. */ MEM32=(.s_ptr,INDIRECT,4), /* Field 6 bytes into structure pointed at by s_ptr is a */ /* pointer to a structure, log 8 bytes past begin of struct.*/ MEM32=(.s_ptr,INDIRECT*+6*+8,10), /* logs ten bytes */ /* s_ptr points to a variable length record, second field */ /* is the record length(offset 4 from record beginning). */ LEN=(s_ptr,INDIRECT*+4), MEM32=(.s_ptr,INDIRECT,LEN) /* s_end points to the end of same variable length record,*/ /* second field is the record length(offset -6 from */ /* record beginning). */ LEN=(s_end,INDIRECT*-6), MEM32=(.s_ptr,INDIRECT,LEN) ═══ 1.3.5.12. MEM Keyword ═══ This is used to log memory in a function compiled using 16-bit segment:offset addressing and is coded as: MEM=(address_spec,flag,{length|LEN}), where: address_spec is a segmented memory address specification as described in Address Specification. flag is a mandatory parameter that identifies the level of indirection to be used on the address. It is one of: D[IRECT] I[NDIRECT][*[{+|-}iiiiiiii]]... IF DIRECT implies that the address specifies a memory location to be saved in the trace buffer. INDIRECT means that the address contains a segmented address and is dereferenced to obtain the memory location. The optional asterisks denote the level of indirection, one for each level. The indirect offsets iiiiiiii are added to or subtracted from the value found at the given level of indirection. IF(Indirect Flat) means that the address contains a flat address that is dereferenced to obtain the memory location. Only far pointers may be dereferenced when using segmented addressing. length is the number of bytes at the memory location to be saved in the trace buffer. If length is too big, a warning message will be given, and length will be set to MAXDATALENGTH. If length is 0 an error message will be given, and this tracepoint will be ignored. LEN specifies that this is a variable length record to log and the length was specified by the preceding LEN statement. If there was no preceding LEN statement, this tracepoint is rejected. Either length or LEN must be specified, but not both. ═══ 1.3.5.13. ASCIIZ32 Keyword ═══ This is used to log a string in a function compiled using 32-bit flat addressing and is coded as: ASCIIZ32=(address_spec,flag,maxlength), where: address_spec is a 0:32 bit flat memory address specification as described in Address Specification. flag is a mandatory parameter that identifies the level of indirection to be used on the address. It is one of: D[IRECT] I[NDIRECT][*[{+|-}iiiiiiii]]... IS DIRECT implies that the address points to a memory location, the contents of which are to be saved in the trace buffer. INDIRECT means that the address points to a flat address pointer which is dereferenced to obtain the target location to save in the trace buffer. The optional asterisks denote the level of indirection, one for each level. The indirect offsets iiiiiiii are added to or subtracted from the value found at the given level of indirection. IS(Indirect Segmented) means that the address points to a segmented address pointer which is dereferenced to obtain the target location to save in the trace buffer. maxlength is the maximum length of the string that will be saved in the trace buffer. It should be no greater than MAXDATALENGTH. The actual length to be traced will depend on where the zero terminating byte is found. If maxlength is 0 an error message will be given, and this tracepoint will be ignored. Note: When using dynamic tracing, the OS/2 kernel does not place the terminating null byte into the trace buffer; therefore the prefix byte must be used by the Trace Formatter to obtain the length of the string. ═══ 1.3.5.14. ASCIIZ Keyword ═══ This is used to log a string in a function compiled using 16-bit segment:offset addressing and is coded as: ASCIIZ=(address_spec,flag,maxlength), where: address_spec is a segmented memory address specification as described in Address Specification. flag is a mandatory parameter that identifies the level of indirection to be used on the address. It is one of: D[IRECT] I[NDIRECT][*[{+|-}iiiiiiii]]... IF DIRECT implies that the address points to a memory location, the contents of which are to be saved in the trace buffer. INDIRECT means that the address points to a far pointer which is a segmented address that is dereferenced to obtain the target location to save in the trace buffer. The optional asterisks denote the level of indirection, one for each level. The indirect offsets iiiiiiii are added to or subtracted from the value found at the given level of indirection. IF(Indirect Flat) means that the address points to a far pointer which is is a flat address that is dereferenced to obtain the target location to save in the trace buffer. Only far pointers may be dereferenced using segmented addresses. maxlength is the maximum length of the string that will be saved in the trace buffer. It should be no greater than MAXDATALENGTH. The actual length to be traced will depend on where the zero terminating byte is found. If maxlength is 0 an error message will be given, and this tracepoint will be ignored. Note: When using dynamic tracing, the OS/2 kernel does not place the terminating null byte into the trace buffer; therefore the prefix byte must be used by the Trace Formatter to obtain the length of the string. ═══ 1.3.5.15. Address Specification ═══ The syntax for specifying a memory address given here applies to the MEM32, MEM, ASCIIZ32 and ASCIIZ keywords above. An address is specified in one of the following forms: 1. Symbolic name form(can be used for MEM32, MEM, ASCIIZ32, and ASCIIZ). 2. Flat register form(can be used only for MEM32 and ASCIIZ32). 3. Segment register form(can be used only for MEM and ASCIIZ). ═══ 1.3.5.15.1. Symbolic Name Form ═══ This is coded as: .name[{+|-}nnnnnnnn]...[{+|-}(iiiiiiii)], where: name is a symbolic name of a memory location. The "." is required before the name. The debug information in the module is checked for the name and if not found and a MAP was given, the MAP is checked. An error message is output by the Trace Customizer if the symbol is not found and the trace definition is ignored. The name is case sensitive except under the conditions that follow. If the procedure containing name was not compiled with debug option then if name is a C language symbolic name it will be case sensitive and begin with an underscore "_" character unless it was declared with the Pascal naming convention, in which case the underscore is omitted and name is capitalized. nnnnnnnn (optional) is a displacement from the symbolic address. If hex the syntax is 0xnnnnnnnn. iiiiiiii (optional) is a displacement from the indirect address. If hex the syntax is 0xiiiiiiii. This specifies a displacement from the final address when using INDIRECT, IF(Indirect Flat) or IS(Indirect Segmented) addressing. ═══ 1.3.5.15.2. Flat Register Form ═══ This is coded as: Fbreg[{+|-}ireg]...[{+|-}nnnnnnnn]...[{+|-}(iiiiiiii)], where: breg is a flat model(0:32 bit) base register and is one of: EAX,EBX,ECX,EDX,ESP,EBP,ESI,EDI ireg (optional) is an extended data, base or index register. More than one ireg may be used to define a displacement from the flat register value to the memory location. It may be one of: EAX,EBX,ECX,EDX,EBP,ESI,EDI nnnnnnnn (optional) is an optional fixed displacement to be added to the address calculated in the registers. If hex the format is 0xnnnnnnnn. iiiiiiii (optional) is a displacement from the indirect address. If hex the syntax is 0xiiiiiiii. This specifies a displacement from the final address when using INDIRECT or IS(Indirect Segmented) addressing. This form of address is calculated at run time. ═══ 1.3.5.15.3. Segment Register Form ═══ This is coded as: Rsreg[{+|-}dreg]...[{+|-}nnnnn]...[{+|-}(iiiii)], where: sreg is a segment register and is one of: CS,DS,SS,ES,FS,GS dreg (optional) is a data, base or index register. More than one dreg may be used to define a displacement from the segment register value to the memory location. It is one of: BP,SP,SI,DI,AX,BX,CX,DX nnnnn (optional) is an optional fixed displacement to be added to the address calculated in the registers. If hex the syntax is 0xnnnn. iiiii (optional) is a displacement from the indirect address. If hex the syntax is 0xiiii. This specifies a displacement from the final address when using INDIRECT or IF(Indirect Flat) addressing. This form of address is calculated at run time. ═══ 1.4. Formatting Trace Data ═══ This section gives a brief description of the formatting process as an aid to generating correct formatting strings. Each trace record stored in the RAS buffer consists of a header followed by a number of variable length trace data records. The header identifies the major and minor code, time stamp, process ID, etc., and the total length of the trace data for that trace record. Each MEM32, MEM, ASCIIZ32, or ASCIIZ data statement, coded in the trace source file for a tracepoint, produces an associated data record to be stored in the trace buffer. The data records consist of a 3-byte prefix followed by the trace data. This prefix consists of a status byte followed by the length of the data for that statement. The status byte indicates whether valid data has been traced. Dynamic trace can only trace data that is resident in memory at the time that the tracepoint is executed. Data may not be able to be traced for two reasons: it resides in a page that is currently paged out or the address specified is invalid. This latter case usually occurs due to tracing indirectly via invalid pointer variables. In either of these two cases dynamic trace sets the status byte accordingly and stores the pointer in the place of the wanted data. No more data is attempted to be traced for this invocation of the tracepoint, but tracing will resume the next time this tracepoint is encountered. Since the position of these prefix bytes, within a trace record, is dependent on the data being traced and the number of MEM32, MEM, ASCIIZ32, or ASCIIZ statements, the Trace Formatter must be told when to expect the prefix in the trace record. This is the purpose of the %P formatting control. It must be coded in the formatting string at every place a data record is expected. Note: With ASCIIZ and ASCIIZ32 commands, the prefix must be used to obtain the length of the string since the string is not null terminated. ═══ 1.5. Sample Trace Source Files ═══ This section gives four sample TSF files. The first is for a module written in a mix of C and MASM and compiled with 16:16 segmented addressing. The second was compiled with 0:32 flat addressing. The third module consists of routines, some which were compiled using 16-bit segmented addressing and some that were compiled using 32-bit flat addressing. The fourth is for monitoring function references in a module. ═══ 1.5.1. TSF Using 16-bit Segmented Addressing ═══ ; Trace source file for the xxx dynalink. Compiled with 16-bit offsets. MODNAME=\c\src\xxx.dll MAJOR=0xC5 MAXDATALEN=200 ; We will want to trace up to 200 bytes in any one trace call. TYPELIST NAME=API,ID=08, NAME=SYS,ID=04, NAME=PRE,ID=02, NAME=POST,ID=64 GROUPLIST NAME=MEM,ID=1, NAME=FS,ID=3 /* The following tracepoint does not need debug info, only a MAP file is necessary with label xxalloc public in it. The program must be compiled in 16-bit mode because segmented addressing is used(ASCIIZ instead of ASCIIZ32). This logs the word registers AX and BX and the string pointed at by DS:DI for a max of 20 bytes. */ TRACE MINOR=25, TP=.xxalloc, OPCODE=0x8B, /* the opcode is optional */ TYPE=(API,PRE), GROUP=MEM, DESC="(OS) xxalloc Pre-Invocation", FMT =" AX = %W ", FMT =" upper BX = %B", FMT =" lower BX = %B", FMT =" param = %P%S", REGS=(AX,BX), ASCIIZ=(RDS+DI,DIRECT,20) /* This defines a tracepoint at Foo label. The ten words to log are found indirectly through SS:SP. Note that each word needs a format control but since only one memory access was done, one prefix control is needed. */ TRACE MINOR=0xB0, TP=.Foo, TYPE=(SYS), GROUP=FS, DESC="(OS) Foo Pre-Invocation", FMT=" First Five words = %P%W%W%W%W%W", FMT=" Three words ignored %I6", FMT=" Last Two Words = %W%W", MEM=(RSS+SP,INDIRECT,20) /* This defines a tracepoint at Goo label. DS:DI points to a structure whose second field is a pointer to an ASCIIZ string. The offset from the first field in the structure is 4 bytes. Max string size to log is 40 bytes. */ TRACE MINOR=0xB1, TP=.Goo, TYPE=(SYS), GROUP=FS, DESC="(OS) Goo Pre-Invocation", FMT=" Second field in struct points to %P%S", ASCIIZ=(RDS+DI+4,INDIRECT,40) /* This defines a tracepoint at Hoo label. DS:DI points to memory that contains a pointer to a structure. We want to log the third field in the structure(offset 6 from begin of structure). */ TRACE MINOR=0xB2, TP=.Hoo, TYPE=(SYS), GROUP=FS, DESC="(OS) Hoo Pre-Invocation", FMT=" Third field in struct is doubleword = %P%D", MEM=(RDS+DI,INDIRECT*+6,4) /* This defines a tracepoint at Zoo label. DS:DI points to memory that contains a pointer to end of a structure. We want to log the last field in the structure(offset -2 from end of structure). */ TRACE MINOR=0xB3, TP=.Zoo, TYPE=(SYS), GROUP=FS, DESC="(OS) Zoo Pre-Invocation", FMT=" Last field in struct is word = %P%W", MEM=(RDS+DI,INDIRECT*-2,2) /* This defines a tracepoint at procedure CheckIT. This is a C routine compiled with debug information. The data to log is an ASCIIZ string called NameIt. */ TRACE MINOR=0xB3, TP=.CheckIt, TYPE=(PRE), GROUP=FS, DESC="(OS) CheckIt Pre-Invocation", FMT=" NameIt = %P%S", ASCIIZ=(.NameIt,DIRECT,64) /* This defines a tracepoint at the return point of the procedure CheckIt, a C routine compiled with debug. Status_Rec is a record variable. We want to log the age field(four bytes from the begin of Status_Rec), the name(six bytes from Status_Rec that points to an ASCIIZ string), the age of the next Status_Rec (a pointer to the next Status_Rec is ten bytes from the begin of Status_Rec, the age is four bytes from the begin of the next Status_Rec). */ TRACE MINOR=0x80B3, TP=.CheckIt,RETEP, TYPE=(POST), GROUP=FS, DESC="(OS) CheckIt Post-Invocation", FMT=" Status_Rec.age = %P%W", FMT=" Status_Rec.name = %P%S", FMT=" Status_Rec.next->age = %P%W", MEM=(.Status_Rec+4,DIRECT,2), ASCIIZ=(.Status_Rec+6,INDIRECT,64), MEM=(.Status_Rec+10,INDIRECT*+4,2) /* This defines a tracepoint at line 58 in the source file check.c Debug info is needed to use this type of tracepoint. v_ptr is a pointer to a variable sized record. The length is 4 bytes past the beginning of the record. Log that record. */ TRACE MINOR=0x71B4, TP=@check.c,58, TYPE=(SYS), GROUP=FS, DESC="(OS) CheckIt before allocation", FMT=" Variant Record = %P%W%D%U", LEN=(v_ptr,INDIRECT*+4), MEM=(.v_ptr,INDIRECT,LEN) /* This does not define a tracepoint, it only defines a trace formatting string for minor code 181(B5 hex). */ TRACE MINOR=0xB5, TP=@STATIC, DESC="(OS) StaticProcedure Pre-Invocation", FMT=" DI = %W FLAGS = %W" /* This defines a tracepoint at routine LookUp, but no data is to be logged, only the DESC will show up in the Trace log when the tracepoint is formatted. */ TRACE MINOR=0xB6, TP=.LookUp, TYPE=(SYS), GROUP=FS, DESC="(APP) LookUp Pre-Invocation", ═══ 1.5.2. TSF Using 32-bit Addressing ═══ ; Trace source file for the NEW dynalink. Compiled with 32-bit offsets. MODNAME=NEWCALLS.DLL MAJOR=241 MAXDATALEN=200 ; We will want to trace up to 200 bytes in any one trace call. TYPELIST NAME=API,ID=08, NAME=SYS,ID=04, NAME=PRE,ID=02, NAME=POST,ID=64 GROUPLIST NAME=MEM,ID=1, NAME=FS,ID=3 /* The following tracepoint does not need debug info, only a MAP file is necessary with label NewAllocSeg public in it. The program must be compiled in 32-bit mode because flat addressing is used(ASCIIZ32 instead of ASCIIZ). This logs lower word of EAX, the double word of EBX and the string at the address specified by ESP with offset ESI. */ TRACE MINOR=45, TP=.NewAllocSeg, TYPE=(API,PRE), GROUP=MEM, DESC="(NEW) NewAllocSeg Pre-Invocation", FMT =" AX = %W ", FMT =" EBX = %F", FMT =" param = %P%S", REGS=(AX,EBX), ASCIIZ32=(FESP+ESI,DIRECT,20) /* This defines a tracepoint at Foo label. The ten words to log are found indirectly by using EBP with offset EDI. Note that each value logged needs a format control. */ TRACE MINOR=0xD0, TP=.Foo, TYPE=(SYS), GROUP=FS, DESC="(NEW) Foo Pre-Invocation", FMT=" First Five words = %P%W%W%W%W%W", FMT=" Three words ignored %I6", FMT=" Last Two Words = %W%W", MEM32=(FEBP+EDI,INDIRECT,20) /* This defines a tracepoint at Goo label. EAX + EDI points to a structure whose second field is a pointer to an ASCIIZ string. The offset from the first field in the structure is 4 bytes. Max string size to log is 40 bytes.*/ TRACE MINOR=0xD1, TP=.Goo, TYPE=(SYS), GROUP=FS, DESC="(NEW) Goo Pre-Invocation", FMT=" Second field in struct points to %P%S", ASCIIZ32=(FEAX+EDI+4,INDIRECT,40) /* This defines a tracepoint at Hoo label. EBP + EDI points to memory that contains a pointer to a structure. We want to log the third field in the structure(offset 6 from begin of structure). */ TRACE MINOR=0xD2, TP=.Hoo, TYPE=(SYS), GROUP=FS, DESC="(NEW) Hoo Pre-Invocation", FMT=" Third field in struct is doubleword = %P%D", MEM32=(FEBP+EDI,INDIRECT*+6,4) /* This defines a tracepoint at Zoo label. EAX + EDI points to memory that contains a pointer to end of a structure. We want to log the last field in the structure(offset -2 from end of structure). */ TRACE MINOR=0xD3, TP=.Zoo, TYPE=(SYS), GROUP=FS, DESC="(OS) Zoo Pre-Invocation", FMT=" Last field in struct is word = %P%W", MEM=(FEAX+EDI,INDIRECT*-2,2) /* This defines a tracepoint at procedure CheckIT. This is a C routine compiled with debug information. The data to log is an ASCIIZ string called NameIt. */ TRACE MINOR=0xD3, TP=.CheckIt, TYPE=(PRE), GROUP=FS, DESC="(NEW) CheckIt Pre-Invocation", FMT=" NameIt = %P%S", ASCIIZ32=(.NameIt,DIRECT,64) /* This defines a tracepoint at the return point of the procedure CheckIt, a C routine compiled with debug. Status_Rec is a record variable. We want to log the age field(four bytes from the begin of Status_Rec) the name(six bytes from Status_Rec that points to an ASCIIZ string) and the age of the next Status_Rec (a pointer to the next Status_Rec is ten bytes from the begin of Status_Rec, the age is four bytes from the begin of the next Status_Rec). */ TRACE MINOR=0x80D3, TP=.CheckIt,RETEP, TYPE=(POST), GROUP=FS, DESC="(NEW) CheckIt Post-Invocation", FMT=" Status_Rec.age = %P%W", FMT=" Status_Rec.name = %P%S", FMT=" Status_Rec.next->age = %P%W", MEM32=(.Status_Rec+4,DIRECT,2), ASCIIZ32=(.Status_Rec+6,INDIRECT,64), MEM32=(.Status_Rec+10,INDIRECT*+4,2) /* This does not define a tracepoint, it only defines a trace formatting string for minor code 223(DF hex). */ TRACE MINOR=0xDF, TP=@STATIC, DESC="(NEW) StaticProcedure Pre-Invocation", FMT=" DI = %W FLAGS = %W" /* This defines a tracepoint at routine LookUp, but no data is to be logged, only the DESC will show up in the Trace log when the tracepoint is formatted. LookUp is a C language routine not compiled with debug and not declared with Pascal calling conventions; the underscore is needed for this label. */ TRACE MINOR=0xE0, TP=._LookUp, TYPE=(SYS), GROUP=FS, DESC="(NEW) LookUp Pre-Invocation" ═══ 1.5.3. TSF Using Mix of 16-bit and 32-bit Addressing ═══ ; Trace source file for the MIXED dynalink. ; Parts were compiled with 16-bit compiler, some with 32-bit compiler. ; The developer must know how the parameters being sent in are ; to be addressed, whether they are segmented or flat addresses. MODNAME=MIXCALLS.DLL MAJOR=250 MAXDATALEN=200 ; We will want to trace up to 200 bytes in any one trace call. TYPELIST NAME=API,ID=08, NAME=SYS,ID=04, NAME=PRE,ID=02, NAME=POST,ID=64 GROUPLIST NAME=MEM,ID=1, NAME=FS,ID=3 /* The following tracepoint is for the routine MixStub. This was compiled using segmented addressing and one of the parameters to it is a pointer to a control block called mix_ctrl. This pointer, found at SS:SP, is a flat address because the routine that sent it was compiled with the flat addressing specification. This logs the mix_ctrl block for 6 bytes. */ TRACE MINOR=95, TP=.MixStub, TYPE=(API,PRE), GROUP=MEM, DESC="(OS) MixStub Pre-Invocation", FMT =" mix_ctrl = %P%W %W %W", MEM=(RSS+SP,IF,6) /* is an indirect flat address */ /* The following is for the routine FlatStub. This was compiled using 32-bit flat addresses. A parameter to flatstub is a pointer called p_seg_info. This pointer is a segmented address because the routine calling flatstub was compiled using 16-bit segmented addressing. Log where p_seg_info points for 2 bytes. */ TRACE MINOR=0xf0, TP=.FlatStub, TYPE=(SYS), GROUP=FS, DESC="(OS) FlatStub Pre-Invocation", FMT=" seg_info = %P%W", MEM32=(.p_seg_info,IS,2) /* value p_seg_info is a 16-bit */ /* segmented address */ ═══ 1.6. Trace Customizer Messages ═══ The messages generated by the Trace Customizer are given below. In addition to the message itself, the source line in error is displayed. Errors in the FATAL and SEVERE category will cause the compiler to abort immediately. ERROR messages will normally cause a tracepoint definition to be discarded and processing continues with the next definition. WARNING messages will allow a valid tracepoint definition to be produced, and the results will normally be as expected. ═══ 1.6.1. Fatal Messages ═══ Value Message TRCERR_NO_TSF TSF file not specified TRCERR_NO_FILE file not found or access denied : %s TRCERR_FILE_OPEN cannot open file : %s TRCERR_FILE_ACCESS error accessing file : %s TRCERR_FILE_WRITE error writing to file : %s TRCERR_NO_MEM unable to allocate more memory TRCERR_TOOMANYRECS too many tracepoints in file TRCERR_FILE_READ error reading file: %s, Rc = %s TRCERR_FILE_MOVE changing file pointer for: %s, Rc = %s TRCERR_BAD_EXEH unknown EXE header type for: %s TRCERR_COMBINE_PATH invalid path specified in combine file TRCERR_TOOMANYTFF max TFF files to combine is 50 TRCERR_DIF_MAJOR all TFFs not have same major code, file: %s TRCERR_MAP_EXTN invalid MAP file extension given in: %s TRCERR_NO_TCF TCF file not specified TRCERR_FILENAME filename to long: %s TRCERR_TOKENLENGTH token in TSF file exceeds %s bytes ═══ 1.6.2. Severe Messages ═══ Value Message TRCERR_NOMODNAME module name not specified TRCERR_UNEXPECTEDEOF premature end of file encountered TRCERR_SYNTAX_ABORT syntax error : missing '%s' before '%s' TRCERR_NLINLITERAL new line in literal TRCERR_NULLINLITERAL NULL in literal TRCERR_KEYWORD keyword '%s' expected, '%s' found TRCERR_NO_SYMBOLIC symbolic info not given for %s TRCERR_MULTIPLEMAJOR MAJOR redefinition TRCERR_MULTIPLEMAXDL MAXDATALENGTH redefinition TRCERR_LINE_SIZE line too long in input file: %s ═══ 1.6.3. Error Messages ═══ Value Message TRCERR_NOTANUMBER number expected, '%s' found TRCERR_SPURIOUS unexpected: %s, ignored TRCERR_NOMINOR minor code not specified TRCERR_MINORRANGE minor code out of range TRCERR_MULTIPLETYPL TYPELIST redefinition, ignored TRCERR_MULTIPLEGROUPL GROUPLIST redefinition, ignored TRCERR_MULTIPLETP TP redefinition, tracepoint ignored TRCERR_MULTIPLEMINOR MINOR redefinition, tracepoint ignored TRCERR_MULTIPLEOPCD OPCODE redefinition, tracepoint ignored TRCERR_SYNTAX_SKIP syntax error: missing '%s' before '%s' TRCERR_OPCODETOOBIG opcode: %s out of range TRCERR_BADOPCODE opcode at TP address cannot be traced TRCERR_OPCODEMISMTCH opcode mismatch at address to apply TP TRCERR_NOTAREG register expected, '%s' found TRCERR_BADSYMBOL symbol not found: %s TRCERR_BADADDRESS address not found TRCERR_NOTASEGREG segment register expected, '%s' found TRCERR_INCOMPLETE trace record incomplete, '%s' required TRCERR_TPRTOOBIG RPN command record exceeds 255 bytes TRCERR_BADPARM invalid parameter: '%s', ignored TRCERR_BADID invalid ID: %s, ignored TRCERR_MULTIPLEVENTNM group/type redefinition: %s, ignored TRCERR_MULTIPLETYPEID typeid redefinition: %s, ignored TRCERR_MULTIPLEGRPID groupid redefinition: %s, ignored TRCERR_INVALIDADDRESS invalid address specified: %s TRCERR_BADLINENUM line number past end of code for file %s TRCERR_NO_CV Debug info does not exist for: %s TRCERR_INVALIDLINENUM line number missing or invalid: %s TRCERR_BADFILENAME filename %s not found in Debug info TRCERR_DUP_MINOR duplicate minor code = %s, ignored TRCERR_DUP_TFFMINOR duplicate minor code = %s in file %s, ignored TRCERR_VAR_LEN variable LEN parameter not preceding TRCERR_RPN_OVER RPN stack limit of 16 exceeded TRCERR_INVALIDREG invalid flat register specified: %s TRCERR_FMT_LONG total FMT format specs above 4096 bytes TRCERR_ZEROLENGTH zero length specified, tracepoint ignored TRCERR_DUP_SEGOFF duplicate TP address, ignored ═══ 1.6.4. Warning Messages ═══ Value Message TRCERR_INVALIDLENGTH MAXDATALENGTH out of range, 512 used TRCERR_NOTATYPE typename unknown: %s, ignored TRCERR_NOTAGROUP groupname unknown: %s, ignored TRCERR_BAD_EXTN file: %s, extension invalid, using: %s TRCERR_EXPECTED '%s' expected before '%s', one assumed TRCERR_TOOMANYNAMES too many %s, first 16 types, 48 groups used TRCERR_NAMETOOBIG name too long: %s, first 8 characters used TRCERR_NEXTLINENUM linenum in file: %s not found, using #%s TRCERR_BAD_OBJ bad object number: %s used for file %s TRCERR_BAD_OFFSET offset %s is invalid for object number %s TRCERR_BAD_PAGE page tracepoint to be applied at not valid TRCERR_MAXLEN_EXCEED MAXDATALENGTH to log could be exceeded TRCERR_INVALIDMAJOR MAJOR out of range, 1 used TRCERR_INDEXTRUNC index too large, high word ignored