1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe Constraint Logic Programming System.
15 * The Initial Developer of the Original Code is  Cisco Systems, Inc.
16 * Portions created by the Initial Developer are
17 * Copyright (C) 1995-2006 Cisco Systems, Inc.  All Rights Reserved.
18 *
19 * Contributor(s): Kees Schuerman, ECRC
20 *
21 * END LICENSE BLOCK */
22
23/**********************************************************************
24**        File: addrmap.c
25**      Author: Kees Schuerman
26** Description: Address Space Map
27**
28*
29*	The program displays the address map of the machine
30*	using the following categories:
31*
32*	FREE		The area is not mapped and can be mapped.
33*			If the flag ADDR_FLAGS_WRITECHECK is specified,
34*			it is also writable, otherwise this is not certain.
35*	MAPPED		This area is already mapped to this process.
36*	UNAVAILABLE	This are is not mapped to this process and cannot
37*			be mapped, i.e. it is probably being used by
38*			other processes
39*
40***********************************************************************/
41
42#include "config.h"
43
44#ifdef HAVE_MMAP
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <sys/mman.h>
48#include <fcntl.h>
49#include <signal.h>
50#include <setjmp.h>
51
52#ifdef SBRK_UNDEF
53extern char	*sbrk();
54#endif
55extern void	exit(int);
56
57#ifdef HAVE_UNISTD_H
58#include	<unistd.h>
59#endif
60
61#define ADDR_UNAVAILABLE	0
62#define ADDR_MAPPED		1
63#define ADDR_FREE		2
64#define ADDR_FREE_VAR		3
65#define ADDR_TRY	-1
66
67#define ADDR_FLAGS_WRITECHECK	1
68#define ADDR_FLAGS_SHARED	2
69
70#ifndef MAP_NORESERVE
71#define MAP_NORESERVE 0
72#endif
73#ifndef MAP_VARIABLE
74#define MAP_VARIABLE 0
75#endif
76#ifndef MAP_FAILED
77#define MAP_FAILED ((caddr_t) (-1))
78#endif
79#if defined(MAP_ANONYMOUS) || defined(MAP_ANON)
80#  ifndef MAP_FILE
81#  define MAP_FILE 0
82#  endif
83#  ifndef MAP_ANONYMOUS
84#  define MAP_ANONYMOUS MAP_ANON
85#  endif
86#endif
87
88extern char	*shared_mem_base(void);
89
90typedef struct addr_range {
91    struct addr_range * next;
92    char * addr;
93    unsigned size;
94    unsigned state;
95} addr_range_t;
96
97static jmp_buf addr_env;
98
99static addr_range_t * addr_spc_map;
100static addr_range_t * addr_range;
101static char	    * addr_range_addr;
102
103static void	_addr_map(char *from, char *to, long int increment),
104		_addr_init(char *from),
105		_write_address(char *a),
106		_write_range(char *from, char *to, int state);
107
108#ifdef HAVE_SIGACTION
109typedef struct sigaction sig_action_t;
110#else
111#ifdef HAVE_SIGVEC
112typedef struct sigvec sig_action_t;
113#define sa_handler sv_handler
114#define sa_mask sv_mask
115#define sa_flags sv_flags
116#else
117typedef struct {
118	RETSIGTYPE (*sa_handler)();
119	int sa_mask;
120	int sa_flags;
121} sig_action_t;
122#endif
123#endif
124
125static sig_action_t sigsegv_act;
126static sig_action_t sigbus_act;
127
128static unsigned long addr_pagesize;
129static int addr_map_fd;
130static long addr_increment;
131
132static volatile char * addr = 0;
133static volatile int addr_state = ADDR_FREE;
134static volatile int addr_flags = 0;
135static volatile int addr_map_mode = MAP_FIXED;
136
137ec_layout(int flags, char *from, char *to, long int increment)
138{
139
140    if (flags & ADDR_FLAGS_SHARED)
141	write(2,  "\nshared\n", 8);
142    else if (flags & ADDR_FLAGS_WRITECHECK)
143	write(2,  "\nwrite check\n", 13);
144    addr_flags = flags;
145    _addr_init(from);
146    _addr_map(from, to, increment);
147}
148
149static void
150_addr_init(char *from)
151{
152#if defined(HAVE_SYSCONF) && defined(SYSCONF_PAGE)
153    addr_pagesize = sysconf(SYSCONF_PAGE);
154#else
155#ifdef HAVE_GETPAGESIZE
156    addr_pagesize = getpagesize();
157#else
158    addr_pagesize = 4096;
159#endif
160#endif
161
162    if (addr_flags & ADDR_FLAGS_SHARED) {
163	(void) unlink("heap.map");
164	addr_map_fd = open("heap.map", O_RDWR|O_CREAT|O_EXCL, 0700);
165	if (addr_map_fd == -1 ||
166		ftruncate(addr_map_fd, (off_t) addr_pagesize) == -1) {
167	    (void) write(2, "AdrMap: Cannot use the map file\n", 32);
168	    exit(-1);
169	}
170    } else
171#ifdef MAP_ANONYMOUS
172	addr_map_fd = -1;
173#else
174	if ((addr_map_fd = open("/dev/zero", O_RDWR)) == -1) {
175	    (void) write(2, "AdrMap: Cannot open /dev/zero\n", 31);
176	    exit(-1);
177	}
178#endif
179
180    addr_spc_map = (addr_range_t *) 0;
181
182    addr = addr_range_addr = from;
183    addr_range = (addr_range_t *) 0;
184}
185
186/*ARGSUSED*/
187static void
188_sigsegv_handler(int sig)
189{
190    int		addr_state_save;
191    int		map_flags, map_prot;
192    caddr_t		map_result;
193#ifdef HAVE_SIGPROCMASK
194    sigset_t	sig_mask;
195
196    (void) sigemptyset(&sig_mask);
197    (void) sigaddset(&sig_mask, sig);
198    (void) sigprocmask(SIG_UNBLOCK, &sig_mask, (sigset_t *) 0);
199#else
200    int		sig_mask;
201
202    sig_mask = ~sigmask(sig);
203    (void) sigblock(sig_mask);
204#endif
205
206    map_prot = PROT_READ|PROT_WRITE;
207    if(addr_flags & ADDR_FLAGS_SHARED) {
208	map_prot |= PROT_EXEC;
209	map_flags =
210#ifdef MAP_ANONYMOUS
211		    MAP_FILE|
212#endif
213		    		MAP_SHARED|MAP_NORESERVE|addr_map_mode;
214    } else {
215	map_flags =
216#ifdef MAP_ANONYMOUS
217		    MAP_ANONYMOUS|
218#endif
219				    MAP_PRIVATE|addr_map_mode;
220    }
221    map_result = mmap((caddr_t) addr,
222		   (size_t) addr_pagesize,
223		   map_prot,
224		   map_flags,
225		   addr_map_fd,
226		   (off_t) 0);
227    if ((addr_state != ADDR_TRY) && map_result == addr) {
228	if (addr_flags & ADDR_FLAGS_WRITECHECK &&
229	    !(addr_flags & ADDR_FLAGS_SHARED)) {
230	    addr_state_save = addr_state;
231	    addr_state = ADDR_TRY;
232	    *addr = 0xff;
233	    addr_state = addr_state_save;
234	}
235	(void) munmap((caddr_t) addr,(size_t) addr_pagesize);
236	if (addr_state != ADDR_FREE) {
237	    if (addr_range_addr != addr)
238		_write_range(addr_range_addr, (char *) addr, addr_state);
239	    addr_range_addr = (char *) addr;
240	}
241	addr_state = ADDR_FREE;
242    }
243    else if (addr_state != ADDR_UNAVAILABLE) {
244	if (addr_range_addr != addr)
245	    _write_range(addr_range_addr, (char *) addr, addr_state);
246	addr_range_addr = (char *) addr;
247	addr_state = ADDR_UNAVAILABLE;
248    }
249
250    addr += addr_increment;
251
252    longjmp(addr_env,0);
253}
254
255
256static void
257_save_handler(int sig, sig_action_t *action)
258{
259#ifdef HAVE_SIGACTION
260    (void) sigaction(sig,
261              (struct sigaction *) 0,
262              action);
263#else
264#ifdef HAVE_SIGVEC
265    (void) sigvec(sig, (struct sigvec *) 0, action);
266#else
267    /* no flags for signal() */
268#endif
269#endif
270}
271
272static void
273_install_handler(int sig, sig_action_t *action)
274{
275    sig_action_t	act;
276    int			res;
277
278    act.sa_handler = _sigsegv_handler;
279#ifdef HAVE_SIGACTION
280    (void) sigemptyset(&act.sa_mask);
281#ifdef SA_RESETHAND
282    act.sa_flags = action->sa_flags & ~SA_RESETHAND;
283#else
284    act.sa_flags = action->sa_flags;
285#endif
286    res = sigaction(sig, &act, (struct sigaction *) 0);
287#else
288#ifdef HAVE_SIGVEC
289    act.sa_mask = 0;
290    act.sa_flags = action->sa_flags & ~SV_RESETHAND;
291    res = sigvec(sig, &act, (struct sigvec *) 0);
292#else
293    action->sa_handler = (RETSIGTYPE (*)()) signal(sig, act.sa_handler);
294#endif
295#endif
296    if (res < 0)
297	exit(-1);
298}
299
300
301static void
302_restore_handler(int sig, sig_action_t *action)
303{
304    int		res;
305
306#ifdef HAVE_SIGACTION
307    res = sigaction(sig, action, (struct sigaction *) 0);
308#else
309#ifdef HAVE_SIGVEC
310    res = sigvec(sig, action, (struct sigvec *) 0);
311#else
312    res = signal(sig, action->sa_handler);
313#endif
314#endif
315    if (res < 0)
316	exit(-1);
317}
318
319
320static void
321_addr_map(char *from, char *to, long int increment)
322{
323    char byte;
324
325    addr_increment = (increment == 0) ? addr_pagesize: increment;
326    (void) write(2, "page size = ", 12);
327    _write_address((char *) addr_pagesize);
328    if (from != (char *) 0 || to != (char *) 0 || increment != 0) {
329	(void) write(2, "\nstep      = ", 14);
330	_write_address((char *) addr_increment);
331	(void) write(2, "\nstart     = ", 14);
332	_write_address(from);
333	(void) write(2, "\nend       = ", 14);
334	_write_address(to);
335    }
336    (void) write(2, "\n\n", 2);
337
338    _save_handler(SIGSEGV, &sigsegv_act);
339    _save_handler(SIGBUS, &sigbus_act);
340
341    _install_handler(SIGSEGV, &sigsegv_act);
342    _install_handler(SIGBUS, &sigbus_act);
343
344    (void) setjmp(addr_env);
345
346    while (1) {
347	if (to != (char *) 0 && addr + addr_increment > to ||
348	     ((unsigned long) (addr - (char *) 0)) >
349		      ((unsigned long) ((addr + addr_increment)  - (char *) 0))) {
350	    _write_range(addr_range_addr, (char *) addr + addr_increment, addr_state);
351
352	    _restore_handler(SIGSEGV, &sigsegv_act);
353	    _restore_handler(SIGBUS, &sigbus_act);
354	    if (addr_flags & ADDR_FLAGS_SHARED) {
355		(void) close(addr_map_fd);
356		(void) unlink("heap.map");
357	    }
358	    return;
359	}
360	byte = *addr;
361	if (addr_state != ADDR_MAPPED) {
362	    if (addr_range_addr != addr)
363		_write_range(addr_range_addr, (char *) addr, addr_state);
364	    addr_range_addr = (char *) addr;
365	    addr_state = ADDR_MAPPED;
366	}
367        addr += addr_increment;
368    }
369}
370
371/* Output the address without allocating any memory */
372static void
373_write_address(char *a)
374{
375    char	buf[2*sizeof(char *)];
376    int		i;
377    int		c;
378    int		n = 2*sizeof(char *);
379
380    for (i = 0; i < n; i++) {
381	c = ((unsigned long) a & ((unsigned long) 0xf << 4 * (n - i - 1))) >> 4 * (n - i - 1);
382	if (c < 10)
383	    buf[i] = c + '0';
384	else
385	    buf[i] = c - 10 + 'a';
386    }
387    (void) write(2, buf, n);
388}
389
390static void
391_write_range(char *from, char *to, int state)
392{
393    unsigned long size = (to-from);
394    _write_address(from);
395    (void) write(2, " <-> ", 5);
396    _write_address(to);
397    (void) write(2, " (", 2);
398    _write_address((char*) size);
399    (void) write(2, ") ", 2);
400    switch (state) {
401    case ADDR_FREE:
402	(void) write(2, "FREE\n", 5);
403	break;
404
405    case ADDR_FREE_VAR:
406	(void) write(2, "FREE for MAP_VARIABLE\n", 22);
407	break;
408
409    case ADDR_MAPPED:
410	(void) write(2, "MAPPED\n", 7);
411	break;
412
413    case ADDR_UNAVAILABLE:
414	(void) write(2, "UNAVAILABLE\n", 12);
415	break;
416
417    }
418}
419#endif	/* HAVE_MMAP */
420