Release 970112
Sat Jan 11 18:17:59 1997 Alexandre Julliard <julliard@lrc.epfl.ch>
* [controls/menu.c]
Updated to new Win32 types.
* [controls/listbox.c]
Fixed Winfile extended selection bug.
* [files/directory.c]
Changed DIR_SearchPath to return both long and short file names.
* [files/dos_fs.c]
Implemented VFAT ioctl to retrieve the original short filenames
from a VFAT filesystem (Linux only for now).
Replaced DOSFS_GetUnixFileName()/DOSFS_GetDosTrueName() by
DOS_GetFullName().
Properly implemented GetShortPathName() and GetFullPathName().
Made all functions re-entrant.
* [files/file.c] [misc/main.c]
Replaced -allowreadonly option by -failreadonly. The default is
now to report success when opening a read-only file for writing.
* [objects/metafile.c]
Fixed bug in DIB bitmaps pointer calculation.
* [scheduler/process.c]
Implemented environment strings and Get/SetStdHandle with process
environment block.
* [tools/build.c]
Rewrote BuildContext32() to avoid instructions that may not be
supported by all assemblers.
Fri Jan 10 17:11:09 1997 David Faure <david.faure@ifhamy.insa-lyon.fr>
* [windows/event.c]
Created table keyc2vkey, which associate a vkey(+extended bit) to
any keycode. Changed EVENT_event_to_vkey to use this table to
return the correct vkey. Changed EVENT_ToAscii to get the keycode
from this table too. Assigned OEM specific vkeys arbitrarily.
Fri Jan 10 09:26:17 1997 John Harvey <john@division.co.uk>
* [misc/winsock.c] [misc/winsoc_async.c]
Fixed svr4 header files.
Changed bzero() to memset().
* [tools/fnt2bdf.c]
Removed bcopy() and used memcpy() instead.
* [debugger/msc.c]
Include string.h instead of strings.h
* [debugger/stabs.c]
Include string.h instead of strings.h.
Define __ELF__ for svr4 systems.
* [loader/signal.c]
Use wait() instead of wait4() which doesnt exist on Unixware.
* [memory/global.c]
Use sysconf() instead of getpagesize() for svr4 systems.
Thu Jan 9 21:07:20 1997 Robert Pouliot <krynos@clic.net>
* [Make.rules.in] [Makefile.in] [make_os2.sh] [rc/Makefile.in]
[tools/Makefile.in] [documentation/wine_os2.txt]
Patches for OS/2 support. Note that it doesn't compile yet.
Tue Jan 7 20:03:53 1997 Eric Youngdale <eric@sub2304.jic.com>
* [debugger/*]
Many more debugger improvements (see debugger/README for details).
Tue Jan 7 15:12:21 1997 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de>
* [windows/graphics.c] [objects/text.c] [graphics/x11drv/*]
[graphics/metafiledrv/*]
Moved some device dependent code into the resp. subdirs.
* [include/gdi.h] [include/metafiledrv.h] [include/x11drv.h]
Prototypes added,
DC_FUNCTIONS: GetPixel added, some unnecessary functions removed.
* [objects/region.c]
CreatePolyPolygonRgn32 added.
* [files/dos_fs.c]
QueryDosDevice added.
* [misc/lstr.c]
FormatMessage: broken heap management fixed.
* [scheduler/process.c] [scheduler/thread.c]
Get/SetThreadPriority/PriorityClass added.
Mon Jan 6 21:55:30 1997 Philippe De Muyter <phdm@info.ucl.ac.be>
* [misc/keyboard.c]
ToAscii : Use EVENT_ToAscii instead.
* [windows/event.c]
keypad_key : Do not convert XK_Mode_switch to VK_MENU; recognize
keypad cursor keys.
EVENT_event_to_vkey : New function, to transform a X keycode
into a MSwin vkey + extended bit.
EVENT_ToAscii : New function, to transform a vkey + extended bit
(+ key state table) into ascii char(s), using XLookupString, and
recognizing dead chars.
EVENT_key : Transform AltGr into Ctrl+Alt sequence; call
EVENT_event_to_vkey for keycode to vkey conversion; fixed
previous, context and extended bits.
* [windows/keyboard.c]
Include stddebug.h, to get -debugmsg messages.
GetKeyState : Handle VK_MBUTTON case.
GetKeyboardState, SetKeyboardState : Debugging messages added.
* [windows/message.c]
TranslateMessage : Handle dead chars.
Mon Jan 6 20:10:11 1997 Dominik Strasser <bm424953@muenchen.org>
* [if1632/crtdll.spec] [misc/crtdll.c]
C++ functions new/delete/set_new_handler implemented.
Mon Jan 6 15:48:15 1997 Frans van Dorsselaer <dorssel@rulhmpc49.LeidenUniv.nl>
* [controls/edit.c] [include/windows.h]
Moved the edit control to 32 bits.
Included new (win95) message definitions in windows.h
Implemented EM_SCROLLCARET, EM_SETMARGINS, EM_GETMARGINS,
EM_GETLIMITTEXT, EM_POSFROMCHAR, EM_CHARFROMPOS.
Broke EM_SETWORDBREAKPROC (internal wordwrap still works).
Fixed some bugs, introduced a couple of others.
Text buffer is now initially in 32-bit heap.
* [controls/EDIT.TODO] [controls/combo.c] [controls/widgets.c]
[if1632/wprocs.spec] [library/miscstubs.c] [windows/defdlg.c]
[misc/commdlg.c]
Updated to work with 32-bit edit control.
Sat Jan 4 22:07:27 1997 O.Flebbe <O.Flebbe@science-computing.uni-tuebingen.de>
* [loader/pe_image.c]
Use mmap rather then malloc. Better workaround for clean
segments.
diff --git a/debugger/break.c b/debugger/break.c
index eb97f6c..5cf164f 100644
--- a/debugger/break.c
+++ b/debugger/break.c
@@ -14,15 +14,17 @@
#define INT3 0xcc /* int 3 opcode */
-#define MAX_BREAKPOINTS 25
+#define MAX_BREAKPOINTS 100
typedef struct
{
- DBG_ADDR addr;
- BYTE addrlen;
- BYTE opcode;
- BOOL16 enabled;
- BOOL16 in_use;
+ DBG_ADDR addr;
+ BYTE addrlen;
+ BYTE opcode;
+ BOOL16 enabled;
+ WORD skipcount;
+ BOOL16 in_use;
+ struct expr * condition;
} BREAKPOINT;
static BREAKPOINT breakpoints[MAX_BREAKPOINTS];
@@ -65,7 +67,7 @@
* Determine if the instruction at CS:EIP is an instruction that
* we need to step over (like a call or a repetitive string move).
*/
-static BOOL32 DEBUG_IsStepOverInstr(void)
+static BOOL32 DEBUG_IsStepOverInstr()
{
BYTE *instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
EIP_reg(&DEBUG_context) );
@@ -126,6 +128,31 @@
/***********************************************************************
+ * DEBUG_IsFctReturn
+ *
+ * Determine if the instruction at CS:EIP is an instruction that
+ * is a function return.
+ */
+BOOL32 DEBUG_IsFctReturn(void)
+{
+ BYTE *instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
+ EIP_reg(&DEBUG_context) );
+
+ for (;;)
+ {
+ switch(*instr)
+ {
+ case 0xc2:
+ case 0xc3:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+}
+
+
+/***********************************************************************
* DEBUG_SetBreakpoints
*
* Set or remove all the breakpoints.
@@ -205,6 +232,7 @@
breakpoints[num].opcode = *p;
breakpoints[num].enabled = TRUE;
breakpoints[num].in_use = TRUE;
+ breakpoints[num].skipcount = 0;
fprintf( stderr, "Breakpoint %d at ", num );
DEBUG_PrintAddress( &breakpoints[num].addr, breakpoints[num].addrlen,
TRUE );
@@ -226,6 +254,7 @@
}
breakpoints[num].enabled = FALSE;
breakpoints[num].in_use = FALSE;
+ breakpoints[num].skipcount = 0;
}
@@ -242,6 +271,7 @@
return;
}
breakpoints[num].enabled = enable;
+ breakpoints[num].skipcount = 0;
}
@@ -263,6 +293,12 @@
DEBUG_PrintAddress( &breakpoints[i].addr, breakpoints[i].addrlen,
TRUE);
fprintf( stderr, "\n" );
+ if( breakpoints[i].condition != NULL )
+ {
+ fprintf(stderr, "\t\tstop when ");
+ DEBUG_DisplayExpr(breakpoints[i].condition);
+ fprintf(stderr, "\n");
+ }
}
}
}
@@ -274,10 +310,12 @@
* Determine if we should continue execution after a SIGTRAP signal when
* executing in the given mode.
*/
-BOOL32 DEBUG_ShouldContinue( enum exec_mode mode )
+BOOL32 DEBUG_ShouldContinue( enum exec_mode mode, int * count )
{
DBG_ADDR addr;
+ DBG_ADDR cond_addr;
int bpnum;
+ struct list_id list;
/* If not single-stepping, back up over the int3 instruction */
if (!(EFL_reg(&DEBUG_context) & STEP_FLAG)) EIP_reg(&DEBUG_context)--;
@@ -291,20 +329,98 @@
if ((bpnum != 0) && (bpnum != -1))
{
+ if( breakpoints[bpnum].condition != NULL )
+ {
+ cond_addr = DEBUG_EvalExpr(breakpoints[bpnum].condition);
+ if( cond_addr.type == NULL )
+ {
+ /*
+ * Something wrong - unable to evaluate this expression.
+ */
+ fprintf(stderr, "Unable to evaluate expression ");
+ DEBUG_DisplayExpr(breakpoints[bpnum].condition);
+ fprintf(stderr, "\nTurning off condition\n");
+ DEBUG_AddBPCondition(bpnum, NULL);
+ }
+ else if( ! DEBUG_GetExprValue( &cond_addr, NULL) )
+ {
+ return TRUE;
+ }
+ }
+
+ if( breakpoints[bpnum].skipcount > 0 )
+ {
+ breakpoints[bpnum].skipcount--;
+ if( breakpoints[bpnum].skipcount > 0 )
+ {
+ return TRUE;
+ }
+ }
fprintf( stderr, "Stopped on breakpoint %d at ", bpnum );
DEBUG_PrintAddress( &breakpoints[bpnum].addr,
breakpoints[bpnum].addrlen, TRUE );
fprintf( stderr, "\n" );
+
+ /*
+ * See if there is a source file for this bp. If so,
+ * then dig it out and display one line.
+ */
+ DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
+ if( list.sourcefile != NULL )
+ {
+ DEBUG_List(&list, NULL, 0);
+ }
return FALSE;
}
+ /*
+ * If our mode indicates that we are stepping line numbers,
+ * get the current function, and figure out if we are exactly
+ * on a line number or not.
+ */
+ if( mode == EXEC_STEP_OVER
+ || mode == EXEC_STEP_INSTR )
+ {
+ if( DEBUG_CheckLinenoStatus(&addr) == AT_LINENUMBER )
+ {
+ (*count)--;
+ }
+ }
+ else if( mode == EXEC_STEPI_OVER
+ || mode == EXEC_STEPI_INSTR )
+
+ {
+ (*count)--;
+ }
+
+ if( *count > 0 || mode == EXEC_FINISH )
+ {
+ /*
+ * We still need to execute more instructions.
+ */
+ return TRUE;
+ }
+
+ /*
+ * If we are about to stop, then print out the source line if we
+ * have it.
+ */
+ if( (mode != EXEC_CONT && mode != EXEC_FINISH) )
+ {
+ DEBUG_FindNearestSymbol( &addr, TRUE, NULL, 0, &list);
+ if( list.sourcefile != NULL )
+ {
+ DEBUG_List(&list, NULL, 0);
+ }
+ }
+
/* If there's no breakpoint and we are not single-stepping, then we */
/* must have encountered an int3 in the Windows program; let's skip it. */
if ((bpnum == -1) && !(EFL_reg(&DEBUG_context) & STEP_FLAG))
EIP_reg(&DEBUG_context)++;
/* no breakpoint, continue if in continuous mode */
- return (mode == EXEC_CONT);
+ return (mode == EXEC_CONT || mode == EXEC_FINISH);
}
@@ -314,16 +430,102 @@
* Set the breakpoints to the correct state to restart execution
* in the given mode.
*/
-void DEBUG_RestartExecution( enum exec_mode mode, int instr_len )
+enum exec_mode DEBUG_RestartExecution( enum exec_mode mode, int count )
{
DBG_ADDR addr;
+ DBG_ADDR addr2;
+ int bp;
+ int delta;
+ int status;
+ unsigned int * value;
+ enum exec_mode ret_mode;
+ BYTE *instr;
addr.seg = (CS_reg(&DEBUG_context) == WINE_CODE_SELECTOR) ?
0 : CS_reg(&DEBUG_context);
addr.off = EIP_reg(&DEBUG_context);
- if (DEBUG_FindBreakpoint( &addr ) != -1)
- mode = EXEC_STEP_INSTR; /* If there's a breakpoint, skip it */
+ /*
+ * This is the mode we will be running in after we finish. We would like
+ * to be able to modify this in certain cases.
+ */
+ ret_mode = mode;
+
+ bp = DEBUG_FindBreakpoint( &addr );
+ if ( bp != -1 && bp != 0)
+ {
+ /*
+ * If we have set a new value, then save it in the BP number.
+ */
+ if( count != 0 && mode == EXEC_CONT )
+ {
+ breakpoints[bp].skipcount = count;
+ }
+ mode = EXEC_STEPI_INSTR; /* If there's a breakpoint, skip it */
+ }
+ else
+ {
+ if( mode == EXEC_CONT && count > 1 )
+ {
+ fprintf(stderr,"Not stopped at any breakpoint; argument ignored.\n");
+ }
+ }
+
+ if( mode == EXEC_FINISH && DEBUG_IsFctReturn() )
+ {
+ mode = ret_mode = EXEC_STEPI_INSTR;
+ }
+
+ instr = (BYTE *)PTR_SEG_OFF_TO_LIN( CS_reg(&DEBUG_context),
+ EIP_reg(&DEBUG_context) );
+ /*
+ * See if the function we are stepping into has debug info
+ * and line numbers. If not, then we step over it instead.
+ * FIXME - we need to check for things like thunks or trampolines,
+ * as the actual function may in fact have debug info.
+ */
+ if( *instr == 0xe8 )
+ {
+ delta = *(unsigned int*) (instr + 1);
+ addr2 = addr;
+ DEBUG_Disasm(&addr2, FALSE);
+ addr2.off += delta;
+
+ status = DEBUG_CheckLinenoStatus(&addr2);
+ /*
+ * Anytime we have a trampoline, step over it.
+ */
+ if( ((mode == EXEC_STEP_OVER) || (mode == EXEC_STEPI_OVER))
+ && status == FUNC_IS_TRAMPOLINE )
+ {
+#if 0
+ fprintf(stderr, "Not stepping into trampoline at %x (no lines)\n",
+ addr2.off);
+#endif
+ mode = EXEC_STEP_OVER_TRAMPOLINE;
+ }
+
+ if( mode == EXEC_STEP_INSTR && status == FUNC_HAS_NO_LINES )
+ {
+#if 0
+ fprintf(stderr, "Not stepping into function at %x (no lines)\n",
+ addr2.off);
+#endif
+ mode = EXEC_STEP_OVER;
+ }
+ }
+
+
+ if( mode == EXEC_STEP_INSTR )
+ {
+ if( DEBUG_CheckLinenoStatus(&addr) == FUNC_HAS_NO_LINES )
+ {
+ fprintf(stderr, "Single stepping until exit from function, \n");
+ fprintf(stderr, "which has no line number information.\n");
+
+ ret_mode = mode = EXEC_FINISH;
+ }
+ }
switch(mode)
{
@@ -332,14 +534,35 @@
DEBUG_SetBreakpoints( TRUE );
break;
+ case EXEC_STEP_OVER_TRAMPOLINE:
+ /*
+ * This is the means by which we step over our conversion stubs
+ * in callfrom*.s and callto*.s. We dig the appropriate address
+ * off the stack, and we set the breakpoint there instead of the
+ * address just after the call.
+ */
+ value = (unsigned int *) ESP_reg(&DEBUG_context) + 2;
+ addr.off = *value;
+ EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
+ breakpoints[0].addr = addr;
+ breakpoints[0].enabled = TRUE;
+ breakpoints[0].in_use = TRUE;
+ breakpoints[0].skipcount = 0;
+ breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
+ DEBUG_SetBreakpoints( TRUE );
+ break;
+
+ case EXEC_FINISH:
+ case EXEC_STEPI_OVER: /* Stepping over a call */
case EXEC_STEP_OVER: /* Stepping over a call */
if (DEBUG_IsStepOverInstr())
{
EFL_reg(&DEBUG_context) &= ~STEP_FLAG;
- addr.off += instr_len;
+ DEBUG_Disasm(&addr, FALSE);
breakpoints[0].addr = addr;
breakpoints[0].enabled = TRUE;
breakpoints[0].in_use = TRUE;
+ breakpoints[0].skipcount = 0;
breakpoints[0].opcode = *(BYTE *)DBG_ADDR_TO_LIN( &addr );
DEBUG_SetBreakpoints( TRUE );
break;
@@ -347,7 +570,32 @@
/* else fall through to single-stepping */
case EXEC_STEP_INSTR: /* Single-stepping an instruction */
+ case EXEC_STEPI_INSTR: /* Single-stepping an instruction */
EFL_reg(&DEBUG_context) |= STEP_FLAG;
break;
}
+ return ret_mode;
+}
+
+int
+DEBUG_AddBPCondition(int num, struct expr * exp)
+{
+ if ((num <= 0) || (num >= next_bp) || !breakpoints[num].in_use)
+ {
+ fprintf( stderr, "Invalid breakpoint number %d\n", num );
+ return FALSE;
+ }
+
+ if( breakpoints[num].condition != NULL )
+ {
+ DEBUG_FreeExpr(breakpoints[num].condition);
+ breakpoints[num].condition = NULL;
+ }
+
+ if( exp != NULL )
+ {
+ breakpoints[num].condition = DEBUG_CloneExpr(exp);
+ }
+
+ return TRUE;
}