1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <errno.h> |
3 | #include <linux/unistd.h> |
4 | |
5 | #include <sys/ptrace.h> |
6 | #include <sys/syscall.h> |
7 | #include <unistd.h> |
8 | |
9 | #include <sysdep/tls.h> |
10 | |
11 | #ifndef PTRACE_GET_THREAD_AREA |
12 | #define PTRACE_GET_THREAD_AREA 25 |
13 | #endif |
14 | |
15 | #ifndef PTRACE_SET_THREAD_AREA |
16 | #define PTRACE_SET_THREAD_AREA 26 |
17 | #endif |
18 | |
19 | /* Checks whether host supports TLS, and sets *tls_min according to the value |
20 | * valid on the host. |
21 | * i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */ |
22 | void check_host_supports_tls(int *supports_tls, int *tls_min) |
23 | { |
24 | /* Values for x86 and x86_64.*/ |
25 | int val[] = {GDT_ENTRY_TLS_MIN_I386, GDT_ENTRY_TLS_MIN_X86_64}; |
26 | int i; |
27 | |
28 | for (i = 0; i < ARRAY_SIZE(val); i++) { |
29 | user_desc_t info; |
30 | info.entry_number = val[i]; |
31 | |
32 | if (syscall(__NR_get_thread_area, &info) == 0) { |
33 | *tls_min = val[i]; |
34 | *supports_tls = 1; |
35 | return; |
36 | } else { |
37 | if (errno == EINVAL) |
38 | continue; |
39 | else if (errno == ENOSYS) |
40 | *supports_tls = 0; |
41 | return; |
42 | } |
43 | } |
44 | |
45 | *supports_tls = 0; |
46 | } |
47 | |
48 | int os_set_thread_area(user_desc_t *info, int pid) |
49 | { |
50 | int ret; |
51 | |
52 | ret = ptrace(PTRACE_SET_THREAD_AREA, pid, info->entry_number, |
53 | (unsigned long) info); |
54 | if (ret < 0) |
55 | ret = -errno; |
56 | return ret; |
57 | } |
58 | |
59 | int os_get_thread_area(user_desc_t *info, int pid) |
60 | { |
61 | int ret; |
62 | |
63 | ret = ptrace(PTRACE_GET_THREAD_AREA, pid, info->entry_number, |
64 | (unsigned long) info); |
65 | if (ret < 0) |
66 | ret = -errno; |
67 | return ret; |
68 | } |
69 | |