|
1 | 1 | #include <sys/types.h>
|
2 |
| -#include <sys/stat.h> |
3 |
| -#include <fcntl.h> |
4 | 2 | #include <unistd.h>
|
5 | 3 | #include <stdlib.h>
|
6 | 4 | #include <string.h>
|
7 | 5 | #include <stdio.h>
|
8 |
| -#include <errno.h> |
9 | 6 | #include <pthread.h>
|
10 |
| -#include <elf.h> |
11 | 7 | #include <assert.h>
|
| 8 | +#include <signal.h> |
| 9 | +#include <time.h> |
12 | 10 |
|
13 |
| -typedef int (*getpid_pfn)(void); |
14 |
| -struct thread_params { |
15 |
| - long thread_id; |
16 |
| - getpid_pfn getpid; |
17 |
| -}; |
18 |
| - |
19 |
| -#ifdef WITH_DLNS |
20 |
| -static int ended_with(const char* s, const char* pattern) { |
21 |
| - int n = strlen(pattern); |
22 |
| - int m = strlen(s); |
23 |
| - |
24 |
| - if (n > m) return 0; |
25 |
| - |
26 |
| - int j = m - 1; |
27 |
| - int k = n - 1; |
28 |
| - |
29 |
| - while (k >= 0) { |
30 |
| - if(pattern[k--] != s[j--]) { |
31 |
| - return 0; |
32 |
| - } |
33 |
| - } |
34 |
| - return 1; |
35 |
| -} |
36 |
| - |
37 |
| -static unsigned long resolve(int fd, unsigned long dlstart, const char* sym_name) { |
38 |
| - unsigned long off = 0; |
39 |
| - |
40 |
| - Elf64_Ehdr ehdr; |
41 |
| - Elf64_Phdr phdr; |
42 |
| - Elf64_Phdr* dynamic = NULL; |
43 |
| - |
44 |
| - assert(pread(fd, &ehdr, sizeof(ehdr), off) == sizeof(ehdr)); |
45 |
| - |
46 |
| - off += ehdr.e_phoff; |
47 |
| - for (int i = 0; i < ehdr.e_phnum; i++) { |
48 |
| - assert(pread(fd, &phdr, sizeof(phdr), off) == sizeof(phdr)); |
49 |
| - off += sizeof(phdr); |
50 |
| - if (phdr.p_type == PT_DYNAMIC) { |
51 |
| - dynamic = &phdr; |
52 |
| - break; |
53 |
| - } |
54 |
| - } |
55 |
| - |
56 |
| - if (!dynamic) { |
57 |
| - fprintf(stderr, "found no dynamic segment"); |
58 |
| - return -1; |
59 |
| - } |
60 |
| - |
61 |
| - unsigned long dyn[64] = {0,}; |
62 |
| - unsigned long* ptr = (unsigned long*)(dynamic->p_vaddr + dlstart); |
63 |
| - |
64 |
| - while(*ptr) { |
65 |
| - if (ptr[0] < 64) |
66 |
| - dyn[ptr[0]] = ptr[1]; |
67 |
| - ptr += 2; |
68 |
| - } |
69 |
| - |
70 |
| - const char* strtab = (const char*)dyn[DT_STRTAB]; |
71 |
| - if (!strtab) { |
72 |
| - fprintf(stderr, "found no strtab"); |
73 |
| - return -1; |
74 |
| - } |
75 |
| - |
76 |
| - Elf64_Sym* symtab = (Elf64_Sym*)dyn[DT_SYMTAB]; |
77 |
| - if (!symtab) { |
78 |
| - fprintf(stderr, "found no symtab"); |
79 |
| - return -1; |
80 |
| - } |
81 |
| - |
82 |
| - unsigned long symtab_nb = 1 + dynamic->p_memsz / sizeof(void*); |
83 |
| - |
84 |
| - for (int i = 0; i < symtab_nb; i++) { |
85 |
| - const char* name = (const char*)&strtab[symtab[i].st_name]; |
86 |
| - if (!strcmp(name, sym_name)) { |
87 |
| - return symtab[i].st_value + dlstart; |
88 |
| - } |
89 |
| - } |
90 |
| - |
91 |
| - return -1; |
92 |
| -} |
93 |
| - |
94 |
| -unsigned long symbol_resolve(const char* dso, const char* sym) { |
95 |
| - int fd; |
96 |
| - char* buffer; |
97 |
| - |
98 |
| - unsigned long sym_addr = -1; |
99 |
| - |
100 |
| - fd = open("/proc/self/maps", O_RDONLY); |
101 |
| - assert(fd >= 0); |
102 |
| - |
103 |
| - buffer = calloc(1, 8192); |
104 |
| - assert(buffer); |
105 |
| - |
106 |
| - ssize_t n = read(fd, buffer, 8192); |
107 |
| - assert(n > 0); |
108 |
| - |
109 |
| - char* next = buffer; |
110 |
| - char* dso_fullname = NULL; |
111 |
| - int found_dlns_dso = 0; |
112 |
| - unsigned long dlstart, dlend; |
113 |
| - |
114 |
| - while(1) { |
115 |
| - char* curr = strsep(&next, "\n"); |
116 |
| - if (!curr) break; |
117 |
| - |
118 |
| - char* words = curr; |
119 |
| - char* endptr = NULL; |
120 |
| - dlstart = strtoul(curr, &endptr, 16); |
121 |
| - dlend = strtoul(1 + endptr, &words, 16); |
122 |
| - words += 1; |
123 |
| - while(1) { |
124 |
| - while(words && (words[0] == ' ' || words[0] == '\t')) |
125 |
| - ++words; |
126 |
| - char* wp = strsep(&words, " \t"); |
127 |
| - if (!wp) break; |
128 |
| - if (ended_with(wp, dso)) { |
129 |
| - dso_fullname = wp; |
130 |
| - found_dlns_dso = 1; |
131 |
| - goto found; |
132 |
| - } |
133 |
| - } |
134 |
| - } |
135 |
| - |
136 |
| - found: |
137 |
| - close(fd); |
138 |
| - |
139 |
| - if (found_dlns_dso) { |
140 |
| - printf("found %s loaded at %lx-%lx\n", dso_fullname, dlstart, dlend); |
141 |
| - fd = open(dso_fullname, O_RDONLY); |
142 |
| - assert(fd >= 0); |
143 |
| - sym_addr = resolve(fd, dlstart, sym); |
144 |
| - } |
145 |
| - return sym_addr; |
| 11 | +static void handle_sigalrm(int sig) { |
146 | 12 | }
|
147 | 13 |
|
148 |
| -static getpid_pfn resolved_local_getpid = (getpid_pfn)-1; |
149 |
| -static pthread_once_t resolve_getpid_once = PTHREAD_ONCE_INIT; |
150 |
| -static void resolve_local_getpid(void) { |
151 |
| - resolved_local_getpid = (getpid_pfn)symbol_resolve("libdlns.so", "local_getpid"); |
152 |
| -} |
153 |
| -static int local_getpid_real(void) { |
154 |
| - pthread_once(&resolve_getpid_once, resolve_local_getpid); |
155 |
| - if (resolved_local_getpid != (getpid_pfn)-1) { |
156 |
| - return resolved_local_getpid(); |
157 |
| - } |
158 |
| - return 0; |
159 |
| -} |
160 |
| - |
161 |
| -#else |
162 |
| -extern int local_getpid(void); |
163 |
| -static int local_getpid_real(void) { |
164 |
| - return local_getpid(); |
165 |
| -} |
166 |
| -#endif |
167 |
| - |
168 |
| -void* threadfn(void* param) { |
169 |
| - |
170 |
| - struct thread_params* tp = (struct thread_params*)param; |
171 |
| - |
172 |
| - pthread_key_t pkey; |
173 |
| - unsigned long *data = malloc(sizeof(unsigned long)); |
174 |
| - assert(data); |
175 |
| - |
176 |
| - *data = 0x1234; |
177 |
| - |
178 |
| - pthread_key_create(&pkey, free); |
179 |
| - pthread_setspecific(pkey, data); |
180 |
| - |
181 |
| - fprintf(stderr, "#%lu local_getpid addr = %p\n", tp->thread_id, tp->getpid); |
182 |
| - |
183 |
| - if (tp->getpid != (getpid_pfn)-1UL) { |
184 |
| - printf("#%lu local_getpid: %u\n", tp->thread_id, tp->getpid()); |
185 |
| - printf("#%lu local_getpid: %u\n", tp->thread_id, tp->getpid()); |
186 |
| - } |
187 |
| - |
188 |
| - printf("#%lu my own tls: %lx\n", tp->thread_id, *(unsigned long*)pthread_getspecific(pkey)); |
189 |
| - |
190 |
| - return 0; |
| 14 | +void* thread_fn(void* param) { |
| 15 | + signal(SIGALRM, handle_sigalrm); |
| 16 | + printf("pause = %d\n", pause()); |
| 17 | + return NULL; |
191 | 18 | }
|
192 | 19 |
|
193 | 20 | int main(int argc, char* argv[]) {
|
194 |
| - pthread_t threads[4]; |
| 21 | + pthread_t thread; |
| 22 | + |
| 23 | + pthread_create(&thread, NULL, thread_fn, NULL); |
195 | 24 |
|
196 |
| - getpid_pfn getpid = (getpid_pfn)local_getpid_real; |
197 |
| - struct thread_params params[] = { |
198 |
| - {0, getpid}, |
199 |
| - {1, getpid}, |
200 |
| - {2, getpid}, |
201 |
| - {3, getpid}, |
202 |
| - }; |
203 |
| - |
204 |
| - for (int i = 0; i < 4; i++) { |
205 |
| - assert(pthread_create(&threads[i], NULL, threadfn, ¶ms[i]) == 0); |
206 |
| - } |
| 25 | + struct timespec ts = {1, 0}; |
| 26 | + // NB: this could be racy because no guarantee |
| 27 | + // `thread' called pause already |
| 28 | + nanosleep(&ts, NULL); |
| 29 | + pthread_kill(thread, SIGALRM); |
207 | 30 |
|
208 |
| - for (int i = 0; i < 4; i++) { |
209 |
| - pthread_join(threads[i], NULL); |
210 |
| - } |
| 31 | + pthread_join(thread, NULL); |
211 | 32 |
|
212 | 33 | return 0;
|
213 | 34 | }
|
0 commit comments