1da0c48c4Sopenharmony_ci/* Returns the build id if found in a NT_GNU_BUILD_ID note. 2da0c48c4Sopenharmony_ci Copyright (C) 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 "libdwelfP.h" 34da0c48c4Sopenharmony_ci#include "libdwflP.h" 35da0c48c4Sopenharmony_ci 36da0c48c4Sopenharmony_ci#define NO_VADDR ((GElf_Addr) -1l) 37da0c48c4Sopenharmony_ci 38da0c48c4Sopenharmony_cistatic int 39da0c48c4Sopenharmony_cicheck_notes (Elf_Data *data, GElf_Addr data_elfaddr, 40da0c48c4Sopenharmony_ci const void **build_id_bits, GElf_Addr *build_id_elfaddr, 41da0c48c4Sopenharmony_ci int *build_id_len) 42da0c48c4Sopenharmony_ci{ 43da0c48c4Sopenharmony_ci size_t pos = 0; 44da0c48c4Sopenharmony_ci GElf_Nhdr nhdr; 45da0c48c4Sopenharmony_ci size_t name_pos; 46da0c48c4Sopenharmony_ci size_t desc_pos; 47da0c48c4Sopenharmony_ci while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0) 48da0c48c4Sopenharmony_ci if (nhdr.n_type == NT_GNU_BUILD_ID 49da0c48c4Sopenharmony_ci && nhdr.n_namesz == sizeof "GNU" 50da0c48c4Sopenharmony_ci && !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU")) 51da0c48c4Sopenharmony_ci { 52da0c48c4Sopenharmony_ci *build_id_bits = data->d_buf + desc_pos; 53da0c48c4Sopenharmony_ci *build_id_elfaddr = (data_elfaddr == NO_VADDR 54da0c48c4Sopenharmony_ci ? 0 : data_elfaddr + desc_pos); 55da0c48c4Sopenharmony_ci *build_id_len = nhdr.n_descsz; 56da0c48c4Sopenharmony_ci return 1; 57da0c48c4Sopenharmony_ci } 58da0c48c4Sopenharmony_ci return 0; 59da0c48c4Sopenharmony_ci} 60da0c48c4Sopenharmony_ci 61da0c48c4Sopenharmony_ci/* Defined here for reuse. The dwelf interface doesn't care about the 62da0c48c4Sopenharmony_ci address of the note, but libdwfl does. */ 63da0c48c4Sopenharmony_cistatic int 64da0c48c4Sopenharmony_cifind_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf, 65da0c48c4Sopenharmony_ci const void **build_id_bits, GElf_Addr *build_id_elfaddr, 66da0c48c4Sopenharmony_ci int *build_id_len) 67da0c48c4Sopenharmony_ci{ 68da0c48c4Sopenharmony_ci size_t shstrndx = SHN_UNDEF; 69da0c48c4Sopenharmony_ci int result = 0; 70da0c48c4Sopenharmony_ci 71da0c48c4Sopenharmony_ci Elf_Scn *scn = elf_nextscn (elf, NULL); 72da0c48c4Sopenharmony_ci 73da0c48c4Sopenharmony_ci if (scn == NULL) 74da0c48c4Sopenharmony_ci { 75da0c48c4Sopenharmony_ci /* No sections, have to look for phdrs. */ 76da0c48c4Sopenharmony_ci size_t phnum; 77da0c48c4Sopenharmony_ci if (unlikely (elf_getphdrnum (elf, &phnum) != 0)) 78da0c48c4Sopenharmony_ci { 79da0c48c4Sopenharmony_ci if (mod != NULL) 80da0c48c4Sopenharmony_ci __libdwfl_seterrno (DWFL_E_LIBELF); 81da0c48c4Sopenharmony_ci return -1; 82da0c48c4Sopenharmony_ci } 83da0c48c4Sopenharmony_ci for (size_t i = 0; result == 0 && i < phnum; ++i) 84da0c48c4Sopenharmony_ci { 85da0c48c4Sopenharmony_ci GElf_Phdr phdr_mem; 86da0c48c4Sopenharmony_ci GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); 87da0c48c4Sopenharmony_ci if (likely (phdr != NULL) && phdr->p_type == PT_NOTE) 88da0c48c4Sopenharmony_ci result = check_notes (elf_getdata_rawchunk (elf, 89da0c48c4Sopenharmony_ci phdr->p_offset, 90da0c48c4Sopenharmony_ci phdr->p_filesz, 91da0c48c4Sopenharmony_ci (phdr->p_align == 8 92da0c48c4Sopenharmony_ci ? ELF_T_NHDR8 93da0c48c4Sopenharmony_ci : ELF_T_NHDR)), 94da0c48c4Sopenharmony_ci phdr->p_vaddr, 95da0c48c4Sopenharmony_ci build_id_bits, 96da0c48c4Sopenharmony_ci build_id_elfaddr, 97da0c48c4Sopenharmony_ci build_id_len); 98da0c48c4Sopenharmony_ci } 99da0c48c4Sopenharmony_ci } 100da0c48c4Sopenharmony_ci else 101da0c48c4Sopenharmony_ci do 102da0c48c4Sopenharmony_ci { 103da0c48c4Sopenharmony_ci GElf_Shdr shdr_mem; 104da0c48c4Sopenharmony_ci GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 105da0c48c4Sopenharmony_ci if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE) 106da0c48c4Sopenharmony_ci { 107da0c48c4Sopenharmony_ci /* Determine the right sh_addr in this module. */ 108da0c48c4Sopenharmony_ci GElf_Addr vaddr = 0; 109da0c48c4Sopenharmony_ci if (!(shdr->sh_flags & SHF_ALLOC)) 110da0c48c4Sopenharmony_ci vaddr = NO_VADDR; 111da0c48c4Sopenharmony_ci else if (mod == NULL || e_type != ET_REL) 112da0c48c4Sopenharmony_ci vaddr = shdr->sh_addr; 113da0c48c4Sopenharmony_ci else if (__libdwfl_relocate_value (mod, elf, &shstrndx, 114da0c48c4Sopenharmony_ci elf_ndxscn (scn), &vaddr)) 115da0c48c4Sopenharmony_ci vaddr = NO_VADDR; 116da0c48c4Sopenharmony_ci result = check_notes (elf_getdata (scn, NULL), vaddr, 117da0c48c4Sopenharmony_ci build_id_bits, 118da0c48c4Sopenharmony_ci build_id_elfaddr, 119da0c48c4Sopenharmony_ci build_id_len); 120da0c48c4Sopenharmony_ci } 121da0c48c4Sopenharmony_ci } 122da0c48c4Sopenharmony_ci while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL); 123da0c48c4Sopenharmony_ci 124da0c48c4Sopenharmony_ci return result; 125da0c48c4Sopenharmony_ci} 126da0c48c4Sopenharmony_ci 127da0c48c4Sopenharmony_ciint 128da0c48c4Sopenharmony_ciinternal_function 129da0c48c4Sopenharmony_ci__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf, 130da0c48c4Sopenharmony_ci const void **build_id_bits, 131da0c48c4Sopenharmony_ci GElf_Addr *build_id_elfaddr, int *build_id_len) 132da0c48c4Sopenharmony_ci{ 133da0c48c4Sopenharmony_ci GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem); 134da0c48c4Sopenharmony_ci if (unlikely (ehdr == NULL)) 135da0c48c4Sopenharmony_ci { 136da0c48c4Sopenharmony_ci __libdwfl_seterrno (DWFL_E_LIBELF); 137da0c48c4Sopenharmony_ci return -1; 138da0c48c4Sopenharmony_ci } 139da0c48c4Sopenharmony_ci // MOD->E_TYPE is zero here. 140da0c48c4Sopenharmony_ci assert (ehdr->e_type != ET_REL || mod != NULL); 141da0c48c4Sopenharmony_ci 142da0c48c4Sopenharmony_ci return find_elf_build_id (mod, ehdr->e_type, elf, 143da0c48c4Sopenharmony_ci build_id_bits, build_id_elfaddr, build_id_len); 144da0c48c4Sopenharmony_ci} 145da0c48c4Sopenharmony_ci 146da0c48c4Sopenharmony_cissize_t 147da0c48c4Sopenharmony_cidwelf_elf_gnu_build_id (Elf *elf, const void **build_idp) 148da0c48c4Sopenharmony_ci{ 149da0c48c4Sopenharmony_ci GElf_Addr build_id_elfaddr; 150da0c48c4Sopenharmony_ci int build_id_len; 151da0c48c4Sopenharmony_ci int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp, 152da0c48c4Sopenharmony_ci &build_id_elfaddr, &build_id_len); 153da0c48c4Sopenharmony_ci if (result > 0) 154da0c48c4Sopenharmony_ci return build_id_len; 155da0c48c4Sopenharmony_ci 156da0c48c4Sopenharmony_ci return result; 157da0c48c4Sopenharmony_ci} 158da0c48c4Sopenharmony_ciINTDEF(dwelf_elf_gnu_build_id) 159