blob: 2ef4555ccb04635ac62a7ba498741e2b7c117e06 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Standard argp argument parsers for tools using libdwfl.
Roland McGrath8068e062010-03-10 23:49:13 -08002 Copyright (C) 2005-2010 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
29#include "libdwflP.h"
30#include <argp.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <libintl.h>
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000034#include <fcntl.h>
35#include <unistd.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000036
37/* gettext helper macros. */
38#define _(Str) dgettext ("elfutils", Str)
39
40
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000041#define OPT_DEBUGINFO 0x100
42#define OPT_COREFILE 0x101
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000043
44static const struct argp_option options[] =
45{
Roland McGrath4be15242007-04-25 03:09:33 +000046 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000047 { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000048 { "core", OPT_COREFILE, "COREFILE", 0,
49 N_("Find addresses from signatures found in COREFILE"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000050 { "pid", 'p', "PID", 0,
51 N_("Find addresses in files mapped into process PID"), 0 },
Roland McGrath1656bc02005-12-23 01:49:50 +000052 { "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 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000055 { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
Roland McGrathd17fac72005-08-23 08:20:21 +000056 { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
57 N_("Kernel with all modules"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000058 { "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
Roland McGrathd17fac72005-08-23 08:20:21 +000065static 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),
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000071
72 /* We use this table for core files too. */
73 .find_elf = INTUSE(dwfl_build_id_find_elf),
Roland McGrathd17fac72005-08-23 08:20:21 +000074 };
75
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000076static 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
93static error_t
94parse_opt (int key, char *arg, struct argp_state *state)
95{
Roland McGrath1656bc02005-12-23 01:49:50 +000096 inline void failure (Dwfl *dwfl, int errnum, const char *msg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000097 {
Roland McGrathd11f9cb2008-03-26 20:51:59 +000098 if (dwfl != NULL)
99 dwfl_end (dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000100 if (errnum == -1)
101 argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
102 msg, INTUSE(dwfl_errmsg) (-1));
103 else
104 argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
105 }
Roland McGrath1656bc02005-12-23 01:49:50 +0000106 inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000107 {
Roland McGrath1656bc02005-12-23 01:49:50 +0000108 failure (dwfl, errnum, msg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000109 return errnum == -1 ? EIO : errnum;
110 }
111
112 switch (key)
113 {
114 case OPT_DEBUGINFO:
115 debuginfo_path = arg;
116 break;
117
118 case 'e':
Roland McGrathd17fac72005-08-23 08:20:21 +0000119 {
120 Dwfl *dwfl = state->hook;
121 if (dwfl == NULL)
122 {
123 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
124 if (dwfl == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000125 return fail (dwfl, -1, arg);
Roland McGrathd17fac72005-08-23 08:20:21 +0000126 state->hook = dwfl;
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000127
128 /* Start at zero so if there is just one -e foo.so,
129 the DSO is shown without address bias. */
130 dwfl->offline_next_address = 0;
Roland McGrathd17fac72005-08-23 08:20:21 +0000131 }
132 if (dwfl->callbacks == &offline_callbacks)
133 {
134 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000135 return fail (dwfl, -1, arg);
Roland McGrathd17fac72005-08-23 08:20:21 +0000136 state->hook = dwfl;
137 }
138 else
139 {
140 toomany:
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000141 argp_error (state, "%s",
142 _("only one of -e, -p, -k, -K, or --core allowed"));
Roland McGrathd17fac72005-08-23 08:20:21 +0000143 return EINVAL;
144 }
145 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000146 break;
147
148 case 'p':
149 if (state->hook == NULL)
150 {
151 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
152 int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
153 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000154 return fail (dwfl, result, arg);
155 state->hook = dwfl;
156 }
157 else
158 goto toomany;
159 break;
160
161 case 'M':
162 if (state->hook == NULL)
163 {
164 FILE *f = fopen (arg, "r");
165 if (f == NULL)
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000166 nofile:
Roland McGrath1656bc02005-12-23 01:49:50 +0000167 {
168 int code = errno;
169 argp_failure (state, EXIT_FAILURE, code,
170 "cannot open '%s'", arg);
171 return code;
172 }
173 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
174 int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
175 fclose (f);
176 if (result != 0)
177 return fail (dwfl, result, arg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000178 state->hook = dwfl;
179 }
180 else
181 goto toomany;
182 break;
183
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000184 case OPT_COREFILE:
185 {
186 Dwfl *dwfl = state->hook;
187 if (dwfl == NULL)
188 state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
189 /* Permit -e and --core together. */
190 else if (dwfl->callbacks != &offline_callbacks)
191 goto toomany;
192
193 int fd = open64 (arg, O_RDONLY);
194 if (fd < 0)
195 goto nofile;
196
Roland McGrathbca43152009-01-05 23:59:32 -0800197 Elf *core;
198 Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
199 if (error != DWFL_E_NOERROR)
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000200 {
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000201 argp_failure (state, EXIT_FAILURE, 0,
202 _("cannot read ELF core file: %s"),
Roland McGrathbca43152009-01-05 23:59:32 -0800203 INTUSE(dwfl_errmsg) (error));
204 return error == DWFL_E_ERRNO ? errno : EIO;
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000205 }
206
Roland McGrath8068e062010-03-10 23:49:13 -0800207 int result = INTUSE(dwfl_core_file_report) (dwfl, core);
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000208 if (result < 0)
209 {
210 elf_end (core);
211 close (fd);
212 return fail (dwfl, result, arg);
213 }
214
215 /* From now we leak FD and CORE. */
216
217 if (result == 0)
218 {
219 argp_failure (state, EXIT_FAILURE, 0,
220 _("No modules recognized in core file"));
221 return ENOENT;
222 }
223 }
224 break;
225
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000226 case 'k':
227 if (state->hook == NULL)
228 {
229 Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
230 int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
231 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000232 return fail (dwfl, result, _("cannot load kernel symbols"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000233 result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
234 if (result != 0)
235 /* Non-fatal to have no modules since we do have the kernel. */
Roland McGrath1656bc02005-12-23 01:49:50 +0000236 failure (dwfl, result, _("cannot find kernel modules"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000237 state->hook = dwfl;
238 }
239 else
240 goto toomany;
241 break;
242
Roland McGrathd17fac72005-08-23 08:20:21 +0000243 case 'K':
244 if (state->hook == NULL)
245 {
246 Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
247 int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
248 NULL);
249 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000250 return fail (dwfl, result, _("cannot find kernel or modules"));
Roland McGrathd17fac72005-08-23 08:20:21 +0000251 state->hook = dwfl;
252 }
253 else
254 goto toomany;
255 break;
256
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000257 case ARGP_KEY_SUCCESS:
258 {
259 Dwfl *dwfl = state->hook;
260
261 if (dwfl == NULL)
262 {
263 /* Default if no -e, -p, or -k, is "-e a.out". */
264 arg = "a.out";
Roland McGrathd17fac72005-08-23 08:20:21 +0000265 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
266 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000267 return fail (dwfl, -1, arg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000268 state->hook = dwfl;
269 }
270
271 /* One of the three flavors has done dwfl_begin and some reporting
272 if we got here. Tie up the Dwfl and return it to the caller of
273 argp_parse. */
274
275 int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
276 assert (result == 0);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000277 }
278 break;
279
Roland McGrath4be15242007-04-25 03:09:33 +0000280 case ARGP_KEY_ERROR:
281 dwfl_end (state->hook);
282 state->hook = NULL;
283 break;
284
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000285 default:
286 return ARGP_ERR_UNKNOWN;
287 }
Roland McGrath4be15242007-04-25 03:09:33 +0000288
289 /* Update the input all along, so a parent parser can see it. */
290 *(Dwfl **) state->input = state->hook;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000291 return 0;
292}
293
294static const struct argp libdwfl_argp =
295 { .options = options, .parser = parse_opt };
296
297const struct argp *
298dwfl_standard_argp (void)
299{
300 return &libdwfl_argp;
301}
Roland McGrath80e43a72005-08-24 21:12:15 +0000302
303#ifdef _MUDFLAP
304/* In the absence of a mudflap wrapper for argp_parse, or a libc compiled
305 with -fmudflap, we'll see spurious errors for using the struct argp_state
306 on argp_parse's stack. */
307
308void __attribute__ ((constructor))
309__libdwfl_argp_mudflap_options (void)
310{
311 __mf_set_options ("-heur-stack-bound");
312}
313#endif