|
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