blob: 8ee915870a148bed17813ce35b1afaf6384c5508 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Standard argp argument parsers for tools using libdwfl.
Mark Wielaard355b4082015-12-01 22:16:00 +01002 Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000028
Ulf Hermann575198c2017-04-20 16:31:02 +020029#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000033#include "libdwflP.h"
34#include <argp.h>
35#include <stdlib.h>
36#include <assert.h>
37#include <libintl.h>
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000038#include <fcntl.h>
39#include <unistd.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000040
41/* gettext helper macros. */
42#define _(Str) dgettext ("elfutils", Str)
43
44
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000045#define OPT_DEBUGINFO 0x100
46#define OPT_COREFILE 0x101
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000047
48static const struct argp_option options[] =
49{
Roland McGrath4be15242007-04-25 03:09:33 +000050 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000051 { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000052 { "core", OPT_COREFILE, "COREFILE", 0,
53 N_("Find addresses from signatures found in COREFILE"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000054 { "pid", 'p', "PID", 0,
55 N_("Find addresses in files mapped into process PID"), 0 },
Roland McGrath1656bc02005-12-23 01:49:50 +000056 { "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 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000059 { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
Roland McGrathd17fac72005-08-23 08:20:21 +000060 { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
61 N_("Kernel with all modules"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000062 { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
63 N_("Search path for separate debuginfo files"), 0 },
64 { NULL, 0, NULL, 0, NULL, 0 }
65};
66
67static char *debuginfo_path;
68
Roland McGrathd17fac72005-08-23 08:20:21 +000069static 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),
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000075
76 /* We use this table for core files too. */
Jan Kratochvilc5309462013-12-18 15:02:19 +010077 .find_elf = INTUSE(dwfl_build_id_find_elf),
Roland McGrathd17fac72005-08-23 08:20:21 +000078 };
79
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000080static 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
88static 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
Jan Kratochvild5784af2012-10-18 00:11:30 +020097/* Structure held at state->HOOK. */
98struct 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
Yunlian Jiang33220d52017-07-26 16:25:43 -0700107static inline void
108failure (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
119static inline error_t
120fail (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
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000126static error_t
127parse_opt (int key, char *arg, struct argp_state *state)
128{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000129 switch (key)
130 {
Jan Kratochvild5784af2012-10-18 00:11:30 +0200131 case ARGP_KEY_INIT:
132 {
133 assert (state->hook == NULL);
134 struct parse_opt *opt = calloc (1, sizeof (*opt));
135 if (opt == NULL)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700136 failure (NULL, DWFL_E_ERRNO, "calloc", state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200137 state->hook = opt;
138 }
139 break;
140
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000141 case OPT_DEBUGINFO:
142 debuginfo_path = arg;
143 break;
144
145 case 'e':
Roland McGrathd17fac72005-08-23 08:20:21 +0000146 {
Jan Kratochvild5784af2012-10-18 00:11:30 +0200147 struct parse_opt *opt = state->hook;
148 Dwfl *dwfl = opt->dwfl;
Roland McGrathd17fac72005-08-23 08:20:21 +0000149 if (dwfl == NULL)
150 {
151 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
152 if (dwfl == NULL)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700153 return fail (dwfl, -1, arg, state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200154 opt->dwfl = dwfl;
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000155
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;
Roland McGrathd17fac72005-08-23 08:20:21 +0000159 }
Jan Kratochvild5784af2012-10-18 00:11:30 +0200160 if (dwfl->callbacks != &offline_callbacks)
Roland McGrathd17fac72005-08-23 08:20:21 +0000161 {
162 toomany:
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000163 argp_error (state, "%s",
164 _("only one of -e, -p, -k, -K, or --core allowed"));
Roland McGrathd17fac72005-08-23 08:20:21 +0000165 return EINVAL;
166 }
Jan Kratochvild5784af2012-10-18 00:11:30 +0200167 opt->e = arg;
Roland McGrathd17fac72005-08-23 08:20:21 +0000168 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000169 break;
170
171 case 'p':
Jan Kratochvild5784af2012-10-18 00:11:30 +0200172 {
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)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700179 return fail (dwfl, result, arg, state);
Mark Wielaard19108012013-12-30 22:00:57 +0100180
Mark Wielaard824f3932014-06-10 15:09:23 +0200181 /* Non-fatal to not be able to attach to process, ignore error. */
182 INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false);
183
Jan Kratochvild5784af2012-10-18 00:11:30 +0200184 opt->dwfl = dwfl;
185 }
186 else
187 goto toomany;
188 }
Roland McGrath1656bc02005-12-23 01:49:50 +0000189 break;
190
191 case 'M':
Jan Kratochvild5784af2012-10-18 00:11:30 +0200192 {
193 struct parse_opt *opt = state->hook;
194 if (opt->dwfl == NULL)
195 {
196 FILE *f = fopen (arg, "r");
197 if (f == NULL)
Jan Kratochvild5784af2012-10-18 00:11:30 +0200198 {
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)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700208 return fail (dwfl, result, arg, state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200209 opt->dwfl = dwfl;
210 }
211 else
212 goto toomany;
213 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214 break;
215
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000216 case OPT_COREFILE:
217 {
Jan Kratochvild5784af2012-10-18 00:11:30 +0200218 struct parse_opt *opt = state->hook;
219 Dwfl *dwfl = opt->dwfl;
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000220 if (dwfl == NULL)
Jan Kratochvild5784af2012-10-18 00:11:30 +0200221 opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000222 /* Permit -e and --core together. */
223 else if (dwfl->callbacks != &offline_callbacks)
224 goto toomany;
Jan Kratochvild5784af2012-10-18 00:11:30 +0200225 opt->core = arg;
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000226 }
227 break;
228
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000229 case 'k':
Jan Kratochvild5784af2012-10-18 00:11:30 +0200230 {
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)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700237 return fail (dwfl, result, _("cannot load kernel symbols"), state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200238 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. */
Mark Wielaard557c0002017-10-16 13:25:33 +0200241 argp_failure (state, 0, result, _("cannot find kernel modules"));
Jan Kratochvild5784af2012-10-18 00:11:30 +0200242 opt->dwfl = dwfl;
243 }
244 else
245 goto toomany;
246 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000247 break;
248
Roland McGrathd17fac72005-08-23 08:20:21 +0000249 case 'K':
Jan Kratochvild5784af2012-10-18 00:11:30 +0200250 {
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)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700258 return fail (dwfl, result, _("cannot find kernel or modules"), state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200259 opt->dwfl = dwfl;
260 }
261 else
262 goto toomany;
263 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000264 break;
265
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000266 case ARGP_KEY_SUCCESS:
267 {
Jan Kratochvild5784af2012-10-18 00:11:30 +0200268 struct parse_opt *opt = state->hook;
269 Dwfl *dwfl = opt->dwfl;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000270
271 if (dwfl == NULL)
272 {
273 /* Default if no -e, -p, or -k, is "-e a.out". */
274 arg = "a.out";
Roland McGrathd17fac72005-08-23 08:20:21 +0000275 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
276 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700277 return fail (dwfl, -1, arg, state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200278 opt->dwfl = dwfl;
279 }
280
281 if (opt->core)
282 {
Josh Stone34254542015-10-09 10:10:37 -0700283 int fd = open (opt->core, O_RDONLY);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200284 if (fd < 0)
Mark Wielaard40025812013-02-10 15:07:33 +0100285 {
286 int code = errno;
287 argp_failure (state, EXIT_FAILURE, code,
288 "cannot open '%s'", opt->core);
289 return code;
290 }
Jan Kratochvild5784af2012-10-18 00:11:30 +0200291
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
Jan Kratochvil3cf491e2013-10-30 10:48:20 +0100302 int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200303 if (result < 0)
304 {
305 elf_end (core);
306 close (fd);
Yunlian Jiang33220d52017-07-26 16:25:43 -0700307 return fail (dwfl, result, opt->core, state);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200308 }
309
Mark Wielaard824f3932014-06-10 15:09:23 +0200310 /* Non-fatal to not be able to attach to core, ignore error. */
311 INTUSE(dwfl_core_file_attach) (dwfl, core);
Mark Wielaard19108012013-12-30 22:00:57 +0100312
Mark Wielaard355b4082015-12-01 22:16:00 +0100313 /* 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;
Jan Kratochvild5784af2012-10-18 00:11:30 +0200326
327 if (result == 0)
328 {
329 argp_failure (state, EXIT_FAILURE, 0,
330 _("No modules recognized in core file"));
331 return ENOENT;
332 }
Jan Kratochvild5784af2012-10-18 00:11:30 +0200333 }
334 else if (opt->e)
335 {
336 if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
Yunlian Jiang33220d52017-07-26 16:25:43 -0700337 return fail (dwfl, -1, opt->e, state);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000338 }
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);
Jan Kratochvild5784af2012-10-18 00:11:30 +0200346
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;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000352 }
353 break;
354
Roland McGrath4be15242007-04-25 03:09:33 +0000355 case ARGP_KEY_ERROR:
Jan Kratochvild5784af2012-10-18 00:11:30 +0200356 {
357 struct parse_opt *opt = state->hook;
358 dwfl_end (opt->dwfl);
359 free (opt);
360 state->hook = NULL;
361 }
Roland McGrath4be15242007-04-25 03:09:33 +0000362 break;
363
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000364 default:
365 return ARGP_ERR_UNKNOWN;
366 }
Roland McGrath4be15242007-04-25 03:09:33 +0000367
368 /* Update the input all along, so a parent parser can see it. */
Jan Kratochvild5784af2012-10-18 00:11:30 +0200369 struct parse_opt *opt = state->hook;
370 if (opt)
371 *(Dwfl **) state->input = opt->dwfl;
372
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000373 return 0;
374}
375
376static const struct argp libdwfl_argp =
377 { .options = options, .parser = parse_opt };
378
379const struct argp *
380dwfl_standard_argp (void)
381{
382 return &libdwfl_argp;
383}