Andreas Wacknitz
2024-04-04 8590298b09ebad29af56370cd23105cd0931b389
commit | author | age
80b1b4 1 /*
NJ 2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  *
21  * Copyright (c) 2010, Oracle and/or it's affiliates.  All rights reserved.
22  */
23
24 /*
25  * This compiles to a module that can be preloaded during a build.  If this
61c373 26  * is preloaded, it interposes on time(2), gettimeofday(3C), and
NJ 27  * clock_gethrtime(3C) and returns a constant number of seconds since epoch
28  * when the execname matches one of the desired "programs" and TIME_CONSTANT
80b1b4 29  * contains an integer value to be returned.
NJ 30  */
31
32 #include <stdlib.h>
33 #include <ucontext.h>
34 #include <dlfcn.h>
35 #include <strings.h>
61c373 36 #include <time.h>
80b1b4 37
NJ 38 /* The list of programs that we want to use a constant time. */
acd5ac 39 static char *programs[] = { 
RB 40     "autogen", "bash", "cpp", "cc1", "date", "doxygen",
41     "erl", "grops", "gs", "gtroff", "javadoc", "ksh", "ksh93", "ld",
42     "perl", "perl5.8.4", "perl5.10", "ruby", "sh", NULL
43 };
80b1b4 44
NJ 45 static int
46 stack_info(uintptr_t pc, int signo, void *arg)
47 {
48     Dl_info info;
49     void *sym;
50
d03bb1 51     if (dladdr1((void *)pc, &info, &sym, RTLD_DL_SYMENT) != 0) {
61c373 52         if (strstr(info.dli_fname, ".so") == NULL)
NJ 53             *(char **)arg = (char *)info.dli_fname;
80b1b4 54     }
NJ 55
56     return (0);
57 }
58
59 static char *
60 my_execname()
61 {
62     static char *execname;
63
64     if (execname == NULL) {
65         ucontext_t ctx;
66
67         if (getcontext(&ctx) == 0)
68             walkcontext(&ctx, stack_info, &execname);
69
70         if (execname != NULL) {
71             char *s = strrchr(execname, '/');
72
73             if (s != NULL)
74                 execname = ++s;
75         }
76     }
77
78     return (execname);
79 }
80
81 static time_t
61c373 82 time_constant()
80b1b4 83 {
NJ 84     char *execname = my_execname();
85     time_t result = -1;
86
87     if (execname != NULL) {
88         int i;
89
90         for (i = 0; programs[i] != NULL; i++)
91             if (strcmp(execname, programs[i]) == 0) {
61c373 92                 static char *time_string;
80b1b4 93
61c373 94                 if (time_string == NULL)
NJ 95                     time_string = getenv("TIME_CONSTANT");
80b1b4 96
61c373 97                 if (time_string != NULL)
NJ 98                     result = atoll(time_string);
80b1b4 99
NJ 100                 break;
101             }
102     }
103
104     return (result);
105 }
106
107 time_t
108 time(time_t *ptr)
109 {
61c373 110     time_t result = time_constant();
80b1b4 111
NJ 112     if (result == (time_t)-1) {
113         static time_t (*fptr)(time_t *);
114
115         if (fptr == NULL)
116             fptr = (time_t (*)(time_t *))dlsym(RTLD_NEXT, "time");
117
118         result = (fptr)(ptr);
119     } else if (ptr != NULL)
120             *ptr = result;
121
122     return (result);
123 }
61c373 124
NJ 125 int
126 gettimeofday(struct timeval *tp, void *tzp)
127 {
128     static int (*fptr)(struct timeval *, void *);
129     int result = -1;
130
131     if (fptr == NULL)
132         fptr = (int (*)(struct timeval *, void *))dlsym(RTLD_NEXT,
133                 "gettimeofday");
134
135     if ((result = (fptr)(tp, tzp)) == 0) {
136         time_t curtime = time_constant();
137
138         if (curtime != (time_t)-1)
139             tp->tv_sec = curtime;
140     }
141
142     return (result);
143 }
144
145 int
146 clock_gettime(clockid_t clock_id, struct timespec *tp)
147 {
148     static int (*fptr)(clockid_t, struct timespec *);
149     int result = -1;
150
151     if (fptr == NULL)
152         fptr = (int (*)(clockid_t, struct timespec *))dlsym(RTLD_NEXT,
153                 "clock_gettime");
154
155     if ((result = (fptr)(clock_id, tp)) == 0) {
156         time_t curtime = time_constant();
157
158         if (curtime != (time_t)-1)
159             tp->tv_sec = curtime;
160     }
161
162     return (result);
163 }