1da0c48c4Sopenharmony_ci/* Find the debuginfo file for a module from its build ID.
2da0c48c4Sopenharmony_ci   Copyright (C) 2007, 2009, 2014 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
35da0c48c4Sopenharmony_ciint
36da0c48c4Sopenharmony_cidwfl_build_id_find_debuginfo (Dwfl_Module *mod,
37da0c48c4Sopenharmony_ci			      void **userdata __attribute__ ((unused)),
38da0c48c4Sopenharmony_ci			      const char *modname __attribute__ ((unused)),
39da0c48c4Sopenharmony_ci			      Dwarf_Addr base __attribute__ ((unused)),
40da0c48c4Sopenharmony_ci			      const char *file __attribute__ ((unused)),
41da0c48c4Sopenharmony_ci			      const char *debuglink __attribute__ ((unused)),
42da0c48c4Sopenharmony_ci			      GElf_Word crc __attribute__ ((unused)),
43da0c48c4Sopenharmony_ci			      char **debuginfo_file_name)
44da0c48c4Sopenharmony_ci{
45da0c48c4Sopenharmony_ci  int fd = -1;
46da0c48c4Sopenharmony_ci
47da0c48c4Sopenharmony_ci  /* Are we looking for a separate debug file for the main file or for
48da0c48c4Sopenharmony_ci     an alternate (dwz multi) debug file?  Alternatively we could check
49da0c48c4Sopenharmony_ci     whether the dwbias == -1.  */
50da0c48c4Sopenharmony_ci  if (mod->dw != NULL)
51da0c48c4Sopenharmony_ci    {
52da0c48c4Sopenharmony_ci      const void *build_id;
53da0c48c4Sopenharmony_ci      const char *altname;
54da0c48c4Sopenharmony_ci      ssize_t build_id_len = INTUSE(dwelf_dwarf_gnu_debugaltlink) (mod->dw,
55da0c48c4Sopenharmony_ci								   &altname,
56da0c48c4Sopenharmony_ci								   &build_id);
57da0c48c4Sopenharmony_ci      if (build_id_len > 0)
58da0c48c4Sopenharmony_ci	fd = __libdwfl_open_by_build_id (mod, true, debuginfo_file_name,
59da0c48c4Sopenharmony_ci					 build_id_len, build_id);
60da0c48c4Sopenharmony_ci
61da0c48c4Sopenharmony_ci      if (fd >= 0)
62da0c48c4Sopenharmony_ci	{
63da0c48c4Sopenharmony_ci	  /* We need to open an Elf handle on the file so we can check its
64da0c48c4Sopenharmony_ci	     build ID note for validation.  Backdoor the handle into the
65da0c48c4Sopenharmony_ci	     module data structure since we had to open it early anyway.  */
66da0c48c4Sopenharmony_ci	  Dwfl_Error error = __libdw_open_file (&fd, &mod->alt_elf,
67da0c48c4Sopenharmony_ci						true, false);
68da0c48c4Sopenharmony_ci	  if (error != DWFL_E_NOERROR)
69da0c48c4Sopenharmony_ci	    __libdwfl_seterrno (error);
70da0c48c4Sopenharmony_ci	  else
71da0c48c4Sopenharmony_ci	    {
72da0c48c4Sopenharmony_ci	      const void *alt_build_id;
73da0c48c4Sopenharmony_ci	      ssize_t alt_len = INTUSE(dwelf_elf_gnu_build_id) (mod->alt_elf,
74da0c48c4Sopenharmony_ci								&alt_build_id);
75da0c48c4Sopenharmony_ci	      if (alt_len > 0 && alt_len == build_id_len
76da0c48c4Sopenharmony_ci		  && memcmp (build_id, alt_build_id, alt_len) == 0)
77da0c48c4Sopenharmony_ci		return fd;
78da0c48c4Sopenharmony_ci	      else
79da0c48c4Sopenharmony_ci		{
80da0c48c4Sopenharmony_ci		  /* A mismatch!  */
81da0c48c4Sopenharmony_ci		  elf_end (mod->alt_elf);
82da0c48c4Sopenharmony_ci		  mod->alt_elf = NULL;
83da0c48c4Sopenharmony_ci		  close (fd);
84da0c48c4Sopenharmony_ci		  fd = -1;
85da0c48c4Sopenharmony_ci		}
86da0c48c4Sopenharmony_ci	      free (*debuginfo_file_name);
87da0c48c4Sopenharmony_ci	      *debuginfo_file_name = NULL;
88da0c48c4Sopenharmony_ci	      errno = 0;
89da0c48c4Sopenharmony_ci	    }
90da0c48c4Sopenharmony_ci	}
91da0c48c4Sopenharmony_ci      return fd;
92da0c48c4Sopenharmony_ci    }
93da0c48c4Sopenharmony_ci
94da0c48c4Sopenharmony_ci  /* We don't even have the Dwarf yet and it isn't in the main file.
95da0c48c4Sopenharmony_ci     Try to find separate debug file now using the module build id.  */
96da0c48c4Sopenharmony_ci  const unsigned char *bits;
97da0c48c4Sopenharmony_ci  GElf_Addr vaddr;
98da0c48c4Sopenharmony_ci
99da0c48c4Sopenharmony_ci  if (INTUSE(dwfl_module_build_id) (mod, &bits, &vaddr) > 0)
100da0c48c4Sopenharmony_ci    fd = __libdwfl_open_mod_by_build_id (mod, true, debuginfo_file_name);
101da0c48c4Sopenharmony_ci  if (fd >= 0)
102da0c48c4Sopenharmony_ci    {
103da0c48c4Sopenharmony_ci      /* We need to open an Elf handle on the file so we can check its
104da0c48c4Sopenharmony_ci	 build ID note for validation.  Backdoor the handle into the
105da0c48c4Sopenharmony_ci	 module data structure since we had to open it early anyway.  */
106da0c48c4Sopenharmony_ci      Dwfl_Error error = __libdw_open_file (&fd, &mod->debug.elf, true, false);
107da0c48c4Sopenharmony_ci      if (error != DWFL_E_NOERROR)
108da0c48c4Sopenharmony_ci	__libdwfl_seterrno (error);
109da0c48c4Sopenharmony_ci      else if (likely (__libdwfl_find_build_id (mod, false,
110da0c48c4Sopenharmony_ci						mod->debug.elf) == 2))
111da0c48c4Sopenharmony_ci	{
112da0c48c4Sopenharmony_ci	  /* Also backdoor the gratuitous flag.  */
113da0c48c4Sopenharmony_ci	  mod->debug.valid = true;
114da0c48c4Sopenharmony_ci	  return fd;
115da0c48c4Sopenharmony_ci	}
116da0c48c4Sopenharmony_ci      else
117da0c48c4Sopenharmony_ci	{
118da0c48c4Sopenharmony_ci	  /* A mismatch!  */
119da0c48c4Sopenharmony_ci	  elf_end (mod->debug.elf);
120da0c48c4Sopenharmony_ci	  mod->debug.elf = NULL;
121da0c48c4Sopenharmony_ci	  close (fd);
122da0c48c4Sopenharmony_ci	  fd = -1;
123da0c48c4Sopenharmony_ci	}
124da0c48c4Sopenharmony_ci      free (*debuginfo_file_name);
125da0c48c4Sopenharmony_ci      *debuginfo_file_name = NULL;
126da0c48c4Sopenharmony_ci      errno = 0;
127da0c48c4Sopenharmony_ci    }
128da0c48c4Sopenharmony_ci  return fd;
129da0c48c4Sopenharmony_ci}
130da0c48c4Sopenharmony_ciINTDEF (dwfl_build_id_find_debuginfo)
131