Home | History | Annotate | Download | only in amt
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 /*
     30  * Abstract Machine Test; executes memory access tests to show
     31  * compliance with Common Criteria object reuse and process address
     32  * space separation requirements.
     33  */
     34 #include <errno.h>
     35 #include <fcntl.h>
     36 #include <iso/stdlib_iso.h>
     37 #include <libelf.h>
     38 #include <libintl.h>
     39 #include <locale.h>
     40 #include <signal.h>
     41 #include <stdio.h>
     42 #include <string.h>
     43 #include <sys/param.h>
     44 #include <sys/resource.h>
     45 #include <sys/sysmacros.h>
     46 #include <sys/types.h>
     47 #include <unistd.h>
     48 #include <wait.h>
     49 
     50 #define	NOT_SILENT 0
     51 #define	SILENT_MODE 1
     52 
     53 #define	CHILD_SLEEP_PERIOD 2
     54 #define	PARENT_SLEEP_PERIOD 1
     55 #define	SIG_EVENT SIGUSR1
     56 
     57 #define	PASS	   0		/* test passed, no SEGV */
     58 #define	FAIL_ZERO  1		/* expected to read zero, didn't */
     59 #define	FAIL_SEGV  2		/* expected good read or write, didn't */
     60 #define	PASS_SEGV  3		/* expected SEGV, got it */
     61 #define	FAIL_ABORT 4		/* test logic error */
     62 
     63 #define	PH_VALID   0		/* arg for probe_hole -- do valid memory */
     64 				/* access */
     65 #define	PH_INVALID 1		/* do illegal memory access */
     66 
     67 #define	WASTE_PAGES   8		/* a guess at where virgin stack space */
     68 				/* is likely to exist */
     69 #define	STACK_SLOP  256		/* a guess at how far below current end */
     70 				/* of stack I'll find unused space */
     71 
     72 #if !defined(TEXT_DOMAIN)
     73 #define	TEXT_DOMAIN "SYS_TEST"
     74 #endif
     75 
     76 extern int _end;	/* first address after the end of initialized data */
     77 
     78 static int  data_boundary_test();
     79 static void handler(int);
     80 static int  memory_not_shared_after_use();
     81 static int  memory_allocation_not_shared();
     82 static int  memory_type(const char *);
     83 static void print_message(char *);
     84 static void probe_data_area(void);
     85 static void probe_hole(int);
     86 static void probe_stack(void);
     87 static void probe_text_area(void);
     88 static void segv_action(int, siginfo_t *, void *);
     89 static void set_handler(int);
     90 static int  test_stack_end_of_hole();
     91 static int  text_area_not_writeable();
     92 
     93 static int done_memory_grab = 0;
     94 static int silent;
     95 static int handler_exit_code;
     96 
     97 /*
     98  * Main Routine
     99  */
    100 int
    101 main(int argc, char *argv[])
    102 {
    103 	int fail_count = 0;
    104 	int status = 0;
    105 	int bitsize;
    106 
    107 	/* Internationalization */
    108 	(void) setlocale(LC_ALL, "");
    109 	(void) textdomain(TEXT_DOMAIN);
    110 
    111 	silent = NOT_SILENT;
    112 
    113 	if (argc == 2) {
    114 		/* Pull out argument provided		 */
    115 		/* -s	silent mode, no status or error messages. */
    116 		if (strncmp(argv[1], "-s", 4) == 0)
    117 			silent = SILENT_MODE;
    118 		else {
    119 			/* Wrong argument */
    120 			(void) fprintf(stderr, gettext(
    121 			    "Wrong argument, USAGE: amt [-s]\n"));
    122 			exit(EXIT_FAILURE);
    123 		}
    124 	} else if (argc != 1) {
    125 		/* Illegal number of arguments. */
    126 		(void) fprintf(stderr, gettext(
    127 		    "Wrong usage, USAGE: amt [-s]\n"));
    128 		exit(EXIT_FAILURE);
    129 	}
    130 	bitsize = memory_type(argv[0]);
    131 
    132 	if (silent == NOT_SILENT)
    133 		(void) printf(gettext(
    134 		    "\n\nAMT Test Program -- %d bit application\n"
    135 		    "================\n"), bitsize);
    136 	/*
    137 	 * test_stack_end_of_hole must be the first test, or the stack
    138 	 * is of an unknown size.
    139 	 */
    140 	if ((status = test_stack_end_of_hole()) == EXIT_FAILURE) {
    141 		/* Normal fail */
    142 		fail_count++;
    143 		print_message(gettext("TEST 1 FAILED\n"));
    144 	} else if (status == FAIL_ABORT) {
    145 		/* Test logic failure */
    146 		fail_count++;
    147 		print_message(gettext("FAIL: Logic error in test\n"));
    148 	} else if (status == EXIT_SUCCESS)
    149 		print_message(gettext("TEST 1 PASSED\n"));
    150 
    151 	/* Carry out test 2 */
    152 	if (data_boundary_test() != EXIT_SUCCESS) {
    153 		fail_count++;
    154 		print_message(gettext("TEST 2 FAILED\n"));
    155 	} else
    156 		print_message(gettext("TEST 2 PASSED\n"));
    157 
    158 	/* Carry out test 3 */
    159 	if (text_area_not_writeable() != EXIT_SUCCESS) {
    160 		fail_count++;
    161 		print_message(gettext("TEST 3 FAILED\n"));
    162 	} else
    163 		print_message(gettext("TEST 3 PASSED\n"));
    164 
    165 	/* Carry out test 4 */
    166 	if (memory_not_shared_after_use() != EXIT_SUCCESS) {
    167 		fail_count++;
    168 		print_message(gettext("TEST 4 FAILED\n"));
    169 	} else
    170 		print_message(gettext("TEST 4 PASSED\n"));
    171 
    172 	/* Carry out test 5 */
    173 	if (memory_allocation_not_shared() != EXIT_SUCCESS) {
    174 		fail_count++;
    175 		print_message(gettext("TEST 5 FAILED\n"));
    176 	} else
    177 		print_message(gettext("TEST 5 PASSED\n"));
    178 
    179 	if (silent == NOT_SILENT) {
    180 		if (fail_count > 0)
    181 			(void) printf(gettext("\n %d TESTS FAILED\n\n"),
    182 			    fail_count);
    183 		else
    184 			(void) printf(gettext("\nTESTS SUCCEEDED\n\n"));
    185 	}
    186 	return (fail_count);
    187 }
    188 
    189 /*
    190  * Test the data boundaries. First test inside the data area at the boundary
    191  * of the "hole" area. Second test inside the data area at the text area
    192  * boundary. Both should pass.
    193  */
    194 static int
    195 data_boundary_test()
    196 {
    197 	int exit_status = EXIT_SUCCESS;
    198 	pid_t pid;
    199 	int status;
    200 
    201 	print_message(gettext("\n\nTest 2- Data Side Boundary Test.\n"));
    202 
    203 	if ((pid = fork()) == -1) {
    204 		print_message(gettext("Fork failed\n"));
    205 		return (EXIT_FAILURE);
    206 	} else if (pid == 0) { /* Am I my child? */
    207 		set_handler(SIGSEGV);
    208 
    209 		/* probe_data_area() does exit() */
    210 		probe_data_area();
    211 	}
    212 	/* still parent */
    213 	(void) wait(&status);
    214 	status = WEXITSTATUS(status);
    215 
    216 	if (status == PASS)
    217 		print_message(gettext(
    218 		    "PASS: Successful read/write in data area.\n"));
    219 	else if (status == FAIL_SEGV) {
    220 		print_message(gettext(
    221 		    "FAIL: Caught a segmentation fault while "
    222 		    "attempting to write to the data area.\n"));
    223 		exit_status = EXIT_FAILURE;
    224 	} else {
    225 		(void) printf(gettext("Test program failure: %d\n"),
    226 		    status);
    227 		exit_status = EXIT_FAILURE;
    228 	}
    229 	return (exit_status);
    230 }
    231 
    232 static void
    233 probe_data_area()
    234 {
    235 	int *p;
    236 	/* LINTED */
    237 	volatile int p1;
    238 	void *address;
    239 
    240 	/* set handler status */
    241 	handler_exit_code = FAIL_SEGV;
    242 
    243 	/*
    244 	 * Get an address in the data area, near to the "hole".
    245 	 * sbrk returns prior address value; rather than calculating
    246 	 * the sbrk result, sbrk is called twice, so address points
    247 	 * to the new end of data
    248 	 */
    249 	(void) sbrk(PAGESIZE);
    250 	address = sbrk(0);
    251 	/*
    252 	 * Get to the inside edge of a page boundary
    253 	 * two integer words short of a new page
    254 	 */
    255 	p = ((int *)P2ROUNDUP((uintptr_t)address, PAGESIZE)) - 2;
    256 
    257 	/* Try writing to it, shouldn't cause a segmentation fault. */
    258 	*p = 9999;
    259 
    260 	/* Should be able to read back with no problems. */
    261 	p1 = *p;
    262 
    263 	/*
    264 	 * Get an address near the text area boundary, but in the data
    265 	 * area.  _etext rounded up a page isn't correct since the
    266 	 * initialized data area isn't writeable.
    267 	 *
    268 	 * Future versions should consider handling initialized data
    269 	 * separately -- writing to initialized data should generate
    270 	 * a fault.
    271 	 */
    272 	p = &_end;
    273 
    274 	/* Try writing to it, should succeed. */
    275 	*p = 9898;
    276 
    277 	/* Should be able to read back with no problems. */
    278 	p1 = *p;
    279 
    280 	exit(EXIT_SUCCESS);
    281 }
    282 
    283 /*
    284  * Test that we cannot write to the text area. An attempt to write to
    285  * the text area will result in a segmentation fault. So if we catch it,
    286  * test has succeed, else it has failed.
    287  */
    288 static int
    289 text_area_not_writeable()
    290 {
    291 	int exit_status = EXIT_SUCCESS;
    292 	pid_t pid;
    293 	int status;
    294 
    295 	print_message(gettext(
    296 	    "\n\nTest 3- Text Area Not Writeable\n"
    297 	    "Verify that a write to the text space does not cause "
    298 	    "a write to the executable\n"
    299 	    "file from which it came, or to another process which "
    300 	    "shares that text.\n"));
    301 
    302 	if ((pid = fork()) == -1) {
    303 		print_message(gettext("Fork failed\n"));
    304 		return (EXIT_FAILURE);
    305 	} else if (pid == 0) { /* Am I my child? */
    306 		set_handler(SIGSEGV);
    307 
    308 		/* probe_text_area() does exit() */
    309 		probe_text_area();
    310 	}
    311 	/* still parent */
    312 	(void) wait(&status);
    313 	status = WEXITSTATUS(status);
    314 
    315 	if (status == PASS) {
    316 		print_message(gettext(
    317 		    "FAIL: We did not cause a segmentation fault.\n"));
    318 		exit_status = EXIT_FAILURE;
    319 	} else if (status == FAIL_SEGV) {
    320 		print_message(gettext(
    321 		    "PASS: Caught the segmentation fault, "
    322 		    "meaning we can't write to text area.\n"));
    323 	} else {
    324 		(void) printf(gettext(
    325 		    "Test program failure: %d\n"), status);
    326 		exit_status = EXIT_FAILURE;
    327 	}
    328 	return (exit_status);
    329 }
    330 
    331 /*
    332  * write to text area, trigger a SEGV
    333  */
    334 static void
    335 probe_text_area()
    336 {
    337 	handler_exit_code = FAIL_SEGV;
    338 	*(caddr_t)probe_text_area = 0xff;
    339 	exit(EXIT_FAILURE);
    340 }
    341 
    342 /*
    343  * Test that when we set some values and fork a process, when the child
    344  * writes to these inherited values, the parents copies are not changed.
    345  */
    346 static int
    347 memory_not_shared_after_use()
    348 {
    349 	pid_t pid;
    350 	int x = 1000;
    351 	int exit_status = EXIT_SUCCESS;
    352 
    353 	print_message(gettext("\n\nTest 4- Memory Not Shared After Write\n"
    354 	    "Verify that anonymous memory initially shared by two "
    355 	    "processes (e.g. after a\n"
    356 	    "fork) is not shared after either process writes "
    357 	    "to it.\n"));
    358 
    359 	if ((pid = fork()) == -1) {
    360 		print_message(gettext("Fork failed\n"));
    361 		return (EXIT_FAILURE);
    362 	} else if (pid == 0) { /* I am the child. */
    363 		/*
    364 		 * Change child value; this should not change
    365 		 * parent value.
    366 		 */
    367 		x = 2000;
    368 
    369 		/* Wait for parent to test value */
    370 		(void) sleep(CHILD_SLEEP_PERIOD);
    371 
    372 		exit(EXIT_SUCCESS);
    373 	}
    374 	/* Wait for child to do its stuff. */
    375 	(void) sleep(PARENT_SLEEP_PERIOD);
    376 
    377 	if (x == 1000)
    378 		exit_status = EXIT_SUCCESS;
    379 	else
    380 		exit_status = EXIT_FAILURE;
    381 
    382 	return (exit_status);
    383 }
    384 
    385 /*
    386  * If we fork a process and then allocate some memory in that process,
    387  * we should not see any memory changes in the parent.
    388  */
    389 static int
    390 memory_allocation_not_shared()
    391 {
    392 	pid_t pid;
    393 	pid_t parent_pid;
    394 	int exit_status = 0;
    395 	caddr_t address;
    396 	caddr_t hole_start;
    397 	caddr_t hole_after;
    398 	void (*old_handler) ();
    399 
    400 	print_message(gettext(
    401 	    "\n\nTest 5- Memory Allocation is Not Shared\n"
    402 	    "Verify that newly allocated memory in one of two "
    403 	    "processes created by forking\n"
    404 	    "does not result in newly allocated memory in the other.\n"));
    405 
    406 	/* Save Size of data area and 1st block address of "hole" */
    407 	hole_start = (caddr_t)sbrk(0);
    408 
    409 	if (silent == NOT_SILENT)
    410 		(void) printf(gettext(
    411 		    "Parent address of hole before child change: %08X\n"),
    412 		    hole_start);
    413 
    414 	/* Set handler for signal SIG_EVENT (define at start) */
    415 	old_handler = signal(SIG_EVENT, &handler);
    416 	if (old_handler == SIG_ERR) {
    417 		print_message(gettext(
    418 		    "Can't establish signal handler, test failed\n"));
    419 		return (EXIT_FAILURE);
    420 	}
    421 
    422 	if ((pid = fork()) == -1) {
    423 		print_message(gettext("Fork failed\n"));
    424 		return (EXIT_FAILURE);
    425 	} else if (pid == 0) { /* We are the child. */
    426 		address = sbrk(0);
    427 		if (silent == NOT_SILENT)
    428 			(void) printf(gettext(
    429 			    "Child end of hole before change:  %08X\n"),
    430 			    address);
    431 
    432 		if (brk((address+PAGESIZE)) != 0) {
    433 			print_message(gettext(
    434 			    "Can't change start of hole address.\n"));
    435 			exit(EXIT_FAILURE);
    436 		}
    437 
    438 		address = sbrk(0);
    439 		if (silent == NOT_SILENT)
    440 			(void) printf(gettext(
    441 			    "Child end of hole after change: %08X\n"),
    442 			    address);
    443 
    444 		/* Tell the parent we're done. */
    445 		parent_pid = getppid();
    446 		if (sigsend(P_PID, parent_pid, SIG_EVENT) != 0) {
    447 			print_message(gettext("Can't send signal to parent, "
    448 			    "test failed\n"));
    449 			exit(EXIT_FAILURE);
    450 		}
    451 
    452 		/* Sleep before exiting to allow parent to finish processing. */
    453 		(void) sleep(CHILD_SLEEP_PERIOD);
    454 		exit(EXIT_SUCCESS);
    455 	}
    456 	/* Wait for child to do its work. */
    457 	(void) sleep(PARENT_SLEEP_PERIOD);
    458 
    459 	if (done_memory_grab != 1) {
    460 		print_message(gettext(
    461 		    "Child failed to do memory alterations, "
    462 		    "exiting\n"));
    463 		return (EXIT_FAILURE);
    464 	}
    465 
    466 	hole_after = sbrk(0);
    467 	if (silent == NOT_SILENT)
    468 		(void) printf(gettext(
    469 		    "Parent address of hole after child change: "
    470 		    "%08X\n"), hole_after);
    471 
    472 	/* Test size of hole and data region. */
    473 	if (hole_start == hole_after)
    474 		print_message(gettext(
    475 		    "PASS: Hole is same size in parent.\n"));
    476 	else {
    477 		print_message(gettext(
    478 		    "FAIL: Hole is a different size.\n"));
    479 		exit_status = EXIT_FAILURE;
    480 	}
    481 
    482 	/* Wait for child to finish. */
    483 	(void) wait(0);
    484 
    485 	if (signal(SIG_EVENT, old_handler) == SIG_ERR) {
    486 		print_message(gettext("Couldn't put back old signal handler, "
    487 		    "test failed.\n"));
    488 		return (EXIT_FAILURE);
    489 	}
    490 	return (exit_status);
    491 }
    492 
    493 static void
    494 print_message(char *message)
    495 {
    496 	if (silent == NOT_SILENT)
    497 		(void) printf("%s", message);
    498 }
    499 
    500 static int
    501 test_stack_end_of_hole()
    502 {
    503 	pid_t pid;
    504 	int status;
    505 	int exit_status = EXIT_SUCCESS;
    506 
    507 	print_message(gettext("\n\nTest 1- stack Side Boundary Test\n"));
    508 
    509 	/* sub test 1:  the space the stack grows into is zero */
    510 
    511 	if ((pid = fork()) == -1) {
    512 		print_message(gettext("Fork failed\n"));
    513 		return (EXIT_FAILURE);
    514 	} else if (pid == 0) { /* Am I my child? */
    515 		set_handler(SIGSEGV);
    516 
    517 		/* probe_stack() does exit */
    518 		probe_stack();
    519 	}
    520 	/* still parent */
    521 	(void) wait(&status);
    522 	status = WEXITSTATUS(status);
    523 
    524 	if (status == FAIL_ZERO) {
    525 		print_message(gettext("Fail with non-zero read.\n"));
    526 		exit_status = EXIT_FAILURE;
    527 	} else if (status != PASS) {
    528 		print_message(gettext("Test program failure\n"));
    529 		exit_status = EXIT_FAILURE;
    530 	}
    531 	/* sub test 2:  the space in hole is not readable */
    532 
    533 	if ((pid = fork()) == -1) {
    534 		print_message(gettext("Fork failed\n"));
    535 		return (EXIT_FAILURE);
    536 	} else if (pid == 0) { /* Am I my child? */
    537 		set_handler(SIGSEGV);
    538 
    539 		/* probe_hole does exit */
    540 		probe_hole(PH_INVALID);
    541 	}
    542 	/* still parent */
    543 	(void) wait(&status);
    544 	status = WEXITSTATUS(status);
    545 
    546 	if (status == FAIL_SEGV) {
    547 		print_message(
    548 		    gettext("Fail (SEGV expected, not received).\n"));
    549 		exit_status = EXIT_FAILURE;
    550 	} else if (status != PASS_SEGV) {
    551 		print_message(gettext("Test program failure.\n"));
    552 		exit_status = EXIT_FAILURE;
    553 	}
    554 
    555 	/* sub test 3:  the space in new page below hole is zero */
    556 
    557 	if ((pid = fork()) == -1) {
    558 		print_message(gettext("Fork failed\n"));
    559 		return (EXIT_FAILURE);
    560 	} else if (pid == 0) { /* Am I my child? */
    561 		set_handler(SIGSEGV);
    562 
    563 		/* probe_hole does exit */
    564 		probe_hole(PH_VALID);
    565 	}
    566 	/* still parent */
    567 	(void) wait(&status);
    568 	status = WEXITSTATUS(status);
    569 
    570 	if (status == FAIL_SEGV) {
    571 		print_message(gettext("Fail (got SEGV).\n"));
    572 		exit_status = EXIT_FAILURE;
    573 	} else if (status != PASS) {
    574 		print_message(gettext("Test program failure.\n"));
    575 		exit_status = EXIT_FAILURE;
    576 	}
    577 	return (exit_status);
    578 }
    579 
    580 
    581 /*
    582  * set_handler
    583  */
    584 static void
    585 set_handler(int sig)
    586 {
    587 	struct sigaction act;
    588 
    589 	act.sa_handler = NULL;
    590 	act.sa_flags = SA_SIGINFO;
    591 	act.sa_sigaction = segv_action;
    592 	(void) sigemptyset(&(act.sa_mask));
    593 
    594 	if (sigaction(sig, &act, NULL) < 0) {
    595 		if (silent == NOT_SILENT) {
    596 			(void) fprintf(stderr, gettext(
    597 			    "sigaction() returned error: %s\n"),
    598 			    strerror(errno));
    599 		}
    600 		exit(EXIT_FAILURE);
    601 	}
    602 }
    603 
    604 
    605 /*ARGSUSED*/
    606 static void
    607 segv_action(int which_sig, siginfo_t *t1, void *t2)
    608 {
    609 	exit(handler_exit_code);
    610 }
    611 
    612 /*
    613  * probe_stack
    614  *
    615  * Warning -- if you do a printf or fprintf prior to the actual
    616  * reading from the stack, you've changed the stack to an unknown
    617  * state.  (stack memory isn't free'd automatically and this function
    618  * needs to touch virgin stack space.)
    619  */
    620 static void
    621 probe_stack(void)
    622 {
    623 	unsigned char *end;	/* end of stack */
    624 	unsigned char probe;
    625 	long i;
    626 	int j;
    627 	unsigned char last_fail, *last_fail_address;
    628 	unsigned char mark = 0xAA;	/* roughly the end of stack */
    629 	handler_exit_code = FAIL_SEGV;
    630 
    631 	end = &mark;
    632 	/* stack growth is negative */
    633 	end -= (WASTE_PAGES * PAGESIZE) + STACK_SLOP;
    634 
    635 	for (i = 0, j = 0; i < PAGESIZE; i++) {
    636 		if ((probe = *end) != 0) {
    637 			j++;
    638 			last_fail = probe;
    639 			last_fail_address = end;
    640 		}
    641 		end--;
    642 	}
    643 
    644 	if (j != 0) {
    645 		if (silent == NOT_SILENT)
    646 			(void) fprintf(stderr, gettext(
    647 			    "probe_stack failed. address=0x%08X; "
    648 			    "probe=0x%02X; content = %d\n"),
    649 			    (caddr_t)last_fail_address, last_fail, j);
    650 
    651 		exit(FAIL_ZERO);    /* test failed at least once */
    652 	}
    653 	exit(EXIT_SUCCESS);
    654 }
    655 
    656 static void
    657 probe_hole(int test_type)
    658 {
    659 	long i;
    660 	/* LINTED */
    661 	volatile unsigned char probe;
    662 	unsigned char *probe_adr;
    663 	void *address;
    664 
    665 	address = sbrk(0);  /* current end data + 1 */
    666 
    667 	if (address == (void *)-1) {
    668 		print_message(gettext("Test program logic error\n"));
    669 		exit(FAIL_ABORT);
    670 	}
    671 	if (test_type == PH_VALID) {
    672 		/* show that access works inside the  hole */
    673 		handler_exit_code = FAIL_SEGV;
    674 
    675 		probe_adr =  (unsigned char *)address - sizeof (char);
    676 
    677 		for (i = 0; i < PAGESIZE; i++)
    678 			probe = *probe_adr--;
    679 
    680 		exit(EXIT_SUCCESS);
    681 	} else {
    682 		/* show that a trap occurs in the  hole */
    683 		handler_exit_code = PASS_SEGV;
    684 
    685 		address = (void *)P2ROUNDUP((uintptr_t)address, PAGESIZE);
    686 		probe_adr = (unsigned char *)address;
    687 
    688 		probe = *probe_adr;
    689 		exit(FAIL_SEGV);	/* expected SEGV, didn't get it */
    690 	}
    691 }
    692 
    693 /*
    694  * Catch signal, child to parent
    695  */
    696 /*ARGSUSED*/
    697 void
    698 handler(int signal)
    699 {
    700 	done_memory_grab = 1;
    701 }
    702 /*
    703  * memory_type:  Determine whether a given executable file is compiled
    704  * as 32 or 64 bit.
    705  *
    706  * The following code was stolen from isainfo (1)
    707  */
    708 
    709 static int
    710 memory_type(const char *path) {
    711 	char *idarray;
    712 	Elf *elf;
    713 	int d;
    714 	int bits = 0;
    715 
    716 	if ((d = open(path, O_RDONLY)) < 0) {
    717 		(void) fprintf(stderr,
    718 		    "cannot open: %s -- %s\n",
    719 		    path, strerror(errno));
    720 		return (bits);
    721 	}
    722 
    723 	if (elf_version(EV_CURRENT) == EV_NONE) {
    724 		(void) fprintf(stderr,
    725 		    "internal error: ELF library out of date?\n");
    726 		(void) close(d);
    727 		return (bits);
    728 	}
    729 
    730 	elf = elf_begin(d, ELF_C_READ, (Elf *)0);
    731 	if (elf_kind(elf) != ELF_K_ELF) {
    732 		(void) elf_end(elf);
    733 		(void) close(d);
    734 		return (bits);
    735 	}
    736 
    737 	idarray = elf_getident(elf, 0);
    738 
    739 	if (idarray[EI_CLASS] == ELFCLASS32) {
    740 		bits = 32;
    741 	} else if (idarray[EI_CLASS] == ELFCLASS64) {
    742 		bits = 64;
    743 	}
    744 
    745 	(void) elf_end(elf);
    746 	(void) close(d);
    747 	return (bits);
    748 }
    749