159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath/* Find an ELF file for a module from its build ID.
2c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard   Copyright (C) 2007-2010, 2014, 2015 Red Hat, Inc.
3de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is part of elfutils.
4b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
5de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   This file is free software; you can redistribute it and/or modify
6de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   it under the terms of either
7b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
8de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU Lesser General Public License as published by the Free
9de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 3 of the License, or (at
10de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
11de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
12de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or
13de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
14de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard     * the GNU General Public License as published by the Free
15de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       Software Foundation; either version 2 of the License, or (at
16de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard       your option) any later version
17de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
18de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   or both in parallel, as here.
19de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard
20de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
21361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   WITHOUT ANY WARRANTY; without even the implied warranty of
22361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23361df7da6dfecd817b27e62b91752ac316d7cdd4Ulrich Drepper   General Public License for more details.
24b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
25de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   You should have received copies of the GNU General Public License and
26de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   the GNU Lesser General Public License along with this program.  If
27de2ed97f33139af5c7a0811e4ec66fc896a13cf2Mark Wielaard   not, see <http://www.gnu.org/licenses/>.  */
28b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
2959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include "libdwflP.h"
3059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include <inttypes.h>
3159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath#include <fcntl.h>
32b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper#include <unistd.h>
33b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
34b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
3559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathint
3659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathinternal_function
37df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name,
38df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard			    const size_t id_len, const uint8_t *id)
39b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper{
40c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  /* We don't handle very short or really large build-ids.  We need at
41c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard     at least 3 and allow for up to 64 (normally ids are 20 long).  */
42c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard#define MIN_BUILD_ID_BYTES 3
43c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard#define MAX_BUILD_ID_BYTES 64
44c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  if (id_len < MIN_BUILD_ID_BYTES || id_len > MAX_BUILD_ID_BYTES)
45c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard    {
46c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard      __libdwfl_seterrno (DWFL_E_WRONG_ID_ELF);
47c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard      return -1;
48c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard    }
49c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard
5059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  /* Search debuginfo_path directories' .build-id/ subdirectories.  */
5159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
52c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  char id_name[sizeof "/.build-id/" + 1 + MAX_BUILD_ID_BYTES * 2
53c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard	       + sizeof ".debug" - 1];
5459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  strcpy (id_name, "/.build-id/");
5559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  int n = snprintf (&id_name[sizeof "/.build-id/" - 1],
5659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath		    4, "%02" PRIx8 "/", (uint8_t) id[0]);
5759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  assert (n == 3);
5859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  for (size_t i = 1; i < id_len; ++i)
59b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
6059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      n = snprintf (&id_name[sizeof "/.build-id/" - 1 + 3 + (i - 1) * 2],
6159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath		    3, "%02" PRIx8, (uint8_t) id[i]);
6259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      assert (n == 2);
63b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
6459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (debug)
6559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    strcpy (&id_name[sizeof "/.build-id/" - 1 + 3 + (id_len - 1) * 2],
6659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    ".debug");
6759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
6859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
69c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  char *path = strdup ((cb->debuginfo_path ? *cb->debuginfo_path : NULL)
70c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard		       ?: DEFAULT_DEBUGINFO_PATH);
71c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  if (path == NULL)
72c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard    return -1;
73b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
7459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  int fd = -1;
7559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  char *dir;
768aaf4fc46f5b0b1ed2b567734d06875a39047dd9Mark Wielaard  char *paths = path;
778aaf4fc46f5b0b1ed2b567734d06875a39047dd9Mark Wielaard  while (fd < 0 && (dir = strsep (&paths, ":")) != NULL)
78b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    {
7959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (dir[0] == '+' || dir[0] == '-')
8059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	++dir;
8159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
8259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      /* Only absolute directory names are useful to us.  */
8359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (dir[0] != '/')
8459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	continue;
8559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
8659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      size_t dirlen = strlen (dir);
8759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      char *name = malloc (dirlen + sizeof id_name);
8859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (unlikely (name == NULL))
8959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	break;
9059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      memcpy (mempcpy (name, dir, dirlen), id_name, sizeof id_name);
9159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
923425454a10d307fae891fb667cf7969e945cde79Josh Stone      fd = TEMP_FAILURE_RETRY (open (name, O_RDONLY));
9359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      if (fd >= 0)
9459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
9559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  if (*file_name != NULL)
9659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    free (*file_name);
9759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  *file_name = canonicalize_file_name (name);
9859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  if (*file_name == NULL)
9959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    {
10059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	      *file_name = name;
10159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	      name = NULL;
10259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	    }
10359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
10459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      free (name);
105b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper    }
106b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper
107c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard  free (path);
108c57829bb118bc30d874f7440b421abbebc74a733Mark Wielaard
1091d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath  /* If we simply found nothing, clear errno.  If we had some other error
1101d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath     with the file, report that.  Possibly this should treat other errors
1111d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath     like ENOENT too.  But ignoring all errors could mask some that should
1121d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath     be reported.  */
1131d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath  if (fd < 0 && errno == ENOENT)
1141d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath    errno = 0;
1151d8bb25cac06b5af57f8733e5ea7a068a79edfe0Roland McGrath
11659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  return fd;
11759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath}
11859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath
11959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathint
120df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaardinternal_function
121df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard__libdwfl_open_mod_by_build_id (Dwfl_Module *mod, bool debug, char **file_name)
122df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard{
123df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  /* If *FILE_NAME was primed into the module, leave it there
124df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard     as the fallback when we have nothing to offer.  */
125df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  errno = 0;
126df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  if (mod->build_id_len <= 0)
127df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard    return -1;
128df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard
129df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  const size_t id_len = mod->build_id_len;
130df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  const uint8_t *id = mod->build_id_bits;
131df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard
132df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  return __libdwfl_open_by_build_id (mod, debug, file_name, id_len, id);
133df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard}
134df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard
135df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaardint
13659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathdwfl_build_id_find_elf (Dwfl_Module *mod,
13759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath			void **userdata __attribute__ ((unused)),
13859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath			const char *modname __attribute__ ((unused)),
13959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath			Dwarf_Addr base __attribute__ ((unused)),
14059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath			char **file_name, Elf **elfp)
14159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath{
14259ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  *elfp = NULL;
143355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard  if (mod->is_executable
144355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard      && mod->dwfl->user_core != NULL
145355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard      && mod->dwfl->user_core->executable_for_core != NULL)
146c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil    {
147c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil      /* When dwfl_core_file_report was called with a non-NULL executable file
148c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	 name this callback will replace the Dwfl_Module main.name with the
1496097c00a539873e9baa22e10f9387b9c36c4fa25Jan Kratochvil	 recorded executable file when MOD was identified as main executable
1506097c00a539873e9baa22e10f9387b9c36c4fa25Jan Kratochvil	 (which then triggers opening and reporting of the executable).  */
151355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard      const char *executable = mod->dwfl->user_core->executable_for_core;
152355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard      int fd = open (executable, O_RDONLY);
153c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil      if (fd >= 0)
154c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	{
155355b408bb9aa49703544fa4086e1ae463737fcf6Mark Wielaard	  *file_name = strdup (executable);
156c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	  if (*file_name != NULL)
157c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	    return fd;
158c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	  else
159c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	    close (fd);
160c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil	}
161c53094634516313fb598d67e709f51f20d6acbbaJan Kratochvil    }
162df85bf99021119fcbb2ced66dd69f1cceafb180cMark Wielaard  int fd = __libdwfl_open_mod_by_build_id (mod, false, file_name);
16359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  if (fd >= 0)
16459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    {
165bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath      Dwfl_Error error = __libdw_open_file (&fd, elfp, true, false);
166bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath      if (error != DWFL_E_NOERROR)
167bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	__libdwfl_seterrno (error);
168bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath      else if (__libdwfl_find_build_id (mod, false, *elfp) == 2)
169bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	{
170bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	  /* This is a backdoor signal to short-circuit the ID refresh.  */
171bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	  mod->main.valid = true;
172bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	  return fd;
173bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath	}
17459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath      else
17559ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	{
17659ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  /* This file does not contain the ID it should!  */
17759ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  elf_end (*elfp);
17859ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  *elfp = NULL;
17959ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  close (fd);
18059ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	  fd = -1;
18159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath	}
182bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath      free (*file_name);
183bca43152aa0bcb31b9442c407bf2b86379761c50Roland McGrath      *file_name = NULL;
18459ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath    }
185ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath  else if (errno == 0 && mod->build_id_len > 0)
186ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath    /* Setting this with no file yet loaded is a marker that
187ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath       the build ID is authoritative even if we also know a
188ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath       putative *FILE_NAME.  */
189ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath    mod->main.valid = true;
190ed431ddb74331f24add8c6d932ebed129c4385d8Roland McGrath
19159ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrath  return fd;
192b08d5a8fb42f4586d756068065186b5af7e48daUlrich Drepper}
19359ea7f33f781e6e3f8c9d81d457e5d99eee8f1ceRoland McGrathINTDEF (dwfl_build_id_find_elf)
194