upon Massimo request, here's a patch that allows setting breakpoint by address even if the memory where the bp is to be set is not valid yet the debugger will try, each time a new DLL is loaded, to set the breakpoint by its address however, since this is a very dangerous feature (you don't know where you're going to set the bp), I decided to disable the feature by default it must be turned on by setting the $CanDeferOnBPByAddr internal variable to 1 A+
Name: wdbg_bp ChangeLog: added ability to defer breakpoint setting for breakpoint defined by an absolute address License: X11 GenDate: 2002/07/29 20:15:37 UTC ModifiedFiles: debugger/break.c debugger/dbg.y debugger/debugger.h debugger/intvar.h debugger/stabs.c debugger/winedbg.c AddedFiles: =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/break.c,v retrieving revision 1.34 diff -u -u -r1.34 break.c --- debugger/break.c 20 Jul 2002 20:18:17 -0000 1.34 +++ debugger/break.c 29 Jul 2002 19:34:47 -0000 @@ -274,7 +274,7 @@ * * Find an empty slot in BP table to add a new break/watch point */ -static int DEBUG_InitXPoint(int type, DBG_ADDR* addr) +static int DEBUG_InitXPoint(int type, const DBG_ADDR* addr) { int num; @@ -336,13 +336,48 @@ * * Add a breakpoint. */ -void DEBUG_AddBreakpoint( const DBG_VALUE *_value, BOOL (*func)(void) ) +BOOL DEBUG_AddBreakpoint( const DBG_VALUE *value, BOOL (*func)(void), BOOL verbose ) { - DBG_VALUE value = *_value; int num; BYTE ch; + + if ((num = DEBUG_FindBreakpoint(&value->addr, DBG_BREAK)) >= 1) + { + breakpoints[num].refcount++; + return TRUE; + } + + if (!DEBUG_READ_MEM((void*)DEBUG_ToLinear( &value->addr ), &ch, sizeof(ch))) + { + if (verbose) + DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n"); + return FALSE; + } + + if ((num = DEBUG_InitXPoint(DBG_BREAK, &value->addr)) == -1) + return FALSE; + + breakpoints[num].u.b.opcode = ch; + breakpoints[num].u.b.func = func; + + DEBUG_Printf( DBG_CHN_MESG, "Breakpoint %d at ", num ); + DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, + TRUE ); + DEBUG_Printf( DBG_CHN_MESG, "\n" ); + + return FALSE; +} - if( value.type != NULL && value.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) ) +/*********************************************************************** + * DEBUG_AddBreakpointFromValue + * + * Add a breakpoint. + */ +BOOL DEBUG_AddBreakpointFromValue( const DBG_VALUE *_value ) +{ + DBG_VALUE value = *_value; + + if (value.type != NULL && value.type == DEBUG_GetBasicType(DT_BASIC_CONST_INT) && value.cookie == DV_HOST) { /* * We know that we have the actual offset stored somewhere @@ -353,30 +388,27 @@ value.addr.seg = 0; value.addr.off = DEBUG_GetExprValue(&value, NULL); value.addr.seg = seg2; + value.cookie = DV_TARGET; } - if ((num = DEBUG_FindBreakpoint(&value.addr, DBG_BREAK)) >= 1) + if (!DEBUG_AddBreakpoint( &value, NULL, TRUE )) { - breakpoints[num].refcount++; - return; + if (!DBG_IVAR(CanDeferOnBPByAddr)) + { + DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n" + "You can turn on deferring breakpoints by address by setting $CanDeferOnBPByAddr to 1\n"); + return FALSE; + } + DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint, will check again any time a new DLL is loaded\n"); + DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp, + sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp); + + DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = FALSE; + DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.value = value; + return TRUE; } - if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear( &value.addr ), &ch, sizeof(ch))) - { - DEBUG_Printf( DBG_CHN_MESG, "Invalid address, can't set breakpoint\n"); - return; - } - - if ((num = DEBUG_InitXPoint(DBG_BREAK, &value.addr)) == -1) - return; - - breakpoints[num].u.b.opcode = ch; - breakpoints[num].u.b.func = func; - - DEBUG_Printf( DBG_CHN_MESG, "Breakpoint %d at ", num ); - DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].is32 ? MODE_32 : MODE_16, - TRUE ); - DEBUG_Printf( DBG_CHN_MESG, "\n" ); + return TRUE; } /*********************************************************************** @@ -386,26 +418,29 @@ */ void DEBUG_AddBreakpointFromId(const char *name, int lineno) { - DBG_VALUE value; - int i; - - if (DEBUG_GetSymbolValue(name, lineno, &value, TRUE)) { - DEBUG_AddBreakpoint(&value, NULL); - return; - } + DBG_VALUE value; + int i; - DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint, will check again when a new DLL is loaded\n"); - for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++) { - if (!strcmp(name, DEBUG_CurrProcess->delayed_bp[i].name) && - lineno == DEBUG_CurrProcess->delayed_bp[i].lineno) { - return; - } - } - DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp, - sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp); + if (DEBUG_GetSymbolValue(name, lineno, &value, TRUE)) + { + DEBUG_AddBreakpoint(&value, NULL, TRUE); + return; + } - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].name = strcpy(DBG_alloc(strlen(name) + 1), name); - DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].lineno = lineno; + DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint, will check again when a new DLL is loaded\n"); + for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++) + { + if (DEBUG_CurrProcess->delayed_bp[i].is_symbol && + !strcmp(name, DEBUG_CurrProcess->delayed_bp[i].u.symbol.name) && + lineno == DEBUG_CurrProcess->delayed_bp[i].u.symbol.lineno) + return; + } + DEBUG_CurrProcess->delayed_bp = DBG_realloc(DEBUG_CurrProcess->delayed_bp, + sizeof(DBG_DELAYED_BP) * ++DEBUG_CurrProcess->num_delayed_bp); + + DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].is_symbol = TRUE; + DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.name = strcpy(DBG_alloc(strlen(name) + 1), name); + DEBUG_CurrProcess->delayed_bp[DEBUG_CurrProcess->num_delayed_bp - 1].u.symbol.lineno = lineno; } /*********************************************************************** @@ -415,24 +450,26 @@ */ void DEBUG_AddBreakpointFromLineno(int lineno) { - DBG_VALUE value; - - DEBUG_GetCurrentAddress(&value.addr); - - if (lineno != -1) { - struct name_hash* nh; - - DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL); - if (nh == NULL) { - DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint\n"); - return; - } - DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE); - } - - value.type = NULL; - value.cookie = DV_TARGET; - DEBUG_AddBreakpoint( &value, NULL ); + DBG_VALUE value; + + DEBUG_GetCurrentAddress(&value.addr); + + if (lineno != -1) + { + struct name_hash* nh; + + DEBUG_FindNearestSymbol(&value.addr, TRUE, &nh, 0, NULL); + if (nh == NULL) + { + DEBUG_Printf(DBG_CHN_MESG, "Unable to add breakpoint\n"); + return; + } + DEBUG_GetLineNumberAddr(nh, lineno, &value.addr, TRUE); + } + + value.type = NULL; + value.cookie = DV_TARGET; + DEBUG_AddBreakpoint( &value,NULL, TRUE ); } /*********************************************************************** @@ -442,18 +479,32 @@ */ void DEBUG_CheckDelayedBP(void) { - DBG_VALUE value; - int i = 0; - DBG_DELAYED_BP* dbp = DEBUG_CurrProcess->delayed_bp; - - while (i < DEBUG_CurrProcess->num_delayed_bp) { - if (DEBUG_GetSymbolValue(dbp[i].name, dbp[i].lineno, &value, TRUE)) { - DEBUG_AddBreakpoint(&value, NULL); - memmove(&dbp[i], &dbp[i+1], (--DEBUG_CurrProcess->num_delayed_bp - i) * sizeof(*dbp)); - } else { - i++; - } - } + DBG_VALUE value; + int i; + DBG_DELAYED_BP* dbp = DEBUG_CurrProcess->delayed_bp; + + for (i = 0; i < DEBUG_CurrProcess->num_delayed_bp; i++) + { + if (dbp[i].is_symbol) + { + if (!DEBUG_GetSymbolValue(dbp[i].u.symbol.name, dbp[i].u.symbol.lineno, &value, TRUE)) + continue; + } + else + value = dbp[i].u.value; + DEBUG_Printf(DBG_CHN_MESG, "trying to add delayed %s-bp\n", dbp[i].is_symbol ? "S" : "A"); + if (!dbp[i].is_symbol) + DEBUG_Printf(DBG_CHN_MESG, "\t%04x %04lx:%08lx\n", + dbp[i].u.value.cookie, + dbp[i].u.value.addr.seg, + dbp[i].u.value.addr.off); + else + DEBUG_Printf(DBG_CHN_MESG, "\t'%s' @ %d\n", + dbp[i].u.symbol.name, dbp[i].u.symbol.lineno); + + if (DEBUG_AddBreakpoint(&value, NULL, FALSE)) + memmove(&dbp[i], &dbp[i+1], (--DEBUG_CurrProcess->num_delayed_bp - i) * sizeof(*dbp)); + } } /*********************************************************************** Index: debugger/dbg.y =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/dbg.y,v retrieving revision 1.59 diff -u -u -r1.59 dbg.y --- debugger/dbg.y 23 Jul 2002 20:53:41 -0000 1.59 +++ debugger/dbg.y 29 Jul 2002 20:07:21 -0000 @@ -164,7 +166,7 @@ ; set_command: - tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory(&$2,$4); DEBUG_FreeExprMem(); } + tSET lval_addr '=' expr_value tEOL { DEBUG_WriteMemory(&$2, $4); DEBUG_FreeExprMem(); } | tSET '+' tIDENTIFIER tEOL {DEBUG_DbgChannel(TRUE, NULL, $3);} | tSET '-' tIDENTIFIER tEOL {DEBUG_DbgChannel(FALSE, NULL, $3);} | tSET tIDENTIFIER '+' tIDENTIFIER tEOL {DEBUG_DbgChannel(TRUE, $2, $4);} @@ -212,7 +214,7 @@ ; break_command: - tBREAK '*' expr_addr tEOL{ DEBUG_AddBreakpoint( &$3, NULL ); DEBUG_FreeExprMem(); } + tBREAK '*' expr_addr tEOL{ DEBUG_AddBreakpointFromValue( &$3 ); DEBUG_FreeExprMem(); } | tBREAK identifier tEOL { DEBUG_AddBreakpointFromId($2, -1); } | tBREAK identifier ':' tNUM tEOL { DEBUG_AddBreakpointFromId($2, $4); } | tBREAK tNUM tEOL { DEBUG_AddBreakpointFromLineno($2); } Index: debugger/debugger.h =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/debugger.h,v retrieving revision 1.38 diff -u -u -r1.38 debugger.h --- debugger/debugger.h 23 Jul 2002 20:53:41 -0000 1.38 +++ debugger/debugger.h 29 Jul 2002 19:35:31 -0000 @@ -209,8 +209,14 @@ } DBG_THREAD; typedef struct tagDBG_DELAYED_BP { - int lineno; - char* name; + BOOL is_symbol; + union { + struct { + int lineno; + char* name; + } symbol; + DBG_VALUE value; + } u; } DBG_DELAYED_BP; typedef struct tagDBG_PROCESS { @@ -227,7 +233,7 @@ int num_delayed_bp; /* * This is an index we use to keep track of the debug information - * when we have multiple sources. We use the same database to also + * when we have multiple sources. We use the same database to also * allow us to do an 'info shared' type of deal, and we use the index * to eliminate duplicates. */ @@ -286,7 +294,8 @@ /* debugger/break.c */ extern void DEBUG_SetBreakpoints( BOOL set ); -extern void DEBUG_AddBreakpoint( const DBG_VALUE *addr, BOOL (*func)(void) ); +extern BOOL DEBUG_AddBreakpoint( const DBG_VALUE *addr, BOOL (*func)(void), BOOL verbose ); +extern BOOL DEBUG_AddBreakpointFromValue( const DBG_VALUE *addr ); extern void DEBUG_AddBreakpointFromId( const char *name, int lineno ); extern void DEBUG_AddBreakpointFromLineno( int lineno ); extern void DEBUG_AddWatchpoint( const DBG_VALUE *addr, int is_write ); Index: debugger/intvar.h =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/intvar.h,v retrieving revision 1.8 diff -u -u -r1.8 intvar.h --- debugger/intvar.h 9 Mar 2002 23:50:37 -0000 1.8 +++ debugger/intvar.h 29 Jul 2002 14:21:22 -0000 @@ -25,6 +25,7 @@ INTERNAL_VAR(BreakOnAttach, FALSE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnFirstChance, TRUE, NULL, DT_BASIC_CONST_INT) INTERNAL_VAR(BreakOnDllLoad, FALSE, NULL, DT_BASIC_CONST_INT) +INTERNAL_VAR(CanDeferOnBPByAddr, FALSE, NULL, DT_BASIC_CONST_INT) /* output handling */ INTERNAL_VAR(ConChannelMask, DBG_CHN_MESG, NULL, DT_BASIC_CONST_INT) Index: debugger/stabs.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/stabs.c,v retrieving revision 1.50 diff -u -u -r1.50 stabs.c --- debugger/stabs.c 22 Jul 2002 20:38:10 -0000 1.50 +++ debugger/stabs.c 29 Jul 2002 19:33:14 -0000 @@ -1453,7 +1453,7 @@ value.cookie = DV_TARGET; value.addr.seg = 0; value.addr.off = (DWORD)dbg_hdr.r_brk; - DEBUG_AddBreakpoint(&value, DEBUG_RescanElf); + DEBUG_AddBreakpoint(&value, DEBUG_RescanElf, TRUE); DEBUG_SetBreakpoints(TRUE); } Index: debugger/winedbg.c =================================================================== RCS file: /home/cvs/cvsroot/wine/wine/debugger/winedbg.c,v retrieving revision 1.60 diff -u -u -r1.60 winedbg.c --- debugger/winedbg.c 20 Jul 2002 20:29:09 -0000 1.60 +++ debugger/winedbg.c 29 Jul 2002 20:01:45 -0000 @@ -196,9 +196,10 @@ while (p->threads) DEBUG_DelThread(p->threads); - for (i = 0; i < p->num_delayed_bp; i++) { - DBG_free(p->delayed_bp[i].name); - } + for (i = 0; i < p->num_delayed_bp; i++) + if (p->delayed_bp[i].is_symbol) + DBG_free(p->delayed_bp[i].u.symbol.name); + DBG_free(p->delayed_bp); if (p->prev) p->prev->next = p->next; if (p->next) p->next->prev = p->prev; @@ -283,7 +284,7 @@ value.cookie = DV_TARGET; value.addr.seg = 0; value.addr.off = (DWORD)DEBUG_CurrThread->start; - DEBUG_AddBreakpoint(&value, NULL); + DEBUG_AddBreakpointFromValue(&value); DEBUG_SetBreakpoints(TRUE); } } else {