blob: 42b7e78380047ae67560eb77d7ad8ed9b621ae67 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Standard argp argument parsers for tools using libdwfl.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2005-2010, 2012 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004
Elliott Hughes03333822015-02-18 22:19:45 -08005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08007
Elliott Hughes03333822015-02-18 22:19:45 -08008 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080021 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
Elliott Hughes03333822015-02-18 22:19:45 -080025 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080028
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
44static 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
63static char *debuginfo_path;
64
65static const Dwfl_Callbacks offline_callbacks =
66 {
67 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
68 .debuginfo_path = &debuginfo_path,
69
70 .section_address = INTUSE(dwfl_offline_section_address),
71
72 /* We use this table for core files too. */
73 .find_elf = INTUSE(dwfl_build_id_find_elf),
74 };
75
76static const Dwfl_Callbacks proc_callbacks =
77 {
78 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
79 .debuginfo_path = &debuginfo_path,
80
81 .find_elf = INTUSE(dwfl_linux_proc_find_elf),
82 };
83
84static const Dwfl_Callbacks kernel_callbacks =
85 {
86 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
87 .debuginfo_path = &debuginfo_path,
88
89 .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
90 .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
91 };
92
Elliott Hughes03333822015-02-18 22:19:45 -080093/* Structure held at state->HOOK. */
94struct parse_opt
95{
96 Dwfl *dwfl;
97 /* The -e|--executable parameter. */
98 const char *e;
99 /* The --core parameter. */
100 const char *core;
101};
102
Ben Cheng25b3c042013-11-20 14:45:36 -0800103static error_t
104parse_opt (int key, char *arg, struct argp_state *state)
105{
106 inline void failure (Dwfl *dwfl, int errnum, const char *msg)
107 {
108 if (dwfl != NULL)
109 dwfl_end (dwfl);
110 if (errnum == -1)
111 argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
112 msg, INTUSE(dwfl_errmsg) (-1));
113 else
114 argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
115 }
116 inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
117 {
118 failure (dwfl, errnum, msg);
119 return errnum == -1 ? EIO : errnum;
120 }
121
122 switch (key)
123 {
Elliott Hughes03333822015-02-18 22:19:45 -0800124 case ARGP_KEY_INIT:
125 {
126 assert (state->hook == NULL);
127 struct parse_opt *opt = calloc (1, sizeof (*opt));
128 if (opt == NULL)
129 failure (NULL, DWFL_E_ERRNO, "calloc");
130 state->hook = opt;
131 }
132 break;
133
Ben Cheng25b3c042013-11-20 14:45:36 -0800134 case OPT_DEBUGINFO:
135 debuginfo_path = arg;
136 break;
137
138 case 'e':
139 {
Elliott Hughes03333822015-02-18 22:19:45 -0800140 struct parse_opt *opt = state->hook;
141 Dwfl *dwfl = opt->dwfl;
Ben Cheng25b3c042013-11-20 14:45:36 -0800142 if (dwfl == NULL)
143 {
144 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
145 if (dwfl == NULL)
146 return fail (dwfl, -1, arg);
Elliott Hughes03333822015-02-18 22:19:45 -0800147 opt->dwfl = dwfl;
Ben Cheng25b3c042013-11-20 14:45:36 -0800148
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;
152 }
Elliott Hughes03333822015-02-18 22:19:45 -0800153 if (dwfl->callbacks != &offline_callbacks)
Ben Cheng25b3c042013-11-20 14:45:36 -0800154 {
155 toomany:
156 argp_error (state, "%s",
157 _("only one of -e, -p, -k, -K, or --core allowed"));
158 return EINVAL;
159 }
Elliott Hughes03333822015-02-18 22:19:45 -0800160 opt->e = arg;
Ben Cheng25b3c042013-11-20 14:45:36 -0800161 }
162 break;
163
164 case 'p':
Elliott Hughes03333822015-02-18 22:19:45 -0800165 {
166 struct parse_opt *opt = state->hook;
167 if (opt->dwfl == NULL)
168 {
169 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
170 int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
171 if (result != 0)
172 return fail (dwfl, result, arg);
173
174 /* Non-fatal to not be able to attach to process, ignore error. */
175 INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
176
177 opt->dwfl = dwfl;
178 }
179 else
180 goto toomany;
181 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800182 break;
183
184 case 'M':
Elliott Hughes03333822015-02-18 22:19:45 -0800185 {
186 struct parse_opt *opt = state->hook;
187 if (opt->dwfl == NULL)
188 {
189 FILE *f = fopen (arg, "r");
190 if (f == NULL)
191 {
192 int code = errno;
193 argp_failure (state, EXIT_FAILURE, code,
194 "cannot open '%s'", arg);
195 return code;
196 }
197 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
198 int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
199 fclose (f);
200 if (result != 0)
201 return fail (dwfl, result, arg);
202 opt->dwfl = dwfl;
203 }
204 else
205 goto toomany;
206 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800207 break;
208
209 case OPT_COREFILE:
210 {
Elliott Hughes03333822015-02-18 22:19:45 -0800211 struct parse_opt *opt = state->hook;
212 Dwfl *dwfl = opt->dwfl;
Ben Cheng25b3c042013-11-20 14:45:36 -0800213 if (dwfl == NULL)
Elliott Hughes03333822015-02-18 22:19:45 -0800214 opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Ben Cheng25b3c042013-11-20 14:45:36 -0800215 /* Permit -e and --core together. */
216 else if (dwfl->callbacks != &offline_callbacks)
217 goto toomany;
Elliott Hughes03333822015-02-18 22:19:45 -0800218 opt->core = arg;
Ben Cheng25b3c042013-11-20 14:45:36 -0800219 }
220 break;
221
222 case 'k':
Elliott Hughes03333822015-02-18 22:19:45 -0800223 {
224 struct parse_opt *opt = state->hook;
225 if (opt->dwfl == NULL)
226 {
227 Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
228 int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
229 if (result != 0)
230 return fail (dwfl, result, _("cannot load kernel symbols"));
231 result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
232 if (result != 0)
233 /* Non-fatal to have no modules since we do have the kernel. */
234 failure (dwfl, result, _("cannot find kernel modules"));
235 opt->dwfl = dwfl;
236 }
237 else
238 goto toomany;
239 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800240 break;
241
242 case 'K':
Elliott Hughes03333822015-02-18 22:19:45 -0800243 {
244 struct parse_opt *opt = state->hook;
245 if (opt->dwfl == NULL)
246 {
247 Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
248 int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
249 NULL);
250 if (result != 0)
251 return fail (dwfl, result, _("cannot find kernel or modules"));
252 opt->dwfl = dwfl;
253 }
254 else
255 goto toomany;
256 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800257 break;
258
259 case ARGP_KEY_SUCCESS:
260 {
Elliott Hughes03333822015-02-18 22:19:45 -0800261 struct parse_opt *opt = state->hook;
262 Dwfl *dwfl = opt->dwfl;
Ben Cheng25b3c042013-11-20 14:45:36 -0800263
264 if (dwfl == NULL)
265 {
266 /* Default if no -e, -p, or -k, is "-e a.out". */
267 arg = "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);
Elliott Hughes03333822015-02-18 22:19:45 -0800271 opt->dwfl = dwfl;
272 }
273
274 if (opt->core)
275 {
276 int fd = open64 (opt->core, O_RDONLY);
277 if (fd < 0)
278 {
279 int code = errno;
280 argp_failure (state, EXIT_FAILURE, code,
281 "cannot open '%s'", opt->core);
282 return code;
283 }
284
285 Elf *core;
286 Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
287 if (error != DWFL_E_NOERROR)
288 {
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;
293 }
294
295 int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
296 if (result < 0)
297 {
298 elf_end (core);
299 close (fd);
300 return fail (dwfl, result, opt->core);
301 }
302
303 /* Non-fatal to not be able to attach to core, ignore error. */
304 INTUSE(dwfl_core_file_attach) (dwfl, core);
305
306 /* From now we leak FD and CORE. */
307
308 if (result == 0)
309 {
310 argp_failure (state, EXIT_FAILURE, 0,
311 _("No modules recognized in core file"));
312 return ENOENT;
313 }
314 }
315 else if (opt->e)
316 {
317 if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
318 return fail (dwfl, -1, opt->e);
Ben Cheng25b3c042013-11-20 14:45:36 -0800319 }
320
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
323 argp_parse. */
324
325 int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
326 assert (result == 0);
Elliott Hughes03333822015-02-18 22:19:45 -0800327
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;
331 free (opt);
332 state->hook = NULL;
Ben Cheng25b3c042013-11-20 14:45:36 -0800333 }
334 break;
335
336 case ARGP_KEY_ERROR:
Elliott Hughes03333822015-02-18 22:19:45 -0800337 {
338 struct parse_opt *opt = state->hook;
339 dwfl_end (opt->dwfl);
340 free (opt);
341 state->hook = NULL;
342 }
Ben Cheng25b3c042013-11-20 14:45:36 -0800343 break;
344
345 default:
346 return ARGP_ERR_UNKNOWN;
347 }
348
349 /* Update the input all along, so a parent parser can see it. */
Elliott Hughes03333822015-02-18 22:19:45 -0800350 struct parse_opt *opt = state->hook;
351 if (opt)
352 *(Dwfl **) state->input = opt->dwfl;
353
Ben Cheng25b3c042013-11-20 14:45:36 -0800354 return 0;
355}
356
357static const struct argp libdwfl_argp =
358 { .options = options, .parser = parse_opt };
359
360const struct argp *
361dwfl_standard_argp (void)
362{
363 return &libdwfl_argp;
364}