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