xref: /aosp_15_r20/external/elfutils/libdwfl/linux-kernel-modules.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1*7304104dSAndroid Build Coastguard Worker /* Standard libdwfl callbacks for debugging the running Linux kernel.
2*7304104dSAndroid Build Coastguard Worker    Copyright (C) 2005-2011, 2013, 2014, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker    This file is part of elfutils.
4*7304104dSAndroid Build Coastguard Worker 
5*7304104dSAndroid Build Coastguard Worker    This file is free software; you can redistribute it and/or modify
6*7304104dSAndroid Build Coastguard Worker    it under the terms of either
7*7304104dSAndroid Build Coastguard Worker 
8*7304104dSAndroid Build Coastguard Worker      * the GNU Lesser General Public License as published by the Free
9*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 3 of the License, or (at
10*7304104dSAndroid Build Coastguard Worker        your option) any later version
11*7304104dSAndroid Build Coastguard Worker 
12*7304104dSAndroid Build Coastguard Worker    or
13*7304104dSAndroid Build Coastguard Worker 
14*7304104dSAndroid Build Coastguard Worker      * the GNU General Public License as published by the Free
15*7304104dSAndroid Build Coastguard Worker        Software Foundation; either version 2 of the License, or (at
16*7304104dSAndroid Build Coastguard Worker        your option) any later version
17*7304104dSAndroid Build Coastguard Worker 
18*7304104dSAndroid Build Coastguard Worker    or both in parallel, as here.
19*7304104dSAndroid Build Coastguard Worker 
20*7304104dSAndroid Build Coastguard Worker    elfutils is distributed in the hope that it will be useful, but
21*7304104dSAndroid Build Coastguard Worker    WITHOUT ANY WARRANTY; without even the implied warranty of
22*7304104dSAndroid Build Coastguard Worker    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23*7304104dSAndroid Build Coastguard Worker    General Public License for more details.
24*7304104dSAndroid Build Coastguard Worker 
25*7304104dSAndroid Build Coastguard Worker    You should have received copies of the GNU General Public License and
26*7304104dSAndroid Build Coastguard Worker    the GNU Lesser General Public License along with this program.  If
27*7304104dSAndroid Build Coastguard Worker    not, see <http://www.gnu.org/licenses/>.  */
28*7304104dSAndroid Build Coastguard Worker 
29*7304104dSAndroid Build Coastguard Worker /* In case we have a bad fts we include this before config.h because it
30*7304104dSAndroid Build Coastguard Worker    can't handle _FILE_OFFSET_BITS.
31*7304104dSAndroid Build Coastguard Worker    Everything we need here is fine if its declarations just come first.
32*7304104dSAndroid Build Coastguard Worker    Also, include sys/types.h before fts. On some systems fts.h is not self
33*7304104dSAndroid Build Coastguard Worker    contained. */
34*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
35*7304104dSAndroid Build Coastguard Worker   #include <sys/types.h>
36*7304104dSAndroid Build Coastguard Worker   #include <fts.h>
37*7304104dSAndroid Build Coastguard Worker #endif
38*7304104dSAndroid Build Coastguard Worker 
39*7304104dSAndroid Build Coastguard Worker #include <config.h>
40*7304104dSAndroid Build Coastguard Worker #include <system.h>
41*7304104dSAndroid Build Coastguard Worker 
42*7304104dSAndroid Build Coastguard Worker #include "libelfP.h"
43*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
44*7304104dSAndroid Build Coastguard Worker #include <inttypes.h>
45*7304104dSAndroid Build Coastguard Worker #include <errno.h>
46*7304104dSAndroid Build Coastguard Worker #include <stdio.h>
47*7304104dSAndroid Build Coastguard Worker #include <stdio_ext.h>
48*7304104dSAndroid Build Coastguard Worker #include <string.h>
49*7304104dSAndroid Build Coastguard Worker #include <stdlib.h>
50*7304104dSAndroid Build Coastguard Worker #include <sys/utsname.h>
51*7304104dSAndroid Build Coastguard Worker #include <fcntl.h>
52*7304104dSAndroid Build Coastguard Worker #include <unistd.h>
53*7304104dSAndroid Build Coastguard Worker 
54*7304104dSAndroid Build Coastguard Worker /* If fts.h is included before config.h, its indirect inclusions may not
55*7304104dSAndroid Build Coastguard Worker    give us the right LFS aliases of these functions, so map them manually.  */
56*7304104dSAndroid Build Coastguard Worker #ifdef BAD_FTS
57*7304104dSAndroid Build Coastguard Worker   #ifdef _FILE_OFFSET_BITS
58*7304104dSAndroid Build Coastguard Worker     #define open open64
59*7304104dSAndroid Build Coastguard Worker     #define fopen fopen64
60*7304104dSAndroid Build Coastguard Worker   #endif
61*7304104dSAndroid Build Coastguard Worker #else
62*7304104dSAndroid Build Coastguard Worker   #include <sys/types.h>
63*7304104dSAndroid Build Coastguard Worker   #include <fts.h>
64*7304104dSAndroid Build Coastguard Worker #endif
65*7304104dSAndroid Build Coastguard Worker 
66*7304104dSAndroid Build Coastguard Worker 
67*7304104dSAndroid Build Coastguard Worker #define KERNEL_MODNAME	"kernel"
68*7304104dSAndroid Build Coastguard Worker 
69*7304104dSAndroid Build Coastguard Worker #define MODULEDIRFMT	"/lib/modules/%s"
70*7304104dSAndroid Build Coastguard Worker 
71*7304104dSAndroid Build Coastguard Worker #define KNOTESFILE	"/sys/kernel/notes"
72*7304104dSAndroid Build Coastguard Worker #define	MODNOTESFMT	"/sys/module/%s/notes"
73*7304104dSAndroid Build Coastguard Worker #define KSYMSFILE	"/proc/kallsyms"
74*7304104dSAndroid Build Coastguard Worker #define MODULELIST	"/proc/modules"
75*7304104dSAndroid Build Coastguard Worker #define	SECADDRDIRFMT	"/sys/module/%s/sections/"
76*7304104dSAndroid Build Coastguard Worker #define MODULE_SECT_NAME_LEN 32	/* Minimum any linux/module.h has had.  */
77*7304104dSAndroid Build Coastguard Worker 
78*7304104dSAndroid Build Coastguard Worker 
79*7304104dSAndroid Build Coastguard Worker static const char *vmlinux_suffixes[] =
80*7304104dSAndroid Build Coastguard Worker   {
81*7304104dSAndroid Build Coastguard Worker     ".gz",
82*7304104dSAndroid Build Coastguard Worker #ifdef USE_BZLIB
83*7304104dSAndroid Build Coastguard Worker     ".bz2",
84*7304104dSAndroid Build Coastguard Worker #endif
85*7304104dSAndroid Build Coastguard Worker #ifdef USE_LZMA
86*7304104dSAndroid Build Coastguard Worker     ".xz",
87*7304104dSAndroid Build Coastguard Worker #endif
88*7304104dSAndroid Build Coastguard Worker   };
89*7304104dSAndroid Build Coastguard Worker 
90*7304104dSAndroid Build Coastguard Worker /* Try to open the given file as it is or under the debuginfo directory.  */
91*7304104dSAndroid Build Coastguard Worker static int
try_kernel_name(Dwfl * dwfl,char ** fname,bool try_debug)92*7304104dSAndroid Build Coastguard Worker try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
93*7304104dSAndroid Build Coastguard Worker {
94*7304104dSAndroid Build Coastguard Worker   if (*fname == NULL)
95*7304104dSAndroid Build Coastguard Worker     return -1;
96*7304104dSAndroid Build Coastguard Worker 
97*7304104dSAndroid Build Coastguard Worker   /* Don't bother trying *FNAME itself here if the path will cause it to be
98*7304104dSAndroid Build Coastguard Worker      tried because we give its own basename as DEBUGLINK_FILE.  */
99*7304104dSAndroid Build Coastguard Worker   int fd = ((((dwfl->callbacks->debuginfo_path
100*7304104dSAndroid Build Coastguard Worker 	       ? *dwfl->callbacks->debuginfo_path : NULL)
101*7304104dSAndroid Build Coastguard Worker 	      ?: DEFAULT_DEBUGINFO_PATH)[0] == ':') ? -1
102*7304104dSAndroid Build Coastguard Worker 	    : TEMP_FAILURE_RETRY (open (*fname, O_RDONLY)));
103*7304104dSAndroid Build Coastguard Worker 
104*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
105*7304104dSAndroid Build Coastguard Worker     {
106*7304104dSAndroid Build Coastguard Worker       Dwfl_Module fakemod = { .dwfl = dwfl };
107*7304104dSAndroid Build Coastguard Worker 
108*7304104dSAndroid Build Coastguard Worker       if (try_debug)
109*7304104dSAndroid Build Coastguard Worker 	/* Passing NULL for DEBUGLINK_FILE searches for both the basenamer
110*7304104dSAndroid Build Coastguard Worker 	   "vmlinux" and the default of basename + ".debug", to look for
111*7304104dSAndroid Build Coastguard Worker 	   "vmlinux.debug" files.  */
112*7304104dSAndroid Build Coastguard Worker 	fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
113*7304104dSAndroid Build Coastguard Worker 						   *fname, NULL, 0,
114*7304104dSAndroid Build Coastguard Worker 						   &fakemod.debug.name);
115*7304104dSAndroid Build Coastguard Worker       else
116*7304104dSAndroid Build Coastguard Worker 	/* Try the file's unadorned basename as DEBUGLINK_FILE,
117*7304104dSAndroid Build Coastguard Worker 	   to look only for "vmlinux" files.  */
118*7304104dSAndroid Build Coastguard Worker 	fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
119*7304104dSAndroid Build Coastguard Worker 						   *fname, xbasename (*fname),
120*7304104dSAndroid Build Coastguard Worker 						   0, &fakemod.debug.name);
121*7304104dSAndroid Build Coastguard Worker 
122*7304104dSAndroid Build Coastguard Worker       if (fakemod.debug.name != NULL)
123*7304104dSAndroid Build Coastguard Worker 	{
124*7304104dSAndroid Build Coastguard Worker 	  free (*fname);
125*7304104dSAndroid Build Coastguard Worker 	  *fname = fakemod.debug.name;
126*7304104dSAndroid Build Coastguard Worker 	}
127*7304104dSAndroid Build Coastguard Worker     }
128*7304104dSAndroid Build Coastguard Worker 
129*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
130*7304104dSAndroid Build Coastguard Worker     for (size_t i = 0;
131*7304104dSAndroid Build Coastguard Worker 	 i < sizeof vmlinux_suffixes / sizeof vmlinux_suffixes[0] && fd < 0;
132*7304104dSAndroid Build Coastguard Worker 	 ++i)
133*7304104dSAndroid Build Coastguard Worker       {
134*7304104dSAndroid Build Coastguard Worker 	char *zname;
135*7304104dSAndroid Build Coastguard Worker 	if (asprintf (&zname, "%s%s", *fname, vmlinux_suffixes[i]) > 0)
136*7304104dSAndroid Build Coastguard Worker 	  {
137*7304104dSAndroid Build Coastguard Worker 	    fd = TEMP_FAILURE_RETRY (open (zname, O_RDONLY));
138*7304104dSAndroid Build Coastguard Worker 	    if (fd < 0)
139*7304104dSAndroid Build Coastguard Worker 	      free (zname);
140*7304104dSAndroid Build Coastguard Worker 	    else
141*7304104dSAndroid Build Coastguard Worker 	      {
142*7304104dSAndroid Build Coastguard Worker 		free (*fname);
143*7304104dSAndroid Build Coastguard Worker 		*fname = zname;
144*7304104dSAndroid Build Coastguard Worker 	      }
145*7304104dSAndroid Build Coastguard Worker 	  }
146*7304104dSAndroid Build Coastguard Worker       }
147*7304104dSAndroid Build Coastguard Worker 
148*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
149*7304104dSAndroid Build Coastguard Worker     {
150*7304104dSAndroid Build Coastguard Worker       free (*fname);
151*7304104dSAndroid Build Coastguard Worker       *fname = NULL;
152*7304104dSAndroid Build Coastguard Worker     }
153*7304104dSAndroid Build Coastguard Worker 
154*7304104dSAndroid Build Coastguard Worker   return fd;
155*7304104dSAndroid Build Coastguard Worker }
156*7304104dSAndroid Build Coastguard Worker 
157*7304104dSAndroid Build Coastguard Worker static inline const char *
kernel_release(void)158*7304104dSAndroid Build Coastguard Worker kernel_release (void)
159*7304104dSAndroid Build Coastguard Worker {
160*7304104dSAndroid Build Coastguard Worker #ifdef __linux__
161*7304104dSAndroid Build Coastguard Worker   /* Cache the `uname -r` string we'll use.  */
162*7304104dSAndroid Build Coastguard Worker   static struct utsname utsname;
163*7304104dSAndroid Build Coastguard Worker   if (utsname.release[0] == '\0' && uname (&utsname) != 0)
164*7304104dSAndroid Build Coastguard Worker     return NULL;
165*7304104dSAndroid Build Coastguard Worker   return utsname.release;
166*7304104dSAndroid Build Coastguard Worker #else
167*7304104dSAndroid Build Coastguard Worker   /* Used for finding the running linux kernel, which isn't supported
168*7304104dSAndroid Build Coastguard Worker      on non-linux kernel systems.  */
169*7304104dSAndroid Build Coastguard Worker   errno = ENOTSUP;
170*7304104dSAndroid Build Coastguard Worker   return NULL;
171*7304104dSAndroid Build Coastguard Worker #endif
172*7304104dSAndroid Build Coastguard Worker }
173*7304104dSAndroid Build Coastguard Worker 
174*7304104dSAndroid Build Coastguard Worker static int
find_kernel_elf(Dwfl * dwfl,const char * release,char ** fname)175*7304104dSAndroid Build Coastguard Worker find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
176*7304104dSAndroid Build Coastguard Worker {
177*7304104dSAndroid Build Coastguard Worker   /* First try to find an uncompressed vmlinux image.  Possibly
178*7304104dSAndroid Build Coastguard Worker      including debuginfo.  */
179*7304104dSAndroid Build Coastguard Worker   if (release == NULL
180*7304104dSAndroid Build Coastguard Worker       || ((release[0] == '/'
181*7304104dSAndroid Build Coastguard Worker 	   ? asprintf (fname, "%s/vmlinux", release)
182*7304104dSAndroid Build Coastguard Worker 	   : asprintf (fname, "/boot/vmlinux-%s", release)) < 0))
183*7304104dSAndroid Build Coastguard Worker     return -1;
184*7304104dSAndroid Build Coastguard Worker 
185*7304104dSAndroid Build Coastguard Worker   int fd = try_kernel_name (dwfl, fname, true);
186*7304104dSAndroid Build Coastguard Worker   if (fd < 0 && release[0] != '/')
187*7304104dSAndroid Build Coastguard Worker     {
188*7304104dSAndroid Build Coastguard Worker       free (*fname);
189*7304104dSAndroid Build Coastguard Worker       if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
190*7304104dSAndroid Build Coastguard Worker 	return -1;
191*7304104dSAndroid Build Coastguard Worker       fd = try_kernel_name (dwfl, fname, true);
192*7304104dSAndroid Build Coastguard Worker     }
193*7304104dSAndroid Build Coastguard Worker 
194*7304104dSAndroid Build Coastguard Worker   /* There might be a compressed vmlinuz image.  Probably without
195*7304104dSAndroid Build Coastguard Worker      debuginfo, but try to find it under the debug path also, just in
196*7304104dSAndroid Build Coastguard Worker      case.  */
197*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
198*7304104dSAndroid Build Coastguard Worker     {
199*7304104dSAndroid Build Coastguard Worker       free (*fname);
200*7304104dSAndroid Build Coastguard Worker       if ((release[0] == '/'
201*7304104dSAndroid Build Coastguard Worker            ? asprintf (fname, "%s/vmlinuz", release)
202*7304104dSAndroid Build Coastguard Worker            : asprintf (fname, "/boot/vmlinuz-%s", release)) < 0)
203*7304104dSAndroid Build Coastguard Worker         return -1;
204*7304104dSAndroid Build Coastguard Worker 
205*7304104dSAndroid Build Coastguard Worker       fd = try_kernel_name (dwfl, fname, true);
206*7304104dSAndroid Build Coastguard Worker       if (fd < 0 && release[0] != '/')
207*7304104dSAndroid Build Coastguard Worker 	{
208*7304104dSAndroid Build Coastguard Worker 	  free (*fname);
209*7304104dSAndroid Build Coastguard Worker 	  if (asprintf (fname, MODULEDIRFMT "/vmlinuz", release) < 0)
210*7304104dSAndroid Build Coastguard Worker 	    return -1;
211*7304104dSAndroid Build Coastguard Worker 	  fd = try_kernel_name (dwfl, fname, true);
212*7304104dSAndroid Build Coastguard Worker 	}
213*7304104dSAndroid Build Coastguard Worker     }
214*7304104dSAndroid Build Coastguard Worker 
215*7304104dSAndroid Build Coastguard Worker   return fd;
216*7304104dSAndroid Build Coastguard Worker }
217*7304104dSAndroid Build Coastguard Worker 
218*7304104dSAndroid Build Coastguard Worker static int
get_release(Dwfl * dwfl,const char ** release)219*7304104dSAndroid Build Coastguard Worker get_release (Dwfl *dwfl, const char **release)
220*7304104dSAndroid Build Coastguard Worker {
221*7304104dSAndroid Build Coastguard Worker   if (dwfl == NULL)
222*7304104dSAndroid Build Coastguard Worker     return -1;
223*7304104dSAndroid Build Coastguard Worker 
224*7304104dSAndroid Build Coastguard Worker   const char *release_string = release == NULL ? NULL : *release;
225*7304104dSAndroid Build Coastguard Worker   if (release_string == NULL)
226*7304104dSAndroid Build Coastguard Worker     {
227*7304104dSAndroid Build Coastguard Worker       release_string = kernel_release ();
228*7304104dSAndroid Build Coastguard Worker       if (release_string == NULL)
229*7304104dSAndroid Build Coastguard Worker 	return errno;
230*7304104dSAndroid Build Coastguard Worker       if (release != NULL)
231*7304104dSAndroid Build Coastguard Worker 	*release = release_string;
232*7304104dSAndroid Build Coastguard Worker     }
233*7304104dSAndroid Build Coastguard Worker 
234*7304104dSAndroid Build Coastguard Worker   return 0;
235*7304104dSAndroid Build Coastguard Worker }
236*7304104dSAndroid Build Coastguard Worker 
237*7304104dSAndroid Build Coastguard Worker static int
report_kernel(Dwfl * dwfl,const char ** release,int (* predicate)(const char * module,const char * file))238*7304104dSAndroid Build Coastguard Worker report_kernel (Dwfl *dwfl, const char **release,
239*7304104dSAndroid Build Coastguard Worker 	       int (*predicate) (const char *module, const char *file))
240*7304104dSAndroid Build Coastguard Worker {
241*7304104dSAndroid Build Coastguard Worker   int result = get_release (dwfl, release);
242*7304104dSAndroid Build Coastguard Worker   if (unlikely (result != 0))
243*7304104dSAndroid Build Coastguard Worker     return result;
244*7304104dSAndroid Build Coastguard Worker 
245*7304104dSAndroid Build Coastguard Worker   if (release == NULL || *release == NULL)
246*7304104dSAndroid Build Coastguard Worker     return EINVAL;
247*7304104dSAndroid Build Coastguard Worker 
248*7304104dSAndroid Build Coastguard Worker   char *fname;
249*7304104dSAndroid Build Coastguard Worker   int fd = find_kernel_elf (dwfl, *release, &fname);
250*7304104dSAndroid Build Coastguard Worker 
251*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
252*7304104dSAndroid Build Coastguard Worker     result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
253*7304104dSAndroid Build Coastguard Worker 	      ? 0 : errno ?: ENOENT);
254*7304104dSAndroid Build Coastguard Worker   else
255*7304104dSAndroid Build Coastguard Worker     {
256*7304104dSAndroid Build Coastguard Worker       bool report = true;
257*7304104dSAndroid Build Coastguard Worker 
258*7304104dSAndroid Build Coastguard Worker       if (predicate != NULL)
259*7304104dSAndroid Build Coastguard Worker 	{
260*7304104dSAndroid Build Coastguard Worker 	  /* Let the predicate decide whether to use this one.  */
261*7304104dSAndroid Build Coastguard Worker 	  int want = (*predicate) (KERNEL_MODNAME, fname);
262*7304104dSAndroid Build Coastguard Worker 	  if (want < 0)
263*7304104dSAndroid Build Coastguard Worker 	    result = errno;
264*7304104dSAndroid Build Coastguard Worker 	  report = want > 0;
265*7304104dSAndroid Build Coastguard Worker 	}
266*7304104dSAndroid Build Coastguard Worker 
267*7304104dSAndroid Build Coastguard Worker       if (report)
268*7304104dSAndroid Build Coastguard Worker 	{
269*7304104dSAndroid Build Coastguard Worker 	  /* Note that on some architectures (e.g. x86_64) the vmlinux
270*7304104dSAndroid Build Coastguard Worker 	     is ET_EXEC, while on others (e.g. ppc64) it is ET_DYN.
271*7304104dSAndroid Build Coastguard Worker 	     In both cases the phdr p_vaddr load address will be non-zero.
272*7304104dSAndroid Build Coastguard Worker 	     We want the image to be placed as if it was ET_DYN, so
273*7304104dSAndroid Build Coastguard Worker 	     pass true for add_p_vaddr which will do the right thing
274*7304104dSAndroid Build Coastguard Worker 	     (in combination with a zero base) in either case.  */
275*7304104dSAndroid Build Coastguard Worker 	  Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, KERNEL_MODNAME,
276*7304104dSAndroid Build Coastguard Worker 						      fname, fd, 0, true);
277*7304104dSAndroid Build Coastguard Worker 	  if (mod == NULL)
278*7304104dSAndroid Build Coastguard Worker 	    result = -1;
279*7304104dSAndroid Build Coastguard Worker 	  else
280*7304104dSAndroid Build Coastguard Worker 	    /* The kernel is ET_EXEC, but always treat it as relocatable.  */
281*7304104dSAndroid Build Coastguard Worker 	    mod->e_type = ET_DYN;
282*7304104dSAndroid Build Coastguard Worker 	}
283*7304104dSAndroid Build Coastguard Worker 
284*7304104dSAndroid Build Coastguard Worker       free (fname);
285*7304104dSAndroid Build Coastguard Worker 
286*7304104dSAndroid Build Coastguard Worker       if (!report || result < 0)
287*7304104dSAndroid Build Coastguard Worker 	close (fd);
288*7304104dSAndroid Build Coastguard Worker     }
289*7304104dSAndroid Build Coastguard Worker 
290*7304104dSAndroid Build Coastguard Worker   return result;
291*7304104dSAndroid Build Coastguard Worker }
292*7304104dSAndroid Build Coastguard Worker 
293*7304104dSAndroid Build Coastguard Worker /* Look for a kernel debug archive.  If we find one, report all its modules.
294*7304104dSAndroid Build Coastguard Worker    If not, return ENOENT.  */
295*7304104dSAndroid Build Coastguard Worker static int
report_kernel_archive(Dwfl * dwfl,const char ** release,int (* predicate)(const char * module,const char * file))296*7304104dSAndroid Build Coastguard Worker report_kernel_archive (Dwfl *dwfl, const char **release,
297*7304104dSAndroid Build Coastguard Worker 		       int (*predicate) (const char *module, const char *file))
298*7304104dSAndroid Build Coastguard Worker {
299*7304104dSAndroid Build Coastguard Worker   int result = get_release (dwfl, release);
300*7304104dSAndroid Build Coastguard Worker   if (unlikely (result != 0))
301*7304104dSAndroid Build Coastguard Worker     return result;
302*7304104dSAndroid Build Coastguard Worker 
303*7304104dSAndroid Build Coastguard Worker   if (release == NULL || *release == NULL)
304*7304104dSAndroid Build Coastguard Worker     return EINVAL;
305*7304104dSAndroid Build Coastguard Worker 
306*7304104dSAndroid Build Coastguard Worker   char *archive;
307*7304104dSAndroid Build Coastguard Worker   int res = (((*release)[0] == '/')
308*7304104dSAndroid Build Coastguard Worker 	     ? asprintf (&archive, "%s/debug.a", *release)
309*7304104dSAndroid Build Coastguard Worker 	     : asprintf (&archive, MODULEDIRFMT "/debug.a", *release));
310*7304104dSAndroid Build Coastguard Worker   if (unlikely (res < 0))
311*7304104dSAndroid Build Coastguard Worker     return ENOMEM;
312*7304104dSAndroid Build Coastguard Worker 
313*7304104dSAndroid Build Coastguard Worker   int fd = try_kernel_name (dwfl, &archive, false);
314*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
315*7304104dSAndroid Build Coastguard Worker     result = errno ?: ENOENT;
316*7304104dSAndroid Build Coastguard Worker   else
317*7304104dSAndroid Build Coastguard Worker     {
318*7304104dSAndroid Build Coastguard Worker       /* We have the archive file open!  */
319*7304104dSAndroid Build Coastguard Worker       Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd,
320*7304104dSAndroid Build Coastguard Worker 						    true, predicate);
321*7304104dSAndroid Build Coastguard Worker       if (unlikely (last == NULL))
322*7304104dSAndroid Build Coastguard Worker 	result = -1;
323*7304104dSAndroid Build Coastguard Worker       else
324*7304104dSAndroid Build Coastguard Worker 	{
325*7304104dSAndroid Build Coastguard Worker 	  /* Find the kernel and move it to the head of the list.  */
326*7304104dSAndroid Build Coastguard Worker 	  Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
327*7304104dSAndroid Build Coastguard Worker 	  for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
328*7304104dSAndroid Build Coastguard Worker 	    if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel"))
329*7304104dSAndroid Build Coastguard Worker 	      {
330*7304104dSAndroid Build Coastguard Worker 		*prevp = m->next;
331*7304104dSAndroid Build Coastguard Worker 		m->next = *tailp;
332*7304104dSAndroid Build Coastguard Worker 		*tailp = m;
333*7304104dSAndroid Build Coastguard Worker 		break;
334*7304104dSAndroid Build Coastguard Worker 	      }
335*7304104dSAndroid Build Coastguard Worker 	}
336*7304104dSAndroid Build Coastguard Worker     }
337*7304104dSAndroid Build Coastguard Worker 
338*7304104dSAndroid Build Coastguard Worker   free (archive);
339*7304104dSAndroid Build Coastguard Worker   return result;
340*7304104dSAndroid Build Coastguard Worker }
341*7304104dSAndroid Build Coastguard Worker 
342*7304104dSAndroid Build Coastguard Worker static size_t
check_suffix(const FTSENT * f,size_t namelen)343*7304104dSAndroid Build Coastguard Worker check_suffix (const FTSENT *f, size_t namelen)
344*7304104dSAndroid Build Coastguard Worker {
345*7304104dSAndroid Build Coastguard Worker #define TRY(sfx)							\
346*7304104dSAndroid Build Coastguard Worker   if ((namelen ? f->fts_namelen == namelen + sizeof sfx - 1		\
347*7304104dSAndroid Build Coastguard Worker        : f->fts_namelen >= sizeof sfx)					\
348*7304104dSAndroid Build Coastguard Worker       && !memcmp (f->fts_name + f->fts_namelen - (sizeof sfx - 1),	\
349*7304104dSAndroid Build Coastguard Worker 		  sfx, sizeof sfx))					\
350*7304104dSAndroid Build Coastguard Worker     return sizeof sfx - 1
351*7304104dSAndroid Build Coastguard Worker 
352*7304104dSAndroid Build Coastguard Worker   TRY (".ko");
353*7304104dSAndroid Build Coastguard Worker   TRY (".ko.gz");
354*7304104dSAndroid Build Coastguard Worker #if USE_BZLIB
355*7304104dSAndroid Build Coastguard Worker   TRY (".ko.bz2");
356*7304104dSAndroid Build Coastguard Worker #endif
357*7304104dSAndroid Build Coastguard Worker #if USE_LZMA
358*7304104dSAndroid Build Coastguard Worker   TRY (".ko.xz");
359*7304104dSAndroid Build Coastguard Worker #endif
360*7304104dSAndroid Build Coastguard Worker #if USE_ZSTD
361*7304104dSAndroid Build Coastguard Worker   TRY (".ko.zst");
362*7304104dSAndroid Build Coastguard Worker #endif
363*7304104dSAndroid Build Coastguard Worker 
364*7304104dSAndroid Build Coastguard Worker   return 0;
365*7304104dSAndroid Build Coastguard Worker 
366*7304104dSAndroid Build Coastguard Worker #undef	TRY
367*7304104dSAndroid Build Coastguard Worker }
368*7304104dSAndroid Build Coastguard Worker 
369*7304104dSAndroid Build Coastguard Worker /* Report a kernel and all its modules found on disk, for offline use.
370*7304104dSAndroid Build Coastguard Worker    If RELEASE starts with '/', it names a directory to look in;
371*7304104dSAndroid Build Coastguard Worker    if not, it names a directory to find under /lib/modules/;
372*7304104dSAndroid Build Coastguard Worker    if null, /lib/modules/`uname -r` is used.
373*7304104dSAndroid Build Coastguard Worker    Returns zero on success, -1 if dwfl_report_module failed,
374*7304104dSAndroid Build Coastguard Worker    or an errno code if finding the files on disk failed.  */
375*7304104dSAndroid Build Coastguard Worker int
dwfl_linux_kernel_report_offline(Dwfl * dwfl,const char * release,int (* predicate)(const char * module,const char * file))376*7304104dSAndroid Build Coastguard Worker dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
377*7304104dSAndroid Build Coastguard Worker 				  int (*predicate) (const char *module,
378*7304104dSAndroid Build Coastguard Worker 						    const char *file))
379*7304104dSAndroid Build Coastguard Worker {
380*7304104dSAndroid Build Coastguard Worker   int result = report_kernel_archive (dwfl, &release, predicate);
381*7304104dSAndroid Build Coastguard Worker   if (result != ENOENT)
382*7304104dSAndroid Build Coastguard Worker     return result;
383*7304104dSAndroid Build Coastguard Worker 
384*7304104dSAndroid Build Coastguard Worker   /* First report the kernel.  */
385*7304104dSAndroid Build Coastguard Worker   result = report_kernel (dwfl, &release, predicate);
386*7304104dSAndroid Build Coastguard Worker   if (result == 0)
387*7304104dSAndroid Build Coastguard Worker     {
388*7304104dSAndroid Build Coastguard Worker       /* Do "find /lib/modules/RELEASE -name *.ko".  */
389*7304104dSAndroid Build Coastguard Worker 
390*7304104dSAndroid Build Coastguard Worker       char *modulesdir[] = { NULL, NULL };
391*7304104dSAndroid Build Coastguard Worker       if (release[0] == '/')
392*7304104dSAndroid Build Coastguard Worker 	modulesdir[0] = (char *) release;
393*7304104dSAndroid Build Coastguard Worker       else
394*7304104dSAndroid Build Coastguard Worker 	{
395*7304104dSAndroid Build Coastguard Worker 	  if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
396*7304104dSAndroid Build Coastguard Worker 	    return errno;
397*7304104dSAndroid Build Coastguard Worker 	}
398*7304104dSAndroid Build Coastguard Worker 
399*7304104dSAndroid Build Coastguard Worker       FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
400*7304104dSAndroid Build Coastguard Worker       if (modulesdir[0] == (char *) release)
401*7304104dSAndroid Build Coastguard Worker 	modulesdir[0] = NULL;
402*7304104dSAndroid Build Coastguard Worker       if (fts == NULL)
403*7304104dSAndroid Build Coastguard Worker 	{
404*7304104dSAndroid Build Coastguard Worker 	  free (modulesdir[0]);
405*7304104dSAndroid Build Coastguard Worker 	  return errno;
406*7304104dSAndroid Build Coastguard Worker 	}
407*7304104dSAndroid Build Coastguard Worker 
408*7304104dSAndroid Build Coastguard Worker       FTSENT *f;
409*7304104dSAndroid Build Coastguard Worker       while ((f = fts_read (fts)) != NULL)
410*7304104dSAndroid Build Coastguard Worker 	{
411*7304104dSAndroid Build Coastguard Worker 	  /* Skip a "source" subtree, which tends to be large.
412*7304104dSAndroid Build Coastguard Worker 	     This insane hard-coding of names is what depmod does too.  */
413*7304104dSAndroid Build Coastguard Worker 	  if (f->fts_namelen == sizeof "source" - 1
414*7304104dSAndroid Build Coastguard Worker 	      && !strcmp (f->fts_name, "source"))
415*7304104dSAndroid Build Coastguard Worker 	    {
416*7304104dSAndroid Build Coastguard Worker 	      fts_set (fts, f, FTS_SKIP);
417*7304104dSAndroid Build Coastguard Worker 	      continue;
418*7304104dSAndroid Build Coastguard Worker 	    }
419*7304104dSAndroid Build Coastguard Worker 
420*7304104dSAndroid Build Coastguard Worker 	  switch (f->fts_info)
421*7304104dSAndroid Build Coastguard Worker 	    {
422*7304104dSAndroid Build Coastguard Worker 	    case FTS_F:
423*7304104dSAndroid Build Coastguard Worker 	    case FTS_SL:
424*7304104dSAndroid Build Coastguard Worker 	    case FTS_NSOK:;
425*7304104dSAndroid Build Coastguard Worker 	      /* See if this file name matches "*.ko".  */
426*7304104dSAndroid Build Coastguard Worker 	      const size_t suffix = check_suffix (f, 0);
427*7304104dSAndroid Build Coastguard Worker 	      if (suffix)
428*7304104dSAndroid Build Coastguard Worker 		{
429*7304104dSAndroid Build Coastguard Worker 		  /* We have a .ko file to report.  Following the algorithm
430*7304104dSAndroid Build Coastguard Worker 		     by which the kernel makefiles set KBUILD_MODNAME, we
431*7304104dSAndroid Build Coastguard Worker 		     replace all ',' or '-' with '_' in the file name and
432*7304104dSAndroid Build Coastguard Worker 		     call that the module name.  Modules could well be
433*7304104dSAndroid Build Coastguard Worker 		     built using different embedded names than their file
434*7304104dSAndroid Build Coastguard Worker 		     names.  To handle that, we would have to look at the
435*7304104dSAndroid Build Coastguard Worker 		     __this_module.name contents in the module's text.  */
436*7304104dSAndroid Build Coastguard Worker 
437*7304104dSAndroid Build Coastguard Worker 		  char *name = strndup (f->fts_name, f->fts_namelen - suffix);
438*7304104dSAndroid Build Coastguard Worker 		  if (unlikely (name == NULL))
439*7304104dSAndroid Build Coastguard Worker 		    {
440*7304104dSAndroid Build Coastguard Worker 		      __libdwfl_seterrno (DWFL_E_NOMEM);
441*7304104dSAndroid Build Coastguard Worker 		      result = -1;
442*7304104dSAndroid Build Coastguard Worker 		      break;
443*7304104dSAndroid Build Coastguard Worker 		    }
444*7304104dSAndroid Build Coastguard Worker 		  for (size_t i = 0; i < f->fts_namelen - suffix; ++i)
445*7304104dSAndroid Build Coastguard Worker 		    if (name[i] == '-' || name[i] == ',')
446*7304104dSAndroid Build Coastguard Worker 		      name[i] = '_';
447*7304104dSAndroid Build Coastguard Worker 
448*7304104dSAndroid Build Coastguard Worker 		  if (predicate != NULL)
449*7304104dSAndroid Build Coastguard Worker 		    {
450*7304104dSAndroid Build Coastguard Worker 		      /* Let the predicate decide whether to use this one.  */
451*7304104dSAndroid Build Coastguard Worker 		      int want = (*predicate) (name, f->fts_path);
452*7304104dSAndroid Build Coastguard Worker 		      if (want < 0)
453*7304104dSAndroid Build Coastguard Worker 			{
454*7304104dSAndroid Build Coastguard Worker 			  result = -1;
455*7304104dSAndroid Build Coastguard Worker 			  free (name);
456*7304104dSAndroid Build Coastguard Worker 			  break;
457*7304104dSAndroid Build Coastguard Worker 			}
458*7304104dSAndroid Build Coastguard Worker 		      if (!want)
459*7304104dSAndroid Build Coastguard Worker 			{
460*7304104dSAndroid Build Coastguard Worker 			  free (name);
461*7304104dSAndroid Build Coastguard Worker 			  continue;
462*7304104dSAndroid Build Coastguard Worker 			}
463*7304104dSAndroid Build Coastguard Worker 		    }
464*7304104dSAndroid Build Coastguard Worker 
465*7304104dSAndroid Build Coastguard Worker 		  if (dwfl_report_offline (dwfl, name, f->fts_path, -1) == NULL)
466*7304104dSAndroid Build Coastguard Worker 		    {
467*7304104dSAndroid Build Coastguard Worker 		      free (name);
468*7304104dSAndroid Build Coastguard Worker 		      result = -1;
469*7304104dSAndroid Build Coastguard Worker 		      break;
470*7304104dSAndroid Build Coastguard Worker 		    }
471*7304104dSAndroid Build Coastguard Worker 		  free (name);
472*7304104dSAndroid Build Coastguard Worker 		}
473*7304104dSAndroid Build Coastguard Worker 	      continue;
474*7304104dSAndroid Build Coastguard Worker 
475*7304104dSAndroid Build Coastguard Worker 	    case FTS_ERR:
476*7304104dSAndroid Build Coastguard Worker 	    case FTS_DNR:
477*7304104dSAndroid Build Coastguard Worker 	    case FTS_NS:
478*7304104dSAndroid Build Coastguard Worker 	      result = f->fts_errno;
479*7304104dSAndroid Build Coastguard Worker 	      break;
480*7304104dSAndroid Build Coastguard Worker 
481*7304104dSAndroid Build Coastguard Worker 	    case FTS_SLNONE:
482*7304104dSAndroid Build Coastguard Worker 	    default:
483*7304104dSAndroid Build Coastguard Worker 	      continue;
484*7304104dSAndroid Build Coastguard Worker 	    }
485*7304104dSAndroid Build Coastguard Worker 
486*7304104dSAndroid Build Coastguard Worker 	  /* We only get here in error cases.  */
487*7304104dSAndroid Build Coastguard Worker 	  break;
488*7304104dSAndroid Build Coastguard Worker 	}
489*7304104dSAndroid Build Coastguard Worker       fts_close (fts);
490*7304104dSAndroid Build Coastguard Worker       free (modulesdir[0]);
491*7304104dSAndroid Build Coastguard Worker     }
492*7304104dSAndroid Build Coastguard Worker 
493*7304104dSAndroid Build Coastguard Worker   return result;
494*7304104dSAndroid Build Coastguard Worker }
495*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_linux_kernel_report_offline)
496*7304104dSAndroid Build Coastguard Worker 
497*7304104dSAndroid Build Coastguard Worker 
498*7304104dSAndroid Build Coastguard Worker /* State of read_address used by intuit_kernel_bounds. */
499*7304104dSAndroid Build Coastguard Worker struct read_address_state {
500*7304104dSAndroid Build Coastguard Worker   FILE *f;
501*7304104dSAndroid Build Coastguard Worker   char *line;
502*7304104dSAndroid Build Coastguard Worker   size_t linesz;
503*7304104dSAndroid Build Coastguard Worker   size_t n;
504*7304104dSAndroid Build Coastguard Worker   char *p;
505*7304104dSAndroid Build Coastguard Worker   const char *type;
506*7304104dSAndroid Build Coastguard Worker };
507*7304104dSAndroid Build Coastguard Worker 
508*7304104dSAndroid Build Coastguard Worker static inline bool
read_address(struct read_address_state * state,Dwarf_Addr * addr)509*7304104dSAndroid Build Coastguard Worker read_address (struct read_address_state *state, Dwarf_Addr *addr)
510*7304104dSAndroid Build Coastguard Worker {
511*7304104dSAndroid Build Coastguard Worker   if ((state->n = getline (&state->line, &state->linesz, state->f)) < 1 ||
512*7304104dSAndroid Build Coastguard Worker       state->line[state->n - 2] == ']')
513*7304104dSAndroid Build Coastguard Worker     return false;
514*7304104dSAndroid Build Coastguard Worker   *addr = strtoull (state->line, &state->p, 16);
515*7304104dSAndroid Build Coastguard Worker   state->p += strspn (state->p, " \t");
516*7304104dSAndroid Build Coastguard Worker   state->type = strsep (&state->p, " \t\n");
517*7304104dSAndroid Build Coastguard Worker   if (state->type == NULL)
518*7304104dSAndroid Build Coastguard Worker     return false;
519*7304104dSAndroid Build Coastguard Worker   return state->p != NULL && state->p != state->line;
520*7304104dSAndroid Build Coastguard Worker }
521*7304104dSAndroid Build Coastguard Worker 
522*7304104dSAndroid Build Coastguard Worker 
523*7304104dSAndroid Build Coastguard Worker /* Grovel around to guess the bounds of the runtime kernel image.  */
524*7304104dSAndroid Build Coastguard Worker static int
intuit_kernel_bounds(Dwarf_Addr * start,Dwarf_Addr * end,Dwarf_Addr * notes)525*7304104dSAndroid Build Coastguard Worker intuit_kernel_bounds (Dwarf_Addr *start, Dwarf_Addr *end, Dwarf_Addr *notes)
526*7304104dSAndroid Build Coastguard Worker {
527*7304104dSAndroid Build Coastguard Worker   struct read_address_state state = { NULL, NULL, 0, 0, NULL, NULL };
528*7304104dSAndroid Build Coastguard Worker 
529*7304104dSAndroid Build Coastguard Worker   *notes = 0;
530*7304104dSAndroid Build Coastguard Worker 
531*7304104dSAndroid Build Coastguard Worker   state.f = fopen (KSYMSFILE, "r");
532*7304104dSAndroid Build Coastguard Worker   if (state.f == NULL)
533*7304104dSAndroid Build Coastguard Worker     return errno;
534*7304104dSAndroid Build Coastguard Worker 
535*7304104dSAndroid Build Coastguard Worker   (void) __fsetlocking (state.f, FSETLOCKING_BYCALLER);
536*7304104dSAndroid Build Coastguard Worker 
537*7304104dSAndroid Build Coastguard Worker   int result;
538*7304104dSAndroid Build Coastguard Worker   do
539*7304104dSAndroid Build Coastguard Worker     result = read_address (&state, start) ? 0 : -1;
540*7304104dSAndroid Build Coastguard Worker   while (result == 0 && strchr ("TtRr", *state.type) == NULL);
541*7304104dSAndroid Build Coastguard Worker 
542*7304104dSAndroid Build Coastguard Worker   if (result == 0)
543*7304104dSAndroid Build Coastguard Worker     {
544*7304104dSAndroid Build Coastguard Worker       Dwarf_Addr addr;
545*7304104dSAndroid Build Coastguard Worker       *end = *start;
546*7304104dSAndroid Build Coastguard Worker       while (read_address (&state, &addr) && addr >= *end)
547*7304104dSAndroid Build Coastguard Worker 	{
548*7304104dSAndroid Build Coastguard Worker 	  *end = addr;
549*7304104dSAndroid Build Coastguard Worker 	  if (*notes == 0 && !strcmp (state.p, "__start_notes\n"))
550*7304104dSAndroid Build Coastguard Worker 	    *notes = *end;
551*7304104dSAndroid Build Coastguard Worker 	}
552*7304104dSAndroid Build Coastguard Worker 
553*7304104dSAndroid Build Coastguard Worker       Dwarf_Addr round_kernel = sysconf (_SC_PAGESIZE);
554*7304104dSAndroid Build Coastguard Worker       *start &= -(Dwarf_Addr) round_kernel;
555*7304104dSAndroid Build Coastguard Worker       *end += round_kernel - 1;
556*7304104dSAndroid Build Coastguard Worker       *end &= -(Dwarf_Addr) round_kernel;
557*7304104dSAndroid Build Coastguard Worker       if (*start >= *end || *end - *start < round_kernel)
558*7304104dSAndroid Build Coastguard Worker 	result = -1;
559*7304104dSAndroid Build Coastguard Worker     }
560*7304104dSAndroid Build Coastguard Worker   free (state.line);
561*7304104dSAndroid Build Coastguard Worker 
562*7304104dSAndroid Build Coastguard Worker   if (result == -1)
563*7304104dSAndroid Build Coastguard Worker     result = ferror_unlocked (state.f) ? errno : ENOEXEC;
564*7304104dSAndroid Build Coastguard Worker 
565*7304104dSAndroid Build Coastguard Worker   fclose (state.f);
566*7304104dSAndroid Build Coastguard Worker 
567*7304104dSAndroid Build Coastguard Worker   return result;
568*7304104dSAndroid Build Coastguard Worker }
569*7304104dSAndroid Build Coastguard Worker 
570*7304104dSAndroid Build Coastguard Worker 
571*7304104dSAndroid Build Coastguard Worker /* Look for a build ID note in NOTESFILE and associate the ID with MOD.  */
572*7304104dSAndroid Build Coastguard Worker static int
check_notes(Dwfl_Module * mod,const char * notesfile,Dwarf_Addr vaddr,const char * secname)573*7304104dSAndroid Build Coastguard Worker check_notes (Dwfl_Module *mod, const char *notesfile,
574*7304104dSAndroid Build Coastguard Worker 	     Dwarf_Addr vaddr, const char *secname)
575*7304104dSAndroid Build Coastguard Worker {
576*7304104dSAndroid Build Coastguard Worker   int fd = open (notesfile, O_RDONLY);
577*7304104dSAndroid Build Coastguard Worker   if (fd < 0)
578*7304104dSAndroid Build Coastguard Worker     return 1;
579*7304104dSAndroid Build Coastguard Worker 
580*7304104dSAndroid Build Coastguard Worker   assert (sizeof (Elf32_Nhdr) == sizeof (GElf_Nhdr));
581*7304104dSAndroid Build Coastguard Worker   assert (sizeof (Elf64_Nhdr) == sizeof (GElf_Nhdr));
582*7304104dSAndroid Build Coastguard Worker   union
583*7304104dSAndroid Build Coastguard Worker   {
584*7304104dSAndroid Build Coastguard Worker     GElf_Nhdr nhdr;
585*7304104dSAndroid Build Coastguard Worker     unsigned char data[8192];
586*7304104dSAndroid Build Coastguard Worker   } buf;
587*7304104dSAndroid Build Coastguard Worker 
588*7304104dSAndroid Build Coastguard Worker   ssize_t n = read (fd, buf.data, sizeof buf);
589*7304104dSAndroid Build Coastguard Worker   close (fd);
590*7304104dSAndroid Build Coastguard Worker 
591*7304104dSAndroid Build Coastguard Worker   if (n <= 0)
592*7304104dSAndroid Build Coastguard Worker     return 1;
593*7304104dSAndroid Build Coastguard Worker 
594*7304104dSAndroid Build Coastguard Worker   unsigned char *p = buf.data;
595*7304104dSAndroid Build Coastguard Worker   size_t len = 0;
596*7304104dSAndroid Build Coastguard Worker   while (p < &buf.data[n])
597*7304104dSAndroid Build Coastguard Worker     {
598*7304104dSAndroid Build Coastguard Worker       /* No translation required since we are reading the native kernel.  */
599*7304104dSAndroid Build Coastguard Worker       GElf_Nhdr *nhdr = (void *) p;
600*7304104dSAndroid Build Coastguard Worker       len += sizeof *nhdr;
601*7304104dSAndroid Build Coastguard Worker       p += len;
602*7304104dSAndroid Build Coastguard Worker       unsigned char *name = p;
603*7304104dSAndroid Build Coastguard Worker       unsigned char *bits;
604*7304104dSAndroid Build Coastguard Worker       /* This is somewhat ugly, GNU Property notes use different padding,
605*7304104dSAndroid Build Coastguard Worker 	 but all we have is the file content, so we have to actually check
606*7304104dSAndroid Build Coastguard Worker 	 the name and type.  */
607*7304104dSAndroid Build Coastguard Worker       if (nhdr->n_type == NT_GNU_PROPERTY_TYPE_0
608*7304104dSAndroid Build Coastguard Worker           && nhdr->n_namesz == sizeof "GNU"
609*7304104dSAndroid Build Coastguard Worker           && name + nhdr->n_namesz < &buf.data[n]
610*7304104dSAndroid Build Coastguard Worker           && !memcmp (name, "GNU", sizeof "GNU"))
611*7304104dSAndroid Build Coastguard Worker 	{
612*7304104dSAndroid Build Coastguard Worker 	  len += nhdr->n_namesz;
613*7304104dSAndroid Build Coastguard Worker 	  len = NOTE_ALIGN8 (len);
614*7304104dSAndroid Build Coastguard Worker 	  p = buf.data + len;
615*7304104dSAndroid Build Coastguard Worker 	  bits = p;
616*7304104dSAndroid Build Coastguard Worker 	  len += nhdr->n_descsz;
617*7304104dSAndroid Build Coastguard Worker 	  len = NOTE_ALIGN8 (len);
618*7304104dSAndroid Build Coastguard Worker 	  p = buf.data + len;
619*7304104dSAndroid Build Coastguard Worker 	}
620*7304104dSAndroid Build Coastguard Worker       else
621*7304104dSAndroid Build Coastguard Worker 	{
622*7304104dSAndroid Build Coastguard Worker 	  len += nhdr->n_namesz;
623*7304104dSAndroid Build Coastguard Worker 	  len = NOTE_ALIGN4 (len);
624*7304104dSAndroid Build Coastguard Worker 	  p = buf.data + len;
625*7304104dSAndroid Build Coastguard Worker 	  bits = p;
626*7304104dSAndroid Build Coastguard Worker 	  len += nhdr->n_descsz;
627*7304104dSAndroid Build Coastguard Worker 	  len = NOTE_ALIGN4 (len);
628*7304104dSAndroid Build Coastguard Worker 	  p = buf.data + len;
629*7304104dSAndroid Build Coastguard Worker 	}
630*7304104dSAndroid Build Coastguard Worker 
631*7304104dSAndroid Build Coastguard Worker       if (p <= &buf.data[n]
632*7304104dSAndroid Build Coastguard Worker 	  && nhdr->n_type == NT_GNU_BUILD_ID
633*7304104dSAndroid Build Coastguard Worker 	  && nhdr->n_namesz == sizeof "GNU"
634*7304104dSAndroid Build Coastguard Worker 	  && !memcmp (name, "GNU", sizeof "GNU"))
635*7304104dSAndroid Build Coastguard Worker 	{
636*7304104dSAndroid Build Coastguard Worker 	  /* Found it.  For a module we must figure out its VADDR now.  */
637*7304104dSAndroid Build Coastguard Worker 
638*7304104dSAndroid Build Coastguard Worker 	  if (secname != NULL
639*7304104dSAndroid Build Coastguard Worker 	      && (INTUSE(dwfl_linux_kernel_module_section_address)
640*7304104dSAndroid Build Coastguard Worker 		  (mod, NULL, mod->name, 0, secname, 0, NULL, &vaddr) != 0
641*7304104dSAndroid Build Coastguard Worker 		  || vaddr == (GElf_Addr) -1l))
642*7304104dSAndroid Build Coastguard Worker 	    vaddr = 0;
643*7304104dSAndroid Build Coastguard Worker 
644*7304104dSAndroid Build Coastguard Worker 	  if (vaddr != 0)
645*7304104dSAndroid Build Coastguard Worker 	    vaddr += bits - buf.data;
646*7304104dSAndroid Build Coastguard Worker 	  return INTUSE(dwfl_module_report_build_id) (mod, bits,
647*7304104dSAndroid Build Coastguard Worker 						      nhdr->n_descsz, vaddr);
648*7304104dSAndroid Build Coastguard Worker 	}
649*7304104dSAndroid Build Coastguard Worker     }
650*7304104dSAndroid Build Coastguard Worker 
651*7304104dSAndroid Build Coastguard Worker   return 0;
652*7304104dSAndroid Build Coastguard Worker }
653*7304104dSAndroid Build Coastguard Worker 
654*7304104dSAndroid Build Coastguard Worker /* Look for a build ID for the kernel.  */
655*7304104dSAndroid Build Coastguard Worker static int
check_kernel_notes(Dwfl_Module * kernelmod,GElf_Addr vaddr)656*7304104dSAndroid Build Coastguard Worker check_kernel_notes (Dwfl_Module *kernelmod, GElf_Addr vaddr)
657*7304104dSAndroid Build Coastguard Worker {
658*7304104dSAndroid Build Coastguard Worker   return check_notes (kernelmod, KNOTESFILE, vaddr, NULL) < 0 ? -1 : 0;
659*7304104dSAndroid Build Coastguard Worker }
660*7304104dSAndroid Build Coastguard Worker 
661*7304104dSAndroid Build Coastguard Worker /* Look for a build ID for a loaded kernel module.  */
662*7304104dSAndroid Build Coastguard Worker static int
check_module_notes(Dwfl_Module * mod)663*7304104dSAndroid Build Coastguard Worker check_module_notes (Dwfl_Module *mod)
664*7304104dSAndroid Build Coastguard Worker {
665*7304104dSAndroid Build Coastguard Worker   char *dirs[2] = { NULL, NULL };
666*7304104dSAndroid Build Coastguard Worker   if (asprintf (&dirs[0], MODNOTESFMT, mod->name) < 0)
667*7304104dSAndroid Build Coastguard Worker     return ENOMEM;
668*7304104dSAndroid Build Coastguard Worker 
669*7304104dSAndroid Build Coastguard Worker   FTS *fts = fts_open (dirs, FTS_NOSTAT | FTS_LOGICAL, NULL);
670*7304104dSAndroid Build Coastguard Worker   if (fts == NULL)
671*7304104dSAndroid Build Coastguard Worker     {
672*7304104dSAndroid Build Coastguard Worker       free (dirs[0]);
673*7304104dSAndroid Build Coastguard Worker       return 0;
674*7304104dSAndroid Build Coastguard Worker     }
675*7304104dSAndroid Build Coastguard Worker 
676*7304104dSAndroid Build Coastguard Worker   int result = 0;
677*7304104dSAndroid Build Coastguard Worker   FTSENT *f;
678*7304104dSAndroid Build Coastguard Worker   while ((f = fts_read (fts)) != NULL)
679*7304104dSAndroid Build Coastguard Worker     {
680*7304104dSAndroid Build Coastguard Worker       switch (f->fts_info)
681*7304104dSAndroid Build Coastguard Worker 	{
682*7304104dSAndroid Build Coastguard Worker 	case FTS_F:
683*7304104dSAndroid Build Coastguard Worker 	case FTS_SL:
684*7304104dSAndroid Build Coastguard Worker 	case FTS_NSOK:
685*7304104dSAndroid Build Coastguard Worker 	  result = check_notes (mod, f->fts_accpath, 0, f->fts_name);
686*7304104dSAndroid Build Coastguard Worker 	  if (result > 0)	/* Nothing found.  */
687*7304104dSAndroid Build Coastguard Worker 	    {
688*7304104dSAndroid Build Coastguard Worker 	      result = 0;
689*7304104dSAndroid Build Coastguard Worker 	      continue;
690*7304104dSAndroid Build Coastguard Worker 	    }
691*7304104dSAndroid Build Coastguard Worker 	  break;
692*7304104dSAndroid Build Coastguard Worker 
693*7304104dSAndroid Build Coastguard Worker 	case FTS_ERR:
694*7304104dSAndroid Build Coastguard Worker 	case FTS_DNR:
695*7304104dSAndroid Build Coastguard Worker 	  result = f->fts_errno;
696*7304104dSAndroid Build Coastguard Worker 	  break;
697*7304104dSAndroid Build Coastguard Worker 
698*7304104dSAndroid Build Coastguard Worker 	case FTS_NS:
699*7304104dSAndroid Build Coastguard Worker 	case FTS_SLNONE:
700*7304104dSAndroid Build Coastguard Worker 	default:
701*7304104dSAndroid Build Coastguard Worker 	  continue;
702*7304104dSAndroid Build Coastguard Worker 	}
703*7304104dSAndroid Build Coastguard Worker 
704*7304104dSAndroid Build Coastguard Worker       /* We only get here when finished or in error cases.  */
705*7304104dSAndroid Build Coastguard Worker       break;
706*7304104dSAndroid Build Coastguard Worker     }
707*7304104dSAndroid Build Coastguard Worker   fts_close (fts);
708*7304104dSAndroid Build Coastguard Worker   free (dirs[0]);
709*7304104dSAndroid Build Coastguard Worker 
710*7304104dSAndroid Build Coastguard Worker   return result;
711*7304104dSAndroid Build Coastguard Worker }
712*7304104dSAndroid Build Coastguard Worker 
713*7304104dSAndroid Build Coastguard Worker int
dwfl_linux_kernel_report_kernel(Dwfl * dwfl)714*7304104dSAndroid Build Coastguard Worker dwfl_linux_kernel_report_kernel (Dwfl *dwfl)
715*7304104dSAndroid Build Coastguard Worker {
716*7304104dSAndroid Build Coastguard Worker   Dwarf_Addr start = 0;
717*7304104dSAndroid Build Coastguard Worker   Dwarf_Addr end = 0;
718*7304104dSAndroid Build Coastguard Worker 
719*7304104dSAndroid Build Coastguard Worker   #define report() \
720*7304104dSAndroid Build Coastguard Worker     (INTUSE(dwfl_report_module) (dwfl, KERNEL_MODNAME, start, end))
721*7304104dSAndroid Build Coastguard Worker 
722*7304104dSAndroid Build Coastguard Worker   /* This is a bit of a kludge.  If we already reported the kernel,
723*7304104dSAndroid Build Coastguard Worker      don't bother figuring it out again--it never changes.  */
724*7304104dSAndroid Build Coastguard Worker   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
725*7304104dSAndroid Build Coastguard Worker     if (!strcmp (m->name, KERNEL_MODNAME))
726*7304104dSAndroid Build Coastguard Worker       {
727*7304104dSAndroid Build Coastguard Worker 	start = m->low_addr;
728*7304104dSAndroid Build Coastguard Worker 	end = m->high_addr;
729*7304104dSAndroid Build Coastguard Worker 	return report () == NULL ? -1 : 0;
730*7304104dSAndroid Build Coastguard Worker       }
731*7304104dSAndroid Build Coastguard Worker 
732*7304104dSAndroid Build Coastguard Worker   /* Try to figure out the bounds of the kernel image without
733*7304104dSAndroid Build Coastguard Worker      looking for any vmlinux file.  */
734*7304104dSAndroid Build Coastguard Worker   Dwarf_Addr notes;
735*7304104dSAndroid Build Coastguard Worker   int result = intuit_kernel_bounds (&start, &end, &notes);
736*7304104dSAndroid Build Coastguard Worker   if (result == 0)
737*7304104dSAndroid Build Coastguard Worker     {
738*7304104dSAndroid Build Coastguard Worker       Dwfl_Module *mod = report ();
739*7304104dSAndroid Build Coastguard Worker       return unlikely (mod == NULL) ? -1 : check_kernel_notes (mod, notes);
740*7304104dSAndroid Build Coastguard Worker     }
741*7304104dSAndroid Build Coastguard Worker   if (result != ENOENT)
742*7304104dSAndroid Build Coastguard Worker     return result;
743*7304104dSAndroid Build Coastguard Worker 
744*7304104dSAndroid Build Coastguard Worker   /* Find the ELF file for the running kernel and dwfl_report_elf it.  */
745*7304104dSAndroid Build Coastguard Worker   return report_kernel (dwfl, NULL, NULL);
746*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_linux_kernel_report_kernel)747*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_linux_kernel_report_kernel)
748*7304104dSAndroid Build Coastguard Worker 
749*7304104dSAndroid Build Coastguard Worker 
750*7304104dSAndroid Build Coastguard Worker static inline bool
751*7304104dSAndroid Build Coastguard Worker subst_name (char from, char to,
752*7304104dSAndroid Build Coastguard Worker             const char * const module_name,
753*7304104dSAndroid Build Coastguard Worker             char * const alternate_name,
754*7304104dSAndroid Build Coastguard Worker             const size_t namelen)
755*7304104dSAndroid Build Coastguard Worker {
756*7304104dSAndroid Build Coastguard Worker   const char *n = memchr (module_name, from, namelen);
757*7304104dSAndroid Build Coastguard Worker   if (n == NULL)
758*7304104dSAndroid Build Coastguard Worker     return false;
759*7304104dSAndroid Build Coastguard Worker   char *a = mempcpy (alternate_name, module_name, n - module_name);
760*7304104dSAndroid Build Coastguard Worker   *a++ = to;
761*7304104dSAndroid Build Coastguard Worker   ++n;
762*7304104dSAndroid Build Coastguard Worker   const char *p;
763*7304104dSAndroid Build Coastguard Worker   while ((p = memchr (n, from, namelen - (n - module_name))) != NULL)
764*7304104dSAndroid Build Coastguard Worker     {
765*7304104dSAndroid Build Coastguard Worker       a = mempcpy (a, n, p - n);
766*7304104dSAndroid Build Coastguard Worker       *a++ = to;
767*7304104dSAndroid Build Coastguard Worker       n = p + 1;
768*7304104dSAndroid Build Coastguard Worker     }
769*7304104dSAndroid Build Coastguard Worker   memcpy (a, n, namelen - (n - module_name) + 1);
770*7304104dSAndroid Build Coastguard Worker   return true;
771*7304104dSAndroid Build Coastguard Worker }
772*7304104dSAndroid Build Coastguard Worker 
773*7304104dSAndroid Build Coastguard Worker /* Dwfl_Callbacks.find_elf for the running Linux kernel and its modules.  */
774*7304104dSAndroid Build Coastguard Worker 
775*7304104dSAndroid Build Coastguard Worker int
dwfl_linux_kernel_find_elf(Dwfl_Module * mod,void ** userdata,const char * module_name,Dwarf_Addr base,char ** file_name,Elf ** elfp)776*7304104dSAndroid Build Coastguard Worker dwfl_linux_kernel_find_elf (Dwfl_Module *mod,
777*7304104dSAndroid Build Coastguard Worker 			    void **userdata __attribute__ ((unused)),
778*7304104dSAndroid Build Coastguard Worker 			    const char *module_name,
779*7304104dSAndroid Build Coastguard Worker 			    Dwarf_Addr base __attribute__ ((unused)),
780*7304104dSAndroid Build Coastguard Worker 			    char **file_name, Elf **elfp)
781*7304104dSAndroid Build Coastguard Worker {
782*7304104dSAndroid Build Coastguard Worker   if (mod->build_id_len > 0)
783*7304104dSAndroid Build Coastguard Worker     {
784*7304104dSAndroid Build Coastguard Worker       int fd = INTUSE(dwfl_build_id_find_elf) (mod, NULL, NULL, 0,
785*7304104dSAndroid Build Coastguard Worker 					       file_name, elfp);
786*7304104dSAndroid Build Coastguard Worker       if (fd >= 0 || mod->main.elf != NULL || errno != 0)
787*7304104dSAndroid Build Coastguard Worker 	return fd;
788*7304104dSAndroid Build Coastguard Worker     }
789*7304104dSAndroid Build Coastguard Worker 
790*7304104dSAndroid Build Coastguard Worker   const char *release = kernel_release ();
791*7304104dSAndroid Build Coastguard Worker   if (release == NULL)
792*7304104dSAndroid Build Coastguard Worker     return errno;
793*7304104dSAndroid Build Coastguard Worker 
794*7304104dSAndroid Build Coastguard Worker   if (!strcmp (module_name, KERNEL_MODNAME))
795*7304104dSAndroid Build Coastguard Worker     return find_kernel_elf (mod->dwfl, release, file_name);
796*7304104dSAndroid Build Coastguard Worker 
797*7304104dSAndroid Build Coastguard Worker   /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko".  */
798*7304104dSAndroid Build Coastguard Worker 
799*7304104dSAndroid Build Coastguard Worker   char *modulesdir[] = { NULL, NULL };
800*7304104dSAndroid Build Coastguard Worker   if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0)
801*7304104dSAndroid Build Coastguard Worker     return -1;
802*7304104dSAndroid Build Coastguard Worker 
803*7304104dSAndroid Build Coastguard Worker   FTS *fts = fts_open (modulesdir, FTS_NOSTAT | FTS_LOGICAL, NULL);
804*7304104dSAndroid Build Coastguard Worker   if (fts == NULL)
805*7304104dSAndroid Build Coastguard Worker     {
806*7304104dSAndroid Build Coastguard Worker       free (modulesdir[0]);
807*7304104dSAndroid Build Coastguard Worker       return -1;
808*7304104dSAndroid Build Coastguard Worker     }
809*7304104dSAndroid Build Coastguard Worker 
810*7304104dSAndroid Build Coastguard Worker   size_t namelen = strlen (module_name);
811*7304104dSAndroid Build Coastguard Worker 
812*7304104dSAndroid Build Coastguard Worker   /* This is a kludge.  There is no actual necessary relationship between
813*7304104dSAndroid Build Coastguard Worker      the name of the .ko file installed and the module name the kernel
814*7304104dSAndroid Build Coastguard Worker      knows it by when it's loaded.  The kernel's only idea of the module
815*7304104dSAndroid Build Coastguard Worker      name comes from the name embedded in the object's magic
816*7304104dSAndroid Build Coastguard Worker      .gnu.linkonce.this_module section.
817*7304104dSAndroid Build Coastguard Worker 
818*7304104dSAndroid Build Coastguard Worker      In practice, these module names match the .ko file names except for
819*7304104dSAndroid Build Coastguard Worker      some using '_' and some using '-'.  So our cheap kludge is to look for
820*7304104dSAndroid Build Coastguard Worker      two files when either a '_' or '-' appears in a module name, one using
821*7304104dSAndroid Build Coastguard Worker      only '_' and one only using '-'.  */
822*7304104dSAndroid Build Coastguard Worker 
823*7304104dSAndroid Build Coastguard Worker   char *alternate_name = malloc (namelen + 1);
824*7304104dSAndroid Build Coastguard Worker   if (unlikely (alternate_name == NULL))
825*7304104dSAndroid Build Coastguard Worker     {
826*7304104dSAndroid Build Coastguard Worker       free (modulesdir[0]);
827*7304104dSAndroid Build Coastguard Worker       return ENOMEM;
828*7304104dSAndroid Build Coastguard Worker     }
829*7304104dSAndroid Build Coastguard Worker   if (!subst_name ('-', '_', module_name, alternate_name, namelen) &&
830*7304104dSAndroid Build Coastguard Worker       !subst_name ('_', '-', module_name, alternate_name, namelen))
831*7304104dSAndroid Build Coastguard Worker     alternate_name[0] = '\0';
832*7304104dSAndroid Build Coastguard Worker 
833*7304104dSAndroid Build Coastguard Worker   FTSENT *f;
834*7304104dSAndroid Build Coastguard Worker   int error = ENOENT;
835*7304104dSAndroid Build Coastguard Worker   while ((f = fts_read (fts)) != NULL)
836*7304104dSAndroid Build Coastguard Worker     {
837*7304104dSAndroid Build Coastguard Worker       /* Skip a "source" subtree, which tends to be large.
838*7304104dSAndroid Build Coastguard Worker 	 This insane hard-coding of names is what depmod does too.  */
839*7304104dSAndroid Build Coastguard Worker       if (f->fts_namelen == sizeof "source" - 1
840*7304104dSAndroid Build Coastguard Worker 	  && !strcmp (f->fts_name, "source"))
841*7304104dSAndroid Build Coastguard Worker 	{
842*7304104dSAndroid Build Coastguard Worker 	  fts_set (fts, f, FTS_SKIP);
843*7304104dSAndroid Build Coastguard Worker 	  continue;
844*7304104dSAndroid Build Coastguard Worker 	}
845*7304104dSAndroid Build Coastguard Worker 
846*7304104dSAndroid Build Coastguard Worker       error = ENOENT;
847*7304104dSAndroid Build Coastguard Worker       switch (f->fts_info)
848*7304104dSAndroid Build Coastguard Worker 	{
849*7304104dSAndroid Build Coastguard Worker 	case FTS_F:
850*7304104dSAndroid Build Coastguard Worker 	case FTS_SL:
851*7304104dSAndroid Build Coastguard Worker 	case FTS_NSOK:
852*7304104dSAndroid Build Coastguard Worker 	  /* See if this file name is "MODULE_NAME.ko".  */
853*7304104dSAndroid Build Coastguard Worker 	  if (check_suffix (f, namelen)
854*7304104dSAndroid Build Coastguard Worker 	      && (!memcmp (f->fts_name, module_name, namelen)
855*7304104dSAndroid Build Coastguard Worker 		  || !memcmp (f->fts_name, alternate_name, namelen)))
856*7304104dSAndroid Build Coastguard Worker 	    {
857*7304104dSAndroid Build Coastguard Worker 	      int fd = open (f->fts_accpath, O_RDONLY);
858*7304104dSAndroid Build Coastguard Worker 	      *file_name = strdup (f->fts_path);
859*7304104dSAndroid Build Coastguard Worker 	      fts_close (fts);
860*7304104dSAndroid Build Coastguard Worker 	      free (modulesdir[0]);
861*7304104dSAndroid Build Coastguard Worker 	      free (alternate_name);
862*7304104dSAndroid Build Coastguard Worker 	      if (fd < 0)
863*7304104dSAndroid Build Coastguard Worker 		free (*file_name);
864*7304104dSAndroid Build Coastguard Worker 	      else if (*file_name == NULL)
865*7304104dSAndroid Build Coastguard Worker 		{
866*7304104dSAndroid Build Coastguard Worker 		  close (fd);
867*7304104dSAndroid Build Coastguard Worker 		  fd = -1;
868*7304104dSAndroid Build Coastguard Worker 		}
869*7304104dSAndroid Build Coastguard Worker 	      return fd;
870*7304104dSAndroid Build Coastguard Worker 	    }
871*7304104dSAndroid Build Coastguard Worker 	  break;
872*7304104dSAndroid Build Coastguard Worker 
873*7304104dSAndroid Build Coastguard Worker 	case FTS_ERR:
874*7304104dSAndroid Build Coastguard Worker 	case FTS_DNR:
875*7304104dSAndroid Build Coastguard Worker 	case FTS_NS:
876*7304104dSAndroid Build Coastguard Worker 	  error = f->fts_errno;
877*7304104dSAndroid Build Coastguard Worker 	  break;
878*7304104dSAndroid Build Coastguard Worker 
879*7304104dSAndroid Build Coastguard Worker 	case FTS_SLNONE:
880*7304104dSAndroid Build Coastguard Worker 	default:
881*7304104dSAndroid Build Coastguard Worker 	  break;
882*7304104dSAndroid Build Coastguard Worker 	}
883*7304104dSAndroid Build Coastguard Worker     }
884*7304104dSAndroid Build Coastguard Worker 
885*7304104dSAndroid Build Coastguard Worker   fts_close (fts);
886*7304104dSAndroid Build Coastguard Worker   free (modulesdir[0]);
887*7304104dSAndroid Build Coastguard Worker   free (alternate_name);
888*7304104dSAndroid Build Coastguard Worker   errno = error;
889*7304104dSAndroid Build Coastguard Worker   return -1;
890*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_linux_kernel_find_elf)891*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_linux_kernel_find_elf)
892*7304104dSAndroid Build Coastguard Worker 
893*7304104dSAndroid Build Coastguard Worker 
894*7304104dSAndroid Build Coastguard Worker /* Dwfl_Callbacks.section_address for kernel modules in the running Linux.
895*7304104dSAndroid Build Coastguard Worker    We read the information from /sys/module directly.  */
896*7304104dSAndroid Build Coastguard Worker 
897*7304104dSAndroid Build Coastguard Worker int
898*7304104dSAndroid Build Coastguard Worker dwfl_linux_kernel_module_section_address
899*7304104dSAndroid Build Coastguard Worker (Dwfl_Module *mod __attribute__ ((unused)),
900*7304104dSAndroid Build Coastguard Worker  void **userdata __attribute__ ((unused)),
901*7304104dSAndroid Build Coastguard Worker  const char *modname, Dwarf_Addr base __attribute__ ((unused)),
902*7304104dSAndroid Build Coastguard Worker  const char *secname, Elf32_Word shndx __attribute__ ((unused)),
903*7304104dSAndroid Build Coastguard Worker  const GElf_Shdr *shdr __attribute__ ((unused)),
904*7304104dSAndroid Build Coastguard Worker  Dwarf_Addr *addr)
905*7304104dSAndroid Build Coastguard Worker {
906*7304104dSAndroid Build Coastguard Worker   char *sysfile;
907*7304104dSAndroid Build Coastguard Worker   if (asprintf (&sysfile, SECADDRDIRFMT "%s", modname, secname) < 0)
908*7304104dSAndroid Build Coastguard Worker     return DWARF_CB_ABORT;
909*7304104dSAndroid Build Coastguard Worker 
910*7304104dSAndroid Build Coastguard Worker   FILE *f = fopen (sysfile, "r");
911*7304104dSAndroid Build Coastguard Worker   free (sysfile);
912*7304104dSAndroid Build Coastguard Worker 
913*7304104dSAndroid Build Coastguard Worker   if (f == NULL)
914*7304104dSAndroid Build Coastguard Worker     {
915*7304104dSAndroid Build Coastguard Worker       if (errno == ENOENT)
916*7304104dSAndroid Build Coastguard Worker 	{
917*7304104dSAndroid Build Coastguard Worker 	  /* The .modinfo and .data.percpu sections are never kept
918*7304104dSAndroid Build Coastguard Worker 	     loaded in the kernel.  If the kernel was compiled without
919*7304104dSAndroid Build Coastguard Worker 	     CONFIG_MODULE_UNLOAD, the .exit.* sections are not
920*7304104dSAndroid Build Coastguard Worker 	     actually loaded at all.
921*7304104dSAndroid Build Coastguard Worker 
922*7304104dSAndroid Build Coastguard Worker 	     Setting *ADDR to -1 tells the caller this section is
923*7304104dSAndroid Build Coastguard Worker 	     actually absent from memory.  */
924*7304104dSAndroid Build Coastguard Worker 
925*7304104dSAndroid Build Coastguard Worker 	  if (!strcmp (secname, ".modinfo")
926*7304104dSAndroid Build Coastguard Worker 	      || !strcmp (secname, ".data.percpu")
927*7304104dSAndroid Build Coastguard Worker 	      || startswith (secname, ".exit"))
928*7304104dSAndroid Build Coastguard Worker 	    {
929*7304104dSAndroid Build Coastguard Worker 	      *addr = (Dwarf_Addr) -1l;
930*7304104dSAndroid Build Coastguard Worker 	      return DWARF_CB_OK;
931*7304104dSAndroid Build Coastguard Worker 	    }
932*7304104dSAndroid Build Coastguard Worker 
933*7304104dSAndroid Build Coastguard Worker 	  /* The goofy PPC64 module_frob_arch_sections function tweaks
934*7304104dSAndroid Build Coastguard Worker 	     the section names as a way to control other kernel code's
935*7304104dSAndroid Build Coastguard Worker 	     behavior, and this cruft leaks out into the /sys information.
936*7304104dSAndroid Build Coastguard Worker 	     The file name for ".init*" may actually look like "_init*".  */
937*7304104dSAndroid Build Coastguard Worker 
938*7304104dSAndroid Build Coastguard Worker 	  const bool is_init = startswith (secname, ".init");
939*7304104dSAndroid Build Coastguard Worker 	  if (is_init)
940*7304104dSAndroid Build Coastguard Worker 	    {
941*7304104dSAndroid Build Coastguard Worker 	      if (asprintf (&sysfile, SECADDRDIRFMT "_%s",
942*7304104dSAndroid Build Coastguard Worker 			    modname, &secname[1]) < 0)
943*7304104dSAndroid Build Coastguard Worker 		return ENOMEM;
944*7304104dSAndroid Build Coastguard Worker 	      f = fopen (sysfile, "r");
945*7304104dSAndroid Build Coastguard Worker 	      free (sysfile);
946*7304104dSAndroid Build Coastguard Worker 	      if (f != NULL)
947*7304104dSAndroid Build Coastguard Worker 		goto ok;
948*7304104dSAndroid Build Coastguard Worker 	    }
949*7304104dSAndroid Build Coastguard Worker 
950*7304104dSAndroid Build Coastguard Worker 	  /* The kernel truncates section names to MODULE_SECT_NAME_LEN - 1.
951*7304104dSAndroid Build Coastguard Worker 	     In case that size increases in the future, look for longer
952*7304104dSAndroid Build Coastguard Worker 	     truncated names first.  */
953*7304104dSAndroid Build Coastguard Worker 	  size_t namelen = strlen (secname);
954*7304104dSAndroid Build Coastguard Worker 	  if (namelen >= MODULE_SECT_NAME_LEN)
955*7304104dSAndroid Build Coastguard Worker 	    {
956*7304104dSAndroid Build Coastguard Worker 	      int len = asprintf (&sysfile, SECADDRDIRFMT "%s",
957*7304104dSAndroid Build Coastguard Worker 				  modname, secname);
958*7304104dSAndroid Build Coastguard Worker 	      if (len < 0)
959*7304104dSAndroid Build Coastguard Worker 		return DWARF_CB_ABORT;
960*7304104dSAndroid Build Coastguard Worker 	      char *end = sysfile + len;
961*7304104dSAndroid Build Coastguard Worker 	      do
962*7304104dSAndroid Build Coastguard Worker 		{
963*7304104dSAndroid Build Coastguard Worker 		  *--end = '\0';
964*7304104dSAndroid Build Coastguard Worker 		  f = fopen (sysfile, "r");
965*7304104dSAndroid Build Coastguard Worker 		  if (is_init && f == NULL && errno == ENOENT)
966*7304104dSAndroid Build Coastguard Worker 		    {
967*7304104dSAndroid Build Coastguard Worker 		      sysfile[len - namelen] = '_';
968*7304104dSAndroid Build Coastguard Worker 		      f = fopen (sysfile, "r");
969*7304104dSAndroid Build Coastguard Worker 		      sysfile[len - namelen] = '.';
970*7304104dSAndroid Build Coastguard Worker 		    }
971*7304104dSAndroid Build Coastguard Worker 		}
972*7304104dSAndroid Build Coastguard Worker 	      while (f == NULL && errno == ENOENT
973*7304104dSAndroid Build Coastguard Worker 		     && end - &sysfile[len - namelen] >= MODULE_SECT_NAME_LEN);
974*7304104dSAndroid Build Coastguard Worker 	      free (sysfile);
975*7304104dSAndroid Build Coastguard Worker 
976*7304104dSAndroid Build Coastguard Worker 	      if (f != NULL)
977*7304104dSAndroid Build Coastguard Worker 		goto ok;
978*7304104dSAndroid Build Coastguard Worker 	    }
979*7304104dSAndroid Build Coastguard Worker 	}
980*7304104dSAndroid Build Coastguard Worker 
981*7304104dSAndroid Build Coastguard Worker       return DWARF_CB_ABORT;
982*7304104dSAndroid Build Coastguard Worker     }
983*7304104dSAndroid Build Coastguard Worker 
984*7304104dSAndroid Build Coastguard Worker  ok:
985*7304104dSAndroid Build Coastguard Worker   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
986*7304104dSAndroid Build Coastguard Worker 
987*7304104dSAndroid Build Coastguard Worker   int result = (fscanf (f, "%" PRIx64 "\n", addr) == 1 ? 0
988*7304104dSAndroid Build Coastguard Worker 		: ferror_unlocked (f) ? errno : ENOEXEC);
989*7304104dSAndroid Build Coastguard Worker   fclose (f);
990*7304104dSAndroid Build Coastguard Worker 
991*7304104dSAndroid Build Coastguard Worker   if (result == 0)
992*7304104dSAndroid Build Coastguard Worker     return DWARF_CB_OK;
993*7304104dSAndroid Build Coastguard Worker 
994*7304104dSAndroid Build Coastguard Worker   errno = result;
995*7304104dSAndroid Build Coastguard Worker   return DWARF_CB_ABORT;
996*7304104dSAndroid Build Coastguard Worker }
INTDEF(dwfl_linux_kernel_module_section_address)997*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_linux_kernel_module_section_address)
998*7304104dSAndroid Build Coastguard Worker 
999*7304104dSAndroid Build Coastguard Worker int
1000*7304104dSAndroid Build Coastguard Worker dwfl_linux_kernel_report_modules (Dwfl *dwfl)
1001*7304104dSAndroid Build Coastguard Worker {
1002*7304104dSAndroid Build Coastguard Worker   FILE *f = fopen (MODULELIST, "r");
1003*7304104dSAndroid Build Coastguard Worker   if (f == NULL)
1004*7304104dSAndroid Build Coastguard Worker     return errno;
1005*7304104dSAndroid Build Coastguard Worker 
1006*7304104dSAndroid Build Coastguard Worker   (void) __fsetlocking (f, FSETLOCKING_BYCALLER);
1007*7304104dSAndroid Build Coastguard Worker 
1008*7304104dSAndroid Build Coastguard Worker   int result = 0;
1009*7304104dSAndroid Build Coastguard Worker   Dwarf_Addr modaddr;
1010*7304104dSAndroid Build Coastguard Worker   unsigned long int modsz;
1011*7304104dSAndroid Build Coastguard Worker   char modname[128+1];
1012*7304104dSAndroid Build Coastguard Worker   char *line = NULL;
1013*7304104dSAndroid Build Coastguard Worker   size_t linesz = 0;
1014*7304104dSAndroid Build Coastguard Worker   /* We can't just use fscanf here because it's not easy to distinguish \n
1015*7304104dSAndroid Build Coastguard Worker      from other whitespace so as to take the optional word following the
1016*7304104dSAndroid Build Coastguard Worker      address but always stop at the end of the line.  */
1017*7304104dSAndroid Build Coastguard Worker   while (getline (&line, &linesz, f) > 0
1018*7304104dSAndroid Build Coastguard Worker 	 && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n",
1019*7304104dSAndroid Build Coastguard Worker 		    modname, &modsz, &modaddr) == 3)
1020*7304104dSAndroid Build Coastguard Worker     {
1021*7304104dSAndroid Build Coastguard Worker       Dwfl_Module *mod = INTUSE(dwfl_report_module) (dwfl, modname,
1022*7304104dSAndroid Build Coastguard Worker 						     modaddr, modaddr + modsz);
1023*7304104dSAndroid Build Coastguard Worker       if (mod == NULL)
1024*7304104dSAndroid Build Coastguard Worker 	{
1025*7304104dSAndroid Build Coastguard Worker 	  result = -1;
1026*7304104dSAndroid Build Coastguard Worker 	  break;
1027*7304104dSAndroid Build Coastguard Worker 	}
1028*7304104dSAndroid Build Coastguard Worker 
1029*7304104dSAndroid Build Coastguard Worker       result = check_module_notes (mod);
1030*7304104dSAndroid Build Coastguard Worker     }
1031*7304104dSAndroid Build Coastguard Worker   free (line);
1032*7304104dSAndroid Build Coastguard Worker 
1033*7304104dSAndroid Build Coastguard Worker   if (result == 0)
1034*7304104dSAndroid Build Coastguard Worker     result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC;
1035*7304104dSAndroid Build Coastguard Worker 
1036*7304104dSAndroid Build Coastguard Worker   fclose (f);
1037*7304104dSAndroid Build Coastguard Worker 
1038*7304104dSAndroid Build Coastguard Worker   return result;
1039*7304104dSAndroid Build Coastguard Worker }
1040*7304104dSAndroid Build Coastguard Worker INTDEF (dwfl_linux_kernel_report_modules)
1041