/* Print the source files of a given ELF file. Copyright (C) 2023 Red Hat, Inc. This file is part of elfutils. Written by Housam Alamour . This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. elfutils is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "printversion.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; /* Name and version of program. */ ARGP_PROGRAM_VERSION_HOOK_DEF = print_version; /* Bug report address. */ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { { NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 }, { "null", '0', NULL, 0, N_ ("Separate items by a null instead of a newline."), 0 }, { "verbose", 'v', NULL, 0, N_ ("Increase verbosity of logging messages."), 0 }, { "cu-only", 'c', NULL, 0, N_ ("Only list the CU names."), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; /* Short description of program. */ static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'."); /* Strings for arguments in help texts. */ static const char args_doc[] = N_("INPUT"); /* Prototype for option handler. */ static error_t parse_opt (int key, char *arg, struct argp_state *state); static struct argp_child argp_children[2]; /* [0] is set in main. */ /* Data structure to communicate with argp functions. */ static const struct argp argp = { options, parse_opt, args_doc, doc, argp_children, NULL, NULL }; /* Verbose message printing. */ static bool verbose; /* Delimit the output with nulls. */ static bool null_arg; /* Only print compilation unit names. */ static bool CU_only; /* Handle program arguments. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { /* Suppress "unused parameter" warning. */ (void)arg; switch (key) { case ARGP_KEY_INIT: state->child_inputs[0] = state->input; break; case '0': null_arg = true; break; case 'v': verbose = true; break; case 'c': CU_only = true; break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* Global list of collected source files. Normally, it'll contain the sources of just one named binary, but the '-K' option can cause multiple dwfl modules to be loaded, thus listed. */ set debug_sourcefiles; static int collect_sourcefiles (Dwfl_Module *dwflmod, void **userdata __attribute__ ((unused)), const char *name __attribute__ ((unused)), Dwarf_Addr base __attribute__ ((unused)), void *arg __attribute__ ((unused))) { Dwarf *dbg; Dwarf_Addr bias; /* ignored - for addressing purposes only */ dbg = dwfl_module_getdwarf (dwflmod, &bias); Dwarf_Off offset = 0; Dwarf_Off old_offset; size_t hsize; /* Traverse all CUs of this module. */ while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0) { Dwarf_Die cudie_mem; Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem); if (cudie == NULL) continue; const char *cuname = dwarf_diename (cudie) ?: ""; Dwarf_Files *files; size_t nfiles; if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0) continue; /* extract DW_AT_comp_dir to resolve relative file names */ const char *comp_dir = ""; const char *const *dirs; size_t ndirs; if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 && dirs[0] != NULL) comp_dir = dirs[0]; if (comp_dir == NULL) comp_dir = ""; if (verbose) std::clog << "searching for sources for cu=" << cuname << " comp_dir=" << comp_dir << " #files=" << nfiles << " #dirs=" << ndirs << endl; for (size_t f = 1; f < nfiles; f++) { const char *hat; if (CU_only) { if (strcmp(cuname, "") == 0 || strcmp(cuname, "") == 0 ) continue; hat = cuname; } else hat = dwarf_filesrc (files, f, NULL, NULL); if (hat == NULL) continue; if (string(hat).find("") != std::string::npos) /* gcc intrinsics, don't bother record */ continue; string waldo; if (hat[0] == '/') /* absolute */ waldo = (string (hat)); else if (comp_dir[0] != '\0') /* comp_dir relative */ waldo = (string (comp_dir) + string ("/") + string (hat)); debug_sourcefiles.insert (waldo); } } return DWARF_CB_OK; } int main (int argc, char *argv[]) { int remaining; /* Parse and process arguments. This includes opening the modules. */ argp_children[0].argp = dwfl_standard_argp (); argp_children[0].group = 1; Dwfl *dwfl = NULL; (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); assert (dwfl != NULL); /* Process all loaded modules - probably just one, except if -K or -p is used. */ (void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0); if (!debug_sourcefiles.empty ()) for (const string &element : debug_sourcefiles) { std::cout << element; if (null_arg) std::cout << '\0'; else std::cout << '\n'; } dwfl_end (dwfl); return 0; }