& (_dl_pagesize - 1))))
& (GL(dl_pagesize) - 1))))
_dl_start_profile (struct link_map *map, const char *output_dir){  char *filename;  int fd;  struct stat64 st;  const ElfW(Phdr) *ph;  ElfW(Addr) mapstart = ~((ElfW(Addr)) 0);  ElfW(Addr) mapend = 0;  struct gmon_hdr gmon_hdr;  struct gmon_hist_hdr hist_hdr;  char *hist, *cp;  size_t idx;  size_t tossize;  size_t fromssize;  uintptr_t highpc;  struct gmon_hdr *addr = NULL;  off_t expected_size;  /* See profil(2) where this is described.  */  int s_scale;#define SCALE_1_TO_1	0x10000L  /* Compute the size of the sections which contain program code.  */  for (ph = map->l_phdr; ph < &map->l_phdr[map->l_phnum]; ++ph)    if (ph->p_type == PT_LOAD && (ph->p_flags & PF_X))      {	ElfW(Addr) start = (ph->p_vaddr & ~(_dl_pagesize - 1));	ElfW(Addr) end = ((ph->p_vaddr + ph->p_memsz + _dl_pagesize - 1)			  & ~(_dl_pagesize - 1));	if (start < mapstart)	  mapstart = start;	if (end > mapend)	  mapend = end;      }  /* Now we can compute the size of the profiling data.  This is done     with the same formulars as in `monstartup' (see gmon.c).  */  running = 0;  lowpc = ROUNDDOWN (mapstart + map->l_addr,		     HISTFRACTION * sizeof (HISTCOUNTER));  highpc = ROUNDUP (mapend + map->l_addr,		    HISTFRACTION * sizeof (HISTCOUNTER));  textsize = highpc - lowpc;  kcountsize = textsize / HISTFRACTION;  hashfraction = HASHFRACTION;  if ((HASHFRACTION & (HASHFRACTION - 1)) == 0)    /* If HASHFRACTION is a power of two, mcount can use shifting       instead of integer division.  Precompute shift amount.  */    log_hashfraction = __ffs (hashfraction * sizeof (*froms)) - 1;  else    log_hashfraction = -1;  tossize = textsize / HASHFRACTION;  fromlimit = textsize * ARCDENSITY / 100;  if (fromlimit < MINARCS)    fromlimit = MINARCS;  if (fromlimit > MAXARCS)    fromlimit = MAXARCS;  fromssize = fromlimit * sizeof (struct here_fromstruct);  expected_size = (sizeof (struct gmon_hdr)		   + 4 + sizeof (struct gmon_hist_hdr) + kcountsize		   + 4 + 4 + fromssize * sizeof (struct here_cg_arc_record));  /* Create the gmon_hdr we expect or write.  */  memset (&gmon_hdr, '\0', sizeof (struct gmon_hdr));  memcpy (&gmon_hdr.cookie[0], GMON_MAGIC, sizeof (gmon_hdr.cookie));  *(int32_t *) gmon_hdr.version = GMON_SHOBJ_VERSION;  /* Create the hist_hdr we expect or write.  */  *(char **) hist_hdr.low_pc = (char *) mapstart;  *(char **) hist_hdr.high_pc = (char *) mapend;  *(int32_t *) hist_hdr.hist_size = kcountsize / sizeof (HISTCOUNTER);  *(int32_t *) hist_hdr.prof_rate = __profile_frequency ();  strncpy (hist_hdr.dimen, "seconds", sizeof (hist_hdr.dimen));  hist_hdr.dimen_abbrev = 's';  /* First determine the output name.  We write in the directory     OUTPUT_DIR and the name is composed from the shared objects     soname (or the file name) and the ending ".profile".  */  filename = (char *) alloca (strlen (output_dir) + 1 + strlen (_dl_profile)			      + sizeof ".profile");  cp = __stpcpy (filename, output_dir);  *cp++ = '/';  __stpcpy (__stpcpy (cp, _dl_profile), ".profile");#ifdef O_NOFOLLOW# define EXTRA_FLAGS | O_NOFOLLOW#else# define EXTRA_FLAGS#endif  fd = __open (filename, O_RDWR | O_CREAT EXTRA_FLAGS, DEFFILEMODE);  if (fd == -1)    {      /* We cannot write the profiling data so don't do anything.  */      char buf[400];      _dl_error_printf ("%s: cannot open file: %s\n", filename,			__strerror_r (errno, buf, sizeof buf));      return;    }  if (__fxstat64 (_STAT_VER, fd, &st) < 0 || !S_ISREG (st.st_mode))    {      /* Not stat'able or not a regular file => don't use it.  */      char buf[400];      int errnum = errno;      __close (fd);      _dl_error_printf ("%s: cannot stat file: %s\n", filename,			__strerror_r (errnum, buf, sizeof buf));      return;    }  /* Test the size.  If it does not match what we expect from the size     values in the map MAP we don't use it and warn the user.  */  if (st.st_size == 0)    {      /* We have to create the file.  */      char buf[_dl_pagesize];      memset (buf, '\0', _dl_pagesize);      if (__lseek (fd, expected_size & ~(_dl_pagesize - 1), SEEK_SET) == -1)	{	  char buf[400];	  int errnum;	cannot_create:	  errnum = errno;	  __close (fd);	  _dl_error_printf ("%s: cannot create file: %s\n", filename,			    __strerror_r (errnum, buf, sizeof buf));	  return;	}      if (TEMP_FAILURE_RETRY (__libc_write (fd, buf, (expected_size						      & (_dl_pagesize - 1))))	  < 0)	goto cannot_create;    }  else if (st.st_size != expected_size)    {      __close (fd);    wrong_format:      if (addr != NULL)	__munmap ((void *) addr, expected_size);      _dl_error_printf ("%s: file is no correct profile data file for `%s'\n",			filename, _dl_profile);      return;    }  addr = (struct gmon_hdr *) __mmap (NULL, expected_size, PROT_READ|PROT_WRITE,				     MAP_SHARED|MAP_FILE, fd, 0);  if (addr == (struct gmon_hdr *) MAP_FAILED)    {      char buf[400];      int errnum = errno;      __close (fd);      _dl_error_printf ("%s: cannot map file: %s\n", filename,			__strerror_r (errnum, buf, sizeof buf));      return;    }  /* We don't need the file desriptor anymore.  */  __close (fd);  /* Pointer to data after the header.  */  hist = (char *) (addr + 1);  kcount = (uint16_t *) ((char *) hist + sizeof (uint32_t)			 + sizeof (struct gmon_hist_hdr));  /* Compute pointer to array of the arc information.  */  narcsp = (uint32_t *) ((char *) kcount + kcountsize + sizeof (uint32_t));  data = (struct here_cg_arc_record *) ((char *) narcsp + sizeof (uint32_t));  if (st.st_size == 0)    {      /* Create the signature.  */      memcpy (addr, &gmon_hdr, sizeof (struct gmon_hdr));      *(uint32_t *) hist = GMON_TAG_TIME_HIST;      memcpy (hist + sizeof (uint32_t), &hist_hdr,	      sizeof (struct gmon_hist_hdr));      narcsp[-1] = GMON_TAG_CG_ARC;    }  else    {      /* Test the signature in the file.  */      if (memcmp (addr, &gmon_hdr, sizeof (struct gmon_hdr)) != 0	  || *(uint32_t *) hist != GMON_TAG_TIME_HIST	  || memcmp (hist + sizeof (uint32_t), &hist_hdr,		     sizeof (struct gmon_hist_hdr)) != 0	  || narcsp[-1] != GMON_TAG_CG_ARC)	goto wrong_format;    }  /* Allocate memory for the froms data and the pointer to the tos records.  */  tos = (uint16_t *) calloc (tossize + fromssize, 1);  if (tos == NULL)    {      __munmap ((void *) addr, expected_size);      _dl_fatal_printf ("Out of memory while initializing profiler\n");      /* NOTREACHED */    }  froms = (struct here_fromstruct *) ((char *) tos + tossize);  fromidx = 0;  /* Now we have to process all the arc count entries.  BTW: it is     not critical whether the *NARCSP value changes meanwhile.  Before     we enter a new entry in to toset we will check that everything is     available in TOS.  This happens in _dl_mcount.     Loading the entries in reverse order should help to get the most     frequently used entries at the front of the list.  */  for (idx = narcs = MIN (*narcsp, fromlimit); idx > 0; )    {      size_t to_index;      size_t newfromidx;      --idx;      to_index = (data[idx].self_pc / (hashfraction * sizeof (*tos)));      newfromidx = fromidx++;      froms[newfromidx].here = &data[idx];      froms[newfromidx].link = tos[to_index];      tos[to_index] = newfromidx;    }  /* Setup counting data.  */  if (kcountsize < highpc - lowpc)    {#if 0      s_scale = ((double) kcountsize / (highpc - lowpc)) * SCALE_1_TO_1;#else      size_t range = highpc - lowpc;      size_t quot = range / kcountsize;      if (quot >= SCALE_1_TO_1)	s_scale = 1;      else if (quot >= SCALE_1_TO_1 / 256)	s_scale = SCALE_1_TO_1 / quot;      else if (range > ULONG_MAX / 256)	s_scale = (SCALE_1_TO_1 * 256) / (range / (kcountsize / 256));      else	s_scale = (SCALE_1_TO_1 * 256) / ((range * 256) / kcountsize);#endif    }  else    s_scale = SCALE_1_TO_1;  /* Start the profiler.  */  __profil ((void *) kcount, kcountsize, lowpc, s_scale);  /* Turn on profiling.  */  running = 1;}