1*7304104dSAndroid Build Coastguard Worker /* Print the source files of a given ELF file.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2023 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker Written by Housam Alamour <[email protected]>.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of the GNU General Public License as published by
8*7304104dSAndroid Build Coastguard Worker the Free Software Foundation; either version 3 of the License, or
9*7304104dSAndroid Build Coastguard Worker (at your option) any later version.
10*7304104dSAndroid Build Coastguard Worker
11*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
12*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
13*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14*7304104dSAndroid Build Coastguard Worker GNU General Public License for more details.
15*7304104dSAndroid Build Coastguard Worker
16*7304104dSAndroid Build Coastguard Worker You should have received a copy of the GNU General Public License
17*7304104dSAndroid Build Coastguard Worker along with this program. If not, see <http://www.gnu.org/licenses/>. */
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker
20*7304104dSAndroid Build Coastguard Worker /* In case we have a bad fts we include this before config.h because it
21*7304104dSAndroid Build Coastguard Worker can't handle _FILE_OFFSET_BITS.
22*7304104dSAndroid Build Coastguard Worker Everything we need here is fine if its declarations just come first.
23*7304104dSAndroid Build Coastguard Worker Also, include sys/types.h before fts. On some systems fts.h is not self
24*7304104dSAndroid Build Coastguard Worker contained. */
25*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
26*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
27*7304104dSAndroid Build Coastguard Worker #include <fts.h>
28*7304104dSAndroid Build Coastguard Worker #endif
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
31*7304104dSAndroid Build Coastguard Worker # include <config.h>
32*7304104dSAndroid Build Coastguard Worker #endif
33*7304104dSAndroid Build Coastguard Worker
34*7304104dSAndroid Build Coastguard Worker #include "printversion.h"
35*7304104dSAndroid Build Coastguard Worker #include <dwarf.h>
36*7304104dSAndroid Build Coastguard Worker #include <argp.h>
37*7304104dSAndroid Build Coastguard Worker #include <cstring>
38*7304104dSAndroid Build Coastguard Worker #include <set>
39*7304104dSAndroid Build Coastguard Worker #include <string>
40*7304104dSAndroid Build Coastguard Worker #include <cassert>
41*7304104dSAndroid Build Coastguard Worker #include <gelf.h>
42*7304104dSAndroid Build Coastguard Worker #include <memory>
43*7304104dSAndroid Build Coastguard Worker
44*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
45*7304104dSAndroid Build Coastguard Worker #include "debuginfod.h"
46*7304104dSAndroid Build Coastguard Worker #endif
47*7304104dSAndroid Build Coastguard Worker
48*7304104dSAndroid Build Coastguard Worker #include <libdwfl.h>
49*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
50*7304104dSAndroid Build Coastguard Worker #include <iostream>
51*7304104dSAndroid Build Coastguard Worker #include <libdw.h>
52*7304104dSAndroid Build Coastguard Worker #include <sstream>
53*7304104dSAndroid Build Coastguard Worker #include <vector>
54*7304104dSAndroid Build Coastguard Worker
55*7304104dSAndroid Build Coastguard Worker /* Libraries for use by the --zip option */
56*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
57*7304104dSAndroid Build Coastguard Worker #include <archive.h>
58*7304104dSAndroid Build Coastguard Worker #include <archive_entry.h>
59*7304104dSAndroid Build Coastguard Worker #endif
60*7304104dSAndroid Build Coastguard Worker
61*7304104dSAndroid Build Coastguard Worker /* If fts.h is included before config.h, its indirect inclusions may not
62*7304104dSAndroid Build Coastguard Worker give us the right LFS aliases of these functions, so map them manually. */
63*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
64*7304104dSAndroid Build Coastguard Worker #ifdef _FILE_OFFSET_BITS
65*7304104dSAndroid Build Coastguard Worker #define open open64
66*7304104dSAndroid Build Coastguard Worker #define fopen fopen64
67*7304104dSAndroid Build Coastguard Worker #endif
68*7304104dSAndroid Build Coastguard Worker #else
69*7304104dSAndroid Build Coastguard Worker #include <sys/types.h>
70*7304104dSAndroid Build Coastguard Worker #include <fts.h>
71*7304104dSAndroid Build Coastguard Worker #endif
72*7304104dSAndroid Build Coastguard Worker
73*7304104dSAndroid Build Coastguard Worker using namespace std;
74*7304104dSAndroid Build Coastguard Worker
75*7304104dSAndroid Build Coastguard Worker /* Name and version of program. */
76*7304104dSAndroid Build Coastguard Worker ARGP_PROGRAM_VERSION_HOOK_DEF = print_version;
77*7304104dSAndroid Build Coastguard Worker
78*7304104dSAndroid Build Coastguard Worker /* Bug report address. */
79*7304104dSAndroid Build Coastguard Worker ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT;
80*7304104dSAndroid Build Coastguard Worker
81*7304104dSAndroid Build Coastguard Worker constexpr size_t BUFFER_SIZE = 8192;
82*7304104dSAndroid Build Coastguard Worker
83*7304104dSAndroid Build Coastguard Worker /* Definitions of arguments for argp functions. */
84*7304104dSAndroid Build Coastguard Worker static const struct argp_option options[] =
85*7304104dSAndroid Build Coastguard Worker {
86*7304104dSAndroid Build Coastguard Worker { NULL, 0, NULL, OPTION_DOC, N_("Output options:"), 1 },
87*7304104dSAndroid Build Coastguard Worker { "null", '0', NULL, 0,
88*7304104dSAndroid Build Coastguard Worker N_ ("Separate items by a null instead of a newline."), 0 },
89*7304104dSAndroid Build Coastguard Worker { "verbose", 'v', NULL, 0,
90*7304104dSAndroid Build Coastguard Worker N_ ("Increase verbosity of logging messages."), 0 },
91*7304104dSAndroid Build Coastguard Worker { "cu-only", 'c', NULL, 0, N_("Only list the CU names."), 0 },
92*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
93*7304104dSAndroid Build Coastguard Worker { "zip", 'z', NULL, 0, N_("Zip all the source files and send to stdout. "
94*7304104dSAndroid Build Coastguard Worker "Cannot be used with the null option"), 0 },
95*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
96*7304104dSAndroid Build Coastguard Worker { "no-backup", 'b', NULL, 0, N_("Disables local source file search when "
97*7304104dSAndroid Build Coastguard Worker "debuginfod fails to fetch files. This option is only applicable"
98*7304104dSAndroid Build Coastguard Worker "when fetching and zipping files."), 0 },
99*7304104dSAndroid Build Coastguard Worker #endif
100*7304104dSAndroid Build Coastguard Worker #endif
101*7304104dSAndroid Build Coastguard Worker { NULL, 0, NULL, 0, NULL, 0 }
102*7304104dSAndroid Build Coastguard Worker };
103*7304104dSAndroid Build Coastguard Worker
104*7304104dSAndroid Build Coastguard Worker /* Short description of program. */
105*7304104dSAndroid Build Coastguard Worker static const char doc[] = N_("Lists the source files of a DWARF/ELF file. The default input is the file 'a.out'.");
106*7304104dSAndroid Build Coastguard Worker
107*7304104dSAndroid Build Coastguard Worker /* Strings for arguments in help texts. */
108*7304104dSAndroid Build Coastguard Worker static const char args_doc[] = N_("INPUT");
109*7304104dSAndroid Build Coastguard Worker
110*7304104dSAndroid Build Coastguard Worker /* Prototype for option handler. */
111*7304104dSAndroid Build Coastguard Worker static error_t parse_opt (int key, char *arg, struct argp_state *state);
112*7304104dSAndroid Build Coastguard Worker
113*7304104dSAndroid Build Coastguard Worker static struct argp_child argp_children[2]; /* [0] is set in main. */
114*7304104dSAndroid Build Coastguard Worker
115*7304104dSAndroid Build Coastguard Worker /* Data structure to communicate with argp functions. */
116*7304104dSAndroid Build Coastguard Worker static const struct argp argp =
117*7304104dSAndroid Build Coastguard Worker {
118*7304104dSAndroid Build Coastguard Worker options, parse_opt, args_doc, doc, argp_children, NULL, NULL
119*7304104dSAndroid Build Coastguard Worker };
120*7304104dSAndroid Build Coastguard Worker
121*7304104dSAndroid Build Coastguard Worker /* Verbose message printing. */
122*7304104dSAndroid Build Coastguard Worker static bool verbose;
123*7304104dSAndroid Build Coastguard Worker /* Delimit the output with nulls. */
124*7304104dSAndroid Build Coastguard Worker static bool null_arg;
125*7304104dSAndroid Build Coastguard Worker /* Only print compilation unit names. */
126*7304104dSAndroid Build Coastguard Worker static bool CU_only;
127*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
128*7304104dSAndroid Build Coastguard Worker /* Zip all the source files and send to stdout. */
129*7304104dSAndroid Build Coastguard Worker static bool zip;
130*7304104dSAndroid Build Coastguard Worker
131*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
132*7304104dSAndroid Build Coastguard Worker /* Disables local source file search when debuginfod fails to fetch them.
133*7304104dSAndroid Build Coastguard Worker This option is only applicable when fetching and zipping files.*/
134*7304104dSAndroid Build Coastguard Worker static bool no_backup;
135*7304104dSAndroid Build Coastguard Worker #endif
136*7304104dSAndroid Build Coastguard Worker #endif
137*7304104dSAndroid Build Coastguard Worker
138*7304104dSAndroid Build Coastguard Worker /* Handle program arguments. Note null arg and zip
139*7304104dSAndroid Build Coastguard Worker cannot be combined due to warnings raised when unzipping. */
140*7304104dSAndroid Build Coastguard Worker static error_t
parse_opt(int key,char * arg,struct argp_state * state)141*7304104dSAndroid Build Coastguard Worker parse_opt (int key, char *arg, struct argp_state *state)
142*7304104dSAndroid Build Coastguard Worker {
143*7304104dSAndroid Build Coastguard Worker /* Suppress "unused parameter" warning. */
144*7304104dSAndroid Build Coastguard Worker (void)arg;
145*7304104dSAndroid Build Coastguard Worker switch (key)
146*7304104dSAndroid Build Coastguard Worker {
147*7304104dSAndroid Build Coastguard Worker case ARGP_KEY_INIT:
148*7304104dSAndroid Build Coastguard Worker state->child_inputs[0] = state->input;
149*7304104dSAndroid Build Coastguard Worker break;
150*7304104dSAndroid Build Coastguard Worker
151*7304104dSAndroid Build Coastguard Worker case '0':
152*7304104dSAndroid Build Coastguard Worker null_arg = true;
153*7304104dSAndroid Build Coastguard Worker break;
154*7304104dSAndroid Build Coastguard Worker
155*7304104dSAndroid Build Coastguard Worker case 'v':
156*7304104dSAndroid Build Coastguard Worker verbose = true;
157*7304104dSAndroid Build Coastguard Worker break;
158*7304104dSAndroid Build Coastguard Worker
159*7304104dSAndroid Build Coastguard Worker case 'c':
160*7304104dSAndroid Build Coastguard Worker CU_only = true;
161*7304104dSAndroid Build Coastguard Worker break;
162*7304104dSAndroid Build Coastguard Worker
163*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
164*7304104dSAndroid Build Coastguard Worker case 'z':
165*7304104dSAndroid Build Coastguard Worker zip = true;
166*7304104dSAndroid Build Coastguard Worker break;
167*7304104dSAndroid Build Coastguard Worker
168*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
169*7304104dSAndroid Build Coastguard Worker case 'b':
170*7304104dSAndroid Build Coastguard Worker no_backup = true;
171*7304104dSAndroid Build Coastguard Worker break;
172*7304104dSAndroid Build Coastguard Worker #endif
173*7304104dSAndroid Build Coastguard Worker #endif
174*7304104dSAndroid Build Coastguard Worker
175*7304104dSAndroid Build Coastguard Worker default:
176*7304104dSAndroid Build Coastguard Worker return ARGP_ERR_UNKNOWN;
177*7304104dSAndroid Build Coastguard Worker }
178*7304104dSAndroid Build Coastguard Worker return 0;
179*7304104dSAndroid Build Coastguard Worker }
180*7304104dSAndroid Build Coastguard Worker
181*7304104dSAndroid Build Coastguard Worker /* Remove the "/./" , "../" and the preceding directory
182*7304104dSAndroid Build Coastguard Worker that some paths include which raise errors during unzip. */
canonicalize_path(string path)183*7304104dSAndroid Build Coastguard Worker string canonicalize_path(string path)
184*7304104dSAndroid Build Coastguard Worker {
185*7304104dSAndroid Build Coastguard Worker stringstream ss(path);
186*7304104dSAndroid Build Coastguard Worker string token;
187*7304104dSAndroid Build Coastguard Worker vector<string> tokens;
188*7304104dSAndroid Build Coastguard Worker /* Extract each directory of the path and place into a vector. */
189*7304104dSAndroid Build Coastguard Worker while (getline(ss, token, '/')) {
190*7304104dSAndroid Build Coastguard Worker /* Ignore any empty //, or /./ dirs. */
191*7304104dSAndroid Build Coastguard Worker if (token == "" || token == ".")
192*7304104dSAndroid Build Coastguard Worker continue;
193*7304104dSAndroid Build Coastguard Worker /* When /.. is encountered, remove the most recent directory from the vector. */
194*7304104dSAndroid Build Coastguard Worker else if (token == "..") {
195*7304104dSAndroid Build Coastguard Worker if (!tokens.empty())
196*7304104dSAndroid Build Coastguard Worker tokens.pop_back();
197*7304104dSAndroid Build Coastguard Worker } else
198*7304104dSAndroid Build Coastguard Worker tokens.push_back(token);
199*7304104dSAndroid Build Coastguard Worker }
200*7304104dSAndroid Build Coastguard Worker stringstream result;
201*7304104dSAndroid Build Coastguard Worker if (tokens.empty())
202*7304104dSAndroid Build Coastguard Worker return "/";
203*7304104dSAndroid Build Coastguard Worker /* Reconstruct the path from the extracted directories. */
204*7304104dSAndroid Build Coastguard Worker for (const string &t : tokens) {
205*7304104dSAndroid Build Coastguard Worker result << '/' << t;
206*7304104dSAndroid Build Coastguard Worker }
207*7304104dSAndroid Build Coastguard Worker return result.str();
208*7304104dSAndroid Build Coastguard Worker }
209*7304104dSAndroid Build Coastguard Worker
210*7304104dSAndroid Build Coastguard Worker /* Global list of collected source files and their respective module.
211*7304104dSAndroid Build Coastguard Worker Normally, it'll contain the sources of just one named binary, but
212*7304104dSAndroid Build Coastguard Worker the '-K' option can cause multiple dwfl modules to be loaded, thus
213*7304104dSAndroid Build Coastguard Worker listed. */
214*7304104dSAndroid Build Coastguard Worker set<pair<string, Dwfl_Module*>> debug_sourcefiles;
215*7304104dSAndroid Build Coastguard Worker
216*7304104dSAndroid Build Coastguard Worker static int
collect_sourcefiles(Dwfl_Module * dwflmod,void ** userdata,const char * name,Dwarf_Addr base,void * arg)217*7304104dSAndroid Build Coastguard Worker collect_sourcefiles (Dwfl_Module *dwflmod,
218*7304104dSAndroid Build Coastguard Worker void **userdata __attribute__ ((unused)),
219*7304104dSAndroid Build Coastguard Worker const char *name __attribute__ ((unused)),
220*7304104dSAndroid Build Coastguard Worker Dwarf_Addr base __attribute__ ((unused)),
221*7304104dSAndroid Build Coastguard Worker void *arg __attribute__ ((unused)))
222*7304104dSAndroid Build Coastguard Worker {
223*7304104dSAndroid Build Coastguard Worker Dwarf *dbg;
224*7304104dSAndroid Build Coastguard Worker Dwarf_Addr bias; /* ignored - for addressing purposes only. */
225*7304104dSAndroid Build Coastguard Worker
226*7304104dSAndroid Build Coastguard Worker dbg = dwfl_module_getdwarf (dwflmod, &bias);
227*7304104dSAndroid Build Coastguard Worker
228*7304104dSAndroid Build Coastguard Worker Dwarf_Off offset = 0;
229*7304104dSAndroid Build Coastguard Worker Dwarf_Off old_offset;
230*7304104dSAndroid Build Coastguard Worker size_t hsize;
231*7304104dSAndroid Build Coastguard Worker /* Traverse all CUs of this module. */
232*7304104dSAndroid Build Coastguard Worker while (dwarf_nextcu (dbg, old_offset = offset, &offset, &hsize, NULL, NULL, NULL) == 0)
233*7304104dSAndroid Build Coastguard Worker {
234*7304104dSAndroid Build Coastguard Worker Dwarf_Die cudie_mem;
235*7304104dSAndroid Build Coastguard Worker Dwarf_Die *cudie = dwarf_offdie (dbg, old_offset + hsize, &cudie_mem);
236*7304104dSAndroid Build Coastguard Worker
237*7304104dSAndroid Build Coastguard Worker if (cudie == NULL)
238*7304104dSAndroid Build Coastguard Worker continue;
239*7304104dSAndroid Build Coastguard Worker
240*7304104dSAndroid Build Coastguard Worker const char *cuname = dwarf_diename (cudie) ?: "<unknown>";
241*7304104dSAndroid Build Coastguard Worker Dwarf_Files *files;
242*7304104dSAndroid Build Coastguard Worker size_t nfiles;
243*7304104dSAndroid Build Coastguard Worker if (dwarf_getsrcfiles (cudie, &files, &nfiles) != 0)
244*7304104dSAndroid Build Coastguard Worker continue;
245*7304104dSAndroid Build Coastguard Worker
246*7304104dSAndroid Build Coastguard Worker /* extract DW_AT_comp_dir to resolve relative file names. */
247*7304104dSAndroid Build Coastguard Worker const char *comp_dir = "";
248*7304104dSAndroid Build Coastguard Worker const char *const *dirs;
249*7304104dSAndroid Build Coastguard Worker size_t ndirs;
250*7304104dSAndroid Build Coastguard Worker
251*7304104dSAndroid Build Coastguard Worker if (dwarf_getsrcdirs (files, &dirs, &ndirs) == 0 && dirs[0] != NULL)
252*7304104dSAndroid Build Coastguard Worker comp_dir = dirs[0];
253*7304104dSAndroid Build Coastguard Worker if (comp_dir == NULL)
254*7304104dSAndroid Build Coastguard Worker comp_dir = "";
255*7304104dSAndroid Build Coastguard Worker
256*7304104dSAndroid Build Coastguard Worker if (verbose)
257*7304104dSAndroid Build Coastguard Worker clog << "searching for sources for cu=" << cuname
258*7304104dSAndroid Build Coastguard Worker << " comp_dir=" << comp_dir << " #files=" << nfiles
259*7304104dSAndroid Build Coastguard Worker << " #dirs=" << ndirs << endl;
260*7304104dSAndroid Build Coastguard Worker
261*7304104dSAndroid Build Coastguard Worker if (comp_dir[0] == '\0' && cuname[0] != '/')
262*7304104dSAndroid Build Coastguard Worker {
263*7304104dSAndroid Build Coastguard Worker /* This is a common symptom for dwz-compressed debug files,
264*7304104dSAndroid Build Coastguard Worker where the altdebug file cannot be resolved. */
265*7304104dSAndroid Build Coastguard Worker if (verbose)
266*7304104dSAndroid Build Coastguard Worker clog << "skipping cu=" << cuname << " due to empty comp_dir" << endl;
267*7304104dSAndroid Build Coastguard Worker continue;
268*7304104dSAndroid Build Coastguard Worker }
269*7304104dSAndroid Build Coastguard Worker for (size_t f = 1; f < nfiles; ++f)
270*7304104dSAndroid Build Coastguard Worker {
271*7304104dSAndroid Build Coastguard Worker const char *hat;
272*7304104dSAndroid Build Coastguard Worker if (CU_only)
273*7304104dSAndroid Build Coastguard Worker {
274*7304104dSAndroid Build Coastguard Worker if (strcmp(cuname, "<unknown>") == 0 || strcmp(cuname, "<artificial>") == 0 )
275*7304104dSAndroid Build Coastguard Worker continue;
276*7304104dSAndroid Build Coastguard Worker hat = cuname;
277*7304104dSAndroid Build Coastguard Worker }
278*7304104dSAndroid Build Coastguard Worker else
279*7304104dSAndroid Build Coastguard Worker hat = dwarf_filesrc (files, f, NULL, NULL);
280*7304104dSAndroid Build Coastguard Worker
281*7304104dSAndroid Build Coastguard Worker if (hat == NULL)
282*7304104dSAndroid Build Coastguard Worker continue;
283*7304104dSAndroid Build Coastguard Worker
284*7304104dSAndroid Build Coastguard Worker if (string(hat).find("<built-in>")
285*7304104dSAndroid Build Coastguard Worker != string::npos) /* gcc intrinsics, don't bother recording */
286*7304104dSAndroid Build Coastguard Worker continue;
287*7304104dSAndroid Build Coastguard Worker
288*7304104dSAndroid Build Coastguard Worker string waldo;
289*7304104dSAndroid Build Coastguard Worker if (hat[0] == '/') /* absolute */
290*7304104dSAndroid Build Coastguard Worker waldo = (string (hat));
291*7304104dSAndroid Build Coastguard Worker else if (comp_dir[0] != '\0') /* comp_dir relative */
292*7304104dSAndroid Build Coastguard Worker waldo = (string (comp_dir) + string ("/") + string (hat));
293*7304104dSAndroid Build Coastguard Worker else
294*7304104dSAndroid Build Coastguard Worker {
295*7304104dSAndroid Build Coastguard Worker if (verbose)
296*7304104dSAndroid Build Coastguard Worker clog << "skipping file=" << hat << " due to empty comp_dir" << endl;
297*7304104dSAndroid Build Coastguard Worker continue;
298*7304104dSAndroid Build Coastguard Worker }
299*7304104dSAndroid Build Coastguard Worker waldo = canonicalize_path (waldo);
300*7304104dSAndroid Build Coastguard Worker debug_sourcefiles.insert (make_pair(waldo, dwflmod));
301*7304104dSAndroid Build Coastguard Worker }
302*7304104dSAndroid Build Coastguard Worker }
303*7304104dSAndroid Build Coastguard Worker return DWARF_CB_OK;
304*7304104dSAndroid Build Coastguard Worker }
305*7304104dSAndroid Build Coastguard Worker
306*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
zip_files()307*7304104dSAndroid Build Coastguard Worker void zip_files()
308*7304104dSAndroid Build Coastguard Worker {
309*7304104dSAndroid Build Coastguard Worker struct archive *a = archive_write_new();
310*7304104dSAndroid Build Coastguard Worker struct stat st;
311*7304104dSAndroid Build Coastguard Worker char buff[BUFFER_SIZE];
312*7304104dSAndroid Build Coastguard Worker int len;
313*7304104dSAndroid Build Coastguard Worker int fd;
314*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
315*7304104dSAndroid Build Coastguard Worker /* Initialize a debuginfod client. */
316*7304104dSAndroid Build Coastguard Worker static unique_ptr <debuginfod_client, void (*)(debuginfod_client*)>
317*7304104dSAndroid Build Coastguard Worker client (debuginfod_begin(), &debuginfod_end);
318*7304104dSAndroid Build Coastguard Worker #endif
319*7304104dSAndroid Build Coastguard Worker
320*7304104dSAndroid Build Coastguard Worker archive_write_set_format_zip(a);
321*7304104dSAndroid Build Coastguard Worker archive_write_open_fd(a, STDOUT_FILENO);
322*7304104dSAndroid Build Coastguard Worker
323*7304104dSAndroid Build Coastguard Worker int missing_files = 0;
324*7304104dSAndroid Build Coastguard Worker for (const auto &pair : debug_sourcefiles)
325*7304104dSAndroid Build Coastguard Worker {
326*7304104dSAndroid Build Coastguard Worker fd = -1;
327*7304104dSAndroid Build Coastguard Worker const std::string &file_path = pair.first;
328*7304104dSAndroid Build Coastguard Worker
329*7304104dSAndroid Build Coastguard Worker /* Attempt to query debuginfod client to fetch source files. */
330*7304104dSAndroid Build Coastguard Worker #ifdef ENABLE_LIBDEBUGINFOD
331*7304104dSAndroid Build Coastguard Worker Dwfl_Module* dwflmod = pair.second;
332*7304104dSAndroid Build Coastguard Worker /* Obtain source file's build ID. */
333*7304104dSAndroid Build Coastguard Worker const unsigned char *bits;
334*7304104dSAndroid Build Coastguard Worker GElf_Addr vaddr;
335*7304104dSAndroid Build Coastguard Worker int bits_length = dwfl_module_build_id(dwflmod, &bits, &vaddr);
336*7304104dSAndroid Build Coastguard Worker /* Ensure successful client and build ID acquisition. */
337*7304104dSAndroid Build Coastguard Worker if (client.get() != NULL && bits_length > 0)
338*7304104dSAndroid Build Coastguard Worker {
339*7304104dSAndroid Build Coastguard Worker fd = debuginfod_find_source(client.get(),
340*7304104dSAndroid Build Coastguard Worker bits, bits_length,
341*7304104dSAndroid Build Coastguard Worker file_path.c_str(), NULL);
342*7304104dSAndroid Build Coastguard Worker }
343*7304104dSAndroid Build Coastguard Worker else
344*7304104dSAndroid Build Coastguard Worker {
345*7304104dSAndroid Build Coastguard Worker if (client.get() == NULL)
346*7304104dSAndroid Build Coastguard Worker cerr << "Error: Failed to initialize debuginfod client." << endl;
347*7304104dSAndroid Build Coastguard Worker else
348*7304104dSAndroid Build Coastguard Worker cerr << "Error: Invalid build ID length (" << bits_length << ")." << endl;
349*7304104dSAndroid Build Coastguard Worker }
350*7304104dSAndroid Build Coastguard Worker #endif
351*7304104dSAndroid Build Coastguard Worker
352*7304104dSAndroid Build Coastguard Worker if (!no_backup)
353*7304104dSAndroid Build Coastguard Worker /* Files could not be located using debuginfod, search locally */
354*7304104dSAndroid Build Coastguard Worker if (fd < 0)
355*7304104dSAndroid Build Coastguard Worker fd = open(file_path.c_str(), O_RDONLY);
356*7304104dSAndroid Build Coastguard Worker if (fd < 0)
357*7304104dSAndroid Build Coastguard Worker {
358*7304104dSAndroid Build Coastguard Worker if (verbose)
359*7304104dSAndroid Build Coastguard Worker cerr << file_path << endl;
360*7304104dSAndroid Build Coastguard Worker missing_files++;
361*7304104dSAndroid Build Coastguard Worker continue;
362*7304104dSAndroid Build Coastguard Worker }
363*7304104dSAndroid Build Coastguard Worker
364*7304104dSAndroid Build Coastguard Worker /* Create an entry for each file including file information to be placed in the zip. */
365*7304104dSAndroid Build Coastguard Worker if (fstat(fd, &st) == -1)
366*7304104dSAndroid Build Coastguard Worker {
367*7304104dSAndroid Build Coastguard Worker if (verbose)
368*7304104dSAndroid Build Coastguard Worker cerr << file_path << endl;
369*7304104dSAndroid Build Coastguard Worker missing_files++;
370*7304104dSAndroid Build Coastguard Worker if (verbose)
371*7304104dSAndroid Build Coastguard Worker cerr << "Error: Failed to get file status for " << file_path << ": " << strerror(errno) << endl;
372*7304104dSAndroid Build Coastguard Worker continue;
373*7304104dSAndroid Build Coastguard Worker }
374*7304104dSAndroid Build Coastguard Worker struct archive_entry *entry = archive_entry_new();
375*7304104dSAndroid Build Coastguard Worker /* Removing first "/"" to make the path "relative" before zipping, otherwise warnings are raised when unzipping. */
376*7304104dSAndroid Build Coastguard Worker string entry_name = file_path.substr(file_path.find_first_of('/') + 1);
377*7304104dSAndroid Build Coastguard Worker archive_entry_set_pathname(entry, entry_name.c_str());
378*7304104dSAndroid Build Coastguard Worker archive_entry_copy_stat(entry, &st);
379*7304104dSAndroid Build Coastguard Worker if (archive_write_header(a, entry) != ARCHIVE_OK)
380*7304104dSAndroid Build Coastguard Worker {
381*7304104dSAndroid Build Coastguard Worker if (verbose)
382*7304104dSAndroid Build Coastguard Worker cerr << file_path << endl;
383*7304104dSAndroid Build Coastguard Worker missing_files++;
384*7304104dSAndroid Build Coastguard Worker if (verbose)
385*7304104dSAndroid Build Coastguard Worker cerr << "Error: failed to write header for " << file_path << ": " << archive_error_string(a) << endl;
386*7304104dSAndroid Build Coastguard Worker continue;
387*7304104dSAndroid Build Coastguard Worker }
388*7304104dSAndroid Build Coastguard Worker
389*7304104dSAndroid Build Coastguard Worker /* Write the file to the zip. */
390*7304104dSAndroid Build Coastguard Worker len = read(fd, buff, sizeof(buff));
391*7304104dSAndroid Build Coastguard Worker if (len == -1)
392*7304104dSAndroid Build Coastguard Worker {
393*7304104dSAndroid Build Coastguard Worker if (verbose)
394*7304104dSAndroid Build Coastguard Worker cerr << file_path << endl;
395*7304104dSAndroid Build Coastguard Worker missing_files++;
396*7304104dSAndroid Build Coastguard Worker if (verbose)
397*7304104dSAndroid Build Coastguard Worker cerr << "Error: Failed to open file: " << file_path << ": " << strerror(errno) <<endl;
398*7304104dSAndroid Build Coastguard Worker continue;
399*7304104dSAndroid Build Coastguard Worker }
400*7304104dSAndroid Build Coastguard Worker while (len > 0)
401*7304104dSAndroid Build Coastguard Worker {
402*7304104dSAndroid Build Coastguard Worker if (archive_write_data(a, buff, len) < ARCHIVE_OK)
403*7304104dSAndroid Build Coastguard Worker {
404*7304104dSAndroid Build Coastguard Worker if (verbose)
405*7304104dSAndroid Build Coastguard Worker cerr << "Error: Failed to read from the file: " << file_path << ": " << strerror(errno) << endl;
406*7304104dSAndroid Build Coastguard Worker break;
407*7304104dSAndroid Build Coastguard Worker }
408*7304104dSAndroid Build Coastguard Worker len = read(fd, buff, sizeof(buff));
409*7304104dSAndroid Build Coastguard Worker }
410*7304104dSAndroid Build Coastguard Worker close(fd);
411*7304104dSAndroid Build Coastguard Worker archive_entry_free(entry);
412*7304104dSAndroid Build Coastguard Worker }
413*7304104dSAndroid Build Coastguard Worker if (verbose && missing_files > 0 )
414*7304104dSAndroid Build Coastguard Worker cerr << missing_files << " file(s) listed above could not be found. " << endl;
415*7304104dSAndroid Build Coastguard Worker
416*7304104dSAndroid Build Coastguard Worker archive_write_close(a);
417*7304104dSAndroid Build Coastguard Worker archive_write_free(a);
418*7304104dSAndroid Build Coastguard Worker }
419*7304104dSAndroid Build Coastguard Worker #endif
420*7304104dSAndroid Build Coastguard Worker
421*7304104dSAndroid Build Coastguard Worker int
main(int argc,char * argv[])422*7304104dSAndroid Build Coastguard Worker main (int argc, char *argv[])
423*7304104dSAndroid Build Coastguard Worker {
424*7304104dSAndroid Build Coastguard Worker int remaining;
425*7304104dSAndroid Build Coastguard Worker
426*7304104dSAndroid Build Coastguard Worker /* Parse and process arguments. This includes opening the modules. */
427*7304104dSAndroid Build Coastguard Worker argp_children[0].argp = dwfl_standard_argp ();
428*7304104dSAndroid Build Coastguard Worker argp_children[0].group = 1;
429*7304104dSAndroid Build Coastguard Worker
430*7304104dSAndroid Build Coastguard Worker Dwfl *dwfl = NULL;
431*7304104dSAndroid Build Coastguard Worker (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl);
432*7304104dSAndroid Build Coastguard Worker assert (dwfl != NULL);
433*7304104dSAndroid Build Coastguard Worker /* Process all loaded modules - probably just one, except if -K or -p is used. */
434*7304104dSAndroid Build Coastguard Worker (void) dwfl_getmodules (dwfl, &collect_sourcefiles, NULL, 0);
435*7304104dSAndroid Build Coastguard Worker
436*7304104dSAndroid Build Coastguard Worker if (!debug_sourcefiles.empty ())
437*7304104dSAndroid Build Coastguard Worker {
438*7304104dSAndroid Build Coastguard Worker #ifdef HAVE_LIBARCHIVE
439*7304104dSAndroid Build Coastguard Worker if (zip)
440*7304104dSAndroid Build Coastguard Worker zip_files();
441*7304104dSAndroid Build Coastguard Worker else
442*7304104dSAndroid Build Coastguard Worker #endif
443*7304104dSAndroid Build Coastguard Worker {
444*7304104dSAndroid Build Coastguard Worker for (const auto &pair : debug_sourcefiles)
445*7304104dSAndroid Build Coastguard Worker {
446*7304104dSAndroid Build Coastguard Worker cout << pair.first;
447*7304104dSAndroid Build Coastguard Worker if (null_arg)
448*7304104dSAndroid Build Coastguard Worker cout << '\0';
449*7304104dSAndroid Build Coastguard Worker else
450*7304104dSAndroid Build Coastguard Worker cout << '\n';
451*7304104dSAndroid Build Coastguard Worker }
452*7304104dSAndroid Build Coastguard Worker }
453*7304104dSAndroid Build Coastguard Worker }
454*7304104dSAndroid Build Coastguard Worker
455*7304104dSAndroid Build Coastguard Worker dwfl_end (dwfl);
456*7304104dSAndroid Build Coastguard Worker return 0;
457*7304104dSAndroid Build Coastguard Worker }
458