Branch data Line data Source code
1 : : /* Standard argp argument parsers for tools using libdwfl.
2 : : Copyright (C) 2005-2010, 2012 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #include "libdwflP.h"
30 : : #include <argp.h>
31 : : #include <stdlib.h>
32 : : #include <assert.h>
33 : : #include <libintl.h>
34 : : #include <fcntl.h>
35 : : #include <unistd.h>
36 : :
37 : : /* gettext helper macros. */
38 : : #define _(Str) dgettext ("elfutils", Str)
39 : :
40 : :
41 : : #define OPT_DEBUGINFO 0x100
42 : : #define OPT_COREFILE 0x101
43 : :
44 : : static const struct argp_option options[] =
45 : : {
46 : : { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
47 : : { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
48 : : { "core", OPT_COREFILE, "COREFILE", 0,
49 : : N_("Find addresses from signatures found in COREFILE"), 0 },
50 : : { "pid", 'p', "PID", 0,
51 : : N_("Find addresses in files mapped into process PID"), 0 },
52 : : { "linux-process-map", 'M', "FILE", 0,
53 : : N_("Find addresses in files mapped as read from FILE"
54 : : " in Linux /proc/PID/maps format"), 0 },
55 : : { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
56 : : { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
57 : : N_("Kernel with all modules"), 0 },
58 : : { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
59 : : N_("Search path for separate debuginfo files"), 0 },
60 : : { NULL, 0, NULL, 0, NULL, 0 }
61 : : };
62 : :
63 : : /* Wrapper to provide proper FILE_NAME for -e|--executable. */
64 : : static int
65 : 10 : offline_find_elf (Dwfl_Module *mod, void **userdata, const char *modname,
66 : : Dwarf_Addr base, char **file_name, Elf **elfp)
67 : : {
68 [ + - ][ + - ]: 10 : if (modname != NULL && (strcmp (modname, "[exe]") == 0
69 [ + + ]: 10 : || strcmp (modname, "[pie]") == 0)
70 [ + - ]: 2 : && mod->dwfl->executable_for_core)
71 : : {
72 : : /* When both --core and --executable are given in whatever order
73 : : dwfl_core_file_report is called first and this callback will replace
74 : : the Dwfl_Module main.name with the recorded --executable file when the
75 : : modname is [exe] or [pie] (which then triggers opening and reporting
76 : : of the executable). */
77 : 2 : char *e_dup = strdup (mod->dwfl->executable_for_core);
78 [ + - ]: 2 : if (e_dup)
79 : : {
80 : 2 : free (*file_name);
81 : 2 : *file_name = e_dup;
82 : 2 : return -1;
83 : : }
84 : : }
85 : 10 : return INTUSE(dwfl_build_id_find_elf) (mod, userdata, modname, base,
86 : : file_name, elfp);
87 : : }
88 : :
89 : : static char *debuginfo_path;
90 : :
91 : : static const Dwfl_Callbacks offline_callbacks =
92 : : {
93 : : .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
94 : : .debuginfo_path = &debuginfo_path,
95 : :
96 : : .section_address = INTUSE(dwfl_offline_section_address),
97 : :
98 : : /* We use this table for core files too. */
99 : : .find_elf = offline_find_elf,
100 : : };
101 : :
102 : : static const Dwfl_Callbacks proc_callbacks =
103 : : {
104 : : .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
105 : : .debuginfo_path = &debuginfo_path,
106 : :
107 : : .find_elf = INTUSE(dwfl_linux_proc_find_elf),
108 : : };
109 : :
110 : : static const Dwfl_Callbacks kernel_callbacks =
111 : : {
112 : : .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
113 : : .debuginfo_path = &debuginfo_path,
114 : :
115 : : .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
116 : : .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
117 : : };
118 : :
119 : : /* Structure held at state->HOOK. */
120 : : struct parse_opt
121 : : {
122 : : Dwfl *dwfl;
123 : : /* The -e|--executable parameter. */
124 : : const char *e;
125 : : /* The --core parameter. */
126 : : const char *core;
127 : : };
128 : :
129 : : static error_t
130 : 461 : parse_opt (int key, char *arg, struct argp_state *state)
131 : : {
132 : 0 : inline void failure (Dwfl *dwfl, int errnum, const char *msg)
133 : : {
134 [ # # ]: 0 : if (dwfl != NULL)
135 : 0 : dwfl_end (dwfl);
136 [ # # ]: 0 : if (errnum == -1)
137 : 0 : argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
138 : : msg, INTUSE(dwfl_errmsg) (-1));
139 : : else
140 : 0 : argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
141 : 0 : }
142 : 0 : inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
143 : : {
144 : 0 : failure (dwfl, errnum, msg);
145 [ # # ]: 0 : return errnum == -1 ? EIO : errnum;
146 : : }
147 : :
148 [ + - + + : 461 : switch (key)
+ + - - +
+ + ]
149 : : {
150 : : case ARGP_KEY_INIT:
151 : : {
152 [ - + ]: 81 : assert (state->hook == NULL);
153 : 81 : struct parse_opt *opt = calloc (1, sizeof (*opt));
154 [ - + ]: 81 : if (opt == NULL)
155 : 0 : failure (NULL, DWFL_E_ERRNO, "calloc");
156 : 81 : state->hook = opt;
157 : : }
158 : 81 : break;
159 : :
160 : : case OPT_DEBUGINFO:
161 : 0 : debuginfo_path = arg;
162 : 0 : break;
163 : :
164 : : case 'e':
165 : : {
166 : 59 : struct parse_opt *opt = state->hook;
167 : 59 : Dwfl *dwfl = opt->dwfl;
168 [ + + ]: 59 : if (dwfl == NULL)
169 : : {
170 : 58 : dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
171 [ - + ]: 58 : if (dwfl == NULL)
172 : 0 : return fail (dwfl, -1, arg);
173 : 58 : opt->dwfl = dwfl;
174 : :
175 : : /* Start at zero so if there is just one -e foo.so,
176 : : the DSO is shown without address bias. */
177 : 58 : dwfl->offline_next_address = 0;
178 : : }
179 [ - + ]: 59 : if (dwfl->callbacks != &offline_callbacks)
180 : : {
181 : : toomany:
182 : 0 : argp_error (state, "%s",
183 : : _("only one of -e, -p, -k, -K, or --core allowed"));
184 : 0 : return EINVAL;
185 : : }
186 : 59 : opt->e = arg;
187 : : }
188 : 59 : break;
189 : :
190 : : case 'p':
191 : : {
192 : 4 : struct parse_opt *opt = state->hook;
193 [ - + ]: 4 : if (opt->dwfl == NULL)
194 : : {
195 : 4 : Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
196 : 4 : int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
197 [ - + ]: 4 : if (result != 0)
198 : 0 : return fail (dwfl, result, arg);
199 : 4 : opt->dwfl = dwfl;
200 : : }
201 : : else
202 : : goto toomany;
203 : : }
204 : 4 : break;
205 : :
206 : : case 'M':
207 : : {
208 : 5 : struct parse_opt *opt = state->hook;
209 [ - + ]: 5 : if (opt->dwfl == NULL)
210 : : {
211 : 5 : FILE *f = fopen (arg, "r");
212 [ - + ]: 5 : if (f == NULL)
213 : : {
214 : 0 : int code = errno;
215 : 0 : argp_failure (state, EXIT_FAILURE, code,
216 : : "cannot open '%s'", arg);
217 : 0 : return code;
218 : : }
219 : 5 : Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
220 : 5 : int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
221 : 5 : fclose (f);
222 [ - + ]: 5 : if (result != 0)
223 : 0 : return fail (dwfl, result, arg);
224 : 5 : opt->dwfl = dwfl;
225 : : }
226 : : else
227 : : goto toomany;
228 : : }
229 : 5 : break;
230 : :
231 : : case OPT_COREFILE:
232 : : {
233 : 6 : struct parse_opt *opt = state->hook;
234 : 6 : Dwfl *dwfl = opt->dwfl;
235 [ + + ]: 6 : if (dwfl == NULL)
236 : 5 : opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
237 : : /* Permit -e and --core together. */
238 [ - + ]: 1 : else if (dwfl->callbacks != &offline_callbacks)
239 : : goto toomany;
240 : 6 : opt->core = arg;
241 : : }
242 : 6 : break;
243 : :
244 : : case 'k':
245 : : {
246 : 0 : struct parse_opt *opt = state->hook;
247 [ # # ]: 0 : if (opt->dwfl == NULL)
248 : : {
249 : 0 : Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
250 : 0 : int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
251 [ # # ]: 0 : if (result != 0)
252 : 0 : return fail (dwfl, result, _("cannot load kernel symbols"));
253 : 0 : result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
254 [ # # ]: 0 : if (result != 0)
255 : : /* Non-fatal to have no modules since we do have the kernel. */
256 : 0 : failure (dwfl, result, _("cannot find kernel modules"));
257 : 0 : opt->dwfl = dwfl;
258 : : }
259 : : else
260 : : goto toomany;
261 : : }
262 : 0 : break;
263 : :
264 : : case 'K':
265 : : {
266 : 0 : struct parse_opt *opt = state->hook;
267 [ # # ]: 0 : if (opt->dwfl == NULL)
268 : : {
269 : 0 : Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
270 : 0 : int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
271 : : NULL);
272 [ # # ]: 0 : if (result != 0)
273 : 0 : return fail (dwfl, result, _("cannot find kernel or modules"));
274 : 0 : opt->dwfl = dwfl;
275 : : }
276 : : else
277 : : goto toomany;
278 : : }
279 : 0 : break;
280 : :
281 : : case ARGP_KEY_SUCCESS:
282 : : {
283 : 72 : struct parse_opt *opt = state->hook;
284 : 72 : Dwfl *dwfl = opt->dwfl;
285 : :
286 [ - + ]: 72 : if (dwfl == NULL)
287 : : {
288 : : /* Default if no -e, -p, or -k, is "-e a.out". */
289 : 0 : arg = "a.out";
290 : 0 : dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
291 [ # # ]: 0 : if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
292 : 0 : return fail (dwfl, -1, arg);
293 : 0 : opt->dwfl = dwfl;
294 : : }
295 : :
296 [ + + ]: 72 : if (opt->core)
297 : : {
298 : 6 : int fd = open64 (opt->core, O_RDONLY);
299 [ - + ]: 6 : if (fd < 0)
300 : : {
301 : 0 : int code = errno;
302 : 0 : argp_failure (state, EXIT_FAILURE, code,
303 : : "cannot open '%s'", opt->core);
304 : : return code;
305 : : }
306 : :
307 : : Elf *core;
308 : 6 : Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
309 [ - + ]: 6 : if (error != DWFL_E_NOERROR)
310 : : {
311 : 0 : argp_failure (state, EXIT_FAILURE, 0,
312 : 0 : _("cannot read ELF core file: %s"),
313 : : INTUSE(dwfl_errmsg) (error));
314 [ # # ]: 0 : return error == DWFL_E_ERRNO ? errno : EIO;
315 : : }
316 : :
317 : 6 : int result = INTUSE(dwfl_core_file_report) (dwfl, core);
318 [ - + ]: 6 : if (result < 0)
319 : : {
320 : 0 : elf_end (core);
321 : 0 : close (fd);
322 : 0 : return fail (dwfl, result, opt->core);
323 : : }
324 : :
325 : : /* From now we leak FD and CORE. */
326 : :
327 [ - + ]: 6 : if (result == 0)
328 : : {
329 : 0 : argp_failure (state, EXIT_FAILURE, 0,
330 : 0 : _("No modules recognized in core file"));
331 : : return ENOENT;
332 : : }
333 : :
334 [ + + ]: 6 : if (opt->e)
335 : 6 : dwfl->executable_for_core = strdup (opt->e);
336 : : }
337 [ + + ]: 66 : else if (opt->e)
338 : : {
339 [ - + ]: 57 : if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
340 : 0 : return fail (dwfl, -1, opt->e);
341 : : }
342 : :
343 : : /* One of the three flavors has done dwfl_begin and some reporting
344 : : if we got here. Tie up the Dwfl and return it to the caller of
345 : : argp_parse. */
346 : :
347 : 72 : int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
348 [ - + ]: 72 : assert (result == 0);
349 : :
350 : : /* Update the input all along, so a parent parser can see it.
351 : : As we free OPT the update below will be no longer active. */
352 : 72 : *(Dwfl **) state->input = dwfl;
353 : 72 : free (opt);
354 : 72 : state->hook = NULL;
355 : : }
356 : 72 : break;
357 : :
358 : : case ARGP_KEY_ERROR:
359 : : {
360 : 9 : struct parse_opt *opt = state->hook;
361 : 9 : dwfl_end (opt->dwfl);
362 : 9 : free (opt);
363 : 9 : state->hook = NULL;
364 : : }
365 : 9 : break;
366 : :
367 : : default:
368 : : return ARGP_ERR_UNKNOWN;
369 : : }
370 : :
371 : : /* Update the input all along, so a parent parser can see it. */
372 : 236 : struct parse_opt *opt = state->hook;
373 [ + + ]: 236 : if (opt)
374 : 461 : *(Dwfl **) state->input = opt->dwfl;
375 : :
376 : : return 0;
377 : : }
378 : :
379 : : static const struct argp libdwfl_argp =
380 : : { .options = options, .parser = parse_opt };
381 : :
382 : : const struct argp *
383 : 81 : dwfl_standard_argp (void)
384 : : {
385 : 81 : return &libdwfl_argp;
386 : : }
387 : :
388 : : #ifdef _MUDFLAP
389 : : /* In the absence of a mudflap wrapper for argp_parse, or a libc compiled
390 : : with -fmudflap, we'll see spurious errors for using the struct argp_state
391 : : on argp_parse's stack. */
392 : :
393 : : void __attribute__ ((constructor))
394 : : __libdwfl_argp_mudflap_options (void)
395 : : {
396 : : __mf_set_options ("-heur-stack-bound");
397 : : }
398 : : #endif
|