New scheme for keeping track of debug channels that doesn't require

maintaining a list of all loaded dlls.
This commit is contained in:
Alexandre Julliard 2005-09-28 15:21:48 +00:00
parent 9c559cf385
commit cbc38965c0
7 changed files with 140 additions and 198 deletions

View File

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

View File

@ -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)
for (i = 0; i < nb; i++)
{
apply_option( dll, opt );
opt = opt->next;
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,27 +147,49 @@ 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
{
if (*p == '-') clear = ~0;
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);

View File

@ -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 ))
{

View File

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

View File

@ -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;

View File

@ -22,6 +22,7 @@
#define WIN32_LEAN_AND_MEAN /* Exclude rarely-used stuff from Windows headers */
#include <windows.h>
#include <ctype.h>
#include <commctrl.h>
#include <stdlib.h>
#include <malloc.h>
@ -34,7 +35,7 @@
#include "taskmgr.h"
#include "perfdata.h"
#include "column.h"
#include <ctype.h>
#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)
{

View File

@ -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);