|  | Note: The new debugging interface can be considered to be stable, | 
|  | with the exception of the in-memory message construction functions. | 
|  | However, there is still a lot of work to be done to polish | 
|  | things up. To make my life easier, please follow the guidelines | 
|  | described in this document. | 
|  |  | 
|  | Read this document before writing new code. DO NOT USE fprintf | 
|  | (or printf) to output things. Also, instead of writing | 
|  | FIXMEs in the source, output a FIXME message if you can. | 
|  |  | 
|  | IMPORTANT: at the end of the document, there is a "Style Guide" | 
|  | for debugging messages. Please read it. | 
|  |  | 
|  | 28 Mar 1998, Dimitrie O. Paun <dimi@cs.toronto.edu> | 
|  |  | 
|  |  | 
|  | Debugging classes | 
|  | ----------------- | 
|  |  | 
|  | There are 4 types (or classes) of debugging messages: | 
|  |  | 
|  | FIXME -- Messages in this class relate to behavior of Wine that does | 
|  | not correspond to standard Windows behavior and that should | 
|  | be fixed. | 
|  | Examples: stubs, semi-implemented features, etc. | 
|  |  | 
|  | ERR   -- Messages in this class relate to serious errors in Wine. | 
|  | This sort of messages are close to asserts -- that is, | 
|  | you should output an error message when the code detects a | 
|  | condition which should not happen. In other words, important | 
|  | things that are not warnings (see below), are errors. | 
|  | Examples: unexpected change in internal state, etc. | 
|  |  | 
|  | WARN  -- These are warning messages. You should report a warning when | 
|  | something unwanted happen but the function behaves properly. | 
|  | That is, output a warning when you encounter something | 
|  | unexpected (ex: could not open a file) but the function deals | 
|  | correctly with the situation (that is, according to the docs). | 
|  | If you do not deal correctly with it, output a fixme. | 
|  | Examples: fail to access a resource required by the app, etc. | 
|  |  | 
|  | TRACE -- These are detailed debugging messages that are mainly useful | 
|  | to debug a component. These are usually turned off. | 
|  | Examples: everything else that does not fall in one of the | 
|  | above mentioned categories and the user does not | 
|  | need to know about it. | 
|  |  | 
|  |  | 
|  | The user has the capability to turn on or off messages of a particular | 
|  | type. You can expect the following patterns of usage (but note that | 
|  | any combination is possible): | 
|  | -- when you debug a component, all types (TRACE,WARN,ERR,FIXME) | 
|  | will be enabled. | 
|  | -- during the pre-alpha (maybe alpha) stage of Wine, most likely | 
|  | the TRACE class will be disabled by default, but all others | 
|  | (WARN,ERR,FIXME) will be enabled by default. | 
|  | -- when Wine will become stable, most likely the TRACE and WARN | 
|  | classes will be disabled by default, but all ERRs and FIXMEs | 
|  | will be enabled. | 
|  | -- in some installations that want the smallest footprint | 
|  | and where the debug information is of no interest, | 
|  | all classes may be disabled by default. | 
|  |  | 
|  | Of course, the user will have the runtime ability to override these | 
|  | defaults. However, this ability may be turned off and certain classes | 
|  | of messages may be completely disabled at compile time to reduce the | 
|  | size of Wine. | 
|  |  | 
|  | Debugging channels | 
|  | ------------------ | 
|  |  | 
|  | Also, we divide the debugging messages on a component basis. Each | 
|  | component is assigned a debugging channel. The identifier of the | 
|  | channel must be a valid C identifier but note that it may also be a | 
|  | reserved word like int or static. | 
|  |  | 
|  | Examples of debugging channels: | 
|  | reg, updown, string | 
|  |  | 
|  | We will refer to a generic channel as xxx. | 
|  |  | 
|  | Note: for those who know the old interface, the channel/type is | 
|  | what followed the _ in the dprintf_xxx statements. | 
|  | For example, to output a message on the debugging channel | 
|  | reg in the old interface you would had to write: | 
|  |  | 
|  | dprintf_reg(stddeb, "Could not access key!\n"); | 
|  |  | 
|  | In the new interface, we drop the stddeb as it is implicit. | 
|  | However, we add an orthogonal piece of information to the | 
|  | message: its class. This is very important as it will allow | 
|  | us to selectively turn on or off certain messages based on the | 
|  | type of information they report. For this reason it is essential | 
|  | to choose the right class for the message. | 
|  | Anyhow, suppose we figured that this message should belong | 
|  | in the WARN class, so in the new interface, you write: | 
|  |  | 
|  | WARN(reg, "Could not access key!\n"); | 
|  | --- | 
|  |  | 
|  | How to use it | 
|  | ------------- | 
|  |  | 
|  | So, to output a message (class YYY) on channel xxx, do: | 
|  |  | 
|  | #include "debug.h" | 
|  |  | 
|  | .... | 
|  |  | 
|  | YYY(xxx, "<message>", ...); | 
|  |  | 
|  |  | 
|  | Some examples from the code: | 
|  |  | 
|  | #include "debug.h" | 
|  |  | 
|  | ... | 
|  |  | 
|  | TRACE(crtdll, "CRTDLL_setbuf(file %p buf %p)", file, buf); | 
|  |  | 
|  | WARN(aspi, "Error opening device errno=%d", save_error); | 
|  |  | 
|  |  | 
|  | If you need to declare a new debugging channel, use it in your code | 
|  | and then do: | 
|  | %tools/make_debug | 
|  | in the root directory of Wine. | 
|  |  | 
|  | Note that this will result in almost complete recompilation of Wine. | 
|  |  | 
|  | Notes: | 
|  | 1. Please pay attention to which class you assign the message. | 
|  | There are only 4 classes, so it is not hard. The reason | 
|  | it is important to get it right is that too much information | 
|  | is no information. For example, if you put things into the | 
|  | WARN class that should really be in the TRACE class, the | 
|  | output will be too big and this will force the user to | 
|  | turn warnings off. But this way he will fail to see the important | 
|  | ones. Also, if you put warnings into the TRACE class lets say, | 
|  | he will most likely miss those because usually the TRACE class | 
|  | is turned off. A similar argument can be made if you mix any | 
|  | other two classes. | 
|  | 2. All lines should end with a newline.If you can NOT output | 
|  | everything that you want in the line with only one statement, | 
|  | then you need to build the string in memory. | 
|  | Please read the section below "In-memory messages" on the | 
|  | preferred way to do it. PLEASE USE THAT INTERFACE TO BUILD | 
|  | MESSAGES IN MEMORY. The reason is that we are not sure that | 
|  | we like it and having everything in one format will facilitate | 
|  | the (automatic) translation to a better interface. | 
|  |  | 
|  |  | 
|  |  | 
|  | Are we debugging? | 
|  | ----------------- | 
|  |  | 
|  | To test whether the debugging output of class yyy on channel xxx is | 
|  | enabled, use: | 
|  |  | 
|  | TRACE_ON  to test if TRACE is enabled | 
|  | WARN_ON   to test if WARN is enabled | 
|  | FIXME_ON  to test if FIXME is enabled | 
|  | ERR_ON    to test if ERR is enabled | 
|  |  | 
|  | Examples: | 
|  |  | 
|  | if(TRACE_ON(atom)){ | 
|  | ...blah... | 
|  | } | 
|  |  | 
|  | Note that you should normally need to test only if TRACE_ON. At present, | 
|  | none of the other 3 tests (except for ERR_ON which is used only once!) | 
|  | are used in Wine. | 
|  |  | 
|  | In-memory messages | 
|  | ------------------ | 
|  |  | 
|  | If you NEED to build the message from multiple calls, you need to | 
|  | build it in memory. To do that, you should use the following | 
|  | interface: | 
|  |  | 
|  | - declare a string (where you are allowed to declare C variables) | 
|  | as follows: | 
|  | dbg_decl_str(name, len); | 
|  | where name  is the name of the string (you should use the channel | 
|  | name on which you are going to output it) | 
|  |  | 
|  | - print in it with: | 
|  | dsprintf(name, "<message>", ...); | 
|  | which is just like a sprintf function but instead of a C string as | 
|  | first parameter it takes the name you used to declare it. | 
|  |  | 
|  | - obtain a pointer to the string with: | 
|  | dbg_str(name) | 
|  |  | 
|  | - reset the string (if you want to reuse it with): | 
|  | dbg_reset_str(name); | 
|  |  | 
|  | Example (modified from the code): | 
|  |  | 
|  | void some_func(tabs) | 
|  | { | 
|  | INT32 i; | 
|  | LPINT16 p = (LPINT16)tabs; | 
|  | dbg_decl_str(listbox, 256);                   /* declare the string */ | 
|  |  | 
|  | for (i = 0; i < descr->nb_tabs; i++) { | 
|  | descr->tabs[i] = *p++<<1; | 
|  | if(TRACING(listbox))                         /* write in it only if | 
|  | dsprintf(listbox, "%hd ", descr->tabs[i]); /* we are gonna output it */ | 
|  | } | 
|  | TRACE(listbox, "Listbox %04x: settabstops %s", | 
|  | wnd->hwndSelf, dbg_str(listbox));        /* output the whole thing */ | 
|  | } | 
|  |  | 
|  | If you need to use it two times in the same scope do like this: | 
|  |  | 
|  | void some_func(tabs) | 
|  | { | 
|  | INT32 i; | 
|  | LPINT16 p = (LPINT16)tabs; | 
|  | dbg_decl_str(listbox, 256);                   /* declare the string      */ | 
|  |  | 
|  | for (i = 0; i < descr->nb_tabs; i++) { | 
|  | descr->tabs[i] = *p++<<1; | 
|  | if(TRACING(listbox))                         /* write in it only if | 
|  | dsprintf(listbox, "%hd ", descr->tabs[i]); /* we are gonna output it */ | 
|  | } | 
|  | TRACE(listbox, "Listbox %04x: settabstops %s\n", | 
|  | wnd->hwndSelf, dbg_str(listbox));        /* output the whole thing */ | 
|  |  | 
|  | dbg_reset_str(listbox);                        /* !!!reset the string!!! */ | 
|  | for (i = 0; i < descr->extrainfo_nr; i++) { | 
|  | descr->extrainfo = *p+1; | 
|  | if(TRACING(listbox))                         /* write in it only if | 
|  | dsprintf(listbox,"%3d ",descr->extrainfo); /* we are gonna output it */ | 
|  | } | 
|  |  | 
|  | TRACE(listbox, "Listbox %04x: extrainfo %s\n", | 
|  | wnd->hwndSelf, dbg_str(listbox));        /* output the whole thing */ | 
|  |  | 
|  | } | 
|  |  | 
|  | IMPORTANT NOTE: | 
|  | As I already stated, I do not think this will be the ultimate interface | 
|  | for building in-memory debugging messages. In fact, I do have better ideas | 
|  | which I hope to have time to implement for the next release. For this | 
|  | reason, please try not to use it. However, if you need to output a line | 
|  | in more than one dprintf_xxx calls, then USE THIS INTERFACE. DO NOT use | 
|  | other methods. This way, I will easily translate everything to the new | 
|  | interface (when it will become available). So, if you need to use it, | 
|  | then follow the following guidelines: | 
|  | -- wrap calls to dsprintf with a | 
|  | if(YYY(xxx)) | 
|  | dsprintf(xxx,...); | 
|  | Of course, if the call to dsprintf is made from within a function | 
|  | which you know is called only if YYY(xxx) is true | 
|  | (say you call it only like this: | 
|  | if(YYY(xxx)) | 
|  | print_some_debug_info(); | 
|  | ) | 
|  | then you need not (and should not) wrap calls to dsprintf with | 
|  | the before mentioned if. | 
|  | -- name the string EXACTLY like the debugging channel on which | 
|  | is going to be output. Please see the above example. | 
|  |  | 
|  |  | 
|  | Resource identifiers | 
|  | -------------------- | 
|  |  | 
|  | Resource identifiers can be either strings or numbers. To make life a bit | 
|  | easier for outputting this beasts (and to help you avoid the need to build | 
|  | the message in memory), I introduced a new function called: | 
|  |  | 
|  | debugres | 
|  |  | 
|  | The function is defined in debugstr.h | 
|  | and has the following prototype: | 
|  |  | 
|  | LPSTR debugres(const void *id); | 
|  |  | 
|  | It takes a pointer to the resource id and returns a nicely formatted | 
|  | string of the identifier. | 
|  |  | 
|  | It the high word of the pointer is 0, then it assumes that the | 
|  | identifier is a number and thus returns a string of the form: | 
|  |  | 
|  | #xxxx | 
|  |  | 
|  | where xxxx are 4 hex-digits representing the low word of id. | 
|  |  | 
|  | It the high word of the pointer is not 0, then it assumes that the | 
|  | identifier is a string and thus returns a string of the form: | 
|  |  | 
|  | '<identifier>' | 
|  |  | 
|  | Thus, to use it, do something on the following lines: | 
|  |  | 
|  | #include "debug.h" | 
|  |  | 
|  | ... | 
|  |  | 
|  | YYY(xxx, "resource is %s", debugres(myresource)); | 
|  |  | 
|  |  | 
|  | The -debugmsg command line option | 
|  | --------------------------------- | 
|  |  | 
|  | So, the -debugmsg command line option has been changed as follows: | 
|  | - the new syntax is: -debugmsg [yyy]#xxx[,[yyy1]#xxx1]* | 
|  | where # is either + or - | 
|  |  | 
|  | - when the optional class argument (yyy) is not present, | 
|  | then the statement will enable(+)/disable(-) all messages for | 
|  | the given channel (xxx) on all classes. For example: | 
|  |  | 
|  | -debugmsg +reg,-file | 
|  |  | 
|  | enables all messages on the reg channel and disables all | 
|  | messages on the file channel. | 
|  | This is same as the old semantics. | 
|  |  | 
|  | - when the optional class argument (yyy) is present, | 
|  | then the statement will enable(+)/disable(-) messages for | 
|  | the given channel (xxx) only on the given class. For example: | 
|  |  | 
|  | -debugmsg trace+reg,warn-file | 
|  |  | 
|  | enables trace messages on the reg channel and disables warning | 
|  | messages on the file channel. | 
|  |  | 
|  | - also, the pseudo-channel all is also supported and it has the | 
|  | intuitive semantics: | 
|  |  | 
|  | -debugmsg +all      -- enables all debug messages | 
|  | -debugmsg -all      -- disables all debug messages | 
|  | -debugmsg yyy+all   -- enables debug messages for class yyy on all | 
|  | channels. | 
|  | -debugmsg yyy-all   -- disables debug messages for class yyy on all | 
|  | channels. | 
|  |  | 
|  | So, for example: | 
|  |  | 
|  | -debugmsg warn-all  -- disables all warning messages. | 
|  |  | 
|  |  | 
|  | Also, note that at the moment: | 
|  | - the fixme and err classes are enabled by default | 
|  | - the trace and warn  classes are disabled by default | 
|  |  | 
|  |  | 
|  | Compiling Out Debugging Messages | 
|  | -------------------------------- | 
|  |  | 
|  | To compile out the debugging messages, provide configure with the | 
|  | following options: | 
|  |  | 
|  | --disable-debug      -- turns off TRACE, WARN, and FIXME (and DUMP). | 
|  |  | 
|  | --disable-trace      -- turns off TRACE only. | 
|  |  | 
|  | This will result in an executable that, when stripped, is about 15%-20% | 
|  | smaller.  Note, however, that you will not be able to effectively debug | 
|  | Wine without these messages. | 
|  |  | 
|  | This feature has not been extensively tested--it may subtly break some | 
|  | things. | 
|  |  | 
|  |  | 
|  | A Few Notes on Style | 
|  | -------------------- | 
|  |  | 
|  | This new scheme makes certain things more consistent but there is still | 
|  | room for improvement by using a common style of debug messages. Before | 
|  | I continue, let me note that the output format is the following: | 
|  |  | 
|  | yyy:xxx:fff <message> | 
|  |  | 
|  | where: | 
|  | yyy = the class (fixme, err, warn, trace) | 
|  | xxx = the channel (atom, win, font, etc) | 
|  | fff = the function name | 
|  | these fields are output automatically. All you have to provide is | 
|  | the <message> part. | 
|  |  | 
|  | So here are some ideas: | 
|  |  | 
|  | * do NOT include the name of the function: it is included automatically | 
|  |  | 
|  | * if you want to output the parameters of the function, do it as the first | 
|  | thing and include them in parenthesis, like this: | 
|  |  | 
|  | YYY(xxx, "(%d,%p,etc)...\n", par1, par2, ...); | 
|  |  | 
|  | * for stubs, you should output a FIXME message. I suggest this style: | 
|  |  | 
|  | FIXME(xxx, "(%x,%d...): stub\n", par1, par2, ...); | 
|  |  | 
|  | That is, you output the parameters, then a : and then a string | 
|  | containing the word "stub". I've seen "empty stub", and others, but I | 
|  | think that just "stub" suffices. | 
|  |  | 
|  | * output 1 and ONLY 1 line per message. That is, the format string should | 
|  | contain only 1 \n and it should always appear at the end of the string. | 
|  | (there are many reasons  for this requirement, one of them is that each | 
|  | debug macro adds things to the beginning of the line) | 
|  |  | 
|  | * if you want to name a value, use = and NOT :. That is, instead of | 
|  | saying: | 
|  | FIXME(xxx, "(fd: %d, file: %s): stub\n", fd, name); | 
|  | say: | 
|  | FIXME(xxx, "(fd=%d, file=%s): stub\n", fd, name); | 
|  |  | 
|  | use : to separate categories. | 
|  |  | 
|  | * try to avoid the style: | 
|  |  | 
|  | FIXME(xxx, | 
|  | "(fd=%d, file=%s): stub\n", fd, name); | 
|  | but use: | 
|  |  | 
|  | FIXME(xxx, "(fd=%d, file=%s): stub\n", fd, name); | 
|  |  | 
|  | The reason is that if you want to grep for things, you would search for | 
|  | FIXME but in the first case there is no additional information available, | 
|  | where in the second one, there is (e.g. the word stub) | 
|  |  | 
|  | * if you output a string s that might contain control characters, | 
|  | or if s may be null, use debugstr_a (for ASCII strings, or | 
|  | debugstr_w for Unicode strings) to convert s to a C string, like | 
|  | this: | 
|  |  | 
|  | HANDLE32 WINAPI YourFunc(LPCSTR s) | 
|  | { | 
|  | FIXME(xxx, "(%s): stub\n", debugstr_a(s)); | 
|  | } | 
|  |  | 
|  | * if you want to output a resource identifier, use debugres to | 
|  | convert it to a string first, like this: | 
|  |  | 
|  | HANDLE32 WINAPI YourFunc(LPCSTR res) | 
|  | { | 
|  | FIXME(xxx, "(res=%s): stub\n", debugres(s)); | 
|  | } | 
|  |  | 
|  | if the resource identifier is a SEGPTR, use PTR_SEG_TO_LIN to get a | 
|  | liner pointer first: | 
|  |  | 
|  | HRSRC16 WINAPI FindResource16( HMODULE16 hModule, SEGPTR name, SEGPTR type ) | 
|  | { | 
|  | [...] | 
|  | TRACE(resource, "module=%04x name=%s type=%s\n", | 
|  | hModule, debugres(PTR_SEG_TO_LIN(name)), | 
|  | debugres(PTR_SEG_TO_LIN(type)) ); | 
|  | [...] | 
|  | } | 
|  |  | 
|  | * for messages intended for the user (specifically those that report | 
|  | errors in wine.conf), use the MSG macro. Use it like a printf: | 
|  |  | 
|  | MSG( "Definition of drive %d is incorrect!\n", drive ); | 
|  |  | 
|  | However, note that there are _very_ few valid uses of this macro. | 
|  | Most messages are debugging messages, so chances are you will not | 
|  | need to use this macro. Grep the source to get an idea where it | 
|  | is appropriate to use it. | 
|  |  | 
|  | * for structure dumps, use the DUMP macro. Use it like a printf, | 
|  | just like the MSG macro. Similarly, there are only a few valid | 
|  | uses of this macro. Grep the source to see when to use it. |