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.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
37 /* gettext helper macros. */
38 #define _(Str) dgettext ("elfutils", Str)
41 #define OPT_DEBUGINFO 0x100
42 #define OPT_COREFILE 0x101
44 static const struct argp_option options[] =
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 }
63 static char *debuginfo_path;
65 static const Dwfl_Callbacks offline_callbacks =
67 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
68 .debuginfo_path = &debuginfo_path,
70 .section_address = INTUSE(dwfl_offline_section_address),
72 /* We use this table for core files too. */
73 .find_elf = INTUSE(dwfl_build_id_find_elf),
76 static const Dwfl_Callbacks proc_callbacks =
78 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
79 .debuginfo_path = &debuginfo_path,
81 .find_elf = INTUSE(dwfl_linux_proc_find_elf),
84 static const Dwfl_Callbacks kernel_callbacks =
86 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
87 .debuginfo_path = &debuginfo_path,
89 .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
90 .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
93 /* Structure held at state->HOOK. */
97 /* The -e|--executable parameter. */
99 /* The --core parameter. */
104 parse_opt (int key, char *arg, struct argp_state *state)
106 inline void failure (Dwfl *dwfl, int errnum, const char *msg)
111 argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
112 msg, INTUSE(dwfl_errmsg) (-1));
114 argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
116 inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
118 failure (dwfl, errnum, msg);
119 return errnum == -1 ? EIO : errnum;
126 assert (state->hook == NULL);
127 struct parse_opt *opt = calloc (1, sizeof (*opt));
129 failure (NULL, DWFL_E_ERRNO, "calloc");
135 debuginfo_path = arg;
140 struct parse_opt *opt = state->hook;
141 Dwfl *dwfl = opt->dwfl;
144 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
146 return fail (dwfl, -1, arg);
149 /* Start at zero so if there is just one -e foo.so,
150 the DSO is shown without address bias. */
151 dwfl->offline_next_address = 0;
153 if (dwfl->callbacks != &offline_callbacks)
156 argp_error (state, "%s",
157 _("only one of -e, -p, -k, -K, or --core allowed"));
166 struct parse_opt *opt = state->hook;
167 if (opt->dwfl == NULL)
169 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
170 int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
172 return fail (dwfl, result, arg);
174 /* Non-fatal to not be able to attach to process, ignore error. */
175 INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
186 struct parse_opt *opt = state->hook;
187 if (opt->dwfl == NULL)
189 FILE *f = fopen (arg, "r");
193 argp_failure (state, EXIT_FAILURE, code,
194 "cannot open '%s'", arg);
197 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
198 int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
201 return fail (dwfl, result, arg);
211 struct parse_opt *opt = state->hook;
212 Dwfl *dwfl = opt->dwfl;
214 opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
215 /* Permit -e and --core together. */
216 else if (dwfl->callbacks != &offline_callbacks)
224 struct parse_opt *opt = state->hook;
225 if (opt->dwfl == NULL)
227 Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
228 int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
230 return fail (dwfl, result, _("cannot load kernel symbols"));
231 result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
233 /* Non-fatal to have no modules since we do have the kernel. */
234 failure (dwfl, result, _("cannot find kernel modules"));
244 struct parse_opt *opt = state->hook;
245 if (opt->dwfl == NULL)
247 Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
248 int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
251 return fail (dwfl, result, _("cannot find kernel or modules"));
259 case ARGP_KEY_SUCCESS:
261 struct parse_opt *opt = state->hook;
262 Dwfl *dwfl = opt->dwfl;
266 /* Default if no -e, -p, or -k, is "-e a.out". */
268 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
269 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
270 return fail (dwfl, -1, arg);
276 int fd = open64 (opt->core, O_RDONLY);
280 argp_failure (state, EXIT_FAILURE, code,
281 "cannot open '%s'", opt->core);
286 Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
287 if (error != DWFL_E_NOERROR)
289 argp_failure (state, EXIT_FAILURE, 0,
290 _("cannot read ELF core file: %s"),
291 INTUSE(dwfl_errmsg) (error));
292 return error == DWFL_E_ERRNO ? errno : EIO;
295 int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
300 return fail (dwfl, result, opt->core);
303 /* Non-fatal to not be able to attach to core, ignore error. */
304 INTUSE(dwfl_core_file_attach) (dwfl, core);
306 /* From now we leak FD and CORE. */
310 argp_failure (state, EXIT_FAILURE, 0,
311 _("No modules recognized in core file"));
317 if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
318 return fail (dwfl, -1, opt->e);
321 /* One of the three flavors has done dwfl_begin and some reporting
322 if we got here. Tie up the Dwfl and return it to the caller of
325 int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
326 assert (result == 0);
328 /* Update the input all along, so a parent parser can see it.
329 As we free OPT the update below will be no longer active. */
330 *(Dwfl **) state->input = dwfl;
338 struct parse_opt *opt = state->hook;
339 dwfl_end (opt->dwfl);
346 return ARGP_ERR_UNKNOWN;
349 /* Update the input all along, so a parent parser can see it. */
350 struct parse_opt *opt = state->hook;
352 *(Dwfl **) state->input = opt->dwfl;
357 static const struct argp libdwfl_argp =
358 { .options = options, .parser = parse_opt };
361 dwfl_standard_argp (void)
363 return &libdwfl_argp;