Coverage Report

Created: 2026-07-24 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/libdwelf/dwelf_elf_gnu_build_id.c
Line
Count
Source
1
/* Returns the build id if found in a NT_GNU_BUILD_ID note.
2
   Copyright (C) 2014 Red Hat, Inc.
3
   This file is part of elfutils.
4
5
   This file is free software; you can redistribute it and/or modify
6
   it under the terms of either
7
8
     * the GNU Lesser General Public License as published by the Free
9
       Software Foundation; either version 3 of the License, or (at
10
       your option) any later version
11
12
   or
13
14
     * the GNU General Public License as published by the Free
15
       Software Foundation; either version 2 of the License, or (at
16
       your option) any later version
17
18
   or both in parallel, as here.
19
20
   elfutils is distributed in the hope that it will be useful, but
21
   WITHOUT ANY WARRANTY; without even the implied warranty of
22
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23
   General Public License for more details.
24
25
   You should have received copies of the GNU General Public License and
26
   the GNU Lesser General Public License along with this program.  If
27
   not, see <http://www.gnu.org/licenses/>.  */
28
29
#ifdef HAVE_CONFIG_H
30
# include <config.h>
31
#endif
32
33
#include "libdwelfP.h"
34
#include "libdwflP.h"
35
36
3.38k
#define NO_VADDR  ((GElf_Addr) -1l)
37
38
static int
39
check_notes (Elf_Data *data, GElf_Addr data_elfaddr,
40
             const void **build_id_bits, GElf_Addr *build_id_elfaddr,
41
             int *build_id_len)
42
39.2k
{
43
39.2k
  size_t pos = 0;
44
39.2k
  GElf_Nhdr nhdr;
45
39.2k
  size_t name_pos;
46
39.2k
  size_t desc_pos;
47
64.3M
  while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
48
64.3M
    if (nhdr.n_type == NT_GNU_BUILD_ID
49
1.89k
  && nhdr.n_namesz == sizeof "GNU"
50
1.66k
  && !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
51
1.52k
  {
52
1.52k
    *build_id_bits = data->d_buf + desc_pos;
53
1.52k
    *build_id_elfaddr = (data_elfaddr == NO_VADDR
54
1.52k
                        ? 0 : data_elfaddr + desc_pos);
55
1.52k
    *build_id_len = nhdr.n_descsz;
56
1.52k
    return 1;
57
1.52k
  }
58
37.7k
  return 0;
59
39.2k
}
60
61
/* Defined here for reuse. The dwelf interface doesn't care about the
62
   address of the note, but libdwfl does.  */
63
static int
64
find_elf_build_id (Dwfl_Module *mod, int e_type, Elf *elf,
65
       const void **build_id_bits, GElf_Addr *build_id_elfaddr,
66
       int *build_id_len)
67
5.57k
{
68
5.57k
  size_t shstrndx = SHN_UNDEF;
69
5.57k
  int result = 0;
70
71
5.57k
  Elf_Scn *scn = elf_nextscn (elf, NULL);
72
73
5.57k
  if (scn == NULL)
74
1.59k
    {
75
      /* No sections, have to look for phdrs.  */
76
1.59k
      size_t phnum;
77
1.59k
      if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
78
0
  {
79
0
    if (mod != NULL)
80
0
      __libdwfl_seterrno (DWFL_E_LIBELF);
81
0
    return -1;
82
0
  }
83
3.07M
      for (size_t i = 0; result == 0 && i < phnum; ++i)
84
3.07M
  {
85
3.07M
    GElf_Phdr phdr_mem;
86
3.07M
    GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
87
3.07M
    if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
88
34.3k
      result = check_notes (elf_getdata_rawchunk (elf,
89
34.3k
              phdr->p_offset,
90
34.3k
              phdr->p_filesz,
91
34.3k
              (phdr->p_align == 8
92
34.3k
               ? ELF_T_NHDR8
93
34.3k
               : ELF_T_NHDR)),
94
34.3k
          phdr->p_vaddr,
95
34.3k
          build_id_bits,
96
34.3k
          build_id_elfaddr,
97
34.3k
          build_id_len);
98
3.07M
  }
99
1.59k
    }
100
3.98k
  else
101
3.98k
    do
102
263k
      {
103
263k
  GElf_Shdr shdr_mem;
104
263k
  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
105
263k
  if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
106
4.87k
    {
107
      /* Determine the right sh_addr in this module.  */
108
4.87k
      GElf_Addr vaddr = 0;
109
4.87k
      if (!(shdr->sh_flags & SHF_ALLOC))
110
1.84k
        vaddr = NO_VADDR;
111
3.02k
      else if (mod == NULL || e_type != ET_REL)
112
3.01k
        vaddr = shdr->sh_addr;
113
10
      else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
114
10
                 elf_ndxscn (scn), &vaddr))
115
9
        vaddr = NO_VADDR;
116
4.87k
      result = check_notes (elf_getdata (scn, NULL), vaddr,
117
4.87k
                            build_id_bits,
118
4.87k
                            build_id_elfaddr,
119
4.87k
                            build_id_len);
120
4.87k
    }
121
263k
      }
122
263k
    while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
123
124
5.57k
  return result;
125
5.57k
}
126
127
int
128
internal_function
129
__libdwfl_find_elf_build_id (Dwfl_Module *mod, Elf *elf,
130
           const void **build_id_bits,
131
           GElf_Addr *build_id_elfaddr, int *build_id_len)
132
5.52k
{
133
5.52k
  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
134
5.52k
  if (unlikely (ehdr == NULL))
135
0
    {
136
0
      __libdwfl_seterrno (DWFL_E_LIBELF);
137
0
      return -1;
138
0
    }
139
  // MOD->E_TYPE is zero here.
140
5.52k
  assert (ehdr->e_type != ET_REL || mod != NULL);
141
142
5.52k
  return find_elf_build_id (mod, ehdr->e_type, elf,
143
5.52k
          build_id_bits, build_id_elfaddr, build_id_len);
144
5.52k
}
145
146
ssize_t
147
dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp)
148
48
{
149
48
  GElf_Addr build_id_elfaddr;
150
48
  int build_id_len;
151
48
  int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp,
152
48
          &build_id_elfaddr, &build_id_len);
153
48
  if (result > 0)
154
48
    return build_id_len;
155
156
0
  return result;
157
48
}
158
INTDEF(dwelf_elf_gnu_build_id)