1da0c48c4Sopenharmony_ci/* Standard argp argument parsers for tools using libdwfl. 2da0c48c4Sopenharmony_ci Copyright (C) 2005-2010, 2012, 2015 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include "libdwflP.h" 34da0c48c4Sopenharmony_ci#include <argp.h> 35da0c48c4Sopenharmony_ci#include <stdlib.h> 36da0c48c4Sopenharmony_ci#include <assert.h> 37da0c48c4Sopenharmony_ci#include <fcntl.h> 38da0c48c4Sopenharmony_ci 39da0c48c4Sopenharmony_ci 40da0c48c4Sopenharmony_ci#define OPT_DEBUGINFO 0x100 41da0c48c4Sopenharmony_ci#define OPT_COREFILE 0x101 42da0c48c4Sopenharmony_ci 43da0c48c4Sopenharmony_cistatic const struct argp_option options[] = 44da0c48c4Sopenharmony_ci{ 45da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, N_("Input selection options:"), 0 }, 46da0c48c4Sopenharmony_ci { "executable", 'e', "FILE", 0, N_("Find addresses in FILE"), 0 }, 47da0c48c4Sopenharmony_ci { "core", OPT_COREFILE, "COREFILE", 0, 48da0c48c4Sopenharmony_ci N_("Find addresses from signatures found in COREFILE"), 0 }, 49da0c48c4Sopenharmony_ci { "pid", 'p', "PID", 0, 50da0c48c4Sopenharmony_ci N_("Find addresses in files mapped into process PID"), 0 }, 51da0c48c4Sopenharmony_ci { "linux-process-map", 'M', "FILE", 0, 52da0c48c4Sopenharmony_ci N_("Find addresses in files mapped as read from FILE" 53da0c48c4Sopenharmony_ci " in Linux /proc/PID/maps format"), 0 }, 54da0c48c4Sopenharmony_ci { "kernel", 'k', NULL, 0, N_("Find addresses in the running kernel"), 0 }, 55da0c48c4Sopenharmony_ci { "offline-kernel", 'K', "RELEASE", OPTION_ARG_OPTIONAL, 56da0c48c4Sopenharmony_ci N_("Kernel with all modules"), 0 }, 57da0c48c4Sopenharmony_ci { "debuginfo-path", OPT_DEBUGINFO, "PATH", 0, 58da0c48c4Sopenharmony_ci N_("Search path for separate debuginfo files"), 0 }, 59da0c48c4Sopenharmony_ci { NULL, 0, NULL, 0, NULL, 0 } 60da0c48c4Sopenharmony_ci}; 61da0c48c4Sopenharmony_ci 62da0c48c4Sopenharmony_cistatic char *debuginfo_path; 63da0c48c4Sopenharmony_ci 64da0c48c4Sopenharmony_cistatic const Dwfl_Callbacks offline_callbacks = 65da0c48c4Sopenharmony_ci { 66da0c48c4Sopenharmony_ci .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), 67da0c48c4Sopenharmony_ci .debuginfo_path = &debuginfo_path, 68da0c48c4Sopenharmony_ci 69da0c48c4Sopenharmony_ci .section_address = INTUSE(dwfl_offline_section_address), 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_ci /* We use this table for core files too. */ 72da0c48c4Sopenharmony_ci .find_elf = INTUSE(dwfl_build_id_find_elf), 73da0c48c4Sopenharmony_ci }; 74da0c48c4Sopenharmony_ci 75da0c48c4Sopenharmony_cistatic const Dwfl_Callbacks proc_callbacks = 76da0c48c4Sopenharmony_ci { 77da0c48c4Sopenharmony_ci .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), 78da0c48c4Sopenharmony_ci .debuginfo_path = &debuginfo_path, 79da0c48c4Sopenharmony_ci 80da0c48c4Sopenharmony_ci .find_elf = INTUSE(dwfl_linux_proc_find_elf), 81da0c48c4Sopenharmony_ci }; 82da0c48c4Sopenharmony_ci 83da0c48c4Sopenharmony_cistatic const Dwfl_Callbacks kernel_callbacks = 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci .find_debuginfo = INTUSE(dwfl_standard_find_debuginfo), 86da0c48c4Sopenharmony_ci .debuginfo_path = &debuginfo_path, 87da0c48c4Sopenharmony_ci 88da0c48c4Sopenharmony_ci .find_elf = INTUSE(dwfl_linux_kernel_find_elf), 89da0c48c4Sopenharmony_ci .section_address = INTUSE(dwfl_linux_kernel_module_section_address), 90da0c48c4Sopenharmony_ci }; 91da0c48c4Sopenharmony_ci 92da0c48c4Sopenharmony_ci/* Structure held at state->HOOK. */ 93da0c48c4Sopenharmony_cistruct parse_opt 94da0c48c4Sopenharmony_ci{ 95da0c48c4Sopenharmony_ci Dwfl *dwfl; 96da0c48c4Sopenharmony_ci /* The -e|--executable parameter. */ 97da0c48c4Sopenharmony_ci const char *e; 98da0c48c4Sopenharmony_ci /* The --core parameter. */ 99da0c48c4Sopenharmony_ci const char *core; 100da0c48c4Sopenharmony_ci}; 101da0c48c4Sopenharmony_ci 102da0c48c4Sopenharmony_cistatic inline void 103da0c48c4Sopenharmony_cifailure (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state) 104da0c48c4Sopenharmony_ci{ 105da0c48c4Sopenharmony_ci if (dwfl != NULL) 106da0c48c4Sopenharmony_ci dwfl_end (dwfl); 107da0c48c4Sopenharmony_ci if (errnum == -1) 108da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, 0, "%s: %s", 109da0c48c4Sopenharmony_ci msg, INTUSE(dwfl_errmsg) (-1)); 110da0c48c4Sopenharmony_ci else 111da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, errnum, "%s", msg); 112da0c48c4Sopenharmony_ci} 113da0c48c4Sopenharmony_ci 114da0c48c4Sopenharmony_cistatic inline error_t 115da0c48c4Sopenharmony_cifail (Dwfl *dwfl, int errnum, const char *msg, struct argp_state *state) 116da0c48c4Sopenharmony_ci{ 117da0c48c4Sopenharmony_ci failure (dwfl, errnum, msg, state); 118da0c48c4Sopenharmony_ci return errnum == -1 ? EIO : errnum; 119da0c48c4Sopenharmony_ci} 120da0c48c4Sopenharmony_ci 121da0c48c4Sopenharmony_cistatic error_t 122da0c48c4Sopenharmony_ciparse_opt (int key, char *arg, struct argp_state *state) 123da0c48c4Sopenharmony_ci{ 124da0c48c4Sopenharmony_ci switch (key) 125da0c48c4Sopenharmony_ci { 126da0c48c4Sopenharmony_ci case ARGP_KEY_INIT: 127da0c48c4Sopenharmony_ci { 128da0c48c4Sopenharmony_ci assert (state->hook == NULL); 129da0c48c4Sopenharmony_ci struct parse_opt *opt = calloc (1, sizeof (*opt)); 130da0c48c4Sopenharmony_ci if (opt == NULL) 131da0c48c4Sopenharmony_ci failure (NULL, DWFL_E_ERRNO, "calloc", state); 132da0c48c4Sopenharmony_ci state->hook = opt; 133da0c48c4Sopenharmony_ci } 134da0c48c4Sopenharmony_ci break; 135da0c48c4Sopenharmony_ci 136da0c48c4Sopenharmony_ci case OPT_DEBUGINFO: 137da0c48c4Sopenharmony_ci debuginfo_path = arg; 138da0c48c4Sopenharmony_ci break; 139da0c48c4Sopenharmony_ci 140da0c48c4Sopenharmony_ci case 'e': 141da0c48c4Sopenharmony_ci { 142da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 143da0c48c4Sopenharmony_ci Dwfl *dwfl = opt->dwfl; 144da0c48c4Sopenharmony_ci if (dwfl == NULL) 145da0c48c4Sopenharmony_ci { 146da0c48c4Sopenharmony_ci dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 147da0c48c4Sopenharmony_ci if (dwfl == NULL) 148da0c48c4Sopenharmony_ci return fail (dwfl, -1, arg, state); 149da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 150da0c48c4Sopenharmony_ci 151da0c48c4Sopenharmony_ci /* Start at zero so if there is just one -e foo.so, 152da0c48c4Sopenharmony_ci the DSO is shown without address bias. */ 153da0c48c4Sopenharmony_ci dwfl->offline_next_address = 0; 154da0c48c4Sopenharmony_ci } 155da0c48c4Sopenharmony_ci if (dwfl->callbacks != &offline_callbacks) 156da0c48c4Sopenharmony_ci { 157da0c48c4Sopenharmony_ci toomany: 158da0c48c4Sopenharmony_ci argp_error (state, "%s", 159da0c48c4Sopenharmony_ci _("only one of -e, -p, -k, -K, or --core allowed")); 160da0c48c4Sopenharmony_ci return EINVAL; 161da0c48c4Sopenharmony_ci } 162da0c48c4Sopenharmony_ci opt->e = arg; 163da0c48c4Sopenharmony_ci } 164da0c48c4Sopenharmony_ci break; 165da0c48c4Sopenharmony_ci 166da0c48c4Sopenharmony_ci case 'p': 167da0c48c4Sopenharmony_ci { 168da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 169da0c48c4Sopenharmony_ci if (opt->dwfl == NULL) 170da0c48c4Sopenharmony_ci { 171da0c48c4Sopenharmony_ci Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); 172da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_linux_proc_report) (dwfl, atoi (arg)); 173da0c48c4Sopenharmony_ci if (result != 0) 174da0c48c4Sopenharmony_ci return fail (dwfl, result, arg, state); 175da0c48c4Sopenharmony_ci 176da0c48c4Sopenharmony_ci /* Non-fatal to not be able to attach to process, ignore error. */ 177da0c48c4Sopenharmony_ci INTUSE(dwfl_linux_proc_attach) (dwfl, atoi (arg), false); 178da0c48c4Sopenharmony_ci 179da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 180da0c48c4Sopenharmony_ci } 181da0c48c4Sopenharmony_ci else 182da0c48c4Sopenharmony_ci goto toomany; 183da0c48c4Sopenharmony_ci } 184da0c48c4Sopenharmony_ci break; 185da0c48c4Sopenharmony_ci 186da0c48c4Sopenharmony_ci case 'M': 187da0c48c4Sopenharmony_ci { 188da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 189da0c48c4Sopenharmony_ci if (opt->dwfl == NULL) 190da0c48c4Sopenharmony_ci { 191da0c48c4Sopenharmony_ci FILE *f = fopen (arg, "r"); 192da0c48c4Sopenharmony_ci if (f == NULL) 193da0c48c4Sopenharmony_ci { 194da0c48c4Sopenharmony_ci int code = errno; 195da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, code, 196da0c48c4Sopenharmony_ci "cannot open '%s'", arg); 197da0c48c4Sopenharmony_ci return code; 198da0c48c4Sopenharmony_ci } 199da0c48c4Sopenharmony_ci Dwfl *dwfl = INTUSE(dwfl_begin) (&proc_callbacks); 200da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_linux_proc_maps_report) (dwfl, f); 201da0c48c4Sopenharmony_ci fclose (f); 202da0c48c4Sopenharmony_ci if (result != 0) 203da0c48c4Sopenharmony_ci return fail (dwfl, result, arg, state); 204da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 205da0c48c4Sopenharmony_ci } 206da0c48c4Sopenharmony_ci else 207da0c48c4Sopenharmony_ci goto toomany; 208da0c48c4Sopenharmony_ci } 209da0c48c4Sopenharmony_ci break; 210da0c48c4Sopenharmony_ci 211da0c48c4Sopenharmony_ci case OPT_COREFILE: 212da0c48c4Sopenharmony_ci { 213da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 214da0c48c4Sopenharmony_ci Dwfl *dwfl = opt->dwfl; 215da0c48c4Sopenharmony_ci if (dwfl == NULL) 216da0c48c4Sopenharmony_ci opt->dwfl = dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 217da0c48c4Sopenharmony_ci /* Permit -e and --core together. */ 218da0c48c4Sopenharmony_ci else if (dwfl->callbacks != &offline_callbacks) 219da0c48c4Sopenharmony_ci goto toomany; 220da0c48c4Sopenharmony_ci opt->core = arg; 221da0c48c4Sopenharmony_ci } 222da0c48c4Sopenharmony_ci break; 223da0c48c4Sopenharmony_ci 224da0c48c4Sopenharmony_ci case 'k': 225da0c48c4Sopenharmony_ci { 226da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 227da0c48c4Sopenharmony_ci if (opt->dwfl == NULL) 228da0c48c4Sopenharmony_ci { 229da0c48c4Sopenharmony_ci Dwfl *dwfl = INTUSE(dwfl_begin) (&kernel_callbacks); 230da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_linux_kernel_report_kernel) (dwfl); 231da0c48c4Sopenharmony_ci if (result != 0) 232da0c48c4Sopenharmony_ci return fail (dwfl, result, _("cannot load kernel symbols"), state); 233da0c48c4Sopenharmony_ci result = INTUSE(dwfl_linux_kernel_report_modules) (dwfl); 234da0c48c4Sopenharmony_ci if (result != 0) 235da0c48c4Sopenharmony_ci /* Non-fatal to have no modules since we do have the kernel. */ 236da0c48c4Sopenharmony_ci argp_failure (state, 0, result, _("cannot find kernel modules")); 237da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 238da0c48c4Sopenharmony_ci } 239da0c48c4Sopenharmony_ci else 240da0c48c4Sopenharmony_ci goto toomany; 241da0c48c4Sopenharmony_ci } 242da0c48c4Sopenharmony_ci break; 243da0c48c4Sopenharmony_ci 244da0c48c4Sopenharmony_ci case 'K': 245da0c48c4Sopenharmony_ci { 246da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 247da0c48c4Sopenharmony_ci if (opt->dwfl == NULL) 248da0c48c4Sopenharmony_ci { 249da0c48c4Sopenharmony_ci Dwfl *dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 250da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_linux_kernel_report_offline) (dwfl, arg, 251da0c48c4Sopenharmony_ci NULL); 252da0c48c4Sopenharmony_ci if (result != 0) 253da0c48c4Sopenharmony_ci return fail (dwfl, result, _("cannot find kernel or modules"), state); 254da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 255da0c48c4Sopenharmony_ci } 256da0c48c4Sopenharmony_ci else 257da0c48c4Sopenharmony_ci goto toomany; 258da0c48c4Sopenharmony_ci } 259da0c48c4Sopenharmony_ci break; 260da0c48c4Sopenharmony_ci 261da0c48c4Sopenharmony_ci case ARGP_KEY_SUCCESS: 262da0c48c4Sopenharmony_ci { 263da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 264da0c48c4Sopenharmony_ci Dwfl *dwfl = opt->dwfl; 265da0c48c4Sopenharmony_ci 266da0c48c4Sopenharmony_ci if (dwfl == NULL) 267da0c48c4Sopenharmony_ci { 268da0c48c4Sopenharmony_ci /* Default if no -e, -p, or -k, is "-e a.out". */ 269da0c48c4Sopenharmony_ci arg = "a.out"; 270da0c48c4Sopenharmony_ci dwfl = INTUSE(dwfl_begin) (&offline_callbacks); 271da0c48c4Sopenharmony_ci if (INTUSE(dwfl_report_offline) (dwfl, "", arg, -1) == NULL) 272da0c48c4Sopenharmony_ci return fail (dwfl, -1, arg, state); 273da0c48c4Sopenharmony_ci opt->dwfl = dwfl; 274da0c48c4Sopenharmony_ci } 275da0c48c4Sopenharmony_ci 276da0c48c4Sopenharmony_ci if (opt->core) 277da0c48c4Sopenharmony_ci { 278da0c48c4Sopenharmony_ci int fd = open (opt->core, O_RDONLY); 279da0c48c4Sopenharmony_ci if (fd < 0) 280da0c48c4Sopenharmony_ci { 281da0c48c4Sopenharmony_ci int code = errno; 282da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, code, 283da0c48c4Sopenharmony_ci "cannot open '%s'", opt->core); 284da0c48c4Sopenharmony_ci return code; 285da0c48c4Sopenharmony_ci } 286da0c48c4Sopenharmony_ci 287da0c48c4Sopenharmony_ci Elf *core; 288da0c48c4Sopenharmony_ci Dwfl_Error error = __libdw_open_file (&fd, &core, true, false); 289da0c48c4Sopenharmony_ci if (error != DWFL_E_NOERROR) 290da0c48c4Sopenharmony_ci { 291da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, 0, 292da0c48c4Sopenharmony_ci _("cannot read ELF core file: %s"), 293da0c48c4Sopenharmony_ci INTUSE(dwfl_errmsg) (error)); 294da0c48c4Sopenharmony_ci return error == DWFL_E_ERRNO ? errno : EIO; 295da0c48c4Sopenharmony_ci } 296da0c48c4Sopenharmony_ci 297da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_core_file_report) (dwfl, core, opt->e); 298da0c48c4Sopenharmony_ci if (result < 0) 299da0c48c4Sopenharmony_ci { 300da0c48c4Sopenharmony_ci elf_end (core); 301da0c48c4Sopenharmony_ci close (fd); 302da0c48c4Sopenharmony_ci return fail (dwfl, result, opt->core, state); 303da0c48c4Sopenharmony_ci } 304da0c48c4Sopenharmony_ci 305da0c48c4Sopenharmony_ci /* Non-fatal to not be able to attach to core, ignore error. */ 306da0c48c4Sopenharmony_ci INTUSE(dwfl_core_file_attach) (dwfl, core); 307da0c48c4Sopenharmony_ci 308da0c48c4Sopenharmony_ci /* Store core Elf and fd in Dwfl to expose with dwfl_end. */ 309da0c48c4Sopenharmony_ci if (dwfl->user_core == NULL) 310da0c48c4Sopenharmony_ci { 311da0c48c4Sopenharmony_ci dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core)); 312da0c48c4Sopenharmony_ci if (dwfl->user_core == NULL) 313da0c48c4Sopenharmony_ci { 314da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, 0, 315da0c48c4Sopenharmony_ci _("Not enough memory")); 316da0c48c4Sopenharmony_ci return ENOMEM; 317da0c48c4Sopenharmony_ci } 318da0c48c4Sopenharmony_ci } 319da0c48c4Sopenharmony_ci dwfl->user_core->core = core; 320da0c48c4Sopenharmony_ci dwfl->user_core->fd = fd; 321da0c48c4Sopenharmony_ci 322da0c48c4Sopenharmony_ci if (result == 0) 323da0c48c4Sopenharmony_ci { 324da0c48c4Sopenharmony_ci argp_failure (state, EXIT_FAILURE, 0, 325da0c48c4Sopenharmony_ci _("No modules recognized in core file")); 326da0c48c4Sopenharmony_ci return ENOENT; 327da0c48c4Sopenharmony_ci } 328da0c48c4Sopenharmony_ci } 329da0c48c4Sopenharmony_ci else if (opt->e) 330da0c48c4Sopenharmony_ci { 331da0c48c4Sopenharmony_ci if (INTUSE(dwfl_report_offline) (dwfl, "", opt->e, -1) == NULL) 332da0c48c4Sopenharmony_ci return fail (dwfl, -1, opt->e, state); 333da0c48c4Sopenharmony_ci } 334da0c48c4Sopenharmony_ci 335da0c48c4Sopenharmony_ci /* One of the three flavors has done dwfl_begin and some reporting 336da0c48c4Sopenharmony_ci if we got here. Tie up the Dwfl and return it to the caller of 337da0c48c4Sopenharmony_ci argp_parse. */ 338da0c48c4Sopenharmony_ci 339da0c48c4Sopenharmony_ci int result = INTUSE(dwfl_report_end) (dwfl, NULL, NULL); 340da0c48c4Sopenharmony_ci if (result != 0) 341da0c48c4Sopenharmony_ci return fail (dwfl, -1, arg, state); 342da0c48c4Sopenharmony_ci 343da0c48c4Sopenharmony_ci /* Update the input all along, so a parent parser can see it. 344da0c48c4Sopenharmony_ci As we free OPT the update below will be no longer active. */ 345da0c48c4Sopenharmony_ci *(Dwfl **) state->input = dwfl; 346da0c48c4Sopenharmony_ci free (opt); 347da0c48c4Sopenharmony_ci state->hook = NULL; 348da0c48c4Sopenharmony_ci } 349da0c48c4Sopenharmony_ci break; 350da0c48c4Sopenharmony_ci 351da0c48c4Sopenharmony_ci case ARGP_KEY_ERROR: 352da0c48c4Sopenharmony_ci { 353da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 354da0c48c4Sopenharmony_ci dwfl_end (opt->dwfl); 355da0c48c4Sopenharmony_ci free (opt); 356da0c48c4Sopenharmony_ci state->hook = NULL; 357da0c48c4Sopenharmony_ci } 358da0c48c4Sopenharmony_ci break; 359da0c48c4Sopenharmony_ci 360da0c48c4Sopenharmony_ci default: 361da0c48c4Sopenharmony_ci return ARGP_ERR_UNKNOWN; 362da0c48c4Sopenharmony_ci } 363da0c48c4Sopenharmony_ci 364da0c48c4Sopenharmony_ci /* Update the input all along, so a parent parser can see it. */ 365da0c48c4Sopenharmony_ci struct parse_opt *opt = state->hook; 366da0c48c4Sopenharmony_ci if (opt) 367da0c48c4Sopenharmony_ci *(Dwfl **) state->input = opt->dwfl; 368da0c48c4Sopenharmony_ci 369da0c48c4Sopenharmony_ci return 0; 370da0c48c4Sopenharmony_ci} 371da0c48c4Sopenharmony_ci 372da0c48c4Sopenharmony_cistatic const struct argp libdwfl_argp = 373da0c48c4Sopenharmony_ci { .options = options, .parser = parse_opt }; 374da0c48c4Sopenharmony_ci 375da0c48c4Sopenharmony_ciconst struct argp * 376da0c48c4Sopenharmony_cidwfl_standard_argp (void) 377da0c48c4Sopenharmony_ci{ 378da0c48c4Sopenharmony_ci return &libdwfl_argp; 379da0c48c4Sopenharmony_ci} 380