1 /* Standard argp argument parsers for tools using libdwfl.
2 Copyright (C) 2005-2010, 2012, 2015 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 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include "libdwflP.h"
34 #include <argp.h>
35 #include <stdlib.h>
36 #include <assert.h>
37 #include <libintl.h>
38 #include <fcntl.h>
39 #include <unistd.h>
40
41
42 #define OPT_DEBUGINFO 0x100
43 #define OPT_COREFILE 0x101
44
45 static const struct argp_option options[] =
46 {
47 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
48 { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
49 { "core", OPT_COREFILE, "COREFILE", 0,
50 N_("Find addresses from signatures found in COREFILE"), 0 },
51 { "pid", 'p', "PID", 0,
52 N_("Find addresses in files mapped into process PID"), 0 },
53 { "linux-process-map", 'M', "FILE", 0,
54 N_("Find addresses in files mapped as read from FILE"
55 " in Linux /proc/PID/maps format"), 0 },
56 { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
57 { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
58 N_("Kernel with all modules"), 0 },
59 { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
60 N_("Search path for separate debuginfo files"), 0 },
61 { NULL, 0, NULL, 0, NULL, 0 }
62 };
63
64 static char *debuginfo_path;
65
66 static const Dwfl_Callbacks offline_callbacks =
67 {
68 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
69 .debuginfo_path = &debuginfo_path,
70
71 .section_address = INTUSE(dwfl_offline_section_address),
72
73 /* We use this table for core files too. */
74 .find_elf = INTUSE(dwfl_build_id_find_elf),
75 };
76
77 static const Dwfl_Callbacks proc_callbacks =
78 {
79 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
80 .debuginfo_path = &debuginfo_path,
81
82 .find_elf = INTUSE(dwfl_linux_proc_find_elf),
83 };
84
85 static const Dwfl_Callbacks kernel_callbacks =
86 {
87 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
88 .debuginfo_path = &debuginfo_path,
89
90 .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
91 .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
92 };
93
94 /* Structure held at state->HOOK. */
95 struct parse_opt
96 {
97 Dwfl *dwfl;
98 /* The -e|--executable parameter. */
99 const char *e;
100 /* The --core parameter. */
101 const char *core;
102 };
103
104 static inline void
failure(Dwfl * dwfl,int errnum,const char * msg,struct argp_state * state)105 failure (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
106 {
107 if (dwfl != NULL)
108 dwfl_end (dwfl);
109 if (errnum == -1)
110 argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
111 msg, INTUSE(dwfl_errmsg) (-1));
112 else
113 argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
114 }
115
116 static inline error_t
fail(Dwfl * dwfl,int errnum,const char * msg,struct argp_state * state)117 fail (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state)
118 {
119 failure (dwfl, errnum, msg, state);
120 return errnum == -1 ? EIO : errnum;
121 }
122
123 static error_t
parse_opt(int key,char * arg,struct argp_state * state)124 parse_opt (int key, char *arg, struct argp_state *state)
125 {
126 switch (key)
127 {
128 case ARGP_KEY_INIT:
129 {
130 assert (state->hook == NULL);
131 struct parse_opt *opt = calloc (1, sizeof (*opt));
132 if (opt == NULL)
133 failure (NULL, DWFL_E_ERRNO, "calloc", state);
134 state->hook = opt;
135 }
136 break;
137
138 case OPT_DEBUGINFO:
139 debuginfo_path = arg;
140 break;
141
142 case 'e':
143 {
144 struct parse_opt *opt = state->hook;
145 Dwfl *dwfl = opt->dwfl;
146 if (dwfl == NULL)
147 {
148 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
149 if (dwfl == NULL)
150 return fail (dwfl, -1, arg, state);
151 opt->dwfl = dwfl;
152
153 /* Start at zero so if there is just one -e foo.so,
154 the DSO is shown without address bias. */
155 dwfl->offline_next_address = 0;
156 }
157 if (dwfl->callbacks != &offline_callbacks)
158 {
159 toomany:
160 argp_error (state, "%s",
161 _("only one of -e, -p, -k, -K, or --core allowed"));
162 return EINVAL;
163 }
164 opt->e = arg;
165 }
166 break;
167
168 case 'p':
169 {
170 struct parse_opt *opt = state->hook;
171 if (opt->dwfl == NULL)
172 {
173 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
174 int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
175 if (result != 0)
176 return fail (dwfl, result, arg, state);
177
178 /* Non-fatal to not be able to attach to process, ignore error. */
179 INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
180
181 opt->dwfl = dwfl;
182 }
183 else
184 goto toomany;
185 }
186 break;
187
188 case 'M':
189 {
190 struct parse_opt *opt = state->hook;
191 if (opt->dwfl == NULL)
192 {
193 FILE *f = fopen (arg, "r");
194 if (f == NULL)
195 {
196 int code = errno;
197 argp_failure (state, EXIT_FAILURE, code,
198 "cannot open '%s'", arg);
199 return code;
200 }
201 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
202 int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
203 fclose (f);
204 if (result != 0)
205 return fail (dwfl, result, arg, state);
206 opt->dwfl = dwfl;
207 }
208 else
209 goto toomany;
210 }
211 break;
212
213 case OPT_COREFILE:
214 {
215 struct parse_opt *opt = state->hook;
216 Dwfl *dwfl = opt->dwfl;
217 if (dwfl == NULL)
218 opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
219 /* Permit -e and --core together. */
220 else if (dwfl->callbacks != &offline_callbacks)
221 goto toomany;
222 opt->core = arg;
223 }
224 break;
225
226 case 'k':
227 {
228 struct parse_opt *opt = state->hook;
229 if (opt->dwfl == NULL)
230 {
231 Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
232 int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
233 if (result != 0)
234 return fail (dwfl, result, _("cannot load kernel symbols"), state);
235 result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
236 if (result != 0)
237 /* Non-fatal to have no modules since we do have the kernel. */
238 argp_failure (state, 0, result, _("cannot find kernel modules"));
239 opt->dwfl = dwfl;
240 }
241 else
242 goto toomany;
243 }
244 break;
245
246 case 'K':
247 {
248 struct parse_opt *opt = state->hook;
249 if (opt->dwfl == NULL)
250 {
251 Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
252 int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
253 NULL);
254 if (result != 0)
255 return fail (dwfl, result, _("cannot find kernel or modules"), state);
256 opt->dwfl = dwfl;
257 }
258 else
259 goto toomany;
260 }
261 break;
262
263 case ARGP_KEY_SUCCESS:
264 {
265 struct parse_opt *opt = state->hook;
266 Dwfl *dwfl = opt->dwfl;
267
268 if (dwfl == NULL)
269 {
270 /* Default if no -e, -p, or -k, is "-e a.out". */
271 arg = "a.out";
272 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
273 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
274 return fail (dwfl, -1, arg, state);
275 opt->dwfl = dwfl;
276 }
277
278 if (opt->core)
279 {
280 int fd = open (opt->core, O_RDONLY);
281 if (fd < 0)
282 {
283 int code = errno;
284 argp_failure (state, EXIT_FAILURE, code,
285 "cannot open '%s'", opt->core);
286 return code;
287 }
288
289 Elf *core;
290 Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
291 if (error != DWFL_E_NOERROR)
292 {
293 argp_failure (state, EXIT_FAILURE, 0,
294 _("cannot read ELF core file: %s"),
295 INTUSE(dwfl_errmsg) (error));
296 return error == DWFL_E_ERRNO ? errno : EIO;
297 }
298
299 int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
300 if (result < 0)
301 {
302 elf_end (core);
303 close (fd);
304 return fail (dwfl, result, opt->core, state);
305 }
306
307 /* Non-fatal to not be able to attach to core, ignore error. */
308 INTUSE(dwfl_core_file_attach) (dwfl, core);
309
310 /* Store core Elf and fd in Dwfl to expose with dwfl_end. */
311 if (dwfl->user_core == NULL)
312 {
313 dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
314 if (dwfl->user_core == NULL)
315 {
316 argp_failure (state, EXIT_FAILURE, 0,
317 _("Not enough memory"));
318 return ENOMEM;
319 }
320 }
321 dwfl->user_core->core = core;
322 dwfl->user_core->fd = fd;
323
324 if (result == 0)
325 {
326 argp_failure (state, EXIT_FAILURE, 0,
327 _("No modules recognized in core file"));
328 return ENOENT;
329 }
330 }
331 else if (opt->e)
332 {
333 if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
334 return fail (dwfl, -1, opt->e, state);
335 }
336
337 /* One of the three flavors has done dwfl_begin and some reporting
338 if we got here. Tie up the Dwfl and return it to the caller of
339 argp_parse. */
340
341 int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
342 if (result != 0)
343 return fail (dwfl, -1, arg, state);
344
345 /* Update the input all along, so a parent parser can see it.
346 As we free OPT the update below will be no longer active. */
347 *(Dwfl **) state->input = dwfl;
348 free (opt);
349 state->hook = NULL;
350 }
351 break;
352
353 case ARGP_KEY_ERROR:
354 {
355 struct parse_opt *opt = state->hook;
356 dwfl_end (opt->dwfl);
357 free (opt);
358 state->hook = NULL;
359 }
360 break;
361
362 default:
363 return ARGP_ERR_UNKNOWN;
364 }
365
366 /* Update the input all along, so a parent parser can see it. */
367 struct parse_opt *opt = state->hook;
368 if (opt)
369 *(Dwfl **) state->input = opt->dwfl;
370
371 return 0;
372 }
373
374 static const struct argp libdwfl_argp =
375 { .options = options, .parser = parse_opt };
376
377 const struct argp *
dwfl_standard_argp(void)378 dwfl_standard_argp (void)
379 {
380 return &libdwfl_argp;
381 }
382