(EXTRA_DLL_OFILES): Remove. (DLL_OFILES): Remove EXTRA_DLL_OFILES. (ASFLAGS): Define as -D_WIN64 on x86_64. (GMON_OFILES): Add mcountFunc.o. ($(srcdir)/$(TLSOFFSETS_H)): Use target_cpu rather than CONFIG_DIR. * configure.ac (CONFIG_DIR): Remove definition. * configure: Regenerate. * gcrt0.c: Use latest version from Mingw-w64 project. * gmon.c: Ditto. * gmon.h: Ditto. * mcount.c: Ditto. * mcountFunc.S: Ditto, new file. * profil.c: Ditto. * profil.h: Ditto. * config: Remove entire directory.
		
			
				
	
	
		
			210 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* profil.c -- win32 profil.c equivalent
 | 
						|
 | 
						|
   Copyright 1998, 1999, 2000, 2001, 2002 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. */
 | 
						|
 | 
						|
/*
 | 
						|
 * This file is taken from Cygwin distribution. Please keep it in sync.
 | 
						|
 * The differences should be within __MINGW32__ guard.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef WIN32_LEAN_AND_MEAN
 | 
						|
#define WIN32_LEAN_AND_MEAN
 | 
						|
#endif
 | 
						|
#include <windows.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <math.h>
 | 
						|
#include "profil.h"
 | 
						|
 | 
						|
#define SLEEPTIME (1000 / PROF_HZ)
 | 
						|
 | 
						|
/* global profinfo for profil() call */
 | 
						|
static struct profinfo prof;
 | 
						|
 | 
						|
/* Get the pc for thread THR */
 | 
						|
 | 
						|
static size_t
 | 
						|
get_thrpc (HANDLE thr)
 | 
						|
{
 | 
						|
  CONTEXT ctx;
 | 
						|
  size_t pc;
 | 
						|
  int res;
 | 
						|
 | 
						|
  res = SuspendThread (thr);
 | 
						|
  if (res == -1)
 | 
						|
    return (size_t) - 1;
 | 
						|
  ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
 | 
						|
  pc = (size_t) - 1;
 | 
						|
  if (GetThreadContext (thr, &ctx)) {
 | 
						|
#ifndef _WIN64
 | 
						|
    pc = ctx.Eip;
 | 
						|
#else
 | 
						|
    pc = ctx.Rip;
 | 
						|
#endif
 | 
						|
  }
 | 
						|
  ResumeThread (thr);
 | 
						|
  return pc;
 | 
						|
}
 | 
						|
 | 
						|
/* Display cell of profile buffer */
 | 
						|
#if 0
 | 
						|
static void
 | 
						|
print_prof (struct profinfo *p)
 | 
						|
{
 | 
						|
  printf ("profthr %x\ttarget thr %x\n", p->profthr, p->targthr);
 | 
						|
  printf ("pc: %x - %x\n", p->lowpc, p->highpc);
 | 
						|
  printf ("scale: %x\n", p->scale);
 | 
						|
  return;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
/* Everytime we wake up use the main thread pc to hash into the cell in the
 | 
						|
   profile buffer ARG. */
 | 
						|
 | 
						|
static void CALLBACK profthr_func (LPVOID);
 | 
						|
 | 
						|
static void CALLBACK
 | 
						|
profthr_func (LPVOID arg)
 | 
						|
{
 | 
						|
  struct profinfo *p = (struct profinfo *) arg;
 | 
						|
  size_t pc, idx;
 | 
						|
 | 
						|
  for (;;)
 | 
						|
    {
 | 
						|
      pc = (size_t) get_thrpc (p->targthr);
 | 
						|
      if (pc >= p->lowpc && pc < p->highpc)
 | 
						|
	{
 | 
						|
	  idx = PROFIDX (pc, p->lowpc, p->scale);
 | 
						|
	  p->counter[idx]++;
 | 
						|
	}
 | 
						|
#if 0
 | 
						|
      print_prof (p);
 | 
						|
#endif
 | 
						|
      /* Check quit condition, WAIT_OBJECT_0 or WAIT_TIMEOUT */
 | 
						|
      if (WaitForSingleObject (p->quitevt, SLEEPTIME) == WAIT_OBJECT_0)
 | 
						|
	return;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/* Stop profiling to the profiling buffer pointed to by P. */
 | 
						|
 | 
						|
static int
 | 
						|
profile_off (struct profinfo *p)
 | 
						|
{
 | 
						|
  if (p->profthr)
 | 
						|
    {
 | 
						|
      SignalObjectAndWait (p->quitevt, p->profthr, INFINITE, FALSE);
 | 
						|
      CloseHandle (p->quitevt);
 | 
						|
      CloseHandle (p->profthr);
 | 
						|
    }
 | 
						|
  if (p->targthr)
 | 
						|
    CloseHandle (p->targthr);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Create a timer thread and pass it a pointer P to the profiling buffer. */
 | 
						|
 | 
						|
static int
 | 
						|
profile_on (struct profinfo *p)
 | 
						|
{
 | 
						|
  DWORD thrid;
 | 
						|
 | 
						|
  /* get handle for this thread */
 | 
						|
  if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
 | 
						|
			GetCurrentProcess (), &p->targthr, 0, FALSE,
 | 
						|
			DUPLICATE_SAME_ACCESS))
 | 
						|
    {
 | 
						|
      errno = ESRCH;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  p->quitevt = CreateEvent (NULL, TRUE, FALSE, NULL);
 | 
						|
 | 
						|
  if (!p->quitevt)
 | 
						|
    {
 | 
						|
      CloseHandle (p->quitevt);
 | 
						|
      p->targthr = 0;
 | 
						|
      errno = EAGAIN;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  p->profthr = CreateThread (0, 0, (DWORD (WINAPI *)(LPVOID)) profthr_func,
 | 
						|
                             (void *) p, 0, &thrid);
 | 
						|
 | 
						|
  if (!p->profthr)
 | 
						|
    {
 | 
						|
      CloseHandle (p->targthr);
 | 
						|
      CloseHandle (p->quitevt);
 | 
						|
      p->targthr = 0;
 | 
						|
      errno = EAGAIN;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  /* Set profiler thread priority to highest to be sure that it gets the
 | 
						|
     processor as soon it request it (i.e. when the Sleep terminate) to get
 | 
						|
     the next data out of the profile. */
 | 
						|
 | 
						|
  SetThreadPriority (p->profthr, THREAD_PRIORITY_TIME_CRITICAL);
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * start or stop profiling
 | 
						|
 *
 | 
						|
 * profiling goes into the SAMPLES buffer of size SIZE (which is treated
 | 
						|
 * as an array of u_shorts of size size/2)
 | 
						|
 *
 | 
						|
 * each bin represents a range of pc addresses from OFFSET.  The number
 | 
						|
 * of pc addresses in a bin depends on SCALE.  (A scale of 65536 maps
 | 
						|
 * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
 | 
						|
 * a scale of 1 maps each bin to 128k addreses).  Scale may be 1 - 65536,
 | 
						|
 * or zero to turn off profiling
 | 
						|
 */
 | 
						|
int
 | 
						|
profile_ctl (struct profinfo * p, char *samples, size_t size,
 | 
						|
	     size_t offset, u_int scale)
 | 
						|
{
 | 
						|
  size_t maxbin;
 | 
						|
 | 
						|
  if (scale > 65536)
 | 
						|
    {
 | 
						|
      errno = EINVAL;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
 | 
						|
  profile_off (p);
 | 
						|
  if (scale)
 | 
						|
    {
 | 
						|
      memset (samples, 0, size);
 | 
						|
      memset (p, 0, sizeof *p);
 | 
						|
      maxbin = size >> 1;
 | 
						|
      prof.counter = (u_short *) samples;
 | 
						|
      prof.lowpc = offset;
 | 
						|
      prof.highpc = PROFADDR (maxbin, offset, scale);
 | 
						|
      prof.scale = scale;
 | 
						|
 | 
						|
      return profile_on (p);
 | 
						|
    }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* Equivalent to unix profil()
 | 
						|
   Every SLEEPTIME interval, the user's program counter (PC) is examined:
 | 
						|
   offset is subtracted and the result is multiplied by scale.
 | 
						|
   The word pointed to by this address is incremented.  Buf is unused. */
 | 
						|
 | 
						|
int
 | 
						|
profil (char *samples, size_t size, size_t offset, u_int scale)
 | 
						|
{
 | 
						|
  return profile_ctl (&prof, samples, size, offset, scale);
 | 
						|
}
 | 
						|
 |