wdbg_sym: revert to __declspec(naked) because compiler-generated prolog code otherwise trashes the regs

win: formatting
wposix: add mprotect and beef up mmap (WIP).

This was SVN commit r2512.
This commit is contained in:
janwas 2005-07-22 03:54:09 +00:00
parent 4d390f501c
commit 825bd40b68
4 changed files with 153 additions and 97 deletions

View File

@ -282,24 +282,17 @@ int debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int*
#ifdef _M_IX86
// optimized for size.
static void get_current_context(void* pcontext)
// this is the (so far) only case where __declspec(naked) is absolutely
// critical. compiler-generated prolog code trashes EBP and ESP,
// which is especially bad here because the stack trace code relies
// on us returning their correct values.
static __declspec(naked) void get_current_context(void* pcontext)
{
// for safety and future-proofing, we do not use __declspec(naked) and
// access the parameter ourselves. therefore, we need to grab it into
// a register before PUSHAD, which means we'd lose the register's
// previous contents. save it here to prevent that.
static u32 saved_eax;
__asm
{
;// don't write into edi directly so that the compiler (if clever)
;// doesn't need to generate register-save code.
mov [saved_eax], eax
mov eax, [pcontext]
pushad
pushfd
xchg eax, edi ;// edi = (CONTEXT*)pcontext
mov edi, [esp+4+32+4] ;// pcontext
;// ContextFlags
mov eax, 0x10007 ;// segs, int, control
@ -334,13 +327,11 @@ rep stosd
stosd
mov eax, [esp+4+32-8] ;// ecx
stosd
mov eax, [saved_eax]
mov eax, [esp+4+32-4] ;// eax
stosd
;// CONTEXT_CONTROL
mov eax, ebp ;// despite being smaller, don't use XCHG -
;// avoids silly "modifying ebp" warning
;// (we restore via POPAD, but VC is stupid)
;// CONTEXT_CONTROL
xchg eax, ebp ;// ebp restored by POPAD
stosd
mov eax, [esp+4+32] ;// return address
sub eax, 5 ;// skip CALL instruction -> call site.

View File

@ -296,30 +296,30 @@ static int CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam
switch(msg)
{
case WM_INITDIALOG:
{
const DialogParams* params = (const DialogParams*)lParam;
HWND hWnd;
// need to reset for new instance of dialog
dlg_client_origin.x = dlg_client_origin.y = 0;
dlg_prev_client_size.x = dlg_prev_client_size.y = 0;
if(!(params->flags & DE_ALLOW_SUPPRESS))
{
const DialogParams* params = (const DialogParams*)lParam;
HWND hWnd;
// need to reset for new instance of dialog
dlg_client_origin.x = dlg_client_origin.y = 0;
dlg_prev_client_size.x = dlg_prev_client_size.y = 0;
if(!(params->flags & DE_ALLOW_SUPPRESS))
{
hWnd = GetDlgItem(hDlg, IDC_SUPPRESS);
EnableWindow(hWnd, FALSE);
}
// set fixed font for readability
hWnd = GetDlgItem(hDlg, IDC_EDIT1);
HGDIOBJ hObj = (HGDIOBJ)GetStockObject(SYSTEM_FIXED_FONT);
LPARAM redraw = FALSE;
SendMessage(hWnd, WM_SETFONT, (WPARAM)hObj, redraw);
SetDlgItemTextW(hDlg, IDC_EDIT1, params->text);
return TRUE; // set default keyboard focus
hWnd = GetDlgItem(hDlg, IDC_SUPPRESS);
EnableWindow(hWnd, FALSE);
}
// set fixed font for readability
hWnd = GetDlgItem(hDlg, IDC_EDIT1);
HGDIOBJ hObj = (HGDIOBJ)GetStockObject(SYSTEM_FIXED_FONT);
LPARAM redraw = FALSE;
SendMessage(hWnd, WM_SETFONT, (WPARAM)hObj, redraw);
SetDlgItemTextW(hDlg, IDC_EDIT1, params->text);
return TRUE; // set default keyboard focus
}
case WM_SYSCOMMAND:
// close dialog if [X] is clicked (doesn't happen automatically)
// note: lower 4 bits are reserved
@ -330,21 +330,22 @@ static int CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam
}
break;
// return 0 if processed, otherwise break
// return 0 if processed, otherwise break
case WM_COMMAND:
switch(wParam)
{
case IDC_COPY:
{
const size_t max_chars = 128*KiB;
wchar_t* buf = (wchar_t*)malloc(max_chars*sizeof(wchar_t));
if(buf)
{
const size_t max_chars = 100000;
wchar_t* buf = (wchar_t*)malloc(max_chars*sizeof(wchar_t));
if(buf)
{
GetDlgItemTextW(hDlg, IDC_EDIT1, buf, max_chars);
clipboard_set(buf);
}
return 0;
GetDlgItemTextW(hDlg, IDC_EDIT1, buf, max_chars);
clipboard_set(buf);
free(buf);
}
return 0;
}
case IDC_CONTINUE:
EndDialog(hDlg, ER_CONTINUE);
@ -369,15 +370,15 @@ static int CALLBACK error_dialog_proc(HWND hDlg, unsigned int msg, WPARAM wParam
break;
case WM_GETMINMAXINFO:
{
// we must make sure resize_control will never set negative coords -
// Windows would clip them, and its real position would be lost.
// restrict to a reasonable and good looking minimum size [pixels].
MINMAXINFO* mmi = (MINMAXINFO*)lParam;
mmi->ptMinTrackSize.x = 407;
mmi->ptMinTrackSize.y = 159; // determined experimentally
return 0;
}
{
// we must make sure resize_control will never set negative coords -
// Windows would clip them, and its real position would be lost.
// restrict to a reasonable and good looking minimum size [pixels].
MINMAXINFO* mmi = (MINMAXINFO*)lParam;
mmi->ptMinTrackSize.x = 407;
mmi->ptMinTrackSize.y = 159; // determined experimentally
return 0;
}
case WM_SIZE:
dlg_resize(hDlg, wParam, lParam);

View File

@ -503,10 +503,95 @@ int poll(struct pollfd /* fds */[], int /* nfds */, int /* timeout */)
//////////////////////////////////////////////////////////////////////////////
// convert POSIX PROT_* flags to Win32 PAGE_* enumeration.
// used by mprotect.
static DWORD win32_prot(int prot)
{
// this covers all possible combinations of read|write|exec
// (note that "none" means all flags are 0).
switch(prot)
{
case PROT_NONE:
return PAGE_NOACCESS;
case PROT_READ:
return PAGE_READONLY;
case PROT_WRITE:
// not supported by Win32; POSIX allows us to also grant read access.
return PAGE_READWRITE;
case PROT_EXEC:
return PAGE_EXECUTE;
case PROT_READ|PROT_WRITE:
return PAGE_READWRITE;
case PROT_READ|PROT_EXEC:
return PAGE_EXECUTE_READ;
case PROT_WRITE|PROT_EXEC:
// not supported by Win32; POSIX allows us to also grant read access.
return PAGE_EXECUTE_READWRITE;
case PROT_READ|PROT_WRITE|PROT_EXEC:
return PAGE_EXECUTE_READWRITE;
default:
return 0;
}
}
int mprotect(void* addr, size_t len, int prot)
{
const DWORD flNewProtect = win32_prot(prot);
DWORD flOldProtect; // required by VirtualProtect
BOOL ok = VirtualProtect(addr, len, flNewProtect, &flOldProtect);
return ok? 0 : -1;
}
static int mmap_access(int prot, int flags, DWORD& flProtect, DWORD& dwAccess, SECURITY_ATTRIBUTES*& psec)
{
SECURITY_ATTRIBUTES* saved_psec = psec;
// assume read-only with default security; other cases handled below.
flProtect = PAGE_READONLY;
dwAccess = FILE_MAP_READ;
psec = 0;
if(flags & PROT_WRITE)
{
flProtect = PAGE_READWRITE;
dwAccess = FILE_MAP_WRITE; // read and write
// determine write behavior: (whether they change the underlying file)
switch(flags & (MAP_SHARED|MAP_PRIVATE))
{
// .. POSIX says asking for both isn't allowed.
case MAP_SHARED|MAP_PRIVATE:
return ERR_INVALID_PARAM;
// .. changes are written to file and shared between processes.
case MAP_SHARED:
psec = saved_psec;
psec->nLength = sizeof(SECURITY_ATTRIBUTES);
psec->lpSecurityDescriptor = 0;
psec->bInheritHandle = TRUE;
break;
// .. copy-on-write mapping; writes do not affect the file or
// other processes.
case MAP_PRIVATE:
flProtect = PAGE_WRITECOPY;
dwAccess = FILE_MAP_COPY;
break;
// .. changes are written to file but the handle isn't shareable.
default:
break;
}
}
return 0;
}
void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t offset)
{
{
WIN_SAVE_LAST_ERROR;
int err;
// assume fd = -1 (requesting mapping backed by page file),
// so that we notice invalid file handles below.
@ -521,7 +606,8 @@ void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t offs
}
}
// MapView.. will choose start address unless MAP_FIXED was specified.
// if MAP_FIXED, user_start is the start address; otherwise,
// MapViewOfFileEx will choose an address.
void* start = 0;
if(flags & MAP_FIXED)
{
@ -530,39 +616,12 @@ void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t offs
goto fail;
}
// figure out access rights.
// note: reads are always allowed (Win32 limitation).
SECURITY_ATTRIBUTES sec = { sizeof(SECURITY_ATTRIBUTES), (void*)0, FALSE };
DWORD flProtect = PAGE_READONLY;
DWORD dwAccess = FILE_MAP_READ;
// .. no access: not possible on Win32.
if(prot == PROT_NONE)
// figure out protection and access rights.
DWORD flProtect; DWORD dwAccess;
SECURITY_ATTRIBUTES sec; SECURITY_ATTRIBUTES* psec = &sec;
err = mmap_access(prot, flags, flProtect, dwAccess, psec);
if(err < 0)
goto fail;
// .. write or read/write (Win32 doesn't support write-only)
if(prot & PROT_WRITE)
{
flProtect = PAGE_READWRITE;
const bool shared = (flags & MAP_SHARED ) != 0;
const bool priv = (flags & MAP_PRIVATE) != 0;
// .. both aren't allowed
if(shared && priv)
goto fail;
// .. changes are shared & written to file
else if(shared)
{
sec.bInheritHandle = TRUE;
dwAccess = FILE_MAP_ALL_ACCESS;
}
// .. private copy-on-write mapping
else if(priv)
{
flProtect = PAGE_WRITECOPY;
dwAccess = FILE_MAP_COPY;
}
}
// now actually map.
const DWORD len_hi = (DWORD)((u64)len >> 32);
@ -572,7 +631,7 @@ void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t offs
if(hMap == INVALID_HANDLE_VALUE)
// bail now so that MapView.. doesn't overwrite the last error value.
goto fail;
void* ptr = MapViewOfFileEx(hMap, dwAccess, len_hi, offset, len_lo, start);
void* addr = MapViewOfFileEx(hMap, dwAccess, len_hi, offset, len_lo, start);
// free the mapping object now, so that we don't have to hold on to its
// handle until munmap(). it's not actually released yet due to the
@ -580,18 +639,21 @@ void* mmap(void* user_start, size_t len, int prot, int flags, int fd, off_t offs
if(hMap != INVALID_HANDLE_VALUE) // avoid "invalid handle" error
CloseHandle(hMap);
if(!ptr)
if(!addr)
// bail now, before the last error value is restored,
// but after freeing the mapping object.
goto fail;
debug_assert(!(flags & MAP_FIXED) || (ptr == start));
// fixed => ptr = start
// make sure we got the requested address if MAP_FIXED was passed.
debug_assert(!(flags & MAP_FIXED) || (addr == start));
err = mprotect(addr, len, prot);
debug_assert(err == 0);
WIN_RESTORE_LAST_ERROR;
return ptr;
return addr;
}
fail:
return MAP_FAILED;
}

View File

@ -198,9 +198,10 @@ extern int readdir_stat_np(DIR*, struct stat*);
//
// mmap prot flags
#define PROT_NONE 0x00 // no access (not supported on Win32)
#define PROT_NONE 0x00
#define PROT_READ 0x01
#define PROT_WRITE 0x02
#define PROT_EXEC 0x04
// mmap flags
#define MAP_SHARED 0x01 // share changes across processes
@ -212,6 +213,7 @@ extern int readdir_stat_np(DIR*, struct stat*);
extern void* mmap(void* start, size_t len, int prot, int flags, int fd, off_t offset);
extern int munmap(void* start, size_t len);
extern int mprotect(void* addr, size_t len, int prot);
//
// <fcntl.h>