1da0c48c4Sopenharmony_ci/* Standard find_debuginfo callback for libdwfl.
2da0c48c4Sopenharmony_ci   Copyright (C) 2005-2010, 2014, 2015, 2019 Red Hat, Inc.
3da0c48c4Sopenharmony_ci   This file is part of elfutils.
4da0c48c4Sopenharmony_ci
5da0c48c4Sopenharmony_ci   This file is free software; you can redistribute it and/or modify
6da0c48c4Sopenharmony_ci   it under the terms of either
7da0c48c4Sopenharmony_ci
8da0c48c4Sopenharmony_ci     * the GNU Lesser General Public License as published by the Free
9da0c48c4Sopenharmony_ci       Software Foundation; either version 3 of the License, or (at
10da0c48c4Sopenharmony_ci       your option) any later version
11da0c48c4Sopenharmony_ci
12da0c48c4Sopenharmony_ci   or
13da0c48c4Sopenharmony_ci
14da0c48c4Sopenharmony_ci     * the GNU General Public License as published by the Free
15da0c48c4Sopenharmony_ci       Software Foundation; either version 2 of the License, or (at
16da0c48c4Sopenharmony_ci       your option) any later version
17da0c48c4Sopenharmony_ci
18da0c48c4Sopenharmony_ci   or both in parallel, as here.
19da0c48c4Sopenharmony_ci
20da0c48c4Sopenharmony_ci   elfutils is distributed in the hope that it will be useful, but
21da0c48c4Sopenharmony_ci   WITHOUT ANY WARRANTY; without even the implied warranty of
22da0c48c4Sopenharmony_ci   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23da0c48c4Sopenharmony_ci   General Public License for more details.
24da0c48c4Sopenharmony_ci
25da0c48c4Sopenharmony_ci   You should have received copies of the GNU General Public License and
26da0c48c4Sopenharmony_ci   the GNU Lesser General Public License along with this program.  If
27da0c48c4Sopenharmony_ci   not, see <http://www.gnu.org/licenses/>.  */
28da0c48c4Sopenharmony_ci
29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H
30da0c48c4Sopenharmony_ci# include <config.h>
31da0c48c4Sopenharmony_ci#endif
32da0c48c4Sopenharmony_ci
33da0c48c4Sopenharmony_ci#include "libdwflP.h"
34da0c48c4Sopenharmony_ci#include <stdio.h>
35da0c48c4Sopenharmony_ci#include <fcntl.h>
36da0c48c4Sopenharmony_ci#include <sys/stat.h>
37da0c48c4Sopenharmony_ci#include "system.h"
38da0c48c4Sopenharmony_ci
39da0c48c4Sopenharmony_ci
40da0c48c4Sopenharmony_ci/* Try to open [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
41da0c48c4Sopenharmony_ci   On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file.  */
42da0c48c4Sopenharmony_cistatic int
43da0c48c4Sopenharmony_citry_open (const struct stat *main_stat,
44da0c48c4Sopenharmony_ci	  const char *dir, const char *subdir, const char *debuglink,
45da0c48c4Sopenharmony_ci	  char **debuginfo_file_name)
46da0c48c4Sopenharmony_ci{
47da0c48c4Sopenharmony_ci  char *fname;
48da0c48c4Sopenharmony_ci  if (dir == NULL && subdir == NULL)
49da0c48c4Sopenharmony_ci    {
50da0c48c4Sopenharmony_ci      fname = strdup (debuglink);
51da0c48c4Sopenharmony_ci      if (unlikely (fname == NULL))
52da0c48c4Sopenharmony_ci	return -1;
53da0c48c4Sopenharmony_ci    }
54da0c48c4Sopenharmony_ci  else if ((subdir == NULL ? asprintf (&fname, "%s/%s", dir, debuglink)
55da0c48c4Sopenharmony_ci	    : dir == NULL ? asprintf (&fname, "%s/%s", subdir, debuglink)
56da0c48c4Sopenharmony_ci	    : asprintf (&fname, "%s/%s/%s", dir, subdir, debuglink)) < 0)
57da0c48c4Sopenharmony_ci    return -1;
58da0c48c4Sopenharmony_ci
59da0c48c4Sopenharmony_ci  struct stat st;
60da0c48c4Sopenharmony_ci  int fd = TEMP_FAILURE_RETRY (open (fname, O_RDONLY));
61da0c48c4Sopenharmony_ci  if (fd < 0)
62da0c48c4Sopenharmony_ci    free (fname);
63da0c48c4Sopenharmony_ci  else if (fstat (fd, &st) == 0
64da0c48c4Sopenharmony_ci	   && st.st_ino == main_stat->st_ino
65da0c48c4Sopenharmony_ci	   && st.st_dev == main_stat->st_dev)
66da0c48c4Sopenharmony_ci    {
67da0c48c4Sopenharmony_ci      /* This is the main file by another name.  Don't look at it again.  */
68da0c48c4Sopenharmony_ci      free (fname);
69da0c48c4Sopenharmony_ci      close (fd);
70da0c48c4Sopenharmony_ci      errno = ENOENT;
71da0c48c4Sopenharmony_ci      fd = -1;
72da0c48c4Sopenharmony_ci    }
73da0c48c4Sopenharmony_ci  else
74da0c48c4Sopenharmony_ci    *debuginfo_file_name = fname;
75da0c48c4Sopenharmony_ci
76da0c48c4Sopenharmony_ci  return fd;
77da0c48c4Sopenharmony_ci}
78da0c48c4Sopenharmony_ci
79da0c48c4Sopenharmony_ci/* Return true iff the FD's contents CRC matches DEBUGLINK_CRC.  */
80da0c48c4Sopenharmony_cistatic inline bool
81da0c48c4Sopenharmony_cicheck_crc (int fd, GElf_Word debuglink_crc)
82da0c48c4Sopenharmony_ci{
83da0c48c4Sopenharmony_ci  uint32_t file_crc;
84da0c48c4Sopenharmony_ci  return (__libdwfl_crc32_file (fd, &file_crc) == 0
85da0c48c4Sopenharmony_ci	  && file_crc == debuglink_crc);
86da0c48c4Sopenharmony_ci}
87da0c48c4Sopenharmony_ci
88da0c48c4Sopenharmony_cistatic bool
89da0c48c4Sopenharmony_civalidate (Dwfl_Module *mod, int fd, bool check, GElf_Word debuglink_crc)
90da0c48c4Sopenharmony_ci{
91da0c48c4Sopenharmony_ci  /* For alt debug files always check the build-id from the Dwarf and alt.  */
92da0c48c4Sopenharmony_ci  if (mod->dw != NULL)
93da0c48c4Sopenharmony_ci    {
94da0c48c4Sopenharmony_ci      bool valid = false;
95da0c48c4Sopenharmony_ci      const void *build_id;
96da0c48c4Sopenharmony_ci      const char *altname;
97da0c48c4Sopenharmony_ci      ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
98da0c48c4Sopenharmony_ci								   &altname,
99da0c48c4Sopenharmony_ci								   &build_id);
100da0c48c4Sopenharmony_ci      if (build_id_len > 0)
101da0c48c4Sopenharmony_ci	{
102da0c48c4Sopenharmony_ci	  /* We need to open an Elf handle on the file so we can check its
103da0c48c4Sopenharmony_ci	     build ID note for validation.  Backdoor the handle into the
104da0c48c4Sopenharmony_ci	     module data structure since we had to open it early anyway.  */
105da0c48c4Sopenharmony_ci	  Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
106da0c48c4Sopenharmony_ci						false, false);
107da0c48c4Sopenharmony_ci	  if (error != DWFL_E_NOERROR)
108da0c48c4Sopenharmony_ci	    __libdwfl_seterrno (error);
109da0c48c4Sopenharmony_ci	  else
110da0c48c4Sopenharmony_ci	    {
111da0c48c4Sopenharmony_ci	      const void *alt_build_id;
112da0c48c4Sopenharmony_ci	      ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
113da0c48c4Sopenharmony_ci								&alt_build_id);
114da0c48c4Sopenharmony_ci	      if (alt_len > 0 && alt_len == build_id_len
115da0c48c4Sopenharmony_ci		  && memcmp (build_id, alt_build_id, alt_len) == 0)
116da0c48c4Sopenharmony_ci		valid = true;
117da0c48c4Sopenharmony_ci	      else
118da0c48c4Sopenharmony_ci		{
119da0c48c4Sopenharmony_ci		  /* A mismatch!  */
120da0c48c4Sopenharmony_ci		  elf_end (mod->alt_elf);
121da0c48c4Sopenharmony_ci		  mod->alt_elf = NULL;
122da0c48c4Sopenharmony_ci		  close (fd);
123da0c48c4Sopenharmony_ci		  fd = -1;
124da0c48c4Sopenharmony_ci		}
125da0c48c4Sopenharmony_ci	    }
126da0c48c4Sopenharmony_ci	}
127da0c48c4Sopenharmony_ci      return valid;
128da0c48c4Sopenharmony_ci    }
129da0c48c4Sopenharmony_ci
130da0c48c4Sopenharmony_ci  /* If we have a build ID, check only that.  */
131da0c48c4Sopenharmony_ci  if (mod->build_id_len > 0)
132da0c48c4Sopenharmony_ci    {
133da0c48c4Sopenharmony_ci      /* We need to open an Elf handle on the file so we can check its
134da0c48c4Sopenharmony_ci	 build ID note for validation.  Backdoor the handle into the
135da0c48c4Sopenharmony_ci	 module data structure since we had to open it early anyway.  */
136da0c48c4Sopenharmony_ci
137da0c48c4Sopenharmony_ci      mod->debug.valid = false;
138da0c48c4Sopenharmony_ci      Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, false, false);
139da0c48c4Sopenharmony_ci      if (error != DWFL_E_NOERROR)
140da0c48c4Sopenharmony_ci	__libdwfl_seterrno (error);
141da0c48c4Sopenharmony_ci      else if (likely (__libdwfl_find_build_id (mod, false,
142da0c48c4Sopenharmony_ci						mod->debug.elf) == 2))
143da0c48c4Sopenharmony_ci	/* Also backdoor the gratuitous flag.  */
144da0c48c4Sopenharmony_ci	mod->debug.valid = true;
145da0c48c4Sopenharmony_ci      else
146da0c48c4Sopenharmony_ci	{
147da0c48c4Sopenharmony_ci	  /* A mismatch!  */
148da0c48c4Sopenharmony_ci	  elf_end (mod->debug.elf);
149da0c48c4Sopenharmony_ci	  mod->debug.elf = NULL;
150da0c48c4Sopenharmony_ci	  close (fd);
151da0c48c4Sopenharmony_ci	  fd = -1;
152da0c48c4Sopenharmony_ci	}
153da0c48c4Sopenharmony_ci
154da0c48c4Sopenharmony_ci      return mod->debug.valid;
155da0c48c4Sopenharmony_ci    }
156da0c48c4Sopenharmony_ci
157da0c48c4Sopenharmony_ci  return !check || check_crc (fd, debuglink_crc);
158da0c48c4Sopenharmony_ci}
159da0c48c4Sopenharmony_ci
160da0c48c4Sopenharmony_cistatic int
161da0c48c4Sopenharmony_cifind_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
162da0c48c4Sopenharmony_ci			const char *debuglink_file, GElf_Word debuglink_crc,
163da0c48c4Sopenharmony_ci			char **debuginfo_file_name)
164da0c48c4Sopenharmony_ci{
165da0c48c4Sopenharmony_ci  bool cancheck = debuglink_crc != (GElf_Word) 0;
166da0c48c4Sopenharmony_ci
167da0c48c4Sopenharmony_ci  const char *file_basename = file_name == NULL ? NULL : basename (file_name);
168da0c48c4Sopenharmony_ci  char *localname = NULL;
169da0c48c4Sopenharmony_ci
170da0c48c4Sopenharmony_ci  /* We invent a debuglink .debug name if NULL, but then want to try the
171da0c48c4Sopenharmony_ci     basename too.  */
172da0c48c4Sopenharmony_ci  bool debuglink_null = debuglink_file == NULL;
173da0c48c4Sopenharmony_ci  if (debuglink_null)
174da0c48c4Sopenharmony_ci    {
175da0c48c4Sopenharmony_ci      /* For a alt debug multi file we need a name, for a separate debug
176da0c48c4Sopenharmony_ci	 name we may be able to fall back on file_basename.debug.  */
177da0c48c4Sopenharmony_ci      if (file_basename == NULL || mod->dw != NULL)
178da0c48c4Sopenharmony_ci	{
179da0c48c4Sopenharmony_ci	  errno = 0;
180da0c48c4Sopenharmony_ci	  return -1;
181da0c48c4Sopenharmony_ci	}
182da0c48c4Sopenharmony_ci
183da0c48c4Sopenharmony_ci      size_t len = strlen (file_basename);
184da0c48c4Sopenharmony_ci      localname = malloc (len + sizeof ".debug");
185da0c48c4Sopenharmony_ci      if (unlikely (localname == NULL))
186da0c48c4Sopenharmony_ci	return -1;
187da0c48c4Sopenharmony_ci      memcpy (localname, file_basename, len);
188da0c48c4Sopenharmony_ci      memcpy (&localname[len], ".debug", sizeof ".debug");
189da0c48c4Sopenharmony_ci      debuglink_file = localname;
190da0c48c4Sopenharmony_ci      cancheck = false;
191da0c48c4Sopenharmony_ci    }
192da0c48c4Sopenharmony_ci
193da0c48c4Sopenharmony_ci  /* Look for a file named DEBUGLINK_FILE in the directories
194da0c48c4Sopenharmony_ci     indicated by the debug directory path setting.  */
195da0c48c4Sopenharmony_ci
196da0c48c4Sopenharmony_ci  const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
197da0c48c4Sopenharmony_ci  char *localpath = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
198da0c48c4Sopenharmony_ci			    ?: DEFAULT_DEBUGINFO_PATH);
199da0c48c4Sopenharmony_ci  if (unlikely (localpath == NULL))
200da0c48c4Sopenharmony_ci    {
201da0c48c4Sopenharmony_ci      free (localname);
202da0c48c4Sopenharmony_ci      return -1;
203da0c48c4Sopenharmony_ci    }
204da0c48c4Sopenharmony_ci
205da0c48c4Sopenharmony_ci  /* A leading - or + in the whole path sets whether to check file CRCs.  */
206da0c48c4Sopenharmony_ci  bool defcheck = true;
207da0c48c4Sopenharmony_ci  char *path = localpath;
208da0c48c4Sopenharmony_ci  if (path[0] == '-' || path[0] == '+')
209da0c48c4Sopenharmony_ci    {
210da0c48c4Sopenharmony_ci      defcheck = path[0] == '+';
211da0c48c4Sopenharmony_ci      ++path;
212da0c48c4Sopenharmony_ci    }
213da0c48c4Sopenharmony_ci
214da0c48c4Sopenharmony_ci  /* XXX dev/ino should be cached in struct dwfl_file.  */
215da0c48c4Sopenharmony_ci  struct stat main_stat;
216da0c48c4Sopenharmony_ci  if (unlikely ((mod->main.fd != -1 ? fstat (mod->main.fd, &main_stat)
217da0c48c4Sopenharmony_ci		 : file_name != NULL ? stat (file_name, &main_stat)
218da0c48c4Sopenharmony_ci		 : -1) < 0))
219da0c48c4Sopenharmony_ci    {
220da0c48c4Sopenharmony_ci      main_stat.st_dev = 0;
221da0c48c4Sopenharmony_ci      main_stat.st_ino = 0;
222da0c48c4Sopenharmony_ci    }
223da0c48c4Sopenharmony_ci
224da0c48c4Sopenharmony_ci  char *file_dirname = (file_basename == file_name ? NULL
225da0c48c4Sopenharmony_ci			: strndup (file_name, file_basename - 1 - file_name));
226da0c48c4Sopenharmony_ci  if (file_basename != file_name && file_dirname == NULL)
227da0c48c4Sopenharmony_ci    {
228da0c48c4Sopenharmony_ci      free (localpath);
229da0c48c4Sopenharmony_ci      free (localname);
230da0c48c4Sopenharmony_ci      return -1;
231da0c48c4Sopenharmony_ci    }
232da0c48c4Sopenharmony_ci  char *p;
233da0c48c4Sopenharmony_ci  while ((p = strsep (&path, ":")) != NULL)
234da0c48c4Sopenharmony_ci    {
235da0c48c4Sopenharmony_ci      /* A leading - or + says whether to check file CRCs for this element.  */
236da0c48c4Sopenharmony_ci      bool check = defcheck;
237da0c48c4Sopenharmony_ci      if (*p == '+' || *p == '-')
238da0c48c4Sopenharmony_ci	check = *p++ == '+';
239da0c48c4Sopenharmony_ci      check = check && cancheck;
240da0c48c4Sopenharmony_ci
241da0c48c4Sopenharmony_ci      /* Try the basename too, if we made up the debuglink name and this
242da0c48c4Sopenharmony_ci	 is not the main directory.  */
243da0c48c4Sopenharmony_ci      bool try_file_basename;
244da0c48c4Sopenharmony_ci
245da0c48c4Sopenharmony_ci      const char *dir, *subdir, *file;
246da0c48c4Sopenharmony_ci      switch (p[0])
247da0c48c4Sopenharmony_ci	{
248da0c48c4Sopenharmony_ci	case '\0':
249da0c48c4Sopenharmony_ci	  /* An empty entry says to try the main file's directory.  */
250da0c48c4Sopenharmony_ci	  dir = file_dirname;
251da0c48c4Sopenharmony_ci	  subdir = NULL;
252da0c48c4Sopenharmony_ci	  file = debuglink_file;
253da0c48c4Sopenharmony_ci	  try_file_basename = false;
254da0c48c4Sopenharmony_ci	  break;
255da0c48c4Sopenharmony_ci	case '/':
256da0c48c4Sopenharmony_ci	  /* An absolute path says to look there for a subdirectory
257da0c48c4Sopenharmony_ci	     named by the main file's absolute directory.  This cannot
258da0c48c4Sopenharmony_ci	     be applied to a relative file name.  For alt debug files
259da0c48c4Sopenharmony_ci	     it means to look for the basename file in that dir or the
260da0c48c4Sopenharmony_ci	     .dwz subdir (see below).  */
261da0c48c4Sopenharmony_ci	  if (mod->dw == NULL
262da0c48c4Sopenharmony_ci	      && (file_dirname == NULL || file_dirname[0] != '/'))
263da0c48c4Sopenharmony_ci	    continue;
264da0c48c4Sopenharmony_ci	  dir = p;
265da0c48c4Sopenharmony_ci	  if (mod->dw == NULL)
266da0c48c4Sopenharmony_ci	    {
267da0c48c4Sopenharmony_ci	      subdir = file_dirname;
268da0c48c4Sopenharmony_ci	      /* We want to explore all sub-subdirs.  Chop off one slash
269da0c48c4Sopenharmony_ci		 at a time.  */
270da0c48c4Sopenharmony_ci	    explore_dir:
271da0c48c4Sopenharmony_ci	      subdir = strchr (subdir, '/');
272da0c48c4Sopenharmony_ci	      if (subdir != NULL)
273da0c48c4Sopenharmony_ci		subdir = subdir + 1;
274da0c48c4Sopenharmony_ci	      if (subdir && *subdir == 0)
275da0c48c4Sopenharmony_ci		continue;
276da0c48c4Sopenharmony_ci	      file = debuglink_file;
277da0c48c4Sopenharmony_ci	    }
278da0c48c4Sopenharmony_ci	  else
279da0c48c4Sopenharmony_ci	    {
280da0c48c4Sopenharmony_ci	      subdir = NULL;
281da0c48c4Sopenharmony_ci	      file = basename (debuglink_file);
282da0c48c4Sopenharmony_ci	    }
283da0c48c4Sopenharmony_ci	  try_file_basename = debuglink_null;
284da0c48c4Sopenharmony_ci	  break;
285da0c48c4Sopenharmony_ci	default:
286da0c48c4Sopenharmony_ci	  /* A relative path says to try a subdirectory of that name
287da0c48c4Sopenharmony_ci	     in the main file's directory.  */
288da0c48c4Sopenharmony_ci	  dir = file_dirname;
289da0c48c4Sopenharmony_ci	  subdir = p;
290da0c48c4Sopenharmony_ci	  file = debuglink_file;
291da0c48c4Sopenharmony_ci	  try_file_basename = debuglink_null;
292da0c48c4Sopenharmony_ci	  break;
293da0c48c4Sopenharmony_ci	}
294da0c48c4Sopenharmony_ci
295da0c48c4Sopenharmony_ci      char *fname = NULL;
296da0c48c4Sopenharmony_ci      int fd = try_open (&main_stat, dir, subdir, file, &fname);
297da0c48c4Sopenharmony_ci      if (fd < 0 && try_file_basename)
298da0c48c4Sopenharmony_ci	fd = try_open (&main_stat, dir, subdir, file_basename, &fname);
299da0c48c4Sopenharmony_ci      if (fd < 0)
300da0c48c4Sopenharmony_ci	switch (errno)
301da0c48c4Sopenharmony_ci	  {
302da0c48c4Sopenharmony_ci	  case ENOENT:
303da0c48c4Sopenharmony_ci	  case ENOTDIR:
304da0c48c4Sopenharmony_ci	    /* If we are looking for the alt file also try the .dwz subdir.
305da0c48c4Sopenharmony_ci	       But only if this is the empty or absolute path.  */
306da0c48c4Sopenharmony_ci	    if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
307da0c48c4Sopenharmony_ci	      {
308da0c48c4Sopenharmony_ci		fd = try_open (&main_stat, dir, ".dwz",
309da0c48c4Sopenharmony_ci			       basename (file), &fname);
310da0c48c4Sopenharmony_ci		if (fd < 0)
311da0c48c4Sopenharmony_ci		  {
312da0c48c4Sopenharmony_ci		    if (errno != ENOENT && errno != ENOTDIR)
313da0c48c4Sopenharmony_ci		      goto fail_free;
314da0c48c4Sopenharmony_ci		    else
315da0c48c4Sopenharmony_ci		      continue;
316da0c48c4Sopenharmony_ci		  }
317da0c48c4Sopenharmony_ci		break;
318da0c48c4Sopenharmony_ci	      }
319da0c48c4Sopenharmony_ci	    /* If possible try again with a sub-subdir.  */
320da0c48c4Sopenharmony_ci	    if (mod->dw == NULL && subdir)
321da0c48c4Sopenharmony_ci	      goto explore_dir;
322da0c48c4Sopenharmony_ci	    continue;
323da0c48c4Sopenharmony_ci	  default:
324da0c48c4Sopenharmony_ci	    goto fail_free;
325da0c48c4Sopenharmony_ci	  }
326da0c48c4Sopenharmony_ci      if (validate (mod, fd, check, debuglink_crc))
327da0c48c4Sopenharmony_ci	{
328da0c48c4Sopenharmony_ci	  free (localpath);
329da0c48c4Sopenharmony_ci	  free (localname);
330da0c48c4Sopenharmony_ci	  free (file_dirname);
331da0c48c4Sopenharmony_ci	  *debuginfo_file_name = fname;
332da0c48c4Sopenharmony_ci	  return fd;
333da0c48c4Sopenharmony_ci	}
334da0c48c4Sopenharmony_ci      free (fname);
335da0c48c4Sopenharmony_ci      close (fd);
336da0c48c4Sopenharmony_ci    }
337da0c48c4Sopenharmony_ci
338da0c48c4Sopenharmony_ci  /* No dice.  */
339da0c48c4Sopenharmony_ci  errno = 0;
340da0c48c4Sopenharmony_cifail_free:
341da0c48c4Sopenharmony_ci  free (localpath);
342da0c48c4Sopenharmony_ci  free (localname);
343da0c48c4Sopenharmony_ci  free (file_dirname);
344da0c48c4Sopenharmony_ci  return -1;
345da0c48c4Sopenharmony_ci}
346da0c48c4Sopenharmony_ci
347da0c48c4Sopenharmony_ciint
348da0c48c4Sopenharmony_cidwfl_standard_find_debuginfo (Dwfl_Module *mod,
349da0c48c4Sopenharmony_ci			      void **userdata __attribute__ ((unused)),
350da0c48c4Sopenharmony_ci			      const char *modname __attribute__ ((unused)),
351da0c48c4Sopenharmony_ci			      GElf_Addr base __attribute__ ((unused)),
352da0c48c4Sopenharmony_ci			      const char *file_name,
353da0c48c4Sopenharmony_ci			      const char *debuglink_file,
354da0c48c4Sopenharmony_ci			      GElf_Word debuglink_crc,
355da0c48c4Sopenharmony_ci			      char **debuginfo_file_name)
356da0c48c4Sopenharmony_ci{
357da0c48c4Sopenharmony_ci  if (mod == NULL)
358da0c48c4Sopenharmony_ci    return -1;
359da0c48c4Sopenharmony_ci
360da0c48c4Sopenharmony_ci  /* First try by build ID if we have one.  If that succeeds or fails
361da0c48c4Sopenharmony_ci     other than just by finding nothing, that's all we do.  */
362da0c48c4Sopenharmony_ci  const unsigned char *bits = NULL;
363da0c48c4Sopenharmony_ci  GElf_Addr vaddr;
364da0c48c4Sopenharmony_ci  int bits_len;
365da0c48c4Sopenharmony_ci  if ((bits_len = INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr)) > 0)
366da0c48c4Sopenharmony_ci    {
367da0c48c4Sopenharmony_ci      /* Dropping most arguments means we cannot rely on them in
368da0c48c4Sopenharmony_ci	 dwfl_build_id_find_debuginfo.  But leave it that way since
369da0c48c4Sopenharmony_ci	 some user code out there also does this, so we'll have to
370da0c48c4Sopenharmony_ci	 handle it anyway.  */
371da0c48c4Sopenharmony_ci      int fd = INTUSE(dwfl_build_id_find_debuginfo) (mod,
372da0c48c4Sopenharmony_ci						     NULL, NULL, 0,
373da0c48c4Sopenharmony_ci						     NULL, NULL, 0,
374da0c48c4Sopenharmony_ci						     debuginfo_file_name);
375da0c48c4Sopenharmony_ci
376da0c48c4Sopenharmony_ci      /* Did the build_id callback find something or report an error?
377da0c48c4Sopenharmony_ci         Then we are done.  Otherwise fallback on path based search.  */
378da0c48c4Sopenharmony_ci      if (fd >= 0
379da0c48c4Sopenharmony_ci	  || (mod->dw == NULL && mod->debug.elf != NULL)
380da0c48c4Sopenharmony_ci	  || (mod->dw != NULL && mod->alt_elf != NULL)
381da0c48c4Sopenharmony_ci	  || errno != 0)
382da0c48c4Sopenharmony_ci	return fd;
383da0c48c4Sopenharmony_ci    }
384da0c48c4Sopenharmony_ci
385da0c48c4Sopenharmony_ci  /* Failing that, search the path by name.  */
386da0c48c4Sopenharmony_ci  int fd = find_debuginfo_in_path (mod, file_name,
387da0c48c4Sopenharmony_ci				   debuglink_file, debuglink_crc,
388da0c48c4Sopenharmony_ci				   debuginfo_file_name);
389da0c48c4Sopenharmony_ci
390da0c48c4Sopenharmony_ci  if (fd < 0 && errno == 0 && file_name != NULL)
391da0c48c4Sopenharmony_ci    {
392da0c48c4Sopenharmony_ci      /* If FILE_NAME is a symlink, the debug file might be associated
393da0c48c4Sopenharmony_ci	 with the symlink target name instead.  */
394da0c48c4Sopenharmony_ci
395da0c48c4Sopenharmony_ci      char *canon = realpath (file_name, NULL);
396da0c48c4Sopenharmony_ci      if (canon != NULL && strcmp (file_name, canon))
397da0c48c4Sopenharmony_ci	fd = find_debuginfo_in_path (mod, canon,
398da0c48c4Sopenharmony_ci				     debuglink_file, debuglink_crc,
399da0c48c4Sopenharmony_ci				     debuginfo_file_name);
400da0c48c4Sopenharmony_ci      free (canon);
401da0c48c4Sopenharmony_ci    }
402da0c48c4Sopenharmony_ci
403da0c48c4Sopenharmony_ci#ifdef ENABLE_LIBDEBUGINFOD
404da0c48c4Sopenharmony_ci  /* Still nothing? Try if we can use the debuginfod client.
405da0c48c4Sopenharmony_ci     But note that we might be looking for the alt file.
406da0c48c4Sopenharmony_ci     We use the same trick as dwfl_build_id_find_debuginfo.
407da0c48c4Sopenharmony_ci     If the debug file (dw) is already set, then we must be
408da0c48c4Sopenharmony_ci     looking for the altfile. But we cannot use the actual
409da0c48c4Sopenharmony_ci     file/path name given as hint. We'll have to lookup the
410da0c48c4Sopenharmony_ci     alt file "build-id". Because the debuginfod client only
411da0c48c4Sopenharmony_ci     handles build-ids.  */
412da0c48c4Sopenharmony_ci  if (fd < 0)
413da0c48c4Sopenharmony_ci    {
414da0c48c4Sopenharmony_ci      if (mod->dw != NULL)
415da0c48c4Sopenharmony_ci	{
416da0c48c4Sopenharmony_ci	  const char *altname;
417da0c48c4Sopenharmony_ci	  bits_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw, &altname,
418da0c48c4Sopenharmony_ci							   (const void **)
419da0c48c4Sopenharmony_ci							   &bits);
420da0c48c4Sopenharmony_ci	}
421da0c48c4Sopenharmony_ci
422da0c48c4Sopenharmony_ci      if (bits_len > 0)
423da0c48c4Sopenharmony_ci	fd = __libdwfl_debuginfod_find_debuginfo (mod->dwfl, bits, bits_len);
424da0c48c4Sopenharmony_ci    }
425da0c48c4Sopenharmony_ci#endif
426da0c48c4Sopenharmony_ci
427da0c48c4Sopenharmony_ci  return fd;
428da0c48c4Sopenharmony_ci}
429da0c48c4Sopenharmony_ciINTDEF (dwfl_standard_find_debuginfo)
430