|=============================================================================| | Dr. Frank & Tools | |=============================================================================| PREVIOUS USERS: See the "What's New" and "DFA2" sections for a quick update on what's new and improved. ******** Table of sections ******** Quick Start (For those who can't stand to read the full documentation) Introduction (What is Dr. Frank & Tools) What can Dr. Frank show you??? Preparing your programs for Post-mortem debugging Running Dr. Frank Interpreting the results Post-processing the log file Logical Addresses DRFRANK BUILDSYM TMAPSYM EXEMAP DFA2 EXETDS What's new Support |=============================================================================| | Quick Start ( For those who can't stand to read the full documentation | |=============================================================================| If you can't bear to read the full documentation, here's how to use Dr. Frank. It's assumed you know what you're doing here. If these steps aren't clear, please read the actual documentation below. 1) Make sure you have the correct TOOLHELP.DLL installed, and in your path. 2) Run Windows, and run DRFRANK.EXE. 3) Do whatever makes the UAE occur. 4) Look at the log file (DRFRANK.LOG in the windows directory). 5) Go to the directory where the log file is, and run: "DFA2 DRFRANK.LOG DRFRANK.BIN" 6) Look at the DFA.OUT file. 7) Resolve to read the full documentation, because there's a lot you're missing. |=============================================================================| | Introduction | |=============================================================================| Dr. Frank (DRFRANK.EXE) is a program that will help you perform a post-mortem on your Unrecoverable Application Errors (UAE's) with Microsoft Windows. It is part of a suite of tools (described below) to assist programmers, and was written with the programmer in mind, rather then the non-programmer. When an exception occurs, Dr. Frank will intercept it, and write a file (or 2) to your disk with information helpful to finding the cause of the exception. Since Dr. Frank is oriented towards developers, it writes out a short, concise report by default. If however, you do want more information, there are several .INI file options which allow you to configure the report to your needs. Dr. Frank is similar to DRWATSON, and uses the same TOOLHELP.DLL, which is currently in beta testing. TOOLHELP.DLL is shipped with BC++ 3.0, and is also available on Compuserve. It can be found either with DRWTSN.ZIP or as TLLHLP.ZIP on WINADV. The names and locations may move around, so your best bet is to search across all libraries for TOOLHELP or WATSON. DRWATSON and TOOLHELP.DLL are Microsoft products. There are many features that are not discussed in the general "how-to" sections of this file. If you're so inclined, feel free to read the program reference sections to get a better idea of what Dr. Frank & Tools can do. |=============================================================================| | What can Dr. Frank show you??? | |=============================================================================| The most important feature of Dr. Frank is it's ability to show you the "call stack". The call stack shows you what calls your program was executing when the exception occured. Additionally, if you post-process the log file, you can obtain the names and values of your local and global variables (if you have TD debug information available). To the CPU, the call stack is just a series of addresses. However, with a little help from you, Dr. Frank can give you the names of the functions and procedures associated with the addresses, instead of just a series of addresses. With this information, you can very quickly pinpoint where the program is blowing up. Additionally, Dr. Frank can show you the CPU registers at the time of the exception, as well as a disassembly of the instruction that caused the exception. Dr. Frank can also display information concerning the state of Windows when the exception occurred. This includes things like available memory, which version of Windows, events in the programs message queue, etc... |=============================================================================| | Preparing your programs for Post mortem debugging | |=============================================================================| In order to get function names for the call stack, you need to provide symbolic information to Dr. Frank. Dr. Frank can work without any symbolic information, but you'll find that having symbolic information greatly enhances your ability to pinpoint the problem. There are 2 forms of symbolic information that Dr. Frank & Tools understand: 1) .SYM files. These are used by Dr. Frank at the time of the exception. 2) Turbo Debugger debug information. This is used after after the exception occurs. There are advantages to both: - .SYM files are used directly by Dr. Frank when the exception occurs. Thus, there is no need to run another utility afterwards. - .SYM files can be used by other programs, such as Dr. Watson, the Windows Debug Kernel, WDEB386, etc... - Turbo Debugger debug information contains line number information. In addition to giving you function/procedure names, it can also give you the source file and line number for call stack entries. You will also be able to see the names and values of your programs variables. - Turbo Debugger debug information can "find" static functions that .SYM files might not contain information for. There are utilities in Dr. Frank to create and use both kinds of debug information. ======== Creating .SYM files ======== - For your own programs, you first need to create a .MAP file, and then create a .SYM file from that. If you're using a Borland IDE, you should select the linker options that produces a .MAP file. If you're letting BCC invoke TLINK, use the "-M" option on the BCC command line. If you're invoking TLINK yourself, use the "/m" command line option, and make sure that you're not using "/x" (no map file). If you're using TPCW, use the /GD command line switch. If you're using another compiler, do whatever is necessary to create a .MAP file with Public symbols. Next, if your .MAP file is from a Borland product, use TMAPSYM to create the .SYM file for it. For instance: "TMAPSYM mymodule.map" will create MYMODULE.SYM in the current directory. If you're using another compiler, use MAPSYM, provided with the MS SDK to create the .SYM file. If your using a makefile, you can add TMAPSYM as another rule command after the link. - For programs that you don't have source to, i.e., USER.EXE, GDI.EXE, you can still create .SYM files The easiest way to do this is to use BUILDSYM. To do this, make sure that the programs that come with Dr. Frank are somewhere in your path. Next, go to the directory that contains the file(s) that you want to create .SYM files for, i.e., "C:\WINDOWS\SYSTEM" Lastly, type "BUILDSYM", followed by the file specification that you want to build .SYM files for. For instance: "BUILDSYM *.EXE" will create .SYM files for all the .EXE files in the current directory. You'll probably want to build .SYM files in the WINDOWS directory, as well as the SYSTEM subdirectory below it. If you have the SDK, you may wish to make sure you have backups of the SDK provided .SYM files, although the .SYM files created by BUILDSYM are usually superior to the SDK provided .SYM files. Note: The .SYM file must be in the same directory as the .EXE or .DLL that it corresponds to. ======== Creating Turbo Debugger information ======== - For your own programs, you should have the compiler/linker produce debug information. If you're using a Borland IDE, make sure that the option to generate debug info is on. If you're letting BCC invoke TLINK, specify the "-v" option in the BCC command line. If you're invoking TLINK yourself, specify the /V option. If you're using TPCW, use the /V switch. If you're using a compiler that generates CodeView information, and have a copy of Turbo Debugger that has TDCONVRT included, you may be able to convert the CodeView information to TD information with it. - For programs that you don't have source to, i.e., USER.EXE, GDI.EXE, you can still create TD debug information with EXETDS. Go to the directory that contains the file that you'll be creating TD info for, i.e., "C:\WINDOWS\SYSTEM". Enter "EXETDS", followed by the filename, i.e., "EXETDS GDI.EXE" Note: The .TDS file must be in the same directory as the .EXE or .DLL that it corresponds to. |=============================================================================| | Running Dr. Frank | |=============================================================================| The easiest way to use Dr. Frank is to put it in the "load=" section of your WIN.INI. Upon starting up, Dr. Frank will minimize itself. No additional interaction is required on your part. When an exception occurs, Dr. Frank will write it's report out to a log file. The default name for the file is "DRFRANK.LOG" in the Windows directory. Typically, this is "C:\WINDOWS\DRFRANK.LOG". Next, you will see the "Unrecoverable Application Error" box. Click on the "OK" button. Next, you will see a dialog box from Dr. Frank that tells you what happened. If you wish to stop Dr. Frank, you can select "close" from its system menu. |=============================================================================| | Interpreting the log file | |=============================================================================| Here is a sample Dr. Frank Failure report, followed by annotations enclosed in preceeded by [] -------- Dr. Frank failure report - 11/20/1991 21:25:07 Exception 13 at KERNEL 0001:6B35 (0105:6B35) (TASK=ABC) [] The first line contains the date and time that the exception occurred. [] [] The next line tells you an exception 13 occurred in the KERNEL module, [] at logical address 0001:6B35. The "(0105:6B35)" is the actual CS:IP [] of where the exception occured. See the "Logical Address" section of [] this file if you're not familiar with the concept. The task that was [] executing at the time was "ABC". Disassembly: 0105:6B35 REPNE SCASB 0105:6B37 MOV AX,CX 0105:6B39 NEG AX 0105:6B3B DEC AX 0105:6B3C DEC AX [] The first instruction is the instruction that the CPU was attempting [] to excute when the exception occcured. Stack Trace: 0 KERNEL LSTRLEN + 000D CS:IP 0001:6B35 (0105:6B35) SS:BP 096D:1964 C:\WINDOWS\SYSTEM\KRNL386.EXE 1 USER USER.733 + 00E9 CS:IP 0029:0672 (05ED:0672) SS:BP 096D:19D2 C:\WINDOWS\SYSTEM\USER.EXE 2 USER MESSAGEBOX + 008D CS:IP 0001:9232 (04AD:9232) SS:BP 096D:19F6 C:\WINDOWS\SYSTEM\USER.EXE 3 ABC function1(unsigned long,unsigned long,unsigned long) + 001B CS:IP 0001:01DA (0965:01DA) SS:BP 096D:1A0A C:\DRFRANK\ABC.EXE 4 ABC WINMAIN + 008A CS:IP 0001:02DC (0965:02DC) SS:BP 096D:1A9C C:\DRFRANK\ABC.EXE 5 ABC CS:IP 0001:00B3 (0965:00B3) SS:BP 096D:1AAA C:\DRFRANK\ABC.EXE [] The topmost entry is the function/proceedure that you were in when the [] exception/UAE occured. In this case, the CS:IP was 0Dh bytes past the [] start of the LSTRLEN function in the KRNL386 module. [] [] To read a stack trace, start at the bottom, and work your way to the top. [] in this case: [] [] Some unknown function in module ABC called WINMAIN. [] WINMAIN in module ABC called FUNCTION1 in module ABC [] FUNCTION1 in module ABC called MESSAGEBOX in module USER. [] MESSAGEBOX in module USER called the 733'rd entry point in module USER [] entry point 733 called LSTRLEN in module KERNEL. [] At that point, the exception 13 occured. [] [] Note: You'll only have function names if you have a .SYM file for [] that module. If you have the SDK, you should have .SYM files for USER [] KRNLx86, and GDI. If you don't, you can build them yourself with the [] BUILDSYM utility, described elsewhere. Registers: AX 0000 BX 14DC CX FFFF DX 0000 SI 0002 DI 0000 SP 14DC BP 1542 IP 6B35 FL 0246 CS 0105 Limit: 9A7F execute/read DS 06E5 Limit: 4A9F read/write ES 0000 Limit: 0000 NULL SS 0B9D Limit: 269F read/write Message Queue: No messages retrieved yet Waiting in queue: hWnd: 0000 msg: 1234 wParam: 0000 lParam: 00000001 [] If possible, Dr. Frank will tell you what the last message retrived [] from the message queue was, as well as tell you about any messages [] that were waiting to be prcessed. Heaps: USER Max Size: F42F Free CE92 (83%) GDI Max Size: F79F Free D73E (86%) System info: Running in enhanced mode under Windows 3.0 debug version CPU: 80386 Largest Free memory block: D80000 bytes Total linear memory space: f5f000 bytes Free linear memory space : d81000 bytes Swap file Pages: f5f (f5f000 bytes) -------- ======== Additional information: Note: The function name given must be taken with a grain of salt. Dr. Frank will look in the .SYM file for the closest symbol name that appears before the address in the call stack. Some .SYM files do not contain information for all functions. Thus, the function name appearing in the log file will be that of the closest function in the .SYM file thats address precedes the frame address. If the offset field appears too high, be suspicious. Note: What you see in the Message Queue display is not necessarily the last message the program received. Windows may bypass the message queue, i.e., SendMessage(), so keep that in mind when using this information. Also, the message queue structure is not documented to my knowledge, so please let me know if you see something out of the ordinary. ======== Advance Features The optional Verbose Stack Trace section is for people who wish to see what was on the stack at the time of the exception. For each stack frame that doesn't exceed 256 bytes, a hex dump is performed, starting at the SS:BP for that frame. This data can be used to get the values of parameters that were passed to the function. NOTE: It is usually easier to let DFA2 do the hard work of figuring out what your paramters here. However, there may be cases where you don't have TD debug information, so this feature remains. Example: MessageBox() takes 4 parameters, and is a FAR PASCAL function. On the stack, you will have: [BP+0] ; Previous BP, incremented by 1 [BP+2] ; Far return address [BP+6] ; wType [BP+8] ; lpCaption [BP+0C] ; lpText [BP+10] ; hWnd Here's an example of a verbose stack trace entry: -------- 2 USER CS:IP 058D:9232 SS:BP 0BA5:15D4 MESSAGEBOX + 008D 0000: E9 15 85 01 8D 0B 00 00 96 09 E5 06 00 00 00 00 0010: 00 00 3E 02 -------- which you can read as: [BP+0] -> 15E9 -> Previous BP, incremented by 1 [BP+2] -> 0B8D:0185 -> Far return address [BP+6] -> 0 -> wType [BP+8] -> 06E5:0996 -> lpCaption [BP+0C] -> 0000:0000 -> lpText [BP+10] -> 0 -> hWnd |=============================================================================| | Post-processing the log file | |=============================================================================| Although the Dr. Frank log file is oftentimes enough to help you locate the problem, you may also need the additional assistance of TD debug information. To read and interpret the TD debug information at the time of the exception would cause potential system stability problems. The system might crash before the information had been written to disk. Therefore, the TD debug information is merged with the exception report after the exception has been cleared away, and the system is in a more stable state. The post-processing utility for Dr. Frank is called DFA2.EXE (to distinguish it from an earlier, incompatible version called DFA.EXE). By default, after a Dr. Frank has written out the log file, it writes a second file called DRFRANK.BIN. This file will appear in the same directory as the log file. It contains binary information about the task that was running, including copies of the data segments at the time of the exception. DFA2 will take the log file, and the DRFRANK.BIN file, and produce an output file that contains a stack trace, a listing of what selectors were in use by the failed task, and the names and values of your global variables. To run DFA2, you simply specify the file names for it to process. Typically, you will type the following: DFA2 DRFRANK.LOG DRFRANK.BIN The output is written to a file called DFA.OUT. You do not have to specify the second file name, but you will only see the strack trace information in that case. DFA2 has options not described here. See the DFA2 section for more details. Note: There will only be 1 DRFRANK.BIN file written per windows session. It is therefore important that you post-process the file as soon as possible after the exception. In addition, it is a very good idea to either rename, or delete the log file after the post-processing. DFA2 "associates" the first entry in the log file with the DRFRANK.BIN file. If you have multiple entries in the log file, you may not get the results you expect. To alleviate this problem as much as possible, I have changed Dr. Frank from previous versions. It will now default to overwriting any existing log file the first time an exception occurs in a given Windows sessions. Subsequent exceptions in that session will be appended to the file. |=============================================================================| | Logical Addresses | |=============================================================================| To understand a Dr. Frank log file, it is important to understand the difference between a "logical" segment, and a selector. Windows .EXE files are called "New EXE" files, because they have a different format then traditional MS-DOS files. When New EXE files are linked, each segment is placed in a different section of the file. At the same time, a segment table is created, which allows Windows and other programs to quickly find the data for a particular segment. When referring to a particular segment, its position in the segment table is used. Thus, the first segment in the table is logical segment 1, the second is logical segment 2, etc... You can determine the number of segments, their size, and other information by running TDUMP (A Turbo Debugger utility) on the file. Alternatively, if you generate a .MAP file for your program, you can obtain the same information. When the program is loaded, Windows allocates space for each logical segment and assigns it a unique selector. The code for the logical segments is then read into memory, using the assigned selector. Note: For any given .EXE or .DLL, the logical segment that a procedure or function is in will never change. The selector value on the other hand, depends upon what selector Windows decided to allocate for the particular logical segment. In other words, the selector Windows uses for a particualar logical segment can change between different invocations of the .EXE or .DLL. A logical address is comprised of a module name, a logical segment, and an offset. For instance "USER 0001:65EA" means offset 65EA in the first segment of USER.EXE. Logical addresses are what is used in the Publics section of a .MAP file. A physical address is comprised of a selector and an offset. A typical physical address that windows might create would be 09CD:65EA. Physical addresses are what the CPU works with. In the log file, addresses are given in terms of the the logical addresses as well as physical address The logical address appears first, followed by the physical address in ()'s. |=============================================================================| | DRFRANK | |=============================================================================| Since exception can not occur in real mode, Dr. Frank will only run if used in Windows Standand and Enhanced modes. Options for Dr. Frank are specified in the WIN.INI file as follows: LogDir=[directory to put log file]. This defaults to the Windows directory if none is specified. LogFileName=[file name to put log file] There should not be any path information in this string. If you need to specify a log file directory, use the LogDir option. If LogFileName is not specified, DRFRANK.LOG is used. NewLog=0/1 Specifying 0 will cause Dr. Frank to always append reports to the previous log file. Specifying 1 will cause Dr. Frank to overwrite the previous .LOG file the first time an exception occurs. Subsequent exceptions that occur during the same Windows session will be appended to the .LOG file. The default is 1, or always create a new logfile when the first exception occurs. ShowSystemInfo=0/1 Specifying 1 will cause Dr. Frank to output the Task list, the Module list, and information about the USER & GDI heaps. This information is omitted from the report if 0 is specified. ShowSystemInfo=0 is the default. StackData=0/1 Specifying 1 will cause Dr. Frank to add a verbose stack trace display to the end of the log file. Each entry displays the memory at a positive offset from the SS:BP for that stack frame. If there are > 256 bytes between 2 successive stack frames, the memory display is omitted for that frame. Specifying 0 for the StackData will cause the verbose stack trace to not be generated. This is the default. AuxOut=0/1 Specifying 1 will cause Dr. Frank to write an abbreviated form of it's report to AUX when writing the .LOG file. To use this, you should have either be using a device driver that redirects AUX to a second monitor, or a terminal connected to STDAUX. The defualt is 0, or no output to AUX. Here is an example of my entry in the WIN.INI file: [DrFrank] logdir=C:\DRFRANK NewLog=1 StackData=1 ShowSystemInfo=0 AuxOut=1 |=============================================================================| | BUILDSYM | |=============================================================================| BUILDSYM.EXE was written to allow you to automate the process of building .SYM files. For instance, you may not have Microsoft Windows Software Development Kit. Thus, you do not have .SYM files for the Windows DLLs such as USER, GDI, KRNL286, and KRNL386. Or, you may have the SDK, but want the undocumented entry points to be included in your .SYM files. You could manually go in and EXEMAP each file, then TMAPSYM the .MAP file, and then delete the .MAP file. What a drudge... BUILDSYM will do all of that for you, and do it on multiple files. BUILDSYM has 1 command line argument, which is a filespec that can include wildcards. For instance, "BUILDSYM C:\WINDOWS\SYSTEM\*.*" will build .SYM files for all Windows EXE's, DLL's, DRV's, etc... in that directory. Before attempting to build .SYM files, BUILDSYM will first determine if the file is a valid New EXE file. If not, it does not EXEMAP/TMAPSYM it. Thus, you should not be concerned about using *.* as a filespec, although it might take a bit longer then if you used a more restrictive filespec. Note: Any .SYM files created will be placed in the current directory. Thus, you should be in the directory where you want to create .SYM files. In order for Dr. Frank and other utilities to find the .SYM files, they need to be in the same directory as the New EXE file. Note: TMAPSYM will overwrite any existing .SYM files with the same name. Thus, make sure you have backups of any existing .SYM files before using BUILDSYM or TMAPSYM. |=============================================================================| | TMAPSYM | |=============================================================================| TMAPSYM.EXE was written to create .SYM files from any BC++ or TPW created .MAP files. Other .MAP to .SYM file converters may not work properly with Borland .MAP files. For instance, C++ programs have both the function name, as well as it's argument list to the .MAP file. TMAPSYM properly handles this. TMAPSYM has one command line option, namely the name of the .MAP file to be processed. For instance: TMAPSYM mytest.map This will create a file called MYTEST.SYM in the current directory. It is generally faster to have TLINK generate a link map, and use TMAPSYM, then it is to use DFA. Also, by using TMAPSYM, you get an immediate symbolic stack trace, as opposed to having to manually run DFA after an exception occurs. Note: If you are using precompiled headers with BC++, the default extension of the precompiled headers file is .SYM. If you use TMAPSYM, you might inadvertantly overwrite the .SYM file from the compiler. Since other utilities, as well as the Windows debugging version will only look for .SYM files, I would recommend using the -H=filename option with BC++ to name the precompiled headers file to a non-conflicting name. One caveat when using TMAPSYM is that it will only be able to find functions that are in the entry table of the executable. Thus, public functions that are not exported will not be found. In general this is not a problem. |=============================================================================| | EXEMAP | |=============================================================================| EXEMAP was written to create .MAP files from New EXE file format files (.EXE, .DLL, .DRV, etc...) for which you do not have source code or a .MAP file for. .MAP files created from EXEMAP can be processed by TMAPSYM to create .SYM files. These .SYM files are then in turn used by Dr. Frank One particularly good use of EXEMAP is to create .MAP files for DLL's when a .SYM file is not provided. Another reason why EXEMAP was written is because many .SYM files are incomplete. Oftentimes undocumented functions do not appear in the .SYM files. Since EXEMAP works directly from the executable file, many additional function entry points can be found, and included in your .SYM files. The syntax for EXEMAP is: EXEMAP [output file name] The default output filename, if none is supplied, is the input filename, with a .MAP extension. |=============================================================================| | DFA2 | |=============================================================================| DFA.EXE (Dr. Frank Assistant) was written to allow symbolic stack traces and variable values to be obtained via Turbo Debugger symbol tables. DFA2 will give you a file that contains a stack trace similar to the one in the Dr. Frank log file, but with but with the addition of function names and line numbers, as well as local and global variables. Note: DFA2 will not work with log files from previous versions of Dr. Frank. You must use the new DRFANK.EXE with DFA2. The syntax for DFA2 is: DFA2 [options] [DRFRANK.BIN] Options: /O. i.e., /Ogoober will send the output to "goober" /D - Forces DFA2 to write out a hex dump of the saved data segments You do not need to specify the DRFRANK.BIN file, but if you don't, the resulting output file will not contain the program variable information. NOTE: DFA2 takes the first entry in the Dr. Frank log file, and assumes that it corresponds to the data in the DRFRANK.BIN file. Also, you will only get 1 DRFRANK.BIN file per Window sessions. The upshot is that it's a good idea to post-process immediately after the exception occurs, and copy/rename the files if you wish to save the information. ======== How does DFA2 look for TD debug information? First, the filename that is specified in the log file is inspected for TD debug information. If none is found, the file extension is changed to .TDS. ======== Format of the DFA.OUT file If you have to ask... Seriously, it's pretty self explanatory. If you see something wrong, let me know. |=============================================================================| | EXETDS | |=============================================================================| EXETDS (EXE to TDS) was written to allow you to create Turbo Debugger symbol files (.TDS) from the information contained in the exports of an EXE or DLL file. DFA can use these files when processing a log file. Also, TDW (Turbo Debugger for Windows) can use these files to provide symbolic disassembly in the CPU window. The syntax for EXETDS is: EXETDS [output file name] The default output filename, if none is supplied, is the input filename, with a .TDS extension. ---- For Advanced users To see the symbolic disassembly in TDW, you need to go to the VIEW | MODULES dialog box, select the appropriate module name in the right-hand pane, and then select "Load symbol table". To posistion to the start of a function, you can either "GOTO" from the CPU disassembly pane, or select VIEW | VARIABLES. You should see a list of all the functions for the module. You should then be able to select one, and have the disassembly pane be updated to the start of the function. Note: For some reason, TDW will hang if you try to load a symbol table for KRNL386.EXE. KRNL286.EXE, and the other Windows files seem to work correctly. |=============================================================================| | What's New | |=============================================================================| --- ??? The post-processing program DFA.EXE has been replaced by DFA2.EXE. DFA2 gives you all the information DFA gave you, but adds the ability to display the values of your local and global variables. Hard Work!!! See DFA2 section for more info. DFA2 is not backwards compatible, so you must use the new DRFRANK.EXE. The format of the stack trace has changed in the DRFRANK.LOG file. Dr. Frank now defaults to always creating a new LOG file the first time an exception occurs in the Windows session. The ability to disable the display of the filename in the stack trace has been removed. --- 11/21/91 DFA now outputs the original line, as output in the log file, if there is no TD debug info for that entry. DFA will now process all of the stack trace sections in a log file, instead of just the first one. EXETDS is new for this release. --- 10/27/91 --- Dr. Frank now has displays for System information (Task list, Module list, Memory usage), and the Message queue. In addition, the "Exception XX in XXXXXXX" dialog now comes up after the UAE box. This seems to make it more robust in a few oddball situations. DFA now should handle larger symbol tables, and should handle BC++ static functions and functions in TPU's. EXEMAP now outputs the program entry point, and will abort gracefully if there are no segments in the New EXE file, i.e., .FON files. Also, symbol names up to 255 characters should be O.K. TMAPSYM will now process the program entry point from the .MAP file. Symbol names up to 255 characters should be O.K. BUILDSYM is new for this release. |=============================================================================| | Support for Dr. Frank and Tools | |=============================================================================| Dr. Frank is Freeware for the time being. All I ask is that you let me know what you think, and if you have suggestions, or think you have a bug, to let me know. My Compuserve ID is: 76117,1720 Also, my main hangouts on Compuserve are BPROGB, sections 3 & 8 (Debugger/ Profiler, Windows Programming), and WINSDK. Matt Pietrek ===== Legal Disclaimer === Windows, MS-DOS, DRWATSON, WDEB386, and TOOLHELP.DLL are trademarks of Microsoft Inc. Turbo Debugger, Borland C++, Turbo Pascal for Windows, TLINK and TDUMP are trademarks of Borland International. All other names are trademarks of their respective holders. I make no claims as to the usability of these programs, and am not liable for any damages, incidental or consequential arising out of the use of these programs. IANAL, so I hope I got this right...