| #include <stdio.h> |
| #include <dlfcn.h> |
| #include <err.h> |
| #include <sys/auxv.h> |
| |
| #ifndef AT_VDSO_FINDSYM |
| # define AT_VDSO_FINDSYM 37 |
| #endif |
| |
| struct vdso_entry { |
| const char *name, *version; |
| bool findsym_should_fail; |
| }; |
| |
| const struct vdso_entry entries[] = { |
| { "__vdso_clock_gettime", "LINUX_2.6" }, |
| { "__vdso_clock_gettime", "LINUX_NEW" }, |
| { "__vdso_clock_gettime", "LINUX_MISSPELLED" }, |
| { "__vdso_time", "LINUX_2.6" }, |
| { "__vdso_getcpu", "LINUX_2.6" }, |
| { "__vdso_gettimeofday", "LINUX_2.6" }, |
| { "clock_gettime", "LINUX_2.6", true }, |
| { "time", "LINUX_2.6", true }, |
| { "getcpu", "LINUX_2.6", true }, |
| { "gettimeofday", "LINUX_2.6", true }, |
| { } |
| }; |
| |
| /* vsyscalls and vDSO */ |
| typedef void *(*findsym_t)(const char *name, const char *version); |
| |
| static void *vdso; |
| static findsym_t findsym; |
| |
| void init_vdso() |
| { |
| vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| if (!vdso) |
| vdso = dlopen("linux-gate.so.1", |
| RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| if (!vdso) |
| errx(1, "Failed to find vDSO\n"); |
| |
| findsym = (findsym_t)dlvsym(vdso, "__vdso_findsym", "LINUX_2.6"); |
| if (!findsym) |
| printf("Warning: failed to find __vdso_findsym in vDSO\n"); |
| |
| if (findsym != (findsym_t)getauxval(AT_VDSO_FINDSYM)) |
| printf("Warning: AT_VDSO_FINDSYM doesn't match __vdso_findsym\n"); |
| } |
| |
| void test(const struct vdso_entry *entry) |
| { |
| void *findsym_result, *dlvsym_result; |
| |
| if (!findsym) |
| return; |
| |
| findsym_result = findsym(entry->name, entry->version); |
| dlvsym_result = dlvsym(vdso, entry->name, entry->version); |
| |
| if (findsym_result != |
| (entry->findsym_should_fail ? NULL : dlvsym_result)) { |
| printf("Finding \"%s\" (ver \"%s\"): findsym says %p but dlvsym says %p\n", |
| entry->name, entry->version, |
| findsym_result, dlvsym_result); |
| } else { |
| printf("OK: \"%s\" (ver \"%s\") -> %p (%p)\n", |
| entry->name, entry->version, |
| dlvsym_result, findsym_result); |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| const struct vdso_entry *e; |
| init_vdso(); |
| |
| for (e = entries; e->name; e++) |
| test(e); |
| |
| return 0; |
| } |