summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/init.cc
blob: e4ad59f3a6baa2be55c2bef5696cb2641967646b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/* init.cc

   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
   2007, 2008, 2009, 2010, 2011, 2012, 2013, 2015 Red Hat, Inc.

This file is part of Cygwin.

This software is a copyrighted work licensed under the terms of the
Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
details. */

#include "winsup.h"
#include "cygtls.h"
#include "ntdll.h"
#include "shared_info.h"

static DWORD _my_oldfunc;

static char *search_for  = (char *) cygthread::stub;
unsigned threadfunc_ix[8];

static bool dll_finished_loading;
#define OLDFUNC_OFFSET -1

static void WINAPI
threadfunc_fe (VOID *arg)
{
#ifndef __x86_64__
  (void)__builtin_return_address(1);
  asm volatile ("andl $-16,%%esp" ::: "%esp");
#endif
  _cygtls::call ((DWORD (*)  (void *, void *)) TlsGetValue (_my_oldfunc), arg);
}

/* If possible, redirect the thread entry point to a cygwin routine which
   adds tls stuff to the stack. */
static void
munge_threadfunc ()
{
  int i;
  char **ebp = (char **) __builtin_frame_address (0);
  if (!threadfunc_ix[0])
    {
      char **peb;
      char **top = (char **) NtCurrentTeb()->Tib.StackBase;
      for (peb = ebp, i = 0; peb < top && i < 7; peb++)
	if (*peb == search_for)
	  threadfunc_ix[i++] = peb - ebp;
      if (0 && !threadfunc_ix[0])
	{
	  try_to_debug ();
	  return;
	}
    }

  if (threadfunc_ix[0])
    {
      char *threadfunc = NULL;

      /* This call to NtQueryInformationThread crashes under WOW64 on
         64 bit XP and Server 2003. */
      if (wincap.wow64_has_secondary_stack ())
	threadfunc = ebp[threadfunc_ix[0]];
      else
	NtQueryInformationThread (NtCurrentThread (),
				  ThreadQuerySetWin32StartAddress,
				  &threadfunc, sizeof threadfunc, NULL);
      if (!search_for || threadfunc == search_for)
	{
	  search_for = NULL;
	  for (i = 0; threadfunc_ix[i]; i++)
	    if (!threadfunc || ebp[threadfunc_ix[i]] == threadfunc)
	       ebp[threadfunc_ix[i]] = (char *) threadfunc_fe;
	  TlsSetValue (_my_oldfunc, threadfunc);
	}
    }
}

void dll_crt0_0 ();

extern "C" BOOL WINAPI
dll_entry (HANDLE h, DWORD reason, void *static_load)
{
  BOOL test_stack_marker;

  switch (reason)
    {
    case DLL_PROCESS_ATTACH:
      init_console_handler (false);

      cygwin_hmodule = (HMODULE) h;
      dynamically_loaded = (static_load == NULL);

      dll_crt0_0 ();
      _my_oldfunc = TlsAlloc ();
      dll_finished_loading = true;
      break;
    case DLL_PROCESS_DETACH:
      if (dynamically_loaded)
	shared_destroy ();
      break;
    case DLL_THREAD_ATTACH:
      if (dll_finished_loading)
	munge_threadfunc ();
      break;
    case DLL_THREAD_DETACH:
      if (dll_finished_loading
	  && (PVOID) &_my_tls > (PVOID) &test_stack_marker
	  && _my_tls.isinitialized ())
	_my_tls.remove (0);
      break;
    }

  return TRUE;
}