packaging: update homepage url
[platform/upstream/elfutils.git] / libdwfl / argp-std.c
1 /* Standard argp argument parsers for tools using libdwfl.
2    Copyright (C) 2005-2010, 2012, 2015 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 /* Structure held at state->HOOK.  */
94 struct 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
103 static error_t
104 parse_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     {
124     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
134     case OPT_DEBUGINFO:
135       debuginfo_path = arg;
136       break;
137
138     case 'e':
139       {
140         struct parse_opt *opt = state->hook;
141         Dwfl *dwfl = opt->dwfl;
142         if (dwfl == NULL)
143           {
144             dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
145             if (dwfl == NULL)
146               return fail (dwfl, -1, arg);
147             opt->dwfl = dwfl;
148
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           }
153         if (dwfl->callbacks != &offline_callbacks)
154           {
155           toomany:
156             argp_error (state, "%s",
157                         _("only one of -e, -p, -k, -K, or --core allowed"));
158             return EINVAL;
159           }
160         opt->e = arg;
161       }
162       break;
163
164     case 'p':
165       {
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       }
182       break;
183
184     case 'M':
185       {
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       }
207       break;
208
209     case OPT_COREFILE:
210       {
211         struct parse_opt *opt = state->hook;
212         Dwfl *dwfl = opt->dwfl;
213         if (dwfl == NULL)
214           opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks);
215         /* Permit -e and --core together.  */
216         else if (dwfl->callbacks != &offline_callbacks)
217           goto toomany;
218         opt->core = arg;
219       }
220       break;
221
222     case 'k':
223       {
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       }
240       break;
241
242     case 'K':
243       {
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       }
257       break;
258
259     case ARGP_KEY_SUCCESS:
260       {
261         struct parse_opt *opt = state->hook;
262         Dwfl *dwfl = opt->dwfl;
263
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);
271             opt->dwfl = dwfl;
272           }
273
274         if (opt->core)
275           {
276             int fd = open (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             /* Store core Elf and fd in Dwfl to expose with dwfl_end.  */
307             if (dwfl->user_core == NULL)
308               {
309                 dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
310                 if (dwfl->user_core == NULL)
311                   {
312                     argp_failure (state, EXIT_FAILURE, 0,
313                                   _("Not enough memory"));
314                     return ENOMEM;
315                   }
316               }
317             dwfl->user_core->core = core;
318             dwfl->user_core->fd = fd;
319
320             if (result == 0)
321               {
322                 argp_failure (state, EXIT_FAILURE, 0,
323                               _("No modules recognized in core file"));
324                 return ENOENT;
325               }
326           }
327         else if (opt->e)
328           {
329             if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL)
330               return fail (dwfl, -1, opt->e);
331           }
332
333         /* One of the three flavors has done dwfl_begin and some reporting
334            if we got here.  Tie up the Dwfl and return it to the caller of
335            argp_parse.  */
336
337         int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL);
338         assert (result == 0);
339
340         /* Update the input all along, so a parent parser can see it.
341            As we free OPT the update below will be no longer active.  */
342         *(Dwfl **) state->input = dwfl;
343         free (opt);
344         state->hook = NULL;
345       }
346       break;
347
348     case ARGP_KEY_ERROR:
349       {
350         struct parse_opt *opt = state->hook;
351         dwfl_end (opt->dwfl);
352         free (opt);
353         state->hook = NULL;
354       }
355       break;
356
357     default:
358       return ARGP_ERR_UNKNOWN;
359     }
360
361   /* Update the input all along, so a parent parser can see it.  */
362   struct parse_opt *opt = state->hook;
363   if (opt)
364     *(Dwfl **) state->input = opt->dwfl;
365
366   return 0;
367 }
368
369 static const struct argp libdwfl_argp =
370   { .options = options, .parser = parse_opt };
371
372 const struct argp *
373 dwfl_standard_argp (void)
374 {
375   return &libdwfl_argp;
376 }