blob: 0a0f7ebf3d72c50412f43caec349e73ec0ce3c4b [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Standard argp argument parsers for tools using libdwfl.
Roland McGrathd11f9cb2008-03-26 20:51:59 +00002 Copyright (C) 2005, 2007, 2008 Red Hat, Inc.
Ulrich Drepper361df7d2006-04-04 21:38:57 +00003 This file is part of Red Hat elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Ulrich Drepper361df7d2006-04-04 21:38:57 +00005 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Ulrich Drepper361df7d2006-04-04 21:38:57 +00009 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
Ulrich Drepper1e9ef502006-04-04 22:29:06 +000016 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
Ulrich Drepper361df7d2006-04-04 21:38:57 +000017
18 In addition, as a special exception, Red Hat, Inc. gives You the
19 additional right to link the code of Red Hat elfutils with code licensed
20 under any Open Source Initiative certified open source license
21 (http://www.opensource.org/licenses/index.php) which requires the
22 distribution of source code with any binary distribution and to
23 distribute linked combinations of the two. Non-GPL Code permitted under
24 this exception must only link to the code of Red Hat elfutils through
25 those well defined interfaces identified in the file named EXCEPTION
26 found in the source code files (the "Approved Interfaces"). The files
27 of Non-GPL Code may instantiate templates or use macros or inline
28 functions from the Approved Interfaces without causing the resulting
29 work to be covered by the GNU General Public License. Only Red Hat,
30 Inc. may make changes or additions to the list of Approved Interfaces.
31 Red Hat's grant of this exception is conditioned upon your not adding
32 any new exceptions. If you wish to add a new Approved Interface or
33 exception, please contact Red Hat. You must obey the GNU General Public
34 License in all respects for all of the Red Hat elfutils code and other
35 code used in conjunction with Red Hat elfutils except the Non-GPL Code
36 covered by this exception. If you modify this file, you may extend this
37 exception to your version of the file, but you are not obligated to do
38 so. If you do not wish to provide this exception without modification,
39 you must delete this exception statement from your version and license
40 this file solely under the GPL without exception.
41
42 Red Hat elfutils is an included package of the Open Invention Network.
43 An included package of the Open Invention Network is a package for which
44 Open Invention Network licensees cross-license their patents. No patent
45 license is granted, either expressly or impliedly, by designation as an
46 included package. Should you wish to participate in the Open Invention
47 Network licensing program, please visit www.openinventionnetwork.com
48 <http://www.openinventionnetwork.com>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000049
50#include "libdwflP.h"
51#include <argp.h>
52#include <stdlib.h>
53#include <assert.h>
54#include <libintl.h>
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000055#include <fcntl.h>
56#include <unistd.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000057
58/* gettext helper macros. */
59#define _(Str) dgettext ("elfutils", Str)
60
61
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000062#define OPT_DEBUGINFO 0x100
63#define OPT_COREFILE 0x101
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000064
65static const struct argp_option options[] =
66{
Roland McGrath4be15242007-04-25 03:09:33 +000067 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000068 { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 },
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000069 { "core", OPT_COREFILE, "COREFILE", 0,
70 N_("Find addresses from signatures found in COREFILE"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000071 { "pid", 'p', "PID", 0,
72 N_("Find addresses in files mapped into process PID"), 0 },
Roland McGrath1656bc02005-12-23 01:49:50 +000073 { "linux-process-map", 'M', "FILE", 0,
74 N_("Find addresses in files mapped as read from FILE"
75 " in Linux /proc/PID/maps format"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000076 { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 },
Roland McGrathd17fac72005-08-23 08:20:21 +000077 { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL,
78 N_("Kernel with all modules"), 0 },
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000079 { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0,
80 N_("Search path for separate debuginfo files"), 0 },
81 { NULL, 0, NULL, 0, NULL, 0 }
82};
83
84static char *debuginfo_path;
85
Roland McGrathd17fac72005-08-23 08:20:21 +000086static const Dwfl_Callbacks offline_callbacks =
87 {
88 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
89 .debuginfo_path = &debuginfo_path,
90
91 .section_address = INTUSE(dwfl_offline_section_address),
Roland McGrathb4d6f0f2008-08-25 22:55:17 +000092
93 /* We use this table for core files too. */
94 .find_elf = INTUSE(dwfl_build_id_find_elf),
Roland McGrathd17fac72005-08-23 08:20:21 +000095 };
96
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000097static const Dwfl_Callbacks proc_callbacks =
98 {
99 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
100 .debuginfo_path = &debuginfo_path,
101
102 .find_elf = INTUSE(dwfl_linux_proc_find_elf),
103 };
104
105static const Dwfl_Callbacks kernel_callbacks =
106 {
107 .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo),
108 .debuginfo_path = &debuginfo_path,
109
110 .find_elf = INTUSE(dwfl_linux_kernel_find_elf),
111 .section_address = INTUSE(dwfl_linux_kernel_module_section_address),
112 };
113
114static error_t
115parse_opt (int key, char *arg, struct argp_state *state)
116{
Roland McGrath1656bc02005-12-23 01:49:50 +0000117 inline void failure (Dwfl *dwfl, int errnum, const char *msg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000118 {
Roland McGrathd11f9cb2008-03-26 20:51:59 +0000119 if (dwfl != NULL)
120 dwfl_end (dwfl);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000121 if (errnum == -1)
122 argp_failure (state, EXIT_FAILURE, 0, "%s: %s",
123 msg, INTUSE(dwfl_errmsg) (-1));
124 else
125 argp_failure (state, EXIT_FAILURE, errnum, "%s", msg);
126 }
Roland McGrath1656bc02005-12-23 01:49:50 +0000127 inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000128 {
Roland McGrath1656bc02005-12-23 01:49:50 +0000129 failure (dwfl, errnum, msg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000130 return errnum == -1 ? EIO : errnum;
131 }
132
133 switch (key)
134 {
135 case OPT_DEBUGINFO:
136 debuginfo_path = arg;
137 break;
138
139 case 'e':
Roland McGrathd17fac72005-08-23 08:20:21 +0000140 {
141 Dwfl *dwfl = state->hook;
142 if (dwfl == NULL)
143 {
144 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
145 if (dwfl == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000146 return fail (dwfl, -1, arg);
Roland McGrathd17fac72005-08-23 08:20:21 +0000147 state->hook = dwfl;
Ulrich Drepperaa915fd2007-02-05 07:25:33 +0000148
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;
Roland McGrathd17fac72005-08-23 08:20:21 +0000152 }
153 if (dwfl->callbacks == &offline_callbacks)
154 {
155 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000156 return fail (dwfl, -1, arg);
Roland McGrathd17fac72005-08-23 08:20:21 +0000157 state->hook = dwfl;
158 }
159 else
160 {
161 toomany:
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000162 argp_error (state, "%s",
163 _("only one of -e, -p, -k, -K, or --core allowed"));
Roland McGrathd17fac72005-08-23 08:20:21 +0000164 return EINVAL;
165 }
166 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000167 break;
168
169 case 'p':
170 if (state->hook == NULL)
171 {
172 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
173 int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg));
174 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000175 return fail (dwfl, result, arg);
176 state->hook = dwfl;
177 }
178 else
179 goto toomany;
180 break;
181
182 case 'M':
183 if (state->hook == NULL)
184 {
185 FILE *f = fopen (arg, "r");
186 if (f == NULL)
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000187 nofile:
Roland McGrath1656bc02005-12-23 01:49:50 +0000188 {
189 int code = errno;
190 argp_failure (state, EXIT_FAILURE, code,
191 "cannot open '%s'", arg);
192 return code;
193 }
194 Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks);
195 int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f);
196 fclose (f);
197 if (result != 0)
198 return fail (dwfl, result, arg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000199 state->hook = dwfl;
200 }
201 else
202 goto toomany;
203 break;
204
Roland McGrathb4d6f0f2008-08-25 22:55:17 +0000205 case OPT_COREFILE:
206 {
207 Dwfl *dwfl = state->hook;
208 if (dwfl == NULL)
209 state->hook = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
210 /* Permit -e and --core together. */
211 else if (dwfl->callbacks != &offline_callbacks)
212 goto toomany;
213
214 int fd = open64 (arg, O_RDONLY);
215 if (fd < 0)
216 goto nofile;
217
218 Elf *core = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
219 if (core == NULL)
220 {
221 close (fd);
222 argp_failure (state, EXIT_FAILURE, 0,
223 _("cannot read ELF core file: %s"),
224 elf_errmsg (-1));
225 return EIO;
226 }
227
228 GElf_Ehdr ehdr;
229 int result = INTUSE(dwfl_core_file_report) (dwfl, core,
230 gelf_getehdr (core, &ehdr));
231 if (result < 0)
232 {
233 elf_end (core);
234 close (fd);
235 return fail (dwfl, result, arg);
236 }
237
238 /* From now we leak FD and CORE. */
239
240 if (result == 0)
241 {
242 argp_failure (state, EXIT_FAILURE, 0,
243 _("No modules recognized in core file"));
244 return ENOENT;
245 }
246 }
247 break;
248
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000249 case 'k':
250 if (state->hook == NULL)
251 {
252 Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks);
253 int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl);
254 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000255 return fail (dwfl, result, _("cannot load kernel symbols"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000256 result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl);
257 if (result != 0)
258 /* Non-fatal to have no modules since we do have the kernel. */
Roland McGrath1656bc02005-12-23 01:49:50 +0000259 failure (dwfl, result, _("cannot find kernel modules"));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000260 state->hook = dwfl;
261 }
262 else
263 goto toomany;
264 break;
265
Roland McGrathd17fac72005-08-23 08:20:21 +0000266 case 'K':
267 if (state->hook == NULL)
268 {
269 Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
270 int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg,
271 NULL);
272 if (result != 0)
Roland McGrath1656bc02005-12-23 01:49:50 +0000273 return fail (dwfl, result, _("cannot find kernel or modules"));
Roland McGrathd17fac72005-08-23 08:20:21 +0000274 state->hook = dwfl;
275 }
276 else
277 goto toomany;
278 break;
279
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000280 case ARGP_KEY_SUCCESS:
281 {
282 Dwfl *dwfl = state->hook;
283
284 if (dwfl == NULL)
285 {
286 /* Default if no -e, -p, or -k, is "-e a.out". */
287 arg = "a.out";
Roland McGrathd17fac72005-08-23 08:20:21 +0000288 dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
289 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
Roland McGrath1656bc02005-12-23 01:49:50 +0000290 return fail (dwfl, -1, arg);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000291 state->hook = dwfl;
292 }
293
294 /* One of the three flavors has done dwfl_begin and some reporting
295 if we got here. Tie up the Dwfl and return it to the caller of
296 argp_parse. */
297
298 int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
299 assert (result == 0);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000300 }
301 break;
302
Roland McGrath4be15242007-04-25 03:09:33 +0000303 case ARGP_KEY_ERROR:
304 dwfl_end (state->hook);
305 state->hook = NULL;
306 break;
307
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000308 default:
309 return ARGP_ERR_UNKNOWN;
310 }
Roland McGrath4be15242007-04-25 03:09:33 +0000311
312 /* Update the input all along, so a parent parser can see it. */
313 *(Dwfl **) state->input = state->hook;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000314 return 0;
315}
316
317static const struct argp libdwfl_argp =
318 { .options = options, .parser = parse_opt };
319
320const struct argp *
321dwfl_standard_argp (void)
322{
323 return &libdwfl_argp;
324}
Roland McGrath80e43a72005-08-24 21:12:15 +0000325
326#ifdef _MUDFLAP
327/* In the absence of a mudflap wrapper for argp_parse, or a libc compiled
328 with -fmudflap, we'll see spurious errors for using the struct argp_state
329 on argp_parse's stack. */
330
331void __attribute__ ((constructor))
332__libdwfl_argp_mudflap_options (void)
333{
334 __mf_set_options ("-heur-stack-bound");
335}
336#endif