|
1 | 1 | // SPDX-License-Identifier: GPL-2.0-only
|
2 | 2 | /*
|
3 |
| - * vdso_test.c: Sample code to test parse_vdso.c on x86 |
4 |
| - * Copyright (c) 2011-2014 Andy Lutomirski |
| 3 | + * vdso_test_gettimeofday.c: Sample code to test parse_vdso.c and |
| 4 | + * vDSO gettimeofday() |
| 5 | + * Copyright (c) 2014 Andy Lutomirski |
5 | 6 | *
|
6 |
| - * You can amuse yourself by compiling with: |
7 |
| - * gcc -std=gnu99 -nostdlib |
8 |
| - * -Os -fno-asynchronous-unwind-tables -flto -lgcc_s |
9 |
| - * vdso_standalone_test_x86.c parse_vdso.c |
10 |
| - * to generate a small binary. On x86_64, you can omit -lgcc_s |
11 |
| - * if you want the binary to be completely standalone. |
| 7 | + * Compile with: |
| 8 | + * gcc -std=gnu99 vdso_test_gettimeofday.c parse_vdso_gettimeofday.c |
| 9 | + * |
| 10 | + * Tested on x86, 32-bit and 64-bit. It may work on other architectures, too. |
12 | 11 | */
|
13 | 12 |
|
14 |
| -#include <sys/syscall.h> |
| 13 | +#include <stdio.h> |
| 14 | +#ifndef NOLIBC |
| 15 | +#include <sys/auxv.h> |
15 | 16 | #include <sys/time.h>
|
16 |
| -#include <unistd.h> |
17 |
| -#include <stdint.h> |
18 |
| -#include <linux/auxvec.h> |
19 |
| - |
20 |
| -#include "parse_vdso.h" |
21 |
| - |
22 |
| -/* We need some libc functions... */ |
23 |
| -int strcmp(const char *a, const char *b) |
24 |
| -{ |
25 |
| - /* This implementation is buggy: it never returns -1. */ |
26 |
| - while (*a || *b) { |
27 |
| - if (*a != *b) |
28 |
| - return 1; |
29 |
| - if (*a == 0 || *b == 0) |
30 |
| - return 1; |
31 |
| - a++; |
32 |
| - b++; |
33 |
| - } |
34 |
| - |
35 |
| - return 0; |
36 |
| -} |
37 |
| - |
38 |
| -/* |
39 |
| - * The clang build needs this, although gcc does not. |
40 |
| - * Stolen from lib/string.c. |
41 |
| - */ |
42 |
| -void *memcpy(void *dest, const void *src, size_t count) |
43 |
| -{ |
44 |
| - char *tmp = dest; |
45 |
| - const char *s = src; |
46 |
| - |
47 |
| - while (count--) |
48 |
| - *tmp++ = *s++; |
49 |
| - return dest; |
50 |
| -} |
51 |
| - |
52 |
| -/* ...and two syscalls. This is x86-specific. */ |
53 |
| -static inline long x86_syscall3(long nr, long a0, long a1, long a2) |
54 |
| -{ |
55 |
| - long ret; |
56 |
| -#ifdef __x86_64__ |
57 |
| - asm volatile ("syscall" : "=a" (ret) : "a" (nr), |
58 |
| - "D" (a0), "S" (a1), "d" (a2) : |
59 |
| - "cc", "memory", "rcx", |
60 |
| - "r8", "r9", "r10", "r11" ); |
61 |
| -#else |
62 |
| - asm volatile ("int $0x80" : "=a" (ret) : "a" (nr), |
63 |
| - "b" (a0), "c" (a1), "d" (a2) : |
64 |
| - "cc", "memory" ); |
65 | 17 | #endif
|
66 |
| - return ret; |
67 |
| -} |
68 |
| - |
69 |
| -static inline long linux_write(int fd, const void *data, size_t len) |
70 |
| -{ |
71 |
| - return x86_syscall3(__NR_write, fd, (long)data, (long)len); |
72 |
| -} |
73 | 18 |
|
74 |
| -static inline void linux_exit(int code) |
75 |
| -{ |
76 |
| - x86_syscall3(__NR_exit, code, 0, 0); |
77 |
| -} |
78 |
| - |
79 |
| -void to_base10(char *lastdig, time_t n) |
80 |
| -{ |
81 |
| - while (n) { |
82 |
| - *lastdig = (n % 10) + '0'; |
83 |
| - n /= 10; |
84 |
| - lastdig--; |
85 |
| - } |
86 |
| -} |
| 19 | +#include "../kselftest.h" |
| 20 | +#include "parse_vdso.h" |
| 21 | +#include "vdso_config.h" |
| 22 | +#include "vdso_call.h" |
87 | 23 |
|
88 |
| -unsigned long getauxval(const unsigned long *auxv, unsigned long type) |
| 24 | +int main(int argc, char **argv) |
89 | 25 | {
|
90 |
| - unsigned long ret; |
91 |
| - |
92 |
| - if (!auxv) |
93 |
| - return 0; |
94 |
| - |
95 |
| - while (1) { |
96 |
| - if (!auxv[0] && !auxv[1]) { |
97 |
| - ret = 0; |
98 |
| - break; |
99 |
| - } |
| 26 | + const char *version = versions[VDSO_VERSION]; |
| 27 | + const char **name = (const char **)&names[VDSO_NAMES]; |
100 | 28 |
|
101 |
| - if (auxv[0] == type) { |
102 |
| - ret = auxv[1]; |
103 |
| - break; |
104 |
| - } |
105 |
| - |
106 |
| - auxv += 2; |
| 29 | + unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR); |
| 30 | + if (!sysinfo_ehdr) { |
| 31 | + printf("AT_SYSINFO_EHDR is not present!\n"); |
| 32 | + return KSFT_SKIP; |
107 | 33 | }
|
108 | 34 |
|
109 |
| - return ret; |
110 |
| -} |
111 |
| - |
112 |
| -void c_main(void **stack) |
113 |
| -{ |
114 |
| - /* Parse the stack */ |
115 |
| - long argc = (long)*stack; |
116 |
| - stack += argc + 2; |
117 |
| - |
118 |
| - /* Now we're pointing at the environment. Skip it. */ |
119 |
| - while(*stack) |
120 |
| - stack++; |
121 |
| - stack++; |
122 |
| - |
123 |
| - /* Now we're pointing at auxv. Initialize the vDSO parser. */ |
124 |
| - vdso_init_from_sysinfo_ehdr(getauxval((unsigned long *)stack, AT_SYSINFO_EHDR)); |
| 35 | + vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR)); |
125 | 36 |
|
126 | 37 | /* Find gettimeofday. */
|
127 | 38 | typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
|
128 |
| - gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday"); |
| 39 | + gtod_t gtod = (gtod_t)vdso_sym(version, name[0]); |
129 | 40 |
|
130 |
| - if (!gtod) |
131 |
| - linux_exit(1); |
| 41 | + if (!gtod) { |
| 42 | + printf("Could not find %s\n", name[0]); |
| 43 | + return KSFT_SKIP; |
| 44 | + } |
132 | 45 |
|
133 | 46 | struct timeval tv;
|
134 |
| - long ret = gtod(&tv, 0); |
| 47 | + long ret = VDSO_CALL(gtod, 2, &tv, 0); |
135 | 48 |
|
136 | 49 | if (ret == 0) {
|
137 |
| - char buf[] = "The time is .000000\n"; |
138 |
| - to_base10(buf + 31, tv.tv_sec); |
139 |
| - to_base10(buf + 38, tv.tv_usec); |
140 |
| - linux_write(1, buf, sizeof(buf) - 1); |
| 50 | + printf("The time is %lld.%06lld\n", |
| 51 | + (long long)tv.tv_sec, (long long)tv.tv_usec); |
141 | 52 | } else {
|
142 |
| - linux_exit(ret); |
| 53 | + printf("%s failed\n", name[0]); |
| 54 | + return KSFT_FAIL; |
143 | 55 | }
|
144 | 56 |
|
145 |
| - linux_exit(0); |
| 57 | + return 0; |
146 | 58 | }
|
147 |
| - |
148 |
| -/* |
149 |
| - * This is the real entry point. It passes the initial stack into |
150 |
| - * the C entry point. |
151 |
| - */ |
152 |
| -asm ( |
153 |
| - ".text\n" |
154 |
| - ".global _start\n" |
155 |
| - ".type _start,@function\n" |
156 |
| - "_start:\n\t" |
157 |
| -#ifdef __x86_64__ |
158 |
| - "mov %rsp,%rdi\n\t" |
159 |
| - "and $-16,%rsp\n\t" |
160 |
| - "sub $8,%rsp\n\t" |
161 |
| - "jmp c_main" |
162 |
| -#else |
163 |
| - "push %esp\n\t" |
164 |
| - "call c_main\n\t" |
165 |
| - "int $3" |
166 |
| -#endif |
167 |
| - ); |
0 commit comments