Branch data Line data Source code
1 : : /* Print the source files of a given ELF file.
2 : : Copyright (C) 2023 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : : Written by Housam Alamour <alamourh@redhat.com>.
5 : :
6 : : This file is free software; you can redistribute it and/or modify
7 : : it under the terms of the GNU General Public License as published by
8 : : the Free Software Foundation; either version 3 of the License, or
9 : : (at your option) any later version.
10 : :
11 : : elfutils is distributed in the hope that it will be useful, but
12 : : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : GNU General Public License for more details.
15 : :
16 : : You should have received a copy of the GNU General Public License
17 : : along with this program. If not, see <http://www.gnu.org/licenses/>. */
18 : :
19 : : #include "printversion.h"
20 : : #include <dwarf.h>
21 : : #include <argp.h>
22 : : #include <cstring>
23 : : #include <set>
24 : : #include <string>
25 : : #include <cassert>
26 : : #include <config.h>
27 : :
28 : : #include <libdwfl.h>
29 : : #include <fcntl.h>
30 : : #include <iostream>
31 : : #include <libdw.h>
32 : :
33 : : using namespace std;
34 : :
35 : : /* Name and version of program. */
36 : : ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
37 : :
38 : : /* Bug report address. */
39 : : ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
40 : :
41 : : /* Definitions of arguments for argp functions. */
42 : : static const struct argp_option options[] =
43 : : {
44 : : { NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 },
45 : : { "null", '0', NULL, 0,
46 : : N_ ("Separate items by a null instead of a newline."), 0 },
47 : : { "verbose", 'v', NULL, 0,
48 : : N_ ("Increase verbosity of logging messages."), 0 },
49 : : { "cu-only", 'c', NULL, 0, N_ ("Only list the CU names."), 0 },
50 : : { NULL, 0, NULL, 0, NULL, 0 }
51 : : };
52 : :
53 : : /* Short description of program. */
54 : : static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'.");
55 : :
56 : : /* Strings for arguments in help texts. */
57 : : static const char args_doc[] = N_("INPUT");
58 : :
59 : : /* Prototype for option handler. */
60 : : static error_t parse_opt (int key, char *arg, struct argp_state *state);
61 : :
62 : : static struct argp_child argp_children[2]; /* [0] is set in main. */
63 : :
64 : : /* Data structure to communicate with argp functions. */
65 : : static const struct argp argp =
66 : : {
67 : : options, parse_opt, args_doc, doc, argp_children, NULL, NULL
68 : : };
69 : :
70 : : /* Verbose message printing. */
71 : : static bool verbose;
72 : : /* Delimit the output with nulls. */
73 : : static bool null_arg;
74 : : /* Only print compilation unit names. */
75 : : static bool CU_only;
76 : :
77 : : /* Handle program arguments. */
78 : : static error_t
79 : 162 : parse_opt (int key, char *arg, struct argp_state *state)
80 : : {
81 : : /* Suppress "unused parameter" warning. */
82 : 162 : (void)arg;
83 [ + + + + : 162 : switch (key)
+ ]
84 : : {
85 : 26 : case ARGP_KEY_INIT:
86 : 26 : state->child_inputs[0] = state->input;
87 : 26 : break;
88 : :
89 : 12 : case '0':
90 : 12 : null_arg = true;
91 : 12 : break;
92 : :
93 : 12 : case 'v':
94 : 12 : verbose = true;
95 : 12 : break;
96 : :
97 : 8 : case 'c':
98 : 8 : CU_only = true;
99 : 8 : break;
100 : :
101 : : default:
102 : : return ARGP_ERR_UNKNOWN;
103 : : }
104 : : return 0;
105 : : }
106 : :
107 : :
108 : : /* Global list of collected source files. Normally, it'll contain
109 : : the sources of just one named binary, but the '-K' option can cause
110 : : multiple dwfl modules to be loaded, thus listed. */
111 : : set<string> debug_sourcefiles;
112 : :
113 : : static int
114 : 50 : collect_sourcefiles (Dwfl_Module *dwflmod,
115 : : void **userdata __attribute__ ((unused)),
116 : : const char *name __attribute__ ((unused)),
117 : : Dwarf_Addr base __attribute__ ((unused)),
118 : : void *arg __attribute__ ((unused)))
119 : : {
120 : 50 : Dwarf *dbg;
121 : 50 : Dwarf_Addr bias; /* ignored - for addressing purposes only */
122 : :
123 : 50 : dbg = dwfl_module_getdwarf (dwflmod, &bias);
124 : :
125 : 50 : Dwarf_Off offset = 0;
126 : 50 : Dwarf_Off old_offset;
127 : 50 : size_t hsize;
128 : :
129 : : /* Traverse all CUs of this module. */
130 [ + + ]: 22770 : while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0)
131 : : {
132 : 22720 : Dwarf_Die cudie_mem;
133 : 22720 : Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
134 : :
135 [ - + ]: 22720 : if (cudie == NULL)
136 : 0 : continue;
137 : :
138 [ - + ]: 22720 : const char *cuname = dwarf_diename (cudie) ?: "<unknown>";
139 : 22720 : Dwarf_Files *files;
140 : 22720 : size_t nfiles;
141 [ - + ]: 22720 : if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
142 : 0 : continue;
143 : :
144 : : /* extract DW_AT_comp_dir to resolve relative file names */
145 : 22720 : const char *comp_dir = "";
146 : 22720 : const char *const *dirs;
147 : 22720 : size_t ndirs;
148 : :
149 [ + - - + ]: 22720 : if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 && dirs[0] != NULL)
150 : : comp_dir = dirs[0];
151 : 0 : if (comp_dir == NULL)
152 : : comp_dir = "";
153 : :
154 [ + + ]: 22720 : if (verbose)
155 : 11064 : std::clog << "searching for sources for cu=" << cuname
156 : 11064 : << " comp_dir=" << comp_dir << " #files=" << nfiles
157 : 11064 : << " #dirs=" << ndirs << endl;
158 : :
159 [ + + ]: 336246 : for (size_t f = 1; f < nfiles; f++)
160 : : {
161 : 313526 : const char *hat;
162 [ + + ]: 313526 : if (CU_only)
163 : : {
164 [ + - - + ]: 38232 : if (strcmp(cuname, "<unknown>") == 0 || strcmp(cuname, "<artificial>") == 0 )
165 : 3174 : continue;
166 : : hat = cuname;
167 : : }
168 : : else
169 : 275294 : hat = dwarf_filesrc (files, f, NULL, NULL);
170 : :
171 [ - + ]: 275294 : if (hat == NULL)
172 : 0 : continue;
173 : :
174 [ + + ]: 627052 : if (string(hat).find("<built-in>")
175 [ + + ]: 313526 : != std::string::npos) /* gcc intrinsics, don't bother record */
176 : 3174 : continue;
177 : :
178 [ + + ]: 310352 : string waldo;
179 [ + + ]: 310352 : if (hat[0] == '/') /* absolute */
180 [ + - - + ]: 43592 : waldo = (string (hat));
181 [ + - ]: 266760 : else if (comp_dir[0] != '\0') /* comp_dir relative */
182 [ + - + - : 497456 : waldo = (string (comp_dir) + string ("/") + string (hat));
+ - + - +
- - + - +
- + - + +
+ - - - -
- - ]
183 [ + - ]: 310352 : debug_sourcefiles.insert (waldo);
184 : 310352 : }
185 : : }
186 : :
187 : 50 : return DWARF_CB_OK;
188 : : }
189 : :
190 : :
191 : : int
192 : 26 : main (int argc, char *argv[])
193 : : {
194 : 26 : int remaining;
195 : :
196 : : /* Parse and process arguments. This includes opening the modules. */
197 : 26 : argp_children[0].argp = dwfl_standard_argp ();
198 : 26 : argp_children[0].group = 1;
199 : :
200 : 26 : Dwfl *dwfl = NULL;
201 : 26 : (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
202 [ - + ]: 26 : assert (dwfl != NULL);
203 : : /* Process all loaded modules - probably just one, except if -K or -p is used. */
204 : 26 : (void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0);
205 : :
206 [ + - ]: 26 : if (!debug_sourcefiles.empty ())
207 [ + + ]: 44726 : for (const string &element : debug_sourcefiles)
208 : : {
209 : 44700 : std::cout << element;
210 [ + + ]: 44700 : if (null_arg)
211 : 21812 : std::cout << '\0';
212 : : else
213 : 22888 : std::cout << '\n';
214 : : }
215 : :
216 : 26 : dwfl_end (dwfl);
217 : 26 : return 0;
218 : : }
|