FreeBSD regtest: add missing helgrind expecteds
[valgrind.git] / auxprogs / getoff.c
blob7cd9d2414438b03c82a1d31e74decaf5a16e3061
1 /*
2 This file is part of Valgrind, a dynamic binary instrumentation
3 framework.
5 Copyright (C) 2014-2017 Philippe Waroquiers
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 The GNU General Public License is contained in the file COPYING.
23 /* This file is used to generate target executable(s) getoff-<platform>
24 In a bi-arch setup, this is used to build 2 executables
25 (for the primary and secondary platforms).
27 This program uses user space libraries to retrieve some platform
28 dependent offsets needed for Valgrind core, but that cannot (easily)
29 be retrieved by Valgrind core.
31 This is currently used only for handling the gdbsrv QGetTlsAddr query :
32 it only computes and outputs lm_modid_offset in struct link_map
33 of the dynamic linker. In theory, we should also compute the offset needed
34 to get the dtv from the thread register/pointer/...
35 Currently, the various valgrind-low-xxxxxx.c files are hardcoding this
36 offset as it is deemed (?) stable, and there is no clear way how to
37 compute this dtv offset.
39 The getoff-<platform> executable will be launched automatically by
40 Valgrind gdbserver when the first QGetTlsAddr query is retrieved.
42 On plaforms that do not support __thread and/or that do not provide
43 dlinfo RTLD_DI_TLS_MODID, this executable produces no output. */
45 #ifndef _GNU_SOURCE
46 #define _GNU_SOURCE
47 #endif
48 #include <config.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <string.h>
56 #ifdef HAVE_DLINFO_RTLD_DI_TLS_MODID
57 #include <link.h>
58 #include <dlfcn.h>
59 #endif
61 /* true if arg matches the provided option */
62 static
63 int is_opt(char* arg, const char *option)
65 int option_len = strlen(option);
66 if (option[option_len-1] == '=')
67 return (0 == strncmp(option, arg, option_len));
68 else
69 return (0 == strcmp(option, arg));
72 static int verbose = 0;
74 static
75 void usage (char* progname)
77 fprintf(stderr,
78 "Usage: %s [--help] [-h] [-v] [-o <outputfile>]\n"
79 "Outputs various user space offsets\n"
80 "By default, outputs on stdout.\n"
81 "Use -o to output to <outputfile>\n"
82 "-v : be more verbose\n",
83 progname);
87 int main (int argc, char** argv)
89 int i;
90 FILE *outputfile;
91 int nr_errors = 0;
93 outputfile = stdout;
95 i = 1;
96 while (i < argc) {
97 if (is_opt(argv[i], "--help") || is_opt(argv[i], "-h")) {
98 usage(argv[0]);
99 exit(0);
100 } else if (is_opt(argv[i], "-v")) {
101 verbose++;
102 } else if (is_opt(argv[i], "-o")) {
103 if (i+1 == argc) {
104 fprintf(stderr,
105 "missing output file for -o option\n"
106 "Use --help for more information.\n");
107 exit (1);
109 i++;
110 outputfile = fopen(argv[i], "w");
111 if (outputfile == NULL) {
112 fprintf(stderr, "Could not fopen %s in write mode\n", argv[i]);
113 perror ("fopen output file failed");
114 exit (1);
116 } else {
117 fprintf (stderr,
118 "unknown or invalid argument %s\n"
119 "Use --help for more information.\n",
120 argv[i]);
121 exit(1);
123 i++;
126 #ifdef HAVE_DLINFO_RTLD_DI_TLS_MODID
127 /* Compute offset of lm_modid in struct link_map.
128 This is needed to support QGetTlsAddr gdbsrv query.
129 Computation is done using an ugly hack, but less ugly than
130 hardcoding the offset depending on the glibc version and
131 platform.
132 The below works, based the assumption that RTLD_DI_TLS_MODID
133 just access and returns directly the field in the dummy
134 link_map structure we have prepared.
136 If glibc debug info is installed on your system, you can
137 also find this offset by doing in GDB:
138 p &((struct link_map*)0x0)->l_tls_modid
139 (see also coregrind/m_gdbserver/valgrind_low.h target_get_dtv
140 comments).
143 #define MAX_LINKMAP_WORDS 10000
144 size_t dummy_link_map[MAX_LINKMAP_WORDS];
145 size_t off;
146 size_t modid_offset;
147 for (off = 0; off < MAX_LINKMAP_WORDS; off++)
148 dummy_link_map[off] = off;
149 if (dlinfo ((void*)dummy_link_map, RTLD_DI_TLS_MODID,
150 &modid_offset) == 0) {
151 assert(modid_offset >= 0 && modid_offset < MAX_LINKMAP_WORDS);
152 fprintf(outputfile,
153 "lm_modid_offset 0x%zx\n", modid_offset*sizeof(size_t));
154 } else {
155 fprintf(stderr,
156 "Error computing lm_modid_offset.\n"
157 "dlinfo error %s\n", dlerror());
158 nr_errors++;
160 #undef MAX_LINKMAP_WORDS
163 if (outputfile != stdout)
164 if (fclose (outputfile) != 0) {
165 perror ("fclose output file failed\n");
166 nr_errors++;
168 #else
169 if (verbose)
170 fprintf(stderr,
171 "cannot compute lm_modid_offset.\n"
172 "configure did not define HAVE_DLINFO_RTLD_DI_TLS_MODID.\n");
173 #endif
175 if (nr_errors == 0)
176 exit(0);
177 else
178 exit(1);