summaryrefslogtreecommitdiff
path: root/usr/src/cmd/amt
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/amt')
-rw-r--r--usr/src/cmd/amt/Makefile75
-rw-r--r--usr/src/cmd/amt/Makefile.com60
-rw-r--r--usr/src/cmd/amt/amd64/Makefile34
-rw-r--r--usr/src/cmd/amt/amt.c748
-rw-r--r--usr/src/cmd/amt/amt.sh44
-rw-r--r--usr/src/cmd/amt/i386/Makefile34
-rw-r--r--usr/src/cmd/amt/sparcv9/Makefile35
7 files changed, 1030 insertions, 0 deletions
diff --git a/usr/src/cmd/amt/Makefile b/usr/src/cmd/amt/Makefile
new file mode 100644
index 0000000000..dfb4536724
--- /dev/null
+++ b/usr/src/cmd/amt/Makefile
@@ -0,0 +1,75 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/amt/Makefile
+#
+
+PROG= amt
+
+include ../Makefile.cmd
+
+TEXT_DOMAIN=SUNW_OST_OSCMD
+POFILE=$(PROG).po
+
+$(64ONLY)SUBDIRS= $(MACH)
+$(BUILD64)SUBDIRS += $(MACH64)
+CLEANFILES += $(POFILE)
+
+SHFILERCS= $(PROG:%=%.sh)
+
+all := TARGET = all
+install := TARGET = install
+clean := TARGET = clean
+clobber := TARGET = clobber
+lint := TARGET = lint
+
+.KEEP_STATE:
+
+all: $(SUBDIRS) pofile $(PROG)
+
+clean clobber lint: $(SUBDIRS)
+
+install: $(SUBDIRS) $(ROOTPROG)
+
+pofile: $(POFILE)
+
+$(PROG): $(PROG).sh
+ $(RM) -f $(PROG)
+ $(CP) $(PROG).sh $(PROG)
+ $(CHMOD) 555 $(PROG)
+
+$(POFILE): $(SRCS)
+ $(RM) $(TEXT_DOMAIN).po
+ $(XGETTEXT) -s -d $(TEXT_DOMAIN) $<
+ $(MV) $(TEXT_DOMAIN).po $@
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
diff --git a/usr/src/cmd/amt/Makefile.com b/usr/src/cmd/amt/Makefile.com
new file mode 100644
index 0000000000..d3519687af
--- /dev/null
+++ b/usr/src/cmd/amt/Makefile.com
@@ -0,0 +1,60 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/amt/Makefile.com
+#
+
+PROG= amt
+OBJS= amt.o
+SRCS= $(OBJS:%.o=../%.c)
+
+include ../../Makefile.cmd
+
+LDLIBS += -lelf
+
+LINTFLAGS += -erroff=E_NAME_USED_NOT_DEF2
+LINTFLAGS64 += -erroff=E_NAME_USED_NOT_DEF2
+
+CLEANFILES += $(PROG) $(OBJS)
+
+.KEEP_STATE:
+
+all: $(PROG)
+
+$(PROG): $(OBJS)
+ $(LINK.c) $(OBJS) -o $@ $(LDLIBS)
+ $(POST_PROCESS)
+
+lint: lint_SRCS
+
+%.o: ../%.c
+ $(COMPILE.c) $<
+
+clean:
+ $(RM) $(CLEANFILES)
+
+include ../../Makefile.targ
diff --git a/usr/src/cmd/amt/amd64/Makefile b/usr/src/cmd/amt/amd64/Makefile
new file mode 100644
index 0000000000..2a65ac9ed3
--- /dev/null
+++ b/usr/src/cmd/amt/amd64/Makefile
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# ident "%Z%%M% %I% %E% SMI"
+#
+
+.KEEP_STATE:
+
+include ../Makefile.com
+include ../../Makefile.cmd.64
+
+install: $(PROG) $(ROOTPROG64)
diff --git a/usr/src/cmd/amt/amt.c b/usr/src/cmd/amt/amt.c
new file mode 100644
index 0000000000..8c4cfdbe29
--- /dev/null
+++ b/usr/src/cmd/amt/amt.c
@@ -0,0 +1,748 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * Abstract Machine Test; executes memory access tests to show
+ * compliance with Common Criteria object reuse and process address
+ * space separation requirements.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <iso/stdlib_iso.h>
+#include <libelf.h>
+#include <libintl.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wait.h>
+
+#define NOT_SILENT 0
+#define SILENT_MODE 1
+
+#define CHILD_SLEEP_PERIOD 2
+#define PARENT_SLEEP_PERIOD 1
+#define SIG_EVENT SIGUSR1
+
+#define PASS 0 /* test passed, no SEGV */
+#define FAIL_ZERO 1 /* expected to read zero, didn't */
+#define FAIL_SEGV 2 /* expected good read or write, didn't */
+#define PASS_SEGV 3 /* expected SEGV, got it */
+#define FAIL_ABORT 4 /* test logic error */
+
+#define PH_VALID 0 /* arg for probe_hole -- do valid memory */
+ /* access */
+#define PH_INVALID 1 /* do illegal memory access */
+
+#define WASTE_PAGES 8 /* a guess at where virgin stack space */
+ /* is likely to exist */
+#define STACK_SLOP 256 /* a guess at how far below current end */
+ /* of stack I'll find unused space */
+
+#if !defined(TEXT_DOMAIN)
+#define TEXT_DOMAIN "SYS_TEST"
+#endif
+
+extern int _end; /* first address after the end of initialized data */
+
+static int data_boundary_test();
+static void handler(int);
+static int memory_not_shared_after_use();
+static int memory_allocation_not_shared();
+static int memory_type(const char *);
+static void print_message(char *);
+static void probe_data_area(void);
+static void probe_hole(int);
+static void probe_stack(void);
+static void probe_text_area(void);
+static void segv_action(int, siginfo_t *, void *);
+static void set_handler(int);
+static int test_stack_end_of_hole();
+static int text_area_not_writeable();
+
+static int done_memory_grab = 0;
+static int silent;
+static int handler_exit_code;
+
+/*
+ * Main Routine
+ */
+int
+main(int argc, char *argv[])
+{
+ int fail_count = 0;
+ int status = 0;
+ int bitsize;
+
+ /* Internationalization */
+ (void) setlocale(LC_ALL, "");
+ (void) textdomain(TEXT_DOMAIN);
+
+ silent = NOT_SILENT;
+
+ if (argc == 2) {
+ /* Pull out argument provided */
+ /* -s silent mode, no status or error messages. */
+ if (strncmp(argv[1], "-s", 4) == 0)
+ silent = SILENT_MODE;
+ else {
+ /* Wrong argument */
+ (void) fprintf(stderr, gettext(
+ "Wrong argument, USAGE: amt [-s]\n"));
+ exit(EXIT_FAILURE);
+ }
+ } else if (argc != 1) {
+ /* Illegal number of arguments. */
+ (void) fprintf(stderr, gettext(
+ "Wrong usage, USAGE: amt [-s]\n"));
+ exit(EXIT_FAILURE);
+ }
+ bitsize = memory_type(argv[0]);
+
+ if (silent == NOT_SILENT)
+ (void) printf(gettext(
+ "\n\nAMT Test Program -- %d bit application\n"
+ "================\n"), bitsize);
+ /*
+ * test_stack_end_of_hole must be the first test, or the stack
+ * is of an unknown size.
+ */
+ if ((status = test_stack_end_of_hole()) == EXIT_FAILURE) {
+ /* Normal fail */
+ fail_count++;
+ print_message(gettext("TEST 1 FAILED\n"));
+ } else if (status == FAIL_ABORT) {
+ /* Test logic failure */
+ fail_count++;
+ print_message(gettext("FAIL: Logic error in test\n"));
+ } else if (status == EXIT_SUCCESS)
+ print_message(gettext("TEST 1 PASSED\n"));
+
+ /* Carry out test 2 */
+ if (data_boundary_test() != EXIT_SUCCESS) {
+ fail_count++;
+ print_message(gettext("TEST 2 FAILED\n"));
+ } else
+ print_message(gettext("TEST 2 PASSED\n"));
+
+ /* Carry out test 3 */
+ if (text_area_not_writeable() != EXIT_SUCCESS) {
+ fail_count++;
+ print_message(gettext("TEST 3 FAILED\n"));
+ } else
+ print_message(gettext("TEST 3 PASSED\n"));
+
+ /* Carry out test 4 */
+ if (memory_not_shared_after_use() != EXIT_SUCCESS) {
+ fail_count++;
+ print_message(gettext("TEST 4 FAILED\n"));
+ } else
+ print_message(gettext("TEST 4 PASSED\n"));
+
+ /* Carry out test 5 */
+ if (memory_allocation_not_shared() != EXIT_SUCCESS) {
+ fail_count++;
+ print_message(gettext("TEST 5 FAILED\n"));
+ } else
+ print_message(gettext("TEST 5 PASSED\n"));
+
+ if (silent == NOT_SILENT) {
+ if (fail_count > 0)
+ (void) printf(gettext("\n %d TESTS FAILED\n\n"),
+ fail_count);
+ else
+ (void) printf(gettext("\nTESTS SUCCEEDED\n\n"));
+ }
+ return (fail_count);
+}
+
+/*
+ * Test the data boundaries. First test inside the data area at the boundary
+ * of the "hole" area. Second test inside the data area at the text area
+ * boundary. Both should pass.
+ */
+static int
+data_boundary_test()
+{
+ int exit_status = EXIT_SUCCESS;
+ pid_t pid;
+ int status;
+
+ print_message(gettext("\n\nTest 2- Data Side Boundary Test.\n"));
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* Am I my child? */
+ set_handler(SIGSEGV);
+
+ /* probe_data_area() does exit() */
+ probe_data_area();
+ }
+ /* still parent */
+ (void) wait(&status);
+ status = WEXITSTATUS(status);
+
+ if (status == PASS)
+ print_message(gettext(
+ "PASS: Successful read/write in data area.\n"));
+ else if (status == FAIL_SEGV) {
+ print_message(gettext(
+ "FAIL: Caught a segmentation fault while "
+ "attempting to write to the data area.\n"));
+ exit_status = EXIT_FAILURE;
+ } else {
+ (void) printf(gettext("Test program failure: %d\n"),
+ status);
+ exit_status = EXIT_FAILURE;
+ }
+ return (exit_status);
+}
+
+static void
+probe_data_area()
+{
+ int *p;
+ /* LINTED */
+ volatile int p1;
+ void *address;
+
+ /* set handler status */
+ handler_exit_code = FAIL_SEGV;
+
+ /*
+ * Get an address in the data area, near to the "hole".
+ * sbrk returns prior address value; rather than calculating
+ * the sbrk result, sbrk is called twice, so address points
+ * to the new end of data
+ */
+ (void) sbrk(PAGESIZE);
+ address = sbrk(0);
+ /*
+ * Get to the inside edge of a page boundary
+ * two integer words short of a new page
+ */
+ p = ((int *)P2ROUNDUP((uintptr_t)address, PAGESIZE)) - 2;
+
+ /* Try writing to it, shouldn't cause a segmentation fault. */
+ *p = 9999;
+
+ /* Should be able to read back with no problems. */
+ p1 = *p;
+
+ /*
+ * Get an address near the text area boundary, but in the data
+ * area. _etext rounded up a page isn't correct since the
+ * initialized data area isn't writeable.
+ *
+ * Future versions should consider handling initialized data
+ * separately -- writing to initialized data should generate
+ * a fault.
+ */
+ p = &_end;
+
+ /* Try writing to it, should succeed. */
+ *p = 9898;
+
+ /* Should be able to read back with no problems. */
+ p1 = *p;
+
+ exit(EXIT_SUCCESS);
+}
+
+/*
+ * Test that we cannot write to the text area. An attempt to write to
+ * the text area will result in a segmentation fault. So if we catch it,
+ * test has succeed, else it has failed.
+ */
+static int
+text_area_not_writeable()
+{
+ int exit_status = EXIT_SUCCESS;
+ pid_t pid;
+ int status;
+
+ print_message(gettext(
+ "\n\nTest 3- Text Area Not Writeable\n"
+ "Verify that a write to the text space does not cause "
+ "a write to the executable\n"
+ "file from which it came, or to another process which "
+ "shares that text.\n"));
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* Am I my child? */
+ set_handler(SIGSEGV);
+
+ /* probe_text_area() does exit() */
+ probe_text_area();
+ }
+ /* still parent */
+ (void) wait(&status);
+ status = WEXITSTATUS(status);
+
+ if (status == PASS) {
+ print_message(gettext(
+ "FAIL: We did not cause a segmentation fault.\n"));
+ exit_status = EXIT_FAILURE;
+ } else if (status == FAIL_SEGV) {
+ print_message(gettext(
+ "PASS: Caught the segmentation fault, "
+ "meaning we can't write to text area.\n"));
+ } else {
+ (void) printf(gettext(
+ "Test program failure: %d\n"), status);
+ exit_status = EXIT_FAILURE;
+ }
+ return (exit_status);
+}
+
+/*
+ * write to text area, trigger a SEGV
+ */
+static void
+probe_text_area()
+{
+ handler_exit_code = FAIL_SEGV;
+ *(caddr_t)probe_text_area = 0xff;
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Test that when we set some values and fork a process, when the child
+ * writes to these inherited values, the parents copies are not changed.
+ */
+static int
+memory_not_shared_after_use()
+{
+ pid_t pid;
+ int x = 1000;
+ int exit_status = EXIT_SUCCESS;
+
+ print_message(gettext("\n\nTest 4- Memory Not Shared After Write\n"
+ "Verify that anonymous memory initially shared by two "
+ "processes (e.g. after a\n"
+ "fork) is not shared after either process writes "
+ "to it.\n"));
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* I am the child. */
+ /*
+ * Change child value; this should not change
+ * parent value.
+ */
+ x = 2000;
+
+ /* Wait for parent to test value */
+ (void) sleep(CHILD_SLEEP_PERIOD);
+
+ exit(EXIT_SUCCESS);
+ }
+ /* Wait for child to do its stuff. */
+ (void) sleep(PARENT_SLEEP_PERIOD);
+
+ if (x == 1000)
+ exit_status = EXIT_SUCCESS;
+ else
+ exit_status = EXIT_FAILURE;
+
+ return (exit_status);
+}
+
+/*
+ * If we fork a process and then allocate some memory in that process,
+ * we should not see any memory changes in the parent.
+ */
+static int
+memory_allocation_not_shared()
+{
+ pid_t pid;
+ pid_t parent_pid;
+ int exit_status = 0;
+ caddr_t address;
+ caddr_t hole_start;
+ caddr_t hole_after;
+ void (*old_handler) ();
+
+ print_message(gettext(
+ "\n\nTest 5- Memory Allocation is Not Shared\n"
+ "Verify that newly allocated memory in one of two "
+ "processes created by forking\n"
+ "does not result in newly allocated memory in the other.\n"));
+
+ /* Save Size of data area and 1st block address of "hole" */
+ hole_start = (caddr_t)sbrk(0);
+
+ if (silent == NOT_SILENT)
+ (void) printf(gettext(
+ "Parent address of hole before child change: %08X\n"),
+ hole_start);
+
+ /* Set handler for signal SIG_EVENT (define at start) */
+ old_handler = signal(SIG_EVENT, &handler);
+ if (old_handler == SIG_ERR) {
+ print_message(gettext(
+ "Can't establish signal handler, test failed\n"));
+ return (EXIT_FAILURE);
+ }
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* We are the child. */
+ address = sbrk(0);
+ if (silent == NOT_SILENT)
+ (void) printf(gettext(
+ "Child end of hole before change: %08X\n"),
+ address);
+
+ if (brk((address+PAGESIZE)) != 0) {
+ print_message(gettext(
+ "Can't change start of hole address.\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ address = sbrk(0);
+ if (silent == NOT_SILENT)
+ (void) printf(gettext(
+ "Child end of hole after change: %08X\n"),
+ address);
+
+ /* Tell the parent we're done. */
+ parent_pid = getppid();
+ if (sigsend(P_PID, parent_pid, SIG_EVENT) != 0) {
+ print_message(gettext("Can't send signal to parent, "
+ "test failed\n"));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Sleep before exiting to allow parent to finish processing. */
+ (void) sleep(CHILD_SLEEP_PERIOD);
+ exit(EXIT_SUCCESS);
+ }
+ /* Wait for child to do its work. */
+ (void) sleep(PARENT_SLEEP_PERIOD);
+
+ if (done_memory_grab != 1) {
+ print_message(gettext(
+ "Child failed to do memory alterations, "
+ "exiting\n"));
+ return (EXIT_FAILURE);
+ }
+
+ hole_after = sbrk(0);
+ if (silent == NOT_SILENT)
+ (void) printf(gettext(
+ "Parent address of hole after child change: "
+ "%08X\n"), hole_after);
+
+ /* Test size of hole and data region. */
+ if (hole_start == hole_after)
+ print_message(gettext(
+ "PASS: Hole is same size in parent.\n"));
+ else {
+ print_message(gettext(
+ "FAIL: Hole is a different size.\n"));
+ exit_status = EXIT_FAILURE;
+ }
+
+ /* Wait for child to finish. */
+ (void) wait(0);
+
+ if (signal(SIG_EVENT, old_handler) == SIG_ERR) {
+ print_message(gettext("Couldn't put back old signal handler, "
+ "test failed.\n"));
+ return (EXIT_FAILURE);
+ }
+ return (exit_status);
+}
+
+static void
+print_message(char *message)
+{
+ if (silent == NOT_SILENT)
+ (void) printf("%s", message);
+}
+
+static int
+test_stack_end_of_hole()
+{
+ pid_t pid;
+ int status;
+ int exit_status = EXIT_SUCCESS;
+
+ print_message(gettext("\n\nTest 1- stack Side Boundary Test\n"));
+
+ /* sub test 1: the space the stack grows into is zero */
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* Am I my child? */
+ set_handler(SIGSEGV);
+
+ /* probe_stack() does exit */
+ probe_stack();
+ }
+ /* still parent */
+ (void) wait(&status);
+ status = WEXITSTATUS(status);
+
+ if (status == FAIL_ZERO) {
+ print_message(gettext("Fail with non-zero read.\n"));
+ exit_status = EXIT_FAILURE;
+ } else if (status != PASS) {
+ print_message(gettext("Test program failure\n"));
+ exit_status = EXIT_FAILURE;
+ }
+ /* sub test 2: the space in hole is not readable */
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* Am I my child? */
+ set_handler(SIGSEGV);
+
+ /* probe_hole does exit */
+ probe_hole(PH_INVALID);
+ }
+ /* still parent */
+ (void) wait(&status);
+ status = WEXITSTATUS(status);
+
+ if (status == FAIL_SEGV) {
+ print_message(
+ gettext("Fail (SEGV expected, not received).\n"));
+ exit_status = EXIT_FAILURE;
+ } else if (status != PASS_SEGV) {
+ print_message(gettext("Test program failure.\n"));
+ exit_status = EXIT_FAILURE;
+ }
+
+ /* sub test 3: the space in new page below hole is zero */
+
+ if ((pid = fork()) == -1) {
+ print_message(gettext("Fork failed\n"));
+ return (EXIT_FAILURE);
+ } else if (pid == 0) { /* Am I my child? */
+ set_handler(SIGSEGV);
+
+ /* probe_hole does exit */
+ probe_hole(PH_VALID);
+ }
+ /* still parent */
+ (void) wait(&status);
+ status = WEXITSTATUS(status);
+
+ if (status == FAIL_SEGV) {
+ print_message(gettext("Fail (got SEGV).\n"));
+ exit_status = EXIT_FAILURE;
+ } else if (status != PASS) {
+ print_message(gettext("Test program failure.\n"));
+ exit_status = EXIT_FAILURE;
+ }
+ return (exit_status);
+}
+
+
+/*
+ * set_handler
+ */
+static void
+set_handler(int sig)
+{
+ struct sigaction act;
+
+ act.sa_handler = NULL;
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = segv_action;
+ (void) sigemptyset(&(act.sa_mask));
+
+ if (sigaction(sig, &act, NULL) < 0) {
+ if (silent == NOT_SILENT) {
+ (void) fprintf(stderr, gettext(
+ "sigaction() returned error: %s\n"),
+ strerror(errno));
+ }
+ exit(EXIT_FAILURE);
+ }
+}
+
+
+/*ARGSUSED*/
+static void
+segv_action(int which_sig, siginfo_t *t1, void *t2)
+{
+ exit(handler_exit_code);
+}
+
+/*
+ * probe_stack
+ *
+ * Warning -- if you do a printf or fprintf prior to the actual
+ * reading from the stack, you've changed the stack to an unknown
+ * state. (stack memory isn't free'd automatically and this function
+ * needs to touch virgin stack space.)
+ */
+static void
+probe_stack(void)
+{
+ unsigned char *end; /* end of stack */
+ unsigned char probe;
+ long i;
+ int j;
+ unsigned char last_fail, *last_fail_address;
+ unsigned char mark = 0xAA; /* roughly the end of stack */
+ handler_exit_code = FAIL_SEGV;
+
+ end = &mark;
+ /* stack growth is negative */
+ end -= (WASTE_PAGES * PAGESIZE) + STACK_SLOP;
+
+ for (i = 0, j = 0; i < PAGESIZE; i++) {
+ if ((probe = *end) != 0) {
+ j++;
+ last_fail = probe;
+ last_fail_address = end;
+ }
+ end--;
+ }
+
+ if (j != 0) {
+ if (silent == NOT_SILENT)
+ (void) fprintf(stderr, gettext(
+ "probe_stack failed. address=0x%08X; "
+ "probe=0x%02X; content = %d\n"),
+ (caddr_t)last_fail_address, last_fail, j);
+
+ exit(FAIL_ZERO); /* test failed at least once */
+ }
+ exit(EXIT_SUCCESS);
+}
+
+static void
+probe_hole(int test_type)
+{
+ long i;
+ /* LINTED */
+ volatile unsigned char probe;
+ unsigned char *probe_adr;
+ void *address;
+
+ address = sbrk(0); /* current end data + 1 */
+
+ if (address == (void *)-1) {
+ print_message(gettext("Test program logic error\n"));
+ exit(FAIL_ABORT);
+ }
+ if (test_type == PH_VALID) {
+ /* show that access works inside the hole */
+ handler_exit_code = FAIL_SEGV;
+
+ probe_adr = (unsigned char *)address - sizeof (char);
+
+ for (i = 0; i < PAGESIZE; i++)
+ probe = *probe_adr--;
+
+ exit(EXIT_SUCCESS);
+ } else {
+ /* show that a trap occurs in the hole */
+ handler_exit_code = PASS_SEGV;
+
+ address = (void *)P2ROUNDUP((uintptr_t)address, PAGESIZE);
+ probe_adr = (unsigned char *)address;
+
+ probe = *probe_adr;
+ exit(FAIL_SEGV); /* expected SEGV, didn't get it */
+ }
+}
+
+/*
+ * Catch signal, child to parent
+ */
+/*ARGSUSED*/
+void
+handler(int signal)
+{
+ done_memory_grab = 1;
+}
+/*
+ * memory_type: Determine whether a given executable file is compiled
+ * as 32 or 64 bit.
+ *
+ * The following code was stolen from isainfo (1)
+ */
+
+static int
+memory_type(const char *path) {
+ char *idarray;
+ Elf *elf;
+ int d;
+ int bits = 0;
+
+ if ((d = open(path, O_RDONLY)) < 0) {
+ (void) fprintf(stderr,
+ "cannot open: %s -- %s\n",
+ path, strerror(errno));
+ return (bits);
+ }
+
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ (void) fprintf(stderr,
+ "internal error: ELF library out of date?\n");
+ (void) close(d);
+ return (bits);
+ }
+
+ elf = elf_begin(d, ELF_C_READ, (Elf *)0);
+ if (elf_kind(elf) != ELF_K_ELF) {
+ (void) elf_end(elf);
+ (void) close(d);
+ return (bits);
+ }
+
+ idarray = elf_getident(elf, 0);
+
+ if (idarray[EI_CLASS] == ELFCLASS32) {
+ bits = 32;
+ } else if (idarray[EI_CLASS] == ELFCLASS64) {
+ bits = 64;
+ }
+
+ (void) elf_end(elf);
+ (void) close(d);
+ return (bits);
+}
diff --git a/usr/src/cmd/amt/amt.sh b/usr/src/cmd/amt/amt.sh
new file mode 100644
index 0000000000..686738fa9e
--- /dev/null
+++ b/usr/src/cmd/amt/amt.sh
@@ -0,0 +1,44 @@
+#! /usr/bin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 2000 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+
+BIN=`dirname $0`
+cmd=`basename $0`
+
+for d in `/usr/bin/isalist`
+do
+ if [ -x $BIN/$d/$cmd ]; then
+ $BIN/$d/$cmd "$@"
+ res=$?
+ if [ $res != 0 ]; then
+ exit $res
+ fi
+ fi
+done
+
+exit 0
diff --git a/usr/src/cmd/amt/i386/Makefile b/usr/src/cmd/amt/i386/Makefile
new file mode 100644
index 0000000000..600bb4bea5
--- /dev/null
+++ b/usr/src/cmd/amt/i386/Makefile
@@ -0,0 +1,34 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 2000 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/amt/i386/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.com
+
+install: $(PROG) $(ROOTPROG32)
diff --git a/usr/src/cmd/amt/sparcv9/Makefile b/usr/src/cmd/amt/sparcv9/Makefile
new file mode 100644
index 0000000000..da3acb4713
--- /dev/null
+++ b/usr/src/cmd/amt/sparcv9/Makefile
@@ -0,0 +1,35 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+#ident "%Z%%M% %I% %E% SMI"
+#
+# Copyright (c) 2000 by Sun Microsystems, Inc.
+# All rights reserved.
+#
+# cmd/amt/sparcv9/Makefile
+
+.KEEP_STATE:
+
+include ../Makefile.com
+include ../../Makefile.cmd.64
+
+install: $(PROG) $(ROOTPROG64)