1
0
forked from 0ad/0ad

sdl: remove complicated mouse button check/workaround; that's now done in Interact.cpp (which makes the assumptions being tested)

ia32.asm: move get_current_context code here

wdbg_sym: revised get_context code; moved it into walk_stack (fixes bug
on non-ia32)

wsdl: bring in line with real SDL SDL_BUTTON_* (sorry nicolai!)
interact now checks for expected values of SDL_BUTTON.

This was SVN commit r2991.
This commit is contained in:
janwas 2005-10-24 00:06:08 +00:00
parent 359f55700a
commit b80be29eab
6 changed files with 142 additions and 167 deletions

View File

@ -1,16 +1,10 @@
#ifndef _lib_sdl_H
#define _lib_sdl_H
#ifndef LIB_SDL_H__
#define LIB_SDL_H__
#define SDL_BUTTON_INDEX_COUNT 5
#if OS_WIN && !defined(NO_WSDL)
#if OS_WIN && !defined(CONFIG_NO_WSDL)
# include "sysdep/win/wsdl.h"
// The SDL_BUTTON_* enum is zero-based and in the range [0..4] in wsdl.h
#define SDL_BUTTON_TO_INDEX(_but) _but
#define SDL_INDEX_TO_BUTTON(_idx) _idx
#else
# include <SDL/SDL.h>
# include <SDL/SDL_thread.h>
# include <SDL/SDL_endian.h>
@ -19,22 +13,6 @@
// will strip them if unused, and this is more convenient than
// another header that toggles between wsdl and SDL_endian.h.
#if SDL_BUTTON_LEFT == 1 && SDL_BUTTON_MIDDLE == 2 && SDL_BUTTON_RIGHT == 3 \
&& SDL_BUTTON_WHEELUP == 4 && SDL_BUTTON_WHEELDOWN == 5
#define SDL_BUTTON_TO_INDEX(_but) ((_but) - 1)
#define SDL_INDEX_TO_BUTTON(_idx) ((_idx) - 1)
#else
/* Add a test like the one above for your set of button constants, and implement
the BUTTON_TO_INDEX macros so that the resulting indices are within the range
[0, SDL_BUTTON_INDEX_COUNT-1]
*/
#error "Platform with unrecognized SDL constants. Update sdl.h"
#endif
#endif
#endif // _lib_sdl_H
#endif // LIB_SDL_H__

View File

@ -358,6 +358,81 @@ sym(ia32_control87):
xor eax, eax ; return value
ret
; write the current execution state (e.g. all register values) into
; (Win32::CONTEXT*)pcontext (defined as void* to avoid dependency).
; optimized for size; this must be straight asm because __declspec(naked)
; is compiler-specific and compiler-generated prolog code inserted before
; inline asm trashes EBP and ESP (unacceptable).
; extern "C" void ia32_get_current_context(void* pcontext)
global sym(ia32_get_current_context)
sym(ia32_get_current_context):
pushad
pushfd
mov edi, [esp+4+32+4] ; pcontext
; ContextFlags
mov eax, 0x10007 ; segs, int, control
stosd
; DRx and FloatSave
; rationale: we can't access the debug registers from Ring3, and
; the FPU save area is irrelevant, so zero them.
xor eax, eax
push byte 6+8+20
pop ecx
rep stosd
; CONTEXT_SEGMENTS
mov ax, gs
stosd
mov ax, fs
stosd
mov ax, es
stosd
mov ax, ds
stosd
; CONTEXT_INTEGER
mov eax, [esp+4+32-32] ; edi
stosd
xchg eax, esi
stosd
xchg eax, ebx
stosd
xchg eax, edx
stosd
mov eax, [esp+4+32-8] ; ecx
stosd
mov eax, [esp+4+32-4] ; eax
stosd
; 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.
stosd
xor eax, eax
mov ax, cs
stosd
pop eax ; eflags
stosd
lea eax, [esp+32+4+4] ; esp
stosd
xor eax, eax
mov ax, ss
stosd
; ExtendedRegisters
xor ecx, ecx
mov cl, 512/4
rep stosd
popad
ret
;-------------------------------------------------------------------------------
; init
;-------------------------------------------------------------------------------

View File

@ -76,6 +76,9 @@ extern void ia32_debug_break(void);
extern void ia32_memcpy(void* dst, const void* src, size_t nbytes);
// write the current execution state (e.g. all register values) into
// (Win32::CONTEXT*)pcontext (defined as void* to avoid dependency).
extern void ia32_get_current_context(void* pcontext);
// CPU caps (128 bits)
// do not change the order!

View File

@ -21,7 +21,6 @@
#include <stdio.h>
#include "lib.h"
#include "win_internal.h"
#define _NO_CVCONST_H // request SymTagEnum be defined
#include "dbghelp.h"
@ -30,15 +29,13 @@
#include "sysdep/cpu.h"
#include "wdbg.h"
#include "debug_stl.h"
#if CPU_IA32
# include "lib/sysdep/ia32.h"
#endif
#define SELF_TEST_ENABLED 0 // raises an an annoying exception
#include "self_test.h"
// optional: enables translation of the "unhandled exception" dialog.
#ifdef I18N
#include "ps/i18n.h"
#endif
#if MSC_VERSION
#pragma comment(lib, "dbghelp.lib")
@ -265,122 +262,6 @@ int debug_resolve_symbol(void* ptr_of_interest, char* sym_name, char* file, int*
// stack walk via dbghelp
//----------------------------------------------------------------------------
// rationale: to function properly, StackWalk64 requires a CONTEXT on
// non-x86 systems (documented) or when in release mode (observed).
// exception handlers can call walk_stack with their context record;
// otherwise (e.g. dump_stack from debug_assert), we need to query it.
// there are 2 platform-independent ways to do so:
// - intentionally raise an SEH exception, then proceed as above;
// - GetThreadContext while suspended (*).
// the latter is more complicated and slower, so we go with the former
// despite it outputting "first chance exception" on each call.
//
// on IA-32, we use ia32_get_win_context instead of the above because
// it is 100% accurate (noticeable in StackWalk64 results) and simplest.
//
// * it used to be common practice not to query the current thread's context,
// but WinXP SP2 and above require it be suspended.
// copy from CONTEXT to STACKFRAME64
#if CPU_IA32
// optimized for size.
// 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)
{
// squelch W4 unused parameter warning (it's accessed from asm)
UNUSED2(pcontext);
__asm
{
pushad
pushfd
mov edi, [esp+4+32+4] ;// pcontext
;// ContextFlags
mov eax, 0x10007 ;// segs, int, control
stosd
;// DRx and FloatSave
;// rationale: we can't access the debug registers from Ring3, and
;// the FPU save area is irrelevant, so zero them.
xor eax, eax
push 6+8+20
pop ecx
rep stosd
;// CONTEXT_SEGMENTS
mov ax, gs
stosd
mov ax, fs
stosd
mov ax, es
stosd
mov ax, ds
stosd
;// CONTEXT_INTEGER
mov eax, [esp+4+32-32] ;// edi
stosd
xchg eax, esi
stosd
xchg eax, ebx
stosd
xchg eax, edx
stosd
mov eax, [esp+4+32-8] ;// ecx
stosd
mov eax, [esp+4+32-4] ;// eax
stosd
;// 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.
stosd
xor eax, eax
mov ax, cs
stosd
pop eax ;// eflags
stosd
lea eax, [esp+32+4+4] ;// esp
stosd
xor eax, eax
mov ax, ss
stosd
;// ExtendedRegisters
push 512/4
pop ecx
rep stosd
popad
ret
}
}
#else // #if CPU_IA32
static void get_current_context(CONTEXT* pcontext)
{
__try
{
RaiseException(0xF001, 0, 0, 0);
}
__except(*pcontext = (GetExceptionInformation())->ContextRecord, EXCEPTION_CONTINUE_EXECUTION)
{
}
}
#endif
// called for each stack frame found by walk_stack, passing information
// about the frame and <user_arg>.
// return <= 0 to stop immediately and have walk_stack return that;
@ -400,7 +281,10 @@ static int walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip = 0,
const HANDLE hThread = GetCurrentThread();
// get CONTEXT (see above)
// to function properly, StackWalk64 requires a CONTEXT on
// non-x86 systems (documented) or when in release mode (observed).
// exception handlers can call walk_stack with their context record;
// otherwise (e.g. dump_stack from debug_assert), we need to query it.
CONTEXT context;
// .. caller knows the context (most likely from an exception);
// since StackWalk64 may modify it, copy to a local variable.
@ -409,8 +293,43 @@ static int walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip = 0,
// .. need to determine context ourselves.
else
{
get_current_context(&context);
skip++; // skip this frame
// there are 4 ways to do so, in order of preference:
// - asm (easy to use but currently only implemented on IA32)
// - RtlCaptureContext (only available on WinXP or above)
// - intentionally raise an SEH exception and capture its context
// (spams us with "first chance exception")
// - GetThreadContext while suspended* (a bit tricky + slow).
//
// * it used to be common practice to query the current thread's context,
// but WinXP SP2 and above require it be suspended.
//
// this MUST be done inline and not in an external function because
// compiler-generated prolog code trashes some registers.
#if CPU_IA32
ia32_get_current_context(&context);
#else
// try to import RtlCaptureContext (available on WinXP and later)
HMODULE hKernel32Dll = LoadLibrary("kernel32.dll");
VOID(*pRtlCaptureContext)(PCONTEXT*);
*(void**)&pRtlCaptureContext = GetProcAddress(hKernel32Dll, "RtlCaptureContext");
FreeLibrary(hKernel32Dll); // doesn't actually free the lib
if(pRtlCaptureContext)
pRtlCaptureContext(&context);
// not available: raise+handle an exception; grab the reported context.
else
{
__try
{
RaiseException(0xF001, 0, 0, 0);
}
__except(context = (GetExceptionInformation())->ContextRecord, EXCEPTION_CONTINUE_EXECUTION)
{
}
}
#endif
}
pcontext = &context;
@ -427,7 +346,7 @@ static int walk_stack(StackFrameCallback cb, void* user_arg = 0, uint skip = 0,
int ret = WDBG_NO_STACK_FRAMES_FOUND;
for(;;)
{
BOOL ok = StackWalk64(machine, hProcess, hThread, &sf, (void*)pcontext,
BOOL ok = StackWalk64(machine, hProcess, hThread, &sf, (PVOID)pcontext,
0, SymFunctionTableAccess64, SymGetModuleBase64, 0);
// no more frames found - abort.
@ -984,7 +903,7 @@ in_register:
*pp = (const u8*)addr;
debug_printf("DET_SYM_ADDR %ws at %p flags=%X dk=%d sym->addr=%I64X addrofs=%X addr2=%I64X ofs2=%X\n", sym->Name, *pp, sym->Flags, data_kind, sym->Address, addrofs, addr2, ofs2);
debug_printf("SYM: %ws at %p flags=%X dk=%d sym->addr=%I64X addrofs=%X addr2=%I64X ofs2=%X\n", sym->Name, *pp, sym->Flags, data_kind, sym->Address, addrofs, addr2, ofs2);
return 0;
}
@ -1724,7 +1643,7 @@ static int dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState UNUSED
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))
return WDBG_TYPE_INFO_UNAVAILABLE;
debug_printf("Unknown tag: %d\n", type_tag);
debug_printf("SYM: unknown tag: %d\n", type_tag);
out(L"(unknown symbol type)");
return 0;
}
@ -1737,9 +1656,7 @@ static int dump_sym_unknown(DWORD type_id, const u8* UNUSED(p), DumpState UNUSED
// delegates to dump_sym_* depending on the symbol's tag.
static int dump_sym(DWORD type_id, const u8* p, DumpState state)
{
int ret = out_check_limit();
if(ret != 0)
return ret;
RETURN_ERR(out_check_limit());
DWORD type_tag;
if(!SymGetTypeInfo(hProcess, mod_base, type_id, TI_GET_SYMTAG, &type_tag))

View File

@ -204,15 +204,12 @@ SDL_QuitEvent;
enum SDL_MouseButtonEvent_button
{
// do not change order or values
// ... but if you do, update lib/sdl.h so that SDL_BUTTON_TO_INDEX still
// yields contiguous values
SDL_BUTTON_LEFT=0,
SDL_BUTTON_RIGHT=1,
SDL_BUTTON_MIDDLE=2,
SDL_BUTTON_WHEELUP=3,
SDL_BUTTON_WHEELDOWN=4
// to remain compatible with regular SDL, these values must not change!
SDL_BUTTON_LEFT = 1,
SDL_BUTTON_MIDDLE = 2,
SDL_BUTTON_RIGHT = 3,
SDL_BUTTON_WHEELUP = 4,
SDL_BUTTON_WHEELDOWN = 5
};
enum SDL_MouseButtonEvent_state

View File

@ -835,6 +835,11 @@ InReaction interactInputHandler( const SDL_Event* ev )
//CTerrain *pTerrain=g_Game->GetWorld()->GetTerrain();
// One entry for each mouse button
// note: to store these in an array, we make assumptions as to the
// SDL_BUTTON_* values; these are verified at compile time.
cassert(SDL_BUTTON_LEFT == 1 && SDL_BUTTON_MIDDLE == 2 && SDL_BUTTON_RIGHT == 3 && \
SDL_BUTTON_WHEELUP == 4 && SDL_BUTTON_WHEELDOWN == 5);
const uint SDL_BUTTON_INDEX_COUNT = 6;
static double lastclicktime[SDL_BUTTON_INDEX_COUNT];
static HEntity lastclickobject[SDL_BUTTON_INDEX_COUNT];
static u8 clicks[SDL_BUTTON_INDEX_COUNT];
@ -917,7 +922,7 @@ InReaction interactInputHandler( const SDL_Event* ev )
return( IN_HANDLED );
case SDL_MOUSEBUTTONUP:
{
int button = SDL_BUTTON_TO_INDEX(ev->button.button);
int button = ev->button.button;
// Only process buttons within the range for which we have button state
// arrays above.
if (button >= 0 && button < SDL_BUTTON_INDEX_COUNT)