Coverage Report

Created: 2025-11-13 06:36

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
8.96k
#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
70.1k
{
43
70.1k
  size_t pos = 0;
44
70.1k
  GElf_Nhdr nhdr;
45
70.1k
  size_t name_pos;
46
70.1k
  size_t desc_pos;
47
68.7M
  while ((pos = gelf_getnote (data, pos, &nhdr, &name_pos, &desc_pos)) > 0)
48
68.6M
    if (nhdr.n_type == NT_GNU_BUILD_ID
49
8.11k
  && nhdr.n_namesz == sizeof "GNU"
50
7.69k
  && !memcmp (data->d_buf + name_pos, "GNU", sizeof "GNU"))
51
7.18k
  {
52
7.18k
    *build_id_bits = data->d_buf + desc_pos;
53
7.18k
    *build_id_elfaddr = (data_elfaddr == NO_VADDR
54
7.18k
                        ? 0 : data_elfaddr + desc_pos);
55
7.18k
    *build_id_len = nhdr.n_descsz;
56
7.18k
    return 1;
57
7.18k
  }
58
62.9k
  return 0;
59
70.1k
}
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
10.8k
{
68
10.8k
  size_t shstrndx = SHN_UNDEF;
69
10.8k
  int result = 0;
70
71
10.8k
  Elf_Scn *scn = elf_nextscn (elf, NULL);
72
73
10.8k
  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.32M
      for (size_t i = 0; result == 0 && i < phnum; ++i)
84
3.32M
  {
85
3.32M
    GElf_Phdr phdr_mem;
86
3.32M
    GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
87
3.32M
    if (likely (phdr != NULL) && phdr->p_type == PT_NOTE)
88
52.5k
      result = check_notes (elf_getdata_rawchunk (elf,
89
52.5k
              phdr->p_offset,
90
52.5k
              phdr->p_filesz,
91
52.5k
              (phdr->p_align == 8
92
52.5k
               ? ELF_T_NHDR8
93
52.5k
               : ELF_T_NHDR)),
94
52.5k
          phdr->p_vaddr,
95
52.5k
          build_id_bits,
96
52.5k
          build_id_elfaddr,
97
52.5k
          build_id_len);
98
3.32M
  }
99
1.59k
    }
100
9.27k
  else
101
9.27k
    do
102
314k
      {
103
314k
  GElf_Shdr shdr_mem;
104
314k
  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
105
314k
  if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
106
17.5k
    {
107
      /* Determine the right sh_addr in this module.  */
108
17.5k
      GElf_Addr vaddr = 0;
109
17.5k
      if (!(shdr->sh_flags & SHF_ALLOC))
110
1.78k
        vaddr = NO_VADDR;
111
15.7k
      else if (mod == NULL || e_type != ET_REL)
112
15.7k
        vaddr = shdr->sh_addr;
113
0
      else if (__libdwfl_relocate_value (mod, elf, &shstrndx,
114
0
                 elf_ndxscn (scn), &vaddr))
115
0
        vaddr = NO_VADDR;
116
17.5k
      result = check_notes (elf_getdata (scn, NULL), vaddr,
117
17.5k
                            build_id_bits,
118
17.5k
                            build_id_elfaddr,
119
17.5k
                            build_id_len);
120
17.5k
    }
121
314k
      }
122
314k
    while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
123
124
10.8k
  return result;
125
10.8k
}
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
8.02k
{
133
8.02k
  GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
134
8.02k
  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
8.02k
  assert (ehdr->e_type != ET_REL || mod != NULL);
141
142
8.02k
  return find_elf_build_id (mod, ehdr->e_type, elf,
143
8.02k
          build_id_bits, build_id_elfaddr, build_id_len);
144
8.02k
}
145
146
ssize_t
147
dwelf_elf_gnu_build_id (Elf *elf, const void **build_idp)
148
2.85k
{
149
2.85k
  GElf_Addr build_id_elfaddr;
150
2.85k
  int build_id_len;
151
2.85k
  int result = find_elf_build_id (NULL, ET_NONE, elf, build_idp,
152
2.85k
          &build_id_elfaddr, &build_id_len);
153
2.85k
  if (result > 0)
154
2.85k
    return build_id_len;
155
156
0
  return result;
157
2.85k
}
158
INTDEF(dwelf_elf_gnu_build_id)