1 /* Standard argp argument parsers for tools using libdwfl. 2 Copyright (C) 2005, 2007, 2008 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 5 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. 8 9 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, 16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17 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>. */ 49 50 #include "libdwflP.h" 51 #include <argp.h> 52 #include <stdlib.h> 53 #include <assert.h> 54 #include <libintl.h> 55 #include <fcntl.h> 56 #include <unistd.h> 57 58 /* gettext helper macros. */ 59 #define _(Str) dgettext ("elfutils", Str) 60 61 62 #define OPT_DEBUGINFO 0x100 63 #define OPT_COREFILE 0x101 64 65 static const struct argp_option options[] = 66 { 67 { NULL, 0, NULL, 0, N_("Input selection options:"), 0 }, 68 { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, 69 { "core", OPT_COREFILE, "COREFILE", 0, 70 N_("Find addresses from signatures found in COREFILE"), 0 }, 71 { "pid", 'p', "PID", 0, 72 N_("Find addresses in files mapped into process PID"), 0 }, 73 { "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 }, 76 { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 }, 77 { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL, 78 N_("Kernel with all modules"), 0 }, 79 { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0, 80 N_("Search path for separate debuginfo files"), 0 }, 81 { NULL, 0, NULL, 0, NULL, 0 } 82 }; 83 84 static char *debuginfo_path; 85 86 static 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), 92 93 /* We use this table for core files too. */ 94 .find_elf = INTUSE(dwfl_build_id_find_elf), 95 }; 96 97 static 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 105 static 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 114 static error_t 115 parse_opt (int key, char *arg, struct argp_state *state) 116 { 117 inline void failure (Dwfl *dwfl, int errnum, const char *msg) 118 { 119 if (dwfl != NULL) 120 dwfl_end (dwfl); 121 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 } 127 inline error_t fail (Dwfl *dwfl, int errnum, const char *msg) 128 { 129 failure (dwfl, errnum, msg); 130 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': 140 { 141 Dwfl *dwfl = state->hook; 142 if (dwfl == NULL) 143 { 144 dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 145 if (dwfl == NULL) 146 return fail (dwfl, -1, arg); 147 state->hook = 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 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) 156 return fail (dwfl, -1, arg); 157 state->hook = dwfl; 158 } 159 else 160 { 161 toomany: 162 argp_error (state, "%s", 163 _("only one of -e, -p, -k, -K, or --core allowed")); 164 return EINVAL; 165 } 166 } 167 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) 175 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) 187 nofile: 188 { 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); 199 state->hook = dwfl; 200 } 201 else 202 goto toomany; 203 break; 204 205 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 249 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) 255 return fail (dwfl, result, _("cannot load kernel symbols")); 256 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. */ 259 failure (dwfl, result, _("cannot find kernel modules")); 260 state->hook = dwfl; 261 } 262 else 263 goto toomany; 264 break; 265 266 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) 273 return fail (dwfl, result, _("cannot find kernel or modules")); 274 state->hook = dwfl; 275 } 276 else 277 goto toomany; 278 break; 279 280 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"; 288 dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 289 if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) 290 return fail (dwfl, -1, arg); 291 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); 300 } 301 break; 302 303 case ARGP_KEY_ERROR: 304 dwfl_end (state->hook); 305 state->hook = NULL; 306 break; 307 308 default: 309 return ARGP_ERR_UNKNOWN; 310 } 311 312 /* Update the input all along, so a parent parser can see it. */ 313 *(Dwfl **) state->input = state->hook; 314 return 0; 315 } 316 317 static const struct argp libdwfl_argp = 318 { .options = options, .parser = parse_opt }; 319 320 const struct argp * 321 dwfl_standard_argp (void) 322 { 323 return &libdwfl_argp; 324 } 325 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 331 void __attribute__ ((constructor)) 332 __libdwfl_argp_mudflap_options (void) 333 { 334 __mf_set_options ("-heur-stack-bound"); 335 } 336 #endif 337