xref: /aosp_15_r20/external/elfutils/src/srcfiles.cxx (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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