| 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. |