tools/time.c
author Norm Jacobs <Norm.Jacobs@Sun.COM>
Wed, 12 May 2010 00:32:41 -0500
changeset 6 20f80c019d73
child 16 33aaaec59991
permissions -rw-r--r--
add compiler date/time chatter reduction tools
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 (c) 2010, Oracle and/or it's affiliates.  All rights reserved.
 */

/*
 * This compiles to a module that can be preloaded during a build.  If this
 * is preloaded, it interposes on time(2) and returns a constant value when
 * the execname matches one of the desired "programs" and TIME_CONSTANT
 * contains an integer value to be returned.
 */

#include <stdlib.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <strings.h>

/* The list of programs that we want to use a constant time. */
static char *programs[] = { "date", "cpp", "cc1", "perl", NULL };

static int
stack_info(uintptr_t pc, int signo, void *arg)
{
	Dl_info info;
	void *sym;

	if (dladdr1((void *)pc, &info, &sym, RTLD_DL_SYMENT) != NULL) {
		*(char **)arg = (char *)info.dli_fname;
	}

	return (0);
}

static char *
my_execname()
{
	static char *execname;

	if (execname == NULL) {
		ucontext_t ctx;

		if (getcontext(&ctx) == 0)
			walkcontext(&ctx, stack_info, &execname);

		if (execname != NULL) {
			char *s = strrchr(execname, '/');

			if (s != NULL)
				execname = ++s;
		}
	}

	return (execname);
}

static time_t
intercept()
{
	char *execname = my_execname();
	time_t result = -1;

	if (execname != NULL) {
		int i;

		for (i = 0; programs[i] != NULL; i++)
			if (strcmp(execname, programs[i]) == 0) {
				static char *time_constant;

				if (time_constant == NULL)
					time_constant = getenv("TIME_CONSTANT");

				if (time_constant != NULL)
					result = atoll(time_constant);

				break;
			}
	}

	return (result);
}

time_t
time(time_t *ptr)
{
	time_t result = intercept();

	if (result == (time_t)-1) {
		static time_t (*fptr)(time_t *);

		if (fptr == NULL)
			fptr = (time_t (*)(time_t *))dlsym(RTLD_NEXT, "time");

		result = (fptr)(ptr);
	} else if (ptr != NULL)
			*ptr = result;

	return (result);
}