From cbc38965c01bd4827b85e658fa79940e2d0885eb Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Wed, 28 Sep 2005 15:21:48 +0000 Subject: [PATCH] New scheme for keeping track of debug channels that doesn't require maintaining a list of all loaded dlls. --- include/wine/debug.h | 18 ++-- libs/wine/debug.c | 183 ++++++++++++++++++------------------- libs/wine/loader.c | 25 +---- libs/wine/wine.def | 2 - libs/wine/wine.map | 2 - programs/taskmgr/dbgchnl.c | 57 ++++-------- programs/winedbg/info.c | 51 +++++------ 7 files changed, 140 insertions(+), 198 deletions(-) diff --git a/include/wine/debug.h b/include/wine/debug.h index 181d718bd9d..4393b3b4211 100644 --- a/include/wine/debug.h +++ b/include/wine/debug.h @@ -43,7 +43,8 @@ enum __wine_debug_class __WINE_DBCL_ERR, __WINE_DBCL_WARN, __WINE_DBCL_TRACE, - __WINE_DBCL_COUNT + + __WINE_DBCL_INIT = 7 /* lazy init flag */ }; struct __wine_debug_channel @@ -70,8 +71,9 @@ struct __wine_debug_channel #define __WINE_GET_DEBUGGING_ERR(dbch) ((dbch)->flags & (1 << __WINE_DBCL_ERR)) #define __WINE_GET_DEBUGGING(dbcl,dbch) __WINE_GET_DEBUGGING##dbcl(dbch) -#define __WINE_SET_DEBUGGING(dbcl,dbch,on) \ - ((on) ? ((dbch)[0] |= 1 << (dbcl)) : ((dbch)[0] &= ~(1 << (dbcl)))) + +#define __WINE_IS_DEBUG_ON(dbcl,dbch) \ + (__WINE_GET_DEBUGGING##dbcl(dbch) && wine_dbg_log(__WINE_DBCL##dbcl, (dbch), 0, 0) != -1) #ifdef __GNUC__ @@ -128,7 +130,7 @@ struct __wine_debug_channel #define __WINE_DPRINTF(dbcl,dbch) \ (!__WINE_GET_DEBUGGING(dbcl,(dbch)) || \ - (wine_dbg_log(__WINE_DBCL##dbcl,(dbch),__FILE__,"%d: ",__LINE__),0)) ? \ + (wine_dbg_log(__WINE_DBCL##dbcl,(dbch),__FILE__,"%d: ",__LINE__) == -1)) ? \ (void)0 : (void)wine_dbg_printf #define __WINE_PRINTF_ATTR(fmt, args) @@ -213,23 +215,23 @@ static inline const char *wine_dbgstr_longlong( ULONGLONG ll ) #define WINE_TRACE __WINE_DPRINTF(_TRACE,__wine_dbch___default) #define WINE_TRACE_(ch) __WINE_DPRINTF(_TRACE,&__wine_dbch_##ch) #endif -#define WINE_TRACE_ON(ch) __WINE_GET_DEBUGGING(_TRACE,&__wine_dbch_##ch) +#define WINE_TRACE_ON(ch) __WINE_IS_DEBUG_ON(_TRACE,&__wine_dbch_##ch) #ifndef WINE_WARN #define WINE_WARN __WINE_DPRINTF(_WARN,__wine_dbch___default) #define WINE_WARN_(ch) __WINE_DPRINTF(_WARN,&__wine_dbch_##ch) #endif -#define WINE_WARN_ON(ch) __WINE_GET_DEBUGGING(_WARN,&__wine_dbch_##ch) +#define WINE_WARN_ON(ch) __WINE_IS_DEBUG_ON(_WARN,&__wine_dbch_##ch) #ifndef WINE_FIXME #define WINE_FIXME __WINE_DPRINTF(_FIXME,__wine_dbch___default) #define WINE_FIXME_(ch) __WINE_DPRINTF(_FIXME,&__wine_dbch_##ch) #endif -#define WINE_FIXME_ON(ch) __WINE_GET_DEBUGGING(_FIXME,&__wine_dbch_##ch) +#define WINE_FIXME_ON(ch) __WINE_IS_DEBUG_ON(_FIXME,&__wine_dbch_##ch) #define WINE_ERR __WINE_DPRINTF(_ERR,__wine_dbch___default) #define WINE_ERR_(ch) __WINE_DPRINTF(_ERR,&__wine_dbch_##ch) -#define WINE_ERR_ON(ch) __WINE_GET_DEBUGGING(_ERR,&__wine_dbch_##ch) +#define WINE_ERR_ON(ch) __WINE_IS_DEBUG_ON(_ERR,&__wine_dbch_##ch) #define WINE_DECLARE_DEBUG_CHANNEL(ch) \ extern struct __wine_debug_channel __wine_dbch_##ch diff --git a/libs/wine/debug.c b/libs/wine/debug.c index 28a179ad728..95c911045ad 100644 --- a/libs/wine/debug.c +++ b/libs/wine/debug.c @@ -31,126 +31,98 @@ #include "wine/library.h" #include "wine/unicode.h" -struct dll -{ - struct dll *next; /* linked list of dlls */ - struct dll *prev; - struct __wine_debug_channel * const *channels; /* array of channels */ - int nb_channels; /* number of channels in array */ -}; - -static struct dll *first_dll; - -struct debug_option -{ - struct debug_option *next; /* next option in list */ - unsigned char set; /* bits to set */ - unsigned char clear; /* bits to clear */ - char name[14]; /* channel name, or empty for "all" */ -}; - -static struct debug_option *first_option; -static struct debug_option *last_option; -static struct __wine_debug_functions funcs; - static const char * const debug_classes[] = { "fixme", "err", "warn", "trace" }; +#define MAX_DEBUG_OPTIONS 256 + +static unsigned char default_flags = (1 << __WINE_DBCL_ERR) | (1 << __WINE_DBCL_FIXME); +static unsigned int nb_debug_options = 0; +static struct __wine_debug_channel debug_options[MAX_DEBUG_OPTIONS]; + +static struct __wine_debug_functions funcs; + static int cmp_name( const void *p1, const void *p2 ) { const char *name = p1; - const struct __wine_debug_channel * const *chan = p2; - return strcmp( name, (*chan)->name ); + const struct __wine_debug_channel *chan = p2; + return strcmp( name, chan->name ); } -/* apply a debug option to the channels of a given dll */ -static void apply_option( struct dll *dll, const struct debug_option *opt ) +/* get the flags to use for a given channel, possibly setting them too in case of lazy init */ +static inline unsigned char get_channel_flags( struct __wine_debug_channel *channel ) { - if (opt->name[0]) + if (nb_debug_options) { - struct __wine_debug_channel * const *dbch = bsearch( opt->name, dll->channels, dll->nb_channels, - sizeof(*dll->channels), cmp_name ); - if (dbch) (*dbch)->flags = ((*dbch)->flags & ~opt->clear) | opt->set; - } - else /* all */ - { - int i; - for (i = 0; i < dll->nb_channels; i++) - dll->channels[i]->flags = (dll->channels[i]->flags & ~opt->clear) | opt->set; + struct __wine_debug_channel *opt = bsearch( channel->name, debug_options, nb_debug_options, + sizeof(debug_options[0]), cmp_name ); + if (opt) return opt->flags; } + /* no option for this channel */ + if (channel->flags & (1 << __WINE_DBCL_INIT)) channel->flags = default_flags; + return default_flags; } /* register a new set of channels for a dll */ void *__wine_dbg_register( struct __wine_debug_channel * const *channels, int nb ) { - struct debug_option *opt = first_option; - struct dll *dll = malloc( sizeof(*dll) ); - if (dll) - { - dll->channels = channels; - dll->nb_channels = nb; - dll->prev = NULL; - if ((dll->next = first_dll)) dll->next->prev = dll; - first_dll = dll; + int i; - /* apply existing options to this dll */ - while (opt) - { - apply_option( dll, opt ); - opt = opt->next; - } + for (i = 0; i < nb; i++) + { + channels[i]->flags = ~0; + get_channel_flags( channels[i] ); } - return dll; + return NULL; } /* unregister a set of channels; must pass the pointer obtained from wine_dbg_register */ void __wine_dbg_unregister( void *channel ) { - struct dll *dll = channel; - if (dll) - { - if (dll->next) dll->next->prev = dll->prev; - if (dll->prev) dll->prev->next = dll->next; - else first_dll = dll->next; - free( dll ); - } } /* add a new debug option at the end of the option list */ -void wine_dbg_add_option( const char *name, unsigned char set, unsigned char clear ) +static void add_option( const char *name, unsigned char set, unsigned char clear ) { - struct dll *dll = first_dll; - struct debug_option *opt; - size_t len = strlen(name); + int min = 0, max = nb_debug_options - 1, pos, res; - if (!(opt = malloc( sizeof(*opt) ))) return; - opt->next = NULL; - opt->set = set; - opt->clear = clear; - if (len >= sizeof(opt->name)) len = sizeof(opt->name) - 1; - memcpy( opt->name, name, len ); - opt->name[len] = 0; - if (last_option) last_option->next = opt; - else first_option = opt; - last_option = opt; - - /* apply option to all existing dlls */ - while (dll) + if (!name[0]) /* "all" option */ { - apply_option( dll, opt ); - dll = dll->next; + default_flags = (default_flags & ~clear) | set; + return; } + if (strlen(name) >= sizeof(debug_options[0].name)) return; + + while (min <= max) + { + pos = (min + max) / 2; + res = strcmp( name, debug_options[pos].name ); + if (!res) + { + debug_options[pos].flags = (debug_options[pos].flags & ~clear) | set; + return; + } + if (res < 0) max = pos - 1; + else min = pos + 1; + } + if (nb_debug_options >= MAX_DEBUG_OPTIONS) return; + + pos = min; + if (pos < nb_debug_options) memmove( &debug_options[pos + 1], &debug_options[pos], + (nb_debug_options - pos) * sizeof(debug_options[0]) ); + strcpy( debug_options[pos].name, name ); + debug_options[pos].flags = (default_flags & ~clear) | set; + nb_debug_options++; } /* parse a set of debugging option specifications and add them to the option list */ -int wine_dbg_parse_options( const char *str ) +static void parse_options( const char *str ) { char *opt, *next, *options; unsigned int i; - int errors = 0; - if (!(options = strdup(str))) return -1; + if (!(options = strdup(str))) return; for (opt = options; opt; opt = next) { const char *p; @@ -175,10 +147,7 @@ int wine_dbg_parse_options( const char *str ) } } if (i == sizeof(debug_classes)/sizeof(debug_classes[0])) /* bad class name, skip it */ - { - errors++; continue; - } } else { @@ -186,16 +155,41 @@ int wine_dbg_parse_options( const char *str ) else set = ~0; } if (*p == '+' || *p == '-') p++; - if (!p[0]) - { - errors++; - continue; - } - if (!strcmp( p, "all" )) p = ""; /* empty string means all */ - wine_dbg_add_option( p, set, clear ); + if (!p[0]) continue; + + if (!strcmp( p, "all" )) + default_flags = (default_flags & ~clear) | set; + else + add_option( p, set, clear ); } free( options ); - return errors; +} + + +/* print the usage message */ +static void debug_usage(void) +{ + static const char usage[] = + "Syntax of the WINEDEBUG variable:\n" + " WINEDEBUG=[class]+xxx,[class]-yyy,...\n\n" + "Example: WINEDEBUG=+all,warn-heap\n" + " turns on all messages except warning heap messages\n" + "Available message classes: err, warn, fixme, trace\n"; + write( 2, usage, sizeof(usage) - 1 ); + exit(1); +} + + +/* initialize all options at startup */ +void debug_init(void) +{ + char *wine_debug; + + if ((wine_debug = getenv("WINEDEBUG"))) + { + if (!strcmp( wine_debug, "help" )) debug_usage(); + parse_options( wine_debug ); + } } /* varargs wrapper for funcs.dbg_vprintf */ @@ -235,6 +229,9 @@ int wine_dbg_log( enum __wine_debug_class cls, struct __wine_debug_channel *chan int ret; va_list valist; + if (!(get_channel_flags( channel ) & (1 << cls))) return -1; + if (!format) return 0; + va_start(valist, format); ret = funcs.dbg_vlog( cls, channel, func, format, valist ); va_end(valist); diff --git a/libs/wine/loader.c b/libs/wine/loader.c index 32e7d6ddd20..ff87d655dd0 100644 --- a/libs/wine/loader.c +++ b/libs/wine/loader.c @@ -80,6 +80,7 @@ static int nb_dll_paths; static int dll_path_maxlen; extern void mmap_init(void); +extern void debug_init(void); /* build the dll load path from the WINEDLLPATH variable */ static void build_dll_path(void) @@ -524,22 +525,6 @@ int wine_dll_get_owner( const char *name, char *buffer, int size, int *exists ) } -/*********************************************************************** - * debug_usage - */ -static void debug_usage(void) -{ - static const char usage[] = - "Syntax of the WINEDEBUG variable:\n" - " WINEDEBUG=[class]+xxx,[class]-yyy,...\n\n" - "Example: WINEDEBUG=+all,warn-heap\n" - " turns on all messages except warning heap messages\n" - "Available message classes: err, warn, fixme, trace\n"; - write( 2, usage, sizeof(usage) - 1 ); - exit(1); -} - - /*********************************************************************** * wine_init * @@ -549,7 +534,6 @@ void wine_init( int argc, char *argv[], char *error, int error_size ) { struct dll_path_context context; char *path; - char *wine_debug; void *ntdll = NULL; void (*init_func)(void); @@ -559,12 +543,7 @@ void wine_init( int argc, char *argv[], char *error, int error_size ) __wine_main_argv = argv; __wine_main_environ = environ; mmap_init(); - - if ((wine_debug = getenv("WINEDEBUG"))) - { - if (!strcmp( wine_debug, "help" )) debug_usage(); - wine_dbg_parse_options( wine_debug ); - } + debug_init(); for (path = first_dll_path( "ntdll.dll", ".so", &context ); path; path = next_dll_path( &context )) { diff --git a/libs/wine/wine.def b/libs/wine/wine.def index b1adb6b8ef9..aecd1a2211a 100644 --- a/libs/wine/wine.def +++ b/libs/wine/wine.def @@ -10,9 +10,7 @@ EXPORTS __wine_main_environ __wine_main_wargv wine_anon_mmap - wine_dbg_add_option wine_dbg_log - wine_dbg_parse_options wine_dbg_printf wine_dbg_sprintf wine_dbgstr_a diff --git a/libs/wine/wine.map b/libs/wine/wine.map index f85c9c9ccc5..c6205cf1659 100644 --- a/libs/wine/wine.map +++ b/libs/wine/wine.map @@ -10,9 +10,7 @@ WINE_1.0 __wine_main_environ; __wine_main_wargv; wine_anon_mmap; - wine_dbg_add_option; wine_dbg_log; - wine_dbg_parse_options; wine_dbg_printf; wine_dbg_sprintf; wine_dbgstr_a; diff --git a/programs/taskmgr/dbgchnl.c b/programs/taskmgr/dbgchnl.c index ffd65b5675e..b2335e4151e 100644 --- a/programs/taskmgr/dbgchnl.c +++ b/programs/taskmgr/dbgchnl.c @@ -22,6 +22,7 @@ #define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */ #include +#include #include #include #include @@ -34,7 +35,7 @@ #include "taskmgr.h" #include "perfdata.h" #include "column.h" -#include +#include "wine/debug.h" /* TODO: * - the dialog box could be non modal @@ -104,7 +105,7 @@ static DWORD get_selected_pid(void) return dwProcessId; } -static int list_channel_CB(HANDLE hProcess, void* addr, char* buffer, void* user) +static int list_channel_CB(HANDLE hProcess, void* addr, struct __wine_debug_channel* channel, void* user) { int j; char val[2]; @@ -115,7 +116,7 @@ static int list_channel_CB(HANDLE hProcess, void* addr, char* buffer, void* memset(&lvi, 0, sizeof(lvi)); lvi.mask = LVIF_TEXT; - lvi.pszText = buffer + 1; + lvi.pszText = channel->name; index = ListView_InsertItem(hChannelLV, &lvi); if (index == -1) return 0; @@ -123,7 +124,7 @@ static int list_channel_CB(HANDLE hProcess, void* addr, char* buffer, void* val[1] = '\0'; for (j = 0; j < 4; j++) { - val[0] = (buffer[0] & (1 << j)) ? 'x' : ' '; + val[0] = (channel->flags & (1 << j)) ? 'x' : ' '; ListView_SetItemText(hChannelLV, index, j + 1, val); } return 1; @@ -142,14 +143,14 @@ struct cce_user * * Callback used for changing a given channel attributes */ -static int change_channel_CB(HANDLE hProcess, void* addr, char* buffer, void* pmt) +static int change_channel_CB(HANDLE hProcess, void* addr, struct __wine_debug_channel *channel, void* pmt) { struct cce_user* user = (struct cce_user*)pmt; - if (!user->name || !strcmp(buffer + 1, user->name)) + if (!user->name || !strcmp(channel->name, user->name)) { - buffer[0] = (buffer[0] & ~user->mask) | (user->value & user->mask); - if (WriteProcessMemory(hProcess, addr, buffer, 1, NULL)) + channel->flags = (channel->flags & ~user->mask) | (user->value & user->mask); + if (WriteProcessMemory(hProcess, addr, channel, sizeof(*channel), NULL)) user->done++; else user->notdone++; @@ -187,7 +188,7 @@ struct dll_option_layout int nb_channels; }; -typedef int (*EnumChannelCB)(HANDLE, void*, char*, void*); +typedef int (*EnumChannelCB)(HANDLE, void*, struct __wine_debug_channel*, void*); /****************************************************************** * enum_channel @@ -197,49 +198,25 @@ typedef int (*EnumChannelCB)(HANDLE, void*, char*, void*); */ static int enum_channel(HANDLE hProcess, EnumChannelCB ce, void* user, unsigned unique) { - struct dll_option_layout dol; - int i, ret = 1; + struct __wine_debug_channel channel; + int ret = 1; unsigned int j; - void* buf_addr; - char buffer[32]; void* addr; const char** cache = NULL; unsigned num_cache, used_cache; - if (!(addr = get_symbol(hProcess, "first_dll", "libwine.so"))) return -1; + if (!(addr = get_symbol(hProcess, "debug_options", "libwine.so"))) return -1; if (unique) cache = HeapAlloc(GetProcessHeap(), 0, (num_cache = 32) * sizeof(char*)); else num_cache = 0; used_cache = 0; - for (; - ret && addr && ReadProcessMemory(hProcess, addr, &dol, sizeof(dol), NULL); - addr = dol.next) + while (ret && addr && ReadProcessMemory(hProcess, addr, &channel, sizeof(channel), NULL)) { - for (i = 0; i < dol.nb_channels; i++) - { - if (ReadProcessMemory(hProcess, (void const *)(dol.channels + i), &buf_addr, sizeof(buf_addr), NULL) && - ReadProcessMemory(hProcess, buf_addr, buffer, sizeof(buffer), NULL)) - { - if (unique) - { - /* since some channels are defined in multiple compilation units, - * they will appear several times... - * so cache the channel's names we already reported and don't report - * them again - */ - for (j = 0; j < used_cache; j++) - if (!strcmp(cache[j], buffer + 1)) break; - if (j != used_cache) continue; - if (used_cache == num_cache) - cache = HeapReAlloc(GetProcessHeap(), 0, cache, (num_cache *= 2) * sizeof(char*)); - cache[used_cache++] = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(buffer + 1) + 1), - buffer + 1); - } - ret = ce(hProcess, buf_addr, buffer, user); - } - } + if (!channel.name[0]) break; + ret = ce(hProcess, addr, &channel, user); + addr = (struct __wine_debug_channel *)addr + 1; } if (unique) { diff --git a/programs/winedbg/info.c b/programs/winedbg/info.c index e475eff6c0b..c58b3e7721c 100644 --- a/programs/winedbg/info.c +++ b/programs/winedbg/info.c @@ -678,21 +678,10 @@ void info_win32_virtual(DWORD pid) if (pid != dbg_curr_pid) CloseHandle(hProc); } -struct dll_option_layout -{ - void* next; - void* prev; - char* const* channels; - int nb_channels; -}; - -void info_wine_dbg_channel(BOOL turn_on, const char* chnl, const char* name) +void info_wine_dbg_channel(BOOL turn_on, const char* cls, const char* name) { struct dbg_lvalue lvalue; - struct dll_option_layout dol; - int i; - char* str; - char buffer[32]; + struct __wine_debug_channel channel; unsigned char mask; int done = 0; BOOL bAll; @@ -704,32 +693,34 @@ void info_wine_dbg_channel(BOOL turn_on, const char* chnl, const char* name) return; } - if (symbol_get_lvalue("first_dll", -1, &lvalue, FALSE) != sglv_found) + if (symbol_get_lvalue("debug_options", -1, &lvalue, FALSE) != sglv_found) { return; } addr = memory_to_linear_addr(&lvalue.addr); - if (!chnl) mask = 15; - else if (!strcmp(chnl, "fixme")) mask = 1; - else if (!strcmp(chnl, "err")) mask = 2; - else if (!strcmp(chnl, "warn")) mask = 4; - else if (!strcmp(chnl, "trace")) mask = 8; - else { dbg_printf("Unknown channel %s\n", chnl); return; } + + if (!cls) mask = ~0; + else if (!strcmp(cls, "fixme")) mask = (1 << __WINE_DBCL_FIXME); + else if (!strcmp(cls, "err")) mask = (1 << __WINE_DBCL_ERR); + else if (!strcmp(cls, "warn")) mask = (1 << __WINE_DBCL_WARN); + else if (!strcmp(cls, "trace")) mask = (1 << __WINE_DBCL_TRACE); + else + { + dbg_printf("Unknown debug class %s\n", cls); + return; + } bAll = !strcmp("all", name); - while (addr && dbg_read_memory(addr, &dol, sizeof(dol))) + while (addr && dbg_read_memory(addr, &channel, sizeof(channel))) { - for (i = 0; i < dol.nb_channels; i++) + if (!channel.name[0]) break; + if (bAll || !strcmp( channel.name, name )) { - if (dbg_read_memory(dol.channels + i, &str, sizeof(str)) && - dbg_read_memory(str, buffer, sizeof(buffer)) && - (!strcmp(buffer + 1, name) || bAll)) - { - if (turn_on) buffer[0] |= mask; else buffer[0] &= ~mask; - if (dbg_write_memory(str, buffer, 1)) done++; - } + if (turn_on) channel.flags |= mask; + else channel.flags &= ~mask; + if (dbg_write_memory(addr, &channel, sizeof(channel))) done++; } - addr = dol.next; + addr = (struct __wine_debug_channel *)addr + 1; } if (!done) dbg_printf("Unable to find debug channel %s\n", name); else WINE_TRACE("Changed %d channel instances\n", done);