Cygwin: pty: Limit API hook to the program linked with the APIs.

- API hook used for pseudo console support causes slow down.
  This patch limits API hook to only program which is linked
  with the corresponding APIs. Normal cygwin program is not
  linked with such APIs (such as WriteFile, etc...) directly,
  therefore, no slow down occurs. However, console access by
  cygwin.dll itself cannot switch the r/w pipe to pseudo console
  side. Therefore, the code to switch it forcely to pseudo
  console side is added to smallprint.cc and strace.cc.
This commit is contained in:
Takashi Yano 2019-09-04 22:46:51 +09:00 committed by Corinna Vinschen
parent 583102e7c9
commit 83b2d576c8
4 changed files with 65 additions and 70 deletions

View File

@ -88,6 +88,19 @@ set_switch_to_pcon (void)
} }
} }
void
set_ishybrid_and_switch_to_pcon (HANDLE h)
{
DWORD dummy;
if (!isHybrid
&& GetFileType (h) == FILE_TYPE_CHAR
&& GetConsoleMode (h, &dummy))
{
isHybrid = true;
set_switch_to_pcon ();
}
}
#define DEF_HOOK(name) static __typeof__ (name) *name##_Orig #define DEF_HOOK(name) static __typeof__ (name) *name##_Orig
DEF_HOOK (WriteFile); DEF_HOOK (WriteFile);
DEF_HOOK (WriteConsoleA); DEF_HOOK (WriteConsoleA);
@ -100,6 +113,7 @@ DEF_HOOK (WriteConsoleOutputW);
DEF_HOOK (WriteConsoleOutputCharacterA); DEF_HOOK (WriteConsoleOutputCharacterA);
DEF_HOOK (WriteConsoleOutputCharacterW); DEF_HOOK (WriteConsoleOutputCharacterW);
DEF_HOOK (WriteConsoleOutputAttribute); DEF_HOOK (WriteConsoleOutputAttribute);
DEF_HOOK (SetConsoleTextAttribute);
DEF_HOOK (WriteConsoleInputA); DEF_HOOK (WriteConsoleInputA);
DEF_HOOK (WriteConsoleInputW); DEF_HOOK (WriteConsoleInputW);
DEF_HOOK (ReadConsoleInputA); DEF_HOOK (ReadConsoleInputA);
@ -107,140 +121,137 @@ DEF_HOOK (ReadConsoleInputW);
DEF_HOOK (PeekConsoleInputA); DEF_HOOK (PeekConsoleInputA);
DEF_HOOK (PeekConsoleInputW); DEF_HOOK (PeekConsoleInputW);
#define CHK_CONSOLE_ACCESS(h) \
{ \
DWORD dummy; \
if (!isHybrid \
&& GetFileType (h) == FILE_TYPE_CHAR \
&& GetConsoleMode (h, &dummy)) \
{ \
isHybrid = true; \
set_switch_to_pcon (); \
} \
}
static BOOL WINAPI static BOOL WINAPI
WriteFile_Hooked WriteFile_Hooked
(HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o) (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteFile_Orig (h, p, l, n, o); return WriteFile_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleA_Hooked WriteConsoleA_Hooked
(HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o) (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleA_Orig (h, p, l, n, o); return WriteConsoleA_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleW_Hooked WriteConsoleW_Hooked
(HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o) (HANDLE h, LPCVOID p, DWORD l, LPDWORD n, LPVOID o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleW_Orig (h, p, l, n, o); return WriteConsoleW_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
ReadFile_Hooked ReadFile_Hooked
(HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o) (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPOVERLAPPED o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return ReadFile_Orig (h, p, l, n, o); return ReadFile_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
ReadConsoleA_Hooked ReadConsoleA_Hooked
(HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o) (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return ReadConsoleA_Orig (h, p, l, n, o); return ReadConsoleA_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
ReadConsoleW_Hooked ReadConsoleW_Hooked
(HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o) (HANDLE h, LPVOID p, DWORD l, LPDWORD n, LPVOID o)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return ReadConsoleW_Orig (h, p, l, n, o); return ReadConsoleW_Orig (h, p, l, n, o);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleOutputA_Hooked WriteConsoleOutputA_Hooked
(HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r) (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleOutputA_Orig (h, p, s, c, r); return WriteConsoleOutputA_Orig (h, p, s, c, r);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleOutputW_Hooked WriteConsoleOutputW_Hooked
(HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r) (HANDLE h, CONST CHAR_INFO *p, COORD s, COORD c, PSMALL_RECT r)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleOutputW_Orig (h, p, s, c, r); return WriteConsoleOutputW_Orig (h, p, s, c, r);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleOutputCharacterA_Hooked WriteConsoleOutputCharacterA_Hooked
(HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n) (HANDLE h, LPCSTR p, DWORD l, COORD c, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n); return WriteConsoleOutputCharacterA_Orig (h, p, l, c, n);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleOutputCharacterW_Hooked WriteConsoleOutputCharacterW_Hooked
(HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n) (HANDLE h, LPCWSTR p, DWORD l, COORD c, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n); return WriteConsoleOutputCharacterW_Orig (h, p, l, c, n);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleOutputAttribute_Hooked WriteConsoleOutputAttribute_Hooked
(HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n) (HANDLE h, CONST WORD *a, DWORD l, COORD c, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleOutputAttribute_Orig (h, a, l, c, n); return WriteConsoleOutputAttribute_Orig (h, a, l, c, n);
} }
static BOOL WINAPI static BOOL WINAPI
SetConsoleTextAttribute_Hooked
(HANDLE h, WORD a)
{
set_ishybrid_and_switch_to_pcon (h);
return SetConsoleTextAttribute_Orig (h, a);
}
static BOOL WINAPI
WriteConsoleInputA_Hooked WriteConsoleInputA_Hooked
(HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n) (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleInputA_Orig (h, r, l, n); return WriteConsoleInputA_Orig (h, r, l, n);
} }
static BOOL WINAPI static BOOL WINAPI
WriteConsoleInputW_Hooked WriteConsoleInputW_Hooked
(HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n) (HANDLE h, CONST INPUT_RECORD *r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return WriteConsoleInputW_Orig (h, r, l, n); return WriteConsoleInputW_Orig (h, r, l, n);
} }
static BOOL WINAPI static BOOL WINAPI
ReadConsoleInputA_Hooked ReadConsoleInputA_Hooked
(HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n) (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return ReadConsoleInputA_Orig (h, r, l, n); return ReadConsoleInputA_Orig (h, r, l, n);
} }
static BOOL WINAPI static BOOL WINAPI
ReadConsoleInputW_Hooked ReadConsoleInputW_Hooked
(HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n) (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return ReadConsoleInputW_Orig (h, r, l, n); return ReadConsoleInputW_Orig (h, r, l, n);
} }
static BOOL WINAPI static BOOL WINAPI
PeekConsoleInputA_Hooked PeekConsoleInputA_Hooked
(HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n) (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return PeekConsoleInputA_Orig (h, r, l, n); return PeekConsoleInputA_Orig (h, r, l, n);
} }
static BOOL WINAPI static BOOL WINAPI
PeekConsoleInputW_Hooked PeekConsoleInputW_Hooked
(HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n) (HANDLE h, PINPUT_RECORD r, DWORD l, LPDWORD n)
{ {
CHK_CONSOLE_ACCESS (h); set_ishybrid_and_switch_to_pcon (h);
return PeekConsoleInputW_Orig (h, r, l, n); return PeekConsoleInputW_Orig (h, r, l, n);
} }
#else /* USE_API_HOOK */ #else /* USE_API_HOOK */
#define WriteFile_Orig 0 #define WriteFile_Orig 0
#define ReadFile_Orig 0 #define ReadFile_Orig 0
#define PeekConsoleInputA_Orig 0 #define PeekConsoleInputA_Orig 0
void set_ishybrid_and_switch_to_pcon (void) {}
#endif /* USE_API_HOOK */ #endif /* USE_API_HOOK */
bool bool
@ -2871,25 +2882,26 @@ fhandler_pty_slave::fixup_after_exec ()
{ \ { \
void *api = hook_api (module, #name, (void *) name##_Hooked); \ void *api = hook_api (module, #name, (void *) name##_Hooked); \
name##_Orig = (__typeof__ (name) *) api; \ name##_Orig = (__typeof__ (name) *) api; \
if (!api) system_printf("Hooking " #name " failed."); \ /*if (api) system_printf(#name " hooked.");*/ \
} }
DO_HOOK ("kernel32.dll", WriteFile); DO_HOOK (NULL, WriteFile);
DO_HOOK ("kernel32.dll", WriteConsoleA); DO_HOOK (NULL, WriteConsoleA);
DO_HOOK ("kernel32.dll", WriteConsoleW); DO_HOOK (NULL, WriteConsoleW);
DO_HOOK ("kernel32.dll", ReadFile); DO_HOOK (NULL, ReadFile);
DO_HOOK ("kernel32.dll", ReadConsoleA); DO_HOOK (NULL, ReadConsoleA);
DO_HOOK ("kernel32.dll", ReadConsoleW); DO_HOOK (NULL, ReadConsoleW);
DO_HOOK ("kernel32.dll", WriteConsoleOutputA); DO_HOOK (NULL, WriteConsoleOutputA);
DO_HOOK ("kernel32.dll", WriteConsoleOutputW); DO_HOOK (NULL, WriteConsoleOutputW);
DO_HOOK ("kernel32.dll", WriteConsoleOutputCharacterA); DO_HOOK (NULL, WriteConsoleOutputCharacterA);
DO_HOOK ("kernel32.dll", WriteConsoleOutputCharacterW); DO_HOOK (NULL, WriteConsoleOutputCharacterW);
DO_HOOK ("kernel32.dll", WriteConsoleOutputAttribute); DO_HOOK (NULL, WriteConsoleOutputAttribute);
DO_HOOK ("kernel32.dll", WriteConsoleInputA); DO_HOOK (NULL, SetConsoleTextAttribute);
DO_HOOK ("kernel32.dll", WriteConsoleInputW); DO_HOOK (NULL, WriteConsoleInputA);
DO_HOOK ("kernel32.dll", ReadConsoleInputA); DO_HOOK (NULL, WriteConsoleInputW);
DO_HOOK ("kernel32.dll", ReadConsoleInputW); DO_HOOK (NULL, ReadConsoleInputA);
DO_HOOK ("kernel32.dll", PeekConsoleInputA); DO_HOOK (NULL, ReadConsoleInputW);
DO_HOOK ("kernel32.dll", PeekConsoleInputW); DO_HOOK (NULL, PeekConsoleInputA);
DO_HOOK (NULL, PeekConsoleInputW);
} }
#endif /* USE_API_HOOK */ #endif /* USE_API_HOOK */
} }

View File

@ -405,6 +405,7 @@ small_printf (const char *fmt, ...)
count = __small_vsprintf (buf, fmt, ap); count = __small_vsprintf (buf, fmt, ap);
va_end (ap); va_end (ap);
set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL); WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, count, &done, NULL);
FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE)); FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
} }
@ -431,6 +432,7 @@ console_printf (const char *fmt, ...)
count = __small_vsprintf (buf, fmt, ap); count = __small_vsprintf (buf, fmt, ap);
va_end (ap); va_end (ap);
set_ishybrid_and_switch_to_pcon (console_handle);
WriteFile (console_handle, buf, count, &done, NULL); WriteFile (console_handle, buf, count, &done, NULL);
FlushFileBuffers (console_handle); FlushFileBuffers (console_handle);
} }

View File

@ -264,6 +264,7 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
if (category & _STRACE_SYSTEM) if (category & _STRACE_SYSTEM)
{ {
DWORD done; DWORD done;
set_ishybrid_and_switch_to_pcon (GetStdHandle (STD_ERROR_HANDLE));
WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0); WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0);
FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE)); FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE));
/* Make sure that the message shows up on the screen, too, since this is /* Make sure that the message shows up on the screen, too, since this is
@ -275,34 +276,11 @@ strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap
&sec_none, OPEN_EXISTING, 0, 0); &sec_none, OPEN_EXISTING, 0, 0);
if (h != INVALID_HANDLE_VALUE) if (h != INVALID_HANDLE_VALUE)
{ {
set_ishybrid_and_switch_to_pcon (h);
WriteFile (h, buf, len, &done, 0); WriteFile (h, buf, len, &done, 0);
CloseHandle (h); CloseHandle (h);
} }
} }
#if 1 /* Experimental code */
/* PTY with pseudo console cannot display data written to
STD_ERROR_HANDLE (output_handle) if the process is cygwin
process. output_handle works only in native console apps.
Therefore the data should be written to output_handle_cyg
as well. */
fhandler_base *fh = ::cygheap->fdtab[2];
if (fh && fh->get_major () == DEV_PTYS_MAJOR)
{
fhandler_pty_slave *ptys = (fhandler_pty_slave *) fh;
if (ptys->getPseudoConsole ())
{
HANDLE h_cyg = ptys->get_output_handle_cyg ();
if (buf[len-1] == '\n' && len < NT_MAX_PATH - 1)
{
buf[len-1] = '\r';
buf[len] = '\n';
len ++;
}
WriteFile (h_cyg, buf, len, &done, 0);
FlushFileBuffers (h_cyg);
}
}
#endif
} }
#ifndef NOSTRACE #ifndef NOSTRACE

View File

@ -216,6 +216,9 @@ void init_console_handler (bool);
extern bool wsock_started; extern bool wsock_started;
/* PTY related */
void set_ishybrid_and_switch_to_pcon (HANDLE h);
/* Printf type functions */ /* Printf type functions */
extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn)); extern "C" void vapi_fatal (const char *, va_list ap) __attribute__ ((noreturn));
extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn)); extern "C" void api_fatal (const char *, ...) __attribute__ ((noreturn));