2ef4555ccb04635ac62a7ba498741e2b7c117e06
[platform/upstream/elfutils.git] / libdwfl / argp-std.c
1 /* Standard argp argument parsers for tools using libdwfl.
2    Copyright (C) 2005-2010 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
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
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
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.
24
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/>.  */
28
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
44 static 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
63 static char *debuginfo_path;
64
65 static 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
76 static 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
84 static 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
93 static error_t
94 parse_opt (int key, char *arg, struct argp_state *state)
95 {
96   inline void failure (Dwfl *dwfl, int errnum, const char *msg)
97     {
98       if (dwfl != NULL)
99         dwfl_end (dwfl);
100       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     }
106   inline error_t fail (Dwfl *dwfl, int errnum, const char *msg)
107     {
108       failure (dwfl, errnum, msg);
109       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':
119       {
120         Dwfl *dwfl = state->hook;
121         if (dwfl == NULL)
122           {
123             dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
124             if (dwfl == NULL)
125               return fail (dwfl, -1, arg);
126             state->hook = dwfl;
127
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;
131           }
132         if (dwfl->callbacks == &offline_callbacks)
133           {
134             if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
135               return fail (dwfl, -1, arg);
136             state->hook = dwfl;
137           }
138         else
139           {
140           toomany:
141             argp_error (state, "%s",
142                         _("only one of -e, -p, -k, -K, or --core allowed"));
143             return EINVAL;
144           }
145       }
146       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)
154             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)
166           nofile:
167             {
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);
178           state->hook = dwfl;
179         }
180       else
181         goto toomany;
182       break;
183
184     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
197         Elf *core;
198         Dwfl_Error error = __libdw_open_file (&fd, &core, true, false);
199         if (error != DWFL_E_NOERROR)
200           {
201             argp_failure (state, EXIT_FAILURE, 0,
202                           _("cannot read ELF core file: %s"),
203                           INTUSE(dwfl_errmsg) (error));
204             return error == DWFL_E_ERRNO ? errno : EIO;
205           }
206
207         int result = INTUSE(dwfl_core_file_report) (dwfl, core);
208         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
226     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)
232             return fail (dwfl, result, _("cannot load kernel symbols"));
233           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.  */
236             failure (dwfl, result, _("cannot find kernel modules"));
237           state->hook = dwfl;
238         }
239       else
240         goto toomany;
241       break;
242
243     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)
250             return fail (dwfl, result, _("cannot find kernel or modules"));
251           state->hook = dwfl;
252         }
253       else
254         goto toomany;
255       break;
256
257     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";
265             dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
266             if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL)
267               return fail (dwfl, -1, arg);
268             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);
277       }
278       break;
279
280     case ARGP_KEY_ERROR:
281       dwfl_end (state->hook);
282       state->hook = NULL;
283       break;
284
285     default:
286       return ARGP_ERR_UNKNOWN;
287     }
288
289   /* Update the input all along, so a parent parser can see it.  */
290   *(Dwfl **) state->input = state->hook;
291   return 0;
292 }
293
294 static const struct argp libdwfl_argp =
295   { .options = options, .parser = parse_opt };
296
297 const struct argp *
298 dwfl_standard_argp (void)
299 {
300   return &libdwfl_argp;
301 }
302
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
308 void __attribute__ ((constructor))
309 __libdwfl_argp_mudflap_options (void)
310 {
311   __mf_set_options ("-heur-stack-bound");
312 }
313 #endif