1169689Skan/* HP-UX host-specific hook definitions.
2169689Skan   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3169689Skan
4169689Skan   This file is part of GCC.
5169689Skan
6169689Skan   GCC is free software; you can redistribute it and/or modify it
7169689Skan   under the terms of the GNU General Public License as published
8169689Skan   by the Free Software Foundation; either version 2, or (at your
9169689Skan   option) any later version.
10169689Skan
11169689Skan   GCC is distributed in the hope that it will be useful, but WITHOUT
12169689Skan   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13169689Skan   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14169689Skan   License for more details.
15169689Skan
16169689Skan   You should have received a copy of the GNU General Public License
17169689Skan   along with GCC; see the file COPYING.  If not, write to the
18169689Skan   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19169689Skan   MA 02110-1301, USA.  */
20169689Skan
21169689Skan#include "config.h"
22169689Skan#include "system.h"
23169689Skan#include "coretypes.h"
24169689Skan#include <sys/mman.h>
25169689Skan#include <unistd.h>
26169689Skan#include "hosthooks.h"
27169689Skan#include "hosthooks-def.h"
28169689Skan
29169689Skan#ifndef MAP_FAILED
30169689Skan#define MAP_FAILED (void *)-1L
31169689Skan#endif
32169689Skan
33169689Skanstatic void *hpux_gt_pch_get_address (size_t, int);
34169689Skanstatic int hpux_gt_pch_use_address (void *, size_t, int, size_t);
35169689Skan
36169689Skan#undef HOST_HOOKS_GT_PCH_GET_ADDRESS
37169689Skan#define HOST_HOOKS_GT_PCH_GET_ADDRESS hpux_gt_pch_get_address
38169689Skan#undef HOST_HOOKS_GT_PCH_USE_ADDRESS
39169689Skan#define HOST_HOOKS_GT_PCH_USE_ADDRESS hpux_gt_pch_use_address
40169689Skan
41169689Skan/* For various ports, try to guess a fixed spot in the vm space
42169689Skan   that's probably free.  */
43169689Skan#if (defined(__hppa__) || defined(__ia64__)) && defined(__LP64__)
44169689Skan# define TRY_EMPTY_VM_SPACE	0x8000000000000000
45169689Skan#elif defined(__hppa__) || defined(__ia64__)
46169689Skan# define TRY_EMPTY_VM_SPACE	0x60000000
47169689Skan#else
48169689Skan# define TRY_EMPTY_VM_SPACE	0
49169689Skan#endif
50169689Skan
51169689Skan/* Determine a location where we might be able to reliably allocate
52169689Skan   SIZE bytes.  FD is the PCH file, though we should return with the
53169689Skan   file unmapped.  */
54169689Skan
55169689Skanstatic void *
56169689Skanhpux_gt_pch_get_address (size_t size, int fd)
57169689Skan{
58169689Skan  void *addr;
59169689Skan
60169689Skan  addr = mmap ((void *)TRY_EMPTY_VM_SPACE, size, PROT_READ | PROT_WRITE,
61169689Skan	       MAP_PRIVATE, fd, 0);
62169689Skan
63169689Skan  /* If we failed the map, that means there's *no* free space.  */
64169689Skan  if (addr == (void *) MAP_FAILED)
65169689Skan    return NULL;
66169689Skan  /* Unmap the area before returning.  */
67169689Skan  munmap (addr, size);
68169689Skan
69169689Skan  return addr;
70169689Skan}
71169689Skan
72169689Skan/* Map SIZE bytes of FD+OFFSET at BASE.  Return 1 if we succeeded at
73169689Skan   mapping the data at BASE, -1 if we couldn't.
74169689Skan
75169689Skan   It's not possibly to reliably mmap a file using MAP_PRIVATE to
76169689Skan   a specific START address on either hpux or linux.  First we see
77169689Skan   if mmap with MAP_PRIVATE works.  If it does, we are off to the
78169689Skan   races.  If it doesn't, we try an anonymous private mmap since the
79169689Skan   kernel is more likely to honor the BASE address in anonymous maps.
80169689Skan   We then copy the data to the anonymous private map.  This assumes
81169689Skan   of course that we don't need to change the data in the PCH file
82169689Skan   after it is created.
83169689Skan
84169689Skan   This approach obviously causes a performance penalty but there is
85169689Skan   little else we can do given the current PCH implementation.  */
86169689Skan
87169689Skanstatic int
88169689Skanhpux_gt_pch_use_address (void *base, size_t size, int fd, size_t offset)
89169689Skan{
90169689Skan  void *addr;
91169689Skan
92169689Skan  /* We're called with size == 0 if we're not planning to load a PCH
93169689Skan     file at all.  This allows the hook to free any static space that
94169689Skan     we might have allocated at link time.  */
95169689Skan  if (size == 0)
96169689Skan    return -1;
97169689Skan
98169689Skan  /* Try to map the file with MAP_PRIVATE.  */
99169689Skan  addr = mmap (base, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, offset);
100169689Skan
101169689Skan  if (addr == base)
102169689Skan    return 1;
103169689Skan
104169689Skan  if (addr != (void *) MAP_FAILED)
105169689Skan    munmap (addr, size);
106169689Skan
107169689Skan  /* Try to make an anonymous private mmap at the desired location.  */
108169689Skan  addr = mmap (base, size, PROT_READ | PROT_WRITE,
109169689Skan	       MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
110169689Skan
111169689Skan  if (addr != base)
112169689Skan    {
113169689Skan      if (addr != (void *) MAP_FAILED)
114169689Skan        munmap (addr, size);
115169689Skan      return -1;
116169689Skan    }
117169689Skan
118169689Skan  if (lseek (fd, offset, SEEK_SET) == (off_t)-1)
119169689Skan    return -1;
120169689Skan
121169689Skan  while (size)
122169689Skan    {
123169689Skan      ssize_t nbytes;
124169689Skan
125169689Skan      nbytes = read (fd, base, MIN (size, SSIZE_MAX));
126169689Skan      if (nbytes <= 0)
127169689Skan        return -1;
128169689Skan      base = (char *) base + nbytes;
129169689Skan      size -= nbytes;
130169689Skan    }
131169689Skan
132169689Skan  return 1;
133169689Skan}
134169689Skan
135169689Skan
136169689Skanconst struct host_hooks host_hooks = HOST_HOOKS_INITIALIZER;
137