1193N/A/*
1193N/A * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
1193N/A *
1193N/A * Permission is hereby granted, free of charge, to any person obtaining a
1193N/A * copy of this software and associated documentation files (the "Software"),
1193N/A * to deal in the Software without restriction, including without limitation
1193N/A * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1193N/A * and/or sell copies of the Software, and to permit persons to whom the
1193N/A * Software is furnished to do so, subject to the following conditions:
1193N/A *
1193N/A * The above copyright notice and this permission notice (including the next
1193N/A * paragraph) shall be included in all copies or substantial portions of the
1193N/A * Software.
1193N/A *
1193N/A * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1193N/A * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1193N/A * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1193N/A * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1193N/A * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
1193N/A * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1193N/A * DEALINGS IN THE SOFTWARE.
1193N/A */
1193N/A
1193N/A/*
1193N/A * This compiles to a module that can be preloaded during a build. If this
1193N/A * is preloaded, it interposes on time(2), gettimeofday(3C), and
1193N/A * clock_gethrtime(3C) and returns a constant number of seconds since epoch
1193N/A * when the execname matches one of the desired "programs" and TIME_CONSTANT
1193N/A * contains an integer value to be returned.
1193N/A */
1193N/A
1193N/A#include <stdlib.h>
1193N/A#include <ucontext.h>
1193N/A#include <dlfcn.h>
1193N/A#include <strings.h>
1193N/A#include <time.h>
1193N/A
1193N/A/* The list of programs that we want to use a constant time. */
1193N/Astatic char *programs[] = { "autogen", "bash", "cpp", "cc1", "date", "doxygen",
1193N/A "erl", "javadoc", "ksh", "ksh93", "ld", "perl", "perl5.8.4", "perl5.10",
1193N/A "ruby", "sh", "uil", NULL };
1193N/A
1193N/Astatic int
1193N/Astack_info(uintptr_t pc, int signo, void *arg)
1193N/A{
1193N/A Dl_info info;
1193N/A void *sym;
1193N/A
1193N/A if (dladdr1((void *)pc, &info, &sym, RTLD_DL_SYMENT) != NULL) {
1193N/A if (strstr(info.dli_fname, ".so") == NULL)
1193N/A *(char **)arg = (char *)info.dli_fname;
1193N/A }
1193N/A
1193N/A return (0);
1193N/A}
1193N/A
1193N/Astatic char *
1193N/Amy_execname()
1193N/A{
1193N/A static char *execname;
1193N/A
1193N/A if (execname == NULL) {
1193N/A ucontext_t ctx;
1193N/A
1193N/A if (getcontext(&ctx) == 0)
1193N/A walkcontext(&ctx, stack_info, &execname);
1193N/A
1193N/A if (execname != NULL) {
1193N/A char *s = strrchr(execname, '/');
1193N/A
1193N/A if (s != NULL)
1193N/A execname = ++s;
1193N/A }
1193N/A }
1193N/A
1193N/A return (execname);
1193N/A}
1193N/A
1193N/Astatic time_t
1193N/Atime_constant()
1193N/A{
1193N/A char *execname = my_execname();
1193N/A time_t result = -1;
1193N/A
1193N/A if (execname != NULL) {
1193N/A int i;
1193N/A
1193N/A for (i = 0; programs[i] != NULL; i++)
1193N/A if (strcmp(execname, programs[i]) == 0) {
1193N/A static char *time_string;
1193N/A
1193N/A if (time_string == NULL)
1193N/A time_string = getenv("TIME_CONSTANT");
1193N/A
1193N/A if (time_string != NULL)
1193N/A result = atoll(time_string);
1193N/A
1193N/A break;
1193N/A }
1193N/A }
1193N/A
1193N/A return (result);
1193N/A}
1193N/A
1193N/Atime_t
1193N/Atime(time_t *ptr)
1193N/A{
1193N/A time_t result = time_constant();
1193N/A
1193N/A if (result == (time_t)-1) {
1193N/A static time_t (*fptr)(time_t *);
1193N/A
1193N/A if (fptr == NULL)
1193N/A fptr = (time_t (*)(time_t *))dlsym(RTLD_NEXT, "time");
1193N/A
1193N/A result = (fptr)(ptr);
1193N/A } else if (ptr != NULL)
1193N/A *ptr = result;
1193N/A
1193N/A return (result);
1193N/A}
1193N/A
1193N/Aint
1193N/Agettimeofday(struct timeval *tp, void *tzp)
1193N/A{
1193N/A static int (*fptr)(struct timeval *, void *);
1193N/A int result = -1;
1193N/A
1193N/A if (fptr == NULL)
1193N/A fptr = (int (*)(struct timeval *, void *))dlsym(RTLD_NEXT,
1193N/A "gettimeofday");
1193N/A
1193N/A if ((result = (fptr)(tp, tzp)) == 0) {
1193N/A time_t curtime = time_constant();
1193N/A
1193N/A if (curtime != (time_t)-1)
1193N/A tp->tv_sec = curtime;
1193N/A }
1193N/A
1193N/A return (result);
1193N/A}
1193N/A
1193N/Aint
1193N/Aclock_gettime(clockid_t clock_id, struct timespec *tp)
1193N/A{
1193N/A static int (*fptr)(clockid_t, struct timespec *);
1193N/A int result = -1;
1193N/A
1193N/A if (fptr == NULL)
1193N/A fptr = (int (*)(clockid_t, struct timespec *))dlsym(RTLD_NEXT,
1193N/A "clock_gettime");
1193N/A
1193N/A if ((result = (fptr)(clock_id, tp)) == 0) {
1193N/A time_t curtime = time_constant();
1193N/A
1193N/A if (curtime != (time_t)-1)
1193N/A tp->tv_sec = curtime;
1193N/A }
1193N/A
1193N/A return (result);
1193N/A}