1d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard/* Returns the build id if found in a NT_GNU_BUILD_ID note.
2d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   Copyright (C) 2014 Red Hat, Inc.
3d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   This file is part of elfutils.
4d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
5d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   This file is free software; you can redistribute it and/or modify
6d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   it under the terms of either
7d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
8d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard     * the GNU Lesser General Public License as published by the Free
9d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard       Software Foundation; either version 3 of the License, or (at
10d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard       your option) any later version
11d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
12d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   or
13d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
14d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard     * the GNU General Public License as published by the Free
15d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard       Software Foundation; either version 2 of the License, or (at
16d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard       your option) any later version
17d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
18d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   or both in parallel, as here.
19d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
20d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   elfutils is distributed in the hope that it will be useful, but
21d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   WITHOUT ANY WARRANTY; without even the implied warranty of
22d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   General Public License for more details.
24d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
25d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   You should have received copies of the GNU General Public License and
26d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   the GNU Lesser General Public License along with this program.  If
27d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard   not, see <http://www.gnu.org/licenses/>.  */
28d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
29d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard#ifdef HAVE_CONFIG_H
30d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard# include <config.h>
31d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard#endif
32d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
33d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard#include "libdwelfP.h"
34d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard#include "libdwflP.h"
35d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
36d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard#define NO_VADDR	((GElf_Addr) -1l)
37d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
38d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaardstatic int
3911659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsiehcheck_notes (Elf_Data *data, GElf_Addr data_elfaddr,
4011659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh             const void **build_id_bits, GElf_Addr *build_id_elfaddr,
4111659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh             int *build_id_len)
42d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard{
4311659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  size_t pos = 0;
4411659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  GElf_Nhdr nhdr;
4511659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  size_t name_pos;
4611659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  size_t desc_pos;
4711659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
4811659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh    if (nhdr.n_type == NT_GNU_BUILD_ID
4911659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	&& nhdr.n_namesz == sizeof "GNU"
5011659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	&& !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
51d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	{
52d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  *build_id_bits = data->d_buf + desc_pos;
53d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  *build_id_elfaddr = (data_elfaddr == NO_VADDR
5411659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	                      ? 0 : data_elfaddr + desc_pos);
55d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  *build_id_len = nhdr.n_descsz;
56d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  return 1;
57d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	}
5811659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh  return 0;
5911659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh}
60d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
6111659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh/* Defined here for reuse. The dwelf interface doesn't care about the
6211659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh   address of the note, but libdwfl does.  */
6311659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsiehstatic int
6411659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsiehfind_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
6511659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh		   const void **build_id_bits, GElf_Addr *build_id_elfaddr,
6611659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh		   int *build_id_len)
6711659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh{
68d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  size_t shstrndx = SHN_UNDEF;
69d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  int result = 0;
70d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
71d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  Elf_Scn *scn = elf_nextscn (elf, NULL);
72d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
73d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  if (scn == NULL)
74d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    {
75d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      /* No sections, have to look for phdrs.  */
76d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      size_t phnum;
77d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
78d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	{
79d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  if (mod != NULL)
80d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    __libdwfl_seterrno (DWFL_E_LIBELF);
81d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  return -1;
82d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	}
83d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      for (size_t i = 0; result == 0 && i < phnum; ++i)
84d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	{
85d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  GElf_Phdr phdr_mem;
86d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
87d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
88d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    result = check_notes (elf_getdata_rawchunk (elf,
89d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard							phdr->p_offset,
90d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard							phdr->p_filesz,
91d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard							ELF_T_NHDR),
9211659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh				  phdr->p_vaddr,
9311659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh				  build_id_bits,
9411659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh				  build_id_elfaddr,
9511659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh				  build_id_len);
96d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	}
97d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    }
98d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  else
99d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    do
100d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      {
101d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	GElf_Shdr shdr_mem;
102d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
103d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
104d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  {
105d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    /* Determine the right sh_addr in this module.  */
106d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    GElf_Addr vaddr = 0;
107d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    if (!(shdr->sh_flags & SHF_ALLOC))
108d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	      vaddr = NO_VADDR;
109d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    else if (mod == NULL || e_type != ET_REL)
110d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	      vaddr = shdr->sh_addr;
111d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	    else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
112d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard					       elf_ndxscn (scn), &vaddr))
113d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	      vaddr = NO_VADDR;
11411659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	    result = check_notes (elf_getdata (scn, NULL), vaddr,
11511659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	                          build_id_bits,
11611659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	                          build_id_elfaddr,
11711659f252932ac2031209d6601d7e6d4cb66dc3fChih-Hung Hsieh	                          build_id_len);
118d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard	  }
119d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      }
120d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
121d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
122d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  return result;
123d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard}
124d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
125d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaardint
126d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaardinternal_function
127d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
128d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard			     const void **build_id_bits,
129d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard			     GElf_Addr *build_id_elfaddr, int *build_id_len)
130d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard{
131d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
132d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  if (unlikely (ehdr == NULL))
133d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    {
134d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      __libdwfl_seterrno (DWFL_E_LIBELF);
135d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard      return -1;
136d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    }
137d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  // MOD->E_TYPE is zero here.
138d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  assert (ehdr->e_type != ET_REL || mod != NULL);
139d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
140d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  return find_elf_build_id (mod, ehdr->e_type, elf,
141d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard			    build_id_bits, build_id_elfaddr, build_id_len);
142d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard}
143d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
144d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaardssize_t
145d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaarddwelf_elf_gnu_build_id (Elf *elf, const void **build_idp)
146d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard{
147d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  GElf_Addr build_id_elfaddr;
148d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  int build_id_len;
149d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp,
150d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard				  &build_id_elfaddr, &build_id_len);
151d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  if (result > 0)
152d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard    return build_id_len;
153d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard
154d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard  return result;
155d81d32d2a4f92355e4c677b578147dfe819251b9Mark Wielaard}
156d81d32d2a4f92355e4c677b578147dfe819251b9Mark WielaardINTDEF(dwelf_elf_gnu_build_id)
157