forked from 0ad/0ad
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:
parent
4d390f501c
commit
825bd40b68
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user