1e01aa904Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2e01aa904Sopenharmony_ci// -*- Mode: C++ -*-
3e01aa904Sopenharmony_ci//
4e01aa904Sopenharmony_ci// Copyright (C) 2020-2022 Google, Inc.
5e01aa904Sopenharmony_ci
6e01aa904Sopenharmony_ci/// @file
7e01aa904Sopenharmony_ci///
8e01aa904Sopenharmony_ci/// This contains the definitions of the ELF utilities for the dwarf reader.
9e01aa904Sopenharmony_ci#include <sys/types.h>
10e01aa904Sopenharmony_ci#include <sys/stat.h>
11e01aa904Sopenharmony_ci#include <fcntl.h>
12e01aa904Sopenharmony_ci#include <unistd.h>
13e01aa904Sopenharmony_ci#include <limits.h>
14e01aa904Sopenharmony_ci#include <elfutils/libdwfl.h>
15e01aa904Sopenharmony_ci#include "abg-elf-helpers.h"
16e01aa904Sopenharmony_ci#include "abg-tools-utils.h"
17e01aa904Sopenharmony_ci
18e01aa904Sopenharmony_cinamespace abigail
19e01aa904Sopenharmony_ci{
20e01aa904Sopenharmony_ci
21e01aa904Sopenharmony_cinamespace elf_helpers
22e01aa904Sopenharmony_ci{
23e01aa904Sopenharmony_ci
24e01aa904Sopenharmony_ci/// Convert an elf symbol type (given by the ELF{32,64}_ST_TYPE
25e01aa904Sopenharmony_ci/// macros) into an elf_symbol::type value.
26e01aa904Sopenharmony_ci///
27e01aa904Sopenharmony_ci/// Note that this function aborts when given an unexpected value.
28e01aa904Sopenharmony_ci///
29e01aa904Sopenharmony_ci/// @param the symbol type value to convert.
30e01aa904Sopenharmony_ci///
31e01aa904Sopenharmony_ci/// @return the converted value.
32e01aa904Sopenharmony_cielf_symbol::type
33e01aa904Sopenharmony_cistt_to_elf_symbol_type(unsigned char stt)
34e01aa904Sopenharmony_ci{
35e01aa904Sopenharmony_ci  switch (stt)
36e01aa904Sopenharmony_ci    {
37e01aa904Sopenharmony_ci    case STT_NOTYPE:
38e01aa904Sopenharmony_ci      return elf_symbol::NOTYPE_TYPE;
39e01aa904Sopenharmony_ci    case STT_OBJECT:
40e01aa904Sopenharmony_ci      return elf_symbol::OBJECT_TYPE;
41e01aa904Sopenharmony_ci    case STT_FUNC:
42e01aa904Sopenharmony_ci      return elf_symbol::FUNC_TYPE;
43e01aa904Sopenharmony_ci    case STT_SECTION:
44e01aa904Sopenharmony_ci      return elf_symbol::SECTION_TYPE;
45e01aa904Sopenharmony_ci    case STT_FILE:
46e01aa904Sopenharmony_ci      return elf_symbol::FILE_TYPE;
47e01aa904Sopenharmony_ci    case STT_COMMON:
48e01aa904Sopenharmony_ci      return elf_symbol::COMMON_TYPE;
49e01aa904Sopenharmony_ci    case STT_TLS:
50e01aa904Sopenharmony_ci      return elf_symbol::TLS_TYPE;
51e01aa904Sopenharmony_ci    case STT_GNU_IFUNC:
52e01aa904Sopenharmony_ci      return elf_symbol::GNU_IFUNC_TYPE;
53e01aa904Sopenharmony_ci    default:
54e01aa904Sopenharmony_ci      // An unknown value that probably ought to be supported?  Let's
55e01aa904Sopenharmony_ci      // abort right here rather than yielding garbage.
56e01aa904Sopenharmony_ci      ABG_ASSERT_NOT_REACHED;
57e01aa904Sopenharmony_ci    }
58e01aa904Sopenharmony_ci}
59e01aa904Sopenharmony_ci
60e01aa904Sopenharmony_ci/// Convert an elf symbol binding (given by the ELF{32,64}_ST_BIND
61e01aa904Sopenharmony_ci/// macros) into an elf_symbol::binding value.
62e01aa904Sopenharmony_ci///
63e01aa904Sopenharmony_ci/// Note that this function aborts when given an unexpected value.
64e01aa904Sopenharmony_ci///
65e01aa904Sopenharmony_ci/// @param the symbol binding value to convert.
66e01aa904Sopenharmony_ci///
67e01aa904Sopenharmony_ci/// @return the converted value.
68e01aa904Sopenharmony_cielf_symbol::binding
69e01aa904Sopenharmony_cistb_to_elf_symbol_binding(unsigned char stb)
70e01aa904Sopenharmony_ci{
71e01aa904Sopenharmony_ci  switch (stb)
72e01aa904Sopenharmony_ci    {
73e01aa904Sopenharmony_ci    case STB_LOCAL:
74e01aa904Sopenharmony_ci      return elf_symbol::LOCAL_BINDING;
75e01aa904Sopenharmony_ci    case STB_GLOBAL:
76e01aa904Sopenharmony_ci      return elf_symbol::GLOBAL_BINDING;
77e01aa904Sopenharmony_ci    case STB_WEAK:
78e01aa904Sopenharmony_ci      return elf_symbol::WEAK_BINDING;
79e01aa904Sopenharmony_ci    case STB_GNU_UNIQUE:
80e01aa904Sopenharmony_ci      return elf_symbol::GNU_UNIQUE_BINDING;
81e01aa904Sopenharmony_ci    default:
82e01aa904Sopenharmony_ci      ABG_ASSERT_NOT_REACHED;
83e01aa904Sopenharmony_ci    }
84e01aa904Sopenharmony_ci}
85e01aa904Sopenharmony_ci
86e01aa904Sopenharmony_ci/// Convert an ELF symbol visiblity given by the symbols ->st_other
87e01aa904Sopenharmony_ci/// data member as returned by the GELF_ST_VISIBILITY macro into a
88e01aa904Sopenharmony_ci/// elf_symbol::visiblity value.
89e01aa904Sopenharmony_ci///
90e01aa904Sopenharmony_ci/// @param stv the value of the ->st_other data member of the ELF
91e01aa904Sopenharmony_ci/// symbol.
92e01aa904Sopenharmony_ci///
93e01aa904Sopenharmony_ci/// @return the converted elf_symbol::visiblity value.
94e01aa904Sopenharmony_cielf_symbol::visibility
95e01aa904Sopenharmony_cistv_to_elf_symbol_visibility(unsigned char stv)
96e01aa904Sopenharmony_ci{
97e01aa904Sopenharmony_ci  switch (stv)
98e01aa904Sopenharmony_ci    {
99e01aa904Sopenharmony_ci    case STV_DEFAULT:
100e01aa904Sopenharmony_ci      return elf_symbol::DEFAULT_VISIBILITY;
101e01aa904Sopenharmony_ci    case STV_INTERNAL:
102e01aa904Sopenharmony_ci      return elf_symbol::INTERNAL_VISIBILITY;
103e01aa904Sopenharmony_ci    case STV_HIDDEN:
104e01aa904Sopenharmony_ci      return elf_symbol::HIDDEN_VISIBILITY;
105e01aa904Sopenharmony_ci    case STV_PROTECTED:
106e01aa904Sopenharmony_ci      return elf_symbol::PROTECTED_VISIBILITY;
107e01aa904Sopenharmony_ci    default:
108e01aa904Sopenharmony_ci      ABG_ASSERT_NOT_REACHED;
109e01aa904Sopenharmony_ci    }
110e01aa904Sopenharmony_ci}
111e01aa904Sopenharmony_ci
112e01aa904Sopenharmony_ci/// Convert the value of the e_machine field of GElf_Ehdr into a
113e01aa904Sopenharmony_ci/// string.  This is to get a string representing the architecture of
114e01aa904Sopenharmony_ci/// the elf file at hand.
115e01aa904Sopenharmony_ci///
116e01aa904Sopenharmony_ci/// @param e_machine the value of GElf_Ehdr::e_machine.
117e01aa904Sopenharmony_ci///
118e01aa904Sopenharmony_ci/// @return the string representation of GElf_Ehdr::e_machine.
119e01aa904Sopenharmony_cistd::string
120e01aa904Sopenharmony_cie_machine_to_string(GElf_Half e_machine)
121e01aa904Sopenharmony_ci{
122e01aa904Sopenharmony_ci  switch (e_machine)
123e01aa904Sopenharmony_ci    {
124e01aa904Sopenharmony_ci    case EM_NONE:
125e01aa904Sopenharmony_ci      return "elf-no-arch";
126e01aa904Sopenharmony_ci    case EM_M32:
127e01aa904Sopenharmony_ci      return "elf-att-we-32100";
128e01aa904Sopenharmony_ci    case EM_SPARC:
129e01aa904Sopenharmony_ci      return "elf-sun-sparc";
130e01aa904Sopenharmony_ci    case EM_386:
131e01aa904Sopenharmony_ci      return "elf-intel-80386";
132e01aa904Sopenharmony_ci    case EM_68K:
133e01aa904Sopenharmony_ci      return "elf-motorola-68k";
134e01aa904Sopenharmony_ci    case EM_88K:
135e01aa904Sopenharmony_ci      return "elf-motorola-88k";
136e01aa904Sopenharmony_ci    case EM_860:
137e01aa904Sopenharmony_ci      return "elf-intel-80860";
138e01aa904Sopenharmony_ci    case EM_MIPS:
139e01aa904Sopenharmony_ci      return "elf-mips-r3000-be";
140e01aa904Sopenharmony_ci    case EM_S370:
141e01aa904Sopenharmony_ci      return "elf-ibm-s370";
142e01aa904Sopenharmony_ci    case EM_MIPS_RS3_LE:
143e01aa904Sopenharmony_ci      return "elf-mips-r3000-le";
144e01aa904Sopenharmony_ci    case EM_PARISC:
145e01aa904Sopenharmony_ci      return "elf-hp-parisc";
146e01aa904Sopenharmony_ci    case EM_VPP500:
147e01aa904Sopenharmony_ci      return "elf-fujitsu-vpp500";
148e01aa904Sopenharmony_ci    case EM_SPARC32PLUS:
149e01aa904Sopenharmony_ci      return "elf-sun-sparc-v8plus";
150e01aa904Sopenharmony_ci    case EM_960:
151e01aa904Sopenharmony_ci      return "elf-intel-80960";
152e01aa904Sopenharmony_ci    case EM_PPC:
153e01aa904Sopenharmony_ci      return "elf-powerpc";
154e01aa904Sopenharmony_ci    case EM_PPC64:
155e01aa904Sopenharmony_ci      return "elf-powerpc-64";
156e01aa904Sopenharmony_ci    case EM_S390:
157e01aa904Sopenharmony_ci      return "elf-ibm-s390";
158e01aa904Sopenharmony_ci    case EM_V800:
159e01aa904Sopenharmony_ci      return "elf-nec-v800";
160e01aa904Sopenharmony_ci    case EM_FR20:
161e01aa904Sopenharmony_ci      return "elf-fujitsu-fr20";
162e01aa904Sopenharmony_ci    case EM_RH32:
163e01aa904Sopenharmony_ci      return "elf-trw-rh32";
164e01aa904Sopenharmony_ci    case EM_RCE:
165e01aa904Sopenharmony_ci      return "elf-motorola-rce";
166e01aa904Sopenharmony_ci    case EM_ARM:
167e01aa904Sopenharmony_ci      return "elf-arm";
168e01aa904Sopenharmony_ci    case EM_FAKE_ALPHA:
169e01aa904Sopenharmony_ci      return "elf-digital-alpha";
170e01aa904Sopenharmony_ci    case EM_SH:
171e01aa904Sopenharmony_ci      return "elf-hitachi-sh";
172e01aa904Sopenharmony_ci    case EM_SPARCV9:
173e01aa904Sopenharmony_ci      return "elf-sun-sparc-v9-64";
174e01aa904Sopenharmony_ci    case EM_TRICORE:
175e01aa904Sopenharmony_ci      return "elf-siemens-tricore";
176e01aa904Sopenharmony_ci    case EM_ARC:
177e01aa904Sopenharmony_ci      return "elf-argonaut-risc-core";
178e01aa904Sopenharmony_ci    case EM_H8_300:
179e01aa904Sopenharmony_ci      return "elf-hitachi-h8-300";
180e01aa904Sopenharmony_ci    case EM_H8_300H:
181e01aa904Sopenharmony_ci      return "elf-hitachi-h8-300h";
182e01aa904Sopenharmony_ci    case EM_H8S:
183e01aa904Sopenharmony_ci      return "elf-hitachi-h8s";
184e01aa904Sopenharmony_ci    case EM_H8_500:
185e01aa904Sopenharmony_ci      return "elf-hitachi-h8-500";
186e01aa904Sopenharmony_ci    case EM_IA_64:
187e01aa904Sopenharmony_ci      return "elf-intel-ia-64";
188e01aa904Sopenharmony_ci    case EM_MIPS_X:
189e01aa904Sopenharmony_ci      return "elf-stanford-mips-x";
190e01aa904Sopenharmony_ci    case EM_COLDFIRE:
191e01aa904Sopenharmony_ci      return "elf-motorola-coldfire";
192e01aa904Sopenharmony_ci    case EM_68HC12:
193e01aa904Sopenharmony_ci      return "elf-motorola-68hc12";
194e01aa904Sopenharmony_ci    case EM_MMA:
195e01aa904Sopenharmony_ci      return "elf-fujitsu-mma";
196e01aa904Sopenharmony_ci    case EM_PCP:
197e01aa904Sopenharmony_ci      return "elf-siemens-pcp";
198e01aa904Sopenharmony_ci    case EM_NCPU:
199e01aa904Sopenharmony_ci      return "elf-sony-ncpu";
200e01aa904Sopenharmony_ci    case EM_NDR1:
201e01aa904Sopenharmony_ci      return "elf-denso-ndr1";
202e01aa904Sopenharmony_ci    case EM_STARCORE:
203e01aa904Sopenharmony_ci      return "elf-motorola-starcore";
204e01aa904Sopenharmony_ci    case EM_ME16:
205e01aa904Sopenharmony_ci      return "elf-toyota-me16";
206e01aa904Sopenharmony_ci    case EM_ST100:
207e01aa904Sopenharmony_ci      return "elf-stm-st100";
208e01aa904Sopenharmony_ci    case EM_TINYJ:
209e01aa904Sopenharmony_ci      return "elf-alc-tinyj";
210e01aa904Sopenharmony_ci    case EM_X86_64:
211e01aa904Sopenharmony_ci      return "elf-amd-x86_64";
212e01aa904Sopenharmony_ci    case EM_PDSP:
213e01aa904Sopenharmony_ci      return "elf-sony-pdsp";
214e01aa904Sopenharmony_ci    case EM_FX66:
215e01aa904Sopenharmony_ci      return "elf-siemens-fx66";
216e01aa904Sopenharmony_ci    case EM_ST9PLUS:
217e01aa904Sopenharmony_ci      return "elf-stm-st9+";
218e01aa904Sopenharmony_ci    case EM_ST7:
219e01aa904Sopenharmony_ci      return "elf-stm-st7";
220e01aa904Sopenharmony_ci    case EM_68HC16:
221e01aa904Sopenharmony_ci      return "elf-motorola-68hc16";
222e01aa904Sopenharmony_ci    case EM_68HC11:
223e01aa904Sopenharmony_ci      return "elf-motorola-68hc11";
224e01aa904Sopenharmony_ci    case EM_68HC08:
225e01aa904Sopenharmony_ci      return "elf-motorola-68hc08";
226e01aa904Sopenharmony_ci    case EM_68HC05:
227e01aa904Sopenharmony_ci      return "elf-motorola-68hc05";
228e01aa904Sopenharmony_ci    case EM_SVX:
229e01aa904Sopenharmony_ci      return "elf-sg-svx";
230e01aa904Sopenharmony_ci    case EM_ST19:
231e01aa904Sopenharmony_ci      return "elf-stm-st19";
232e01aa904Sopenharmony_ci    case EM_VAX:
233e01aa904Sopenharmony_ci      return "elf-digital-vax";
234e01aa904Sopenharmony_ci    case EM_CRIS:
235e01aa904Sopenharmony_ci      return "elf-axis-cris";
236e01aa904Sopenharmony_ci    case EM_JAVELIN:
237e01aa904Sopenharmony_ci      return "elf-infineon-javelin";
238e01aa904Sopenharmony_ci    case EM_FIREPATH:
239e01aa904Sopenharmony_ci      return "elf-firepath";
240e01aa904Sopenharmony_ci    case EM_ZSP:
241e01aa904Sopenharmony_ci      return "elf-lsi-zsp";
242e01aa904Sopenharmony_ci    case EM_MMIX:
243e01aa904Sopenharmony_ci      return "elf-don-knuth-mmix";
244e01aa904Sopenharmony_ci    case EM_HUANY:
245e01aa904Sopenharmony_ci      return "elf-harvard-huany";
246e01aa904Sopenharmony_ci    case EM_PRISM:
247e01aa904Sopenharmony_ci      return "elf-sitera-prism";
248e01aa904Sopenharmony_ci    case EM_AVR:
249e01aa904Sopenharmony_ci      return "elf-atmel-avr";
250e01aa904Sopenharmony_ci    case EM_FR30:
251e01aa904Sopenharmony_ci      return "elf-fujistu-fr30";
252e01aa904Sopenharmony_ci    case EM_D10V:
253e01aa904Sopenharmony_ci      return "elf-mitsubishi-d10v";
254e01aa904Sopenharmony_ci    case EM_D30V:
255e01aa904Sopenharmony_ci      return "elf-mitsubishi-d30v";
256e01aa904Sopenharmony_ci    case EM_V850:
257e01aa904Sopenharmony_ci      return "elf-nec-v850";
258e01aa904Sopenharmony_ci    case EM_M32R:
259e01aa904Sopenharmony_ci      return "elf-mitsubishi-m32r";
260e01aa904Sopenharmony_ci    case EM_MN10300:
261e01aa904Sopenharmony_ci      return "elf-matsushita-mn10300";
262e01aa904Sopenharmony_ci    case EM_MN10200:
263e01aa904Sopenharmony_ci      return "elf-matsushita-mn10200";
264e01aa904Sopenharmony_ci    case EM_PJ:
265e01aa904Sopenharmony_ci      return "elf-picojava";
266e01aa904Sopenharmony_ci    case EM_OPENRISC:
267e01aa904Sopenharmony_ci      return "elf-openrisc-32";
268e01aa904Sopenharmony_ci    case EM_ARC_A5:
269e01aa904Sopenharmony_ci      return "elf-arc-a5";
270e01aa904Sopenharmony_ci    case EM_XTENSA:
271e01aa904Sopenharmony_ci      return "elf-tensilica-xtensa";
272e01aa904Sopenharmony_ci
273e01aa904Sopenharmony_ci#ifdef HAVE_EM_AARCH64_MACRO
274e01aa904Sopenharmony_ci    case EM_AARCH64:
275e01aa904Sopenharmony_ci      return "elf-arm-aarch64";
276e01aa904Sopenharmony_ci#endif
277e01aa904Sopenharmony_ci
278e01aa904Sopenharmony_ci#ifdef HAVE_EM_TILEPRO_MACRO
279e01aa904Sopenharmony_ci    case EM_TILEPRO:
280e01aa904Sopenharmony_ci      return "elf-tilera-tilepro";
281e01aa904Sopenharmony_ci#endif
282e01aa904Sopenharmony_ci
283e01aa904Sopenharmony_ci#ifdef HAVE_EM_TILEGX_MACRO
284e01aa904Sopenharmony_ci    case EM_TILEGX:
285e01aa904Sopenharmony_ci      return "elf-tilera-tilegx";
286e01aa904Sopenharmony_ci#endif
287e01aa904Sopenharmony_ci
288e01aa904Sopenharmony_ci    case EM_NUM:
289e01aa904Sopenharmony_ci      return "elf-last-arch-number";
290e01aa904Sopenharmony_ci    case EM_ALPHA:
291e01aa904Sopenharmony_ci      return "elf-non-official-alpha";
292e01aa904Sopenharmony_ci    default:
293e01aa904Sopenharmony_ci      {
294e01aa904Sopenharmony_ci	std::ostringstream o;
295e01aa904Sopenharmony_ci	o << "elf-unknown-arch-value-" << e_machine;
296e01aa904Sopenharmony_ci	return o.str();
297e01aa904Sopenharmony_ci      }
298e01aa904Sopenharmony_ci    }
299e01aa904Sopenharmony_ci}
300e01aa904Sopenharmony_ci
301e01aa904Sopenharmony_ci/// Find and return a section by its name.
302e01aa904Sopenharmony_ci///
303e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
304e01aa904Sopenharmony_ci///
305e01aa904Sopenharmony_ci/// @param name the section name.
306e01aa904Sopenharmony_ci///
307e01aa904Sopenharmony_ci/// @return the section found, nor nil if none was found.
308e01aa904Sopenharmony_ciElf_Scn*
309e01aa904Sopenharmony_cifind_section_by_name(Elf* elf_handle, const std::string& name)
310e01aa904Sopenharmony_ci{
311e01aa904Sopenharmony_ci  size_t section_header_string_index = 0;
312e01aa904Sopenharmony_ci  if (elf_getshdrstrndx (elf_handle, &section_header_string_index) < 0)
313e01aa904Sopenharmony_ci    return 0;
314e01aa904Sopenharmony_ci
315e01aa904Sopenharmony_ci  Elf_Scn* section = 0;
316e01aa904Sopenharmony_ci  GElf_Shdr header_mem, *header;
317e01aa904Sopenharmony_ci  while ((section = elf_nextscn(elf_handle, section)) != 0)
318e01aa904Sopenharmony_ci    {
319e01aa904Sopenharmony_ci      header = gelf_getshdr(section, &header_mem);
320e01aa904Sopenharmony_ci      if (header == NULL)
321e01aa904Sopenharmony_ci        continue;
322e01aa904Sopenharmony_ci
323e01aa904Sopenharmony_ci      const char* section_name =
324e01aa904Sopenharmony_ci	elf_strptr(elf_handle, section_header_string_index, header->sh_name);
325e01aa904Sopenharmony_ci      if (section_name && name == section_name)
326e01aa904Sopenharmony_ci	return section;
327e01aa904Sopenharmony_ci    }
328e01aa904Sopenharmony_ci
329e01aa904Sopenharmony_ci  return 0;
330e01aa904Sopenharmony_ci}
331e01aa904Sopenharmony_ci
332e01aa904Sopenharmony_ci/// Find and return a section by its name and its type.
333e01aa904Sopenharmony_ci///
334e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
335e01aa904Sopenharmony_ci///
336e01aa904Sopenharmony_ci/// @param name the name of the section.
337e01aa904Sopenharmony_ci///
338e01aa904Sopenharmony_ci/// @param section_type the type of the section.  This is the
339e01aa904Sopenharmony_ci/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member.
340e01aa904Sopenharmony_ci/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS.
341e01aa904Sopenharmony_ci///
342e01aa904Sopenharmony_ci/// @return the section found, nor nil if none was found.
343e01aa904Sopenharmony_ciElf_Scn*
344e01aa904Sopenharmony_cifind_section(Elf* elf_handle, const std::string& name, Elf64_Word section_type)
345e01aa904Sopenharmony_ci{
346e01aa904Sopenharmony_ci  size_t section_header_string_index = 0;
347e01aa904Sopenharmony_ci  if (elf_getshdrstrndx (elf_handle, &section_header_string_index) < 0)
348e01aa904Sopenharmony_ci    return 0;
349e01aa904Sopenharmony_ci
350e01aa904Sopenharmony_ci  Elf_Scn* section = 0;
351e01aa904Sopenharmony_ci  GElf_Shdr header_mem, *header;
352e01aa904Sopenharmony_ci  while ((section = elf_nextscn(elf_handle, section)) != 0)
353e01aa904Sopenharmony_ci    {
354e01aa904Sopenharmony_ci      header = gelf_getshdr(section, &header_mem);
355e01aa904Sopenharmony_ci      if (header == NULL || header->sh_type != section_type)
356e01aa904Sopenharmony_ci      continue;
357e01aa904Sopenharmony_ci
358e01aa904Sopenharmony_ci      const char* section_name =
359e01aa904Sopenharmony_ci	elf_strptr(elf_handle, section_header_string_index, header->sh_name);
360e01aa904Sopenharmony_ci      if (section_name && name == section_name)
361e01aa904Sopenharmony_ci	return section;
362e01aa904Sopenharmony_ci    }
363e01aa904Sopenharmony_ci
364e01aa904Sopenharmony_ci  return 0;
365e01aa904Sopenharmony_ci}
366e01aa904Sopenharmony_ci
367e01aa904Sopenharmony_ci/// Find and return a section by its type.
368e01aa904Sopenharmony_ci///
369e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
370e01aa904Sopenharmony_ci///
371e01aa904Sopenharmony_ci/// @param section_type the type of the section.  This is the
372e01aa904Sopenharmony_ci/// Elf32_Shdr::sh_type (or Elf64_Shdr::sh_type) data member.
373e01aa904Sopenharmony_ci/// Examples of values of this parameter are SHT_PROGBITS or SHT_NOBITS.
374e01aa904Sopenharmony_ci///
375e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found.
376e01aa904Sopenharmony_ciElf_Scn*
377e01aa904Sopenharmony_cifind_section(Elf* elf_handle, Elf64_Word section_type)
378e01aa904Sopenharmony_ci{
379e01aa904Sopenharmony_ci  Elf_Scn* section = nullptr;
380e01aa904Sopenharmony_ci  while ((section = elf_nextscn(elf_handle, section)) != 0)
381e01aa904Sopenharmony_ci    {
382e01aa904Sopenharmony_ci      GElf_Shdr header_mem, *header;
383e01aa904Sopenharmony_ci      header = gelf_getshdr(section, &header_mem);
384e01aa904Sopenharmony_ci      if (header->sh_type == section_type)
385e01aa904Sopenharmony_ci	break;
386e01aa904Sopenharmony_ci    }
387e01aa904Sopenharmony_ci  return section;
388e01aa904Sopenharmony_ci}
389e01aa904Sopenharmony_ci
390e01aa904Sopenharmony_ci/// Find and return the .symtab section
391e01aa904Sopenharmony_ci///
392e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
393e01aa904Sopenharmony_ci///
394e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found
395e01aa904Sopenharmony_ciElf_Scn*
396e01aa904Sopenharmony_cifind_symtab_section(Elf* elf_handle)
397e01aa904Sopenharmony_ci{
398e01aa904Sopenharmony_ci  return find_section(elf_handle, SHT_SYMTAB);
399e01aa904Sopenharmony_ci}
400e01aa904Sopenharmony_ci
401e01aa904Sopenharmony_ci/// Find and return the .symtab section
402e01aa904Sopenharmony_ci///
403e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
404e01aa904Sopenharmony_ci///
405e01aa904Sopenharmony_ci/// @return the section found, or nil if none was found
406e01aa904Sopenharmony_ciElf_Scn*
407e01aa904Sopenharmony_cifind_dynsym_section(Elf* elf_handle)
408e01aa904Sopenharmony_ci{
409e01aa904Sopenharmony_ci  return find_section(elf_handle, SHT_DYNSYM);
410e01aa904Sopenharmony_ci}
411e01aa904Sopenharmony_ci
412e01aa904Sopenharmony_ci/// Find the symbol table.
413e01aa904Sopenharmony_ci///
414e01aa904Sopenharmony_ci/// If we are looking at a relocatable or executable file, this
415e01aa904Sopenharmony_ci/// function will return the .symtab symbol table (of type
416e01aa904Sopenharmony_ci/// SHT_SYMTAB).  But if we are looking at a DSO it returns the
417e01aa904Sopenharmony_ci/// .dynsym symbol table (of type SHT_DYNSYM).
418e01aa904Sopenharmony_ci///
419e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider.
420e01aa904Sopenharmony_ci///
421e01aa904Sopenharmony_ci/// @param symtab the symbol table found.
422e01aa904Sopenharmony_ci///
423e01aa904Sopenharmony_ci/// @return the symbol table section
424e01aa904Sopenharmony_ciElf_Scn*
425e01aa904Sopenharmony_cifind_symbol_table_section(Elf* elf_handle)
426e01aa904Sopenharmony_ci{
427e01aa904Sopenharmony_ci  Elf_Scn *dynsym = find_dynsym_section(elf_handle),
428e01aa904Sopenharmony_ci	  *sym_tab = find_symtab_section(elf_handle);
429e01aa904Sopenharmony_ci
430e01aa904Sopenharmony_ci  if (dynsym || sym_tab)
431e01aa904Sopenharmony_ci    {
432e01aa904Sopenharmony_ci      GElf_Ehdr eh_mem;
433e01aa904Sopenharmony_ci      GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
434e01aa904Sopenharmony_ci      if (elf_header->e_type == ET_REL
435e01aa904Sopenharmony_ci	  || elf_header->e_type == ET_EXEC)
436e01aa904Sopenharmony_ci	return sym_tab ? sym_tab : dynsym;
437e01aa904Sopenharmony_ci      else
438e01aa904Sopenharmony_ci	return dynsym ? dynsym : sym_tab;
439e01aa904Sopenharmony_ci    }
440e01aa904Sopenharmony_ci  return nullptr;
441e01aa904Sopenharmony_ci}
442e01aa904Sopenharmony_ci
443e01aa904Sopenharmony_ci/// Find the index (in the section headers table) of the symbol table
444e01aa904Sopenharmony_ci/// section.
445e01aa904Sopenharmony_ci///
446e01aa904Sopenharmony_ci/// If we are looking at a relocatable or executable file, this
447e01aa904Sopenharmony_ci/// function will return the index for the .symtab symbol table (of
448e01aa904Sopenharmony_ci/// type SHT_SYMTAB).  But if we are looking at a DSO it returns the
449e01aa904Sopenharmony_ci/// index for the .dynsym symbol table (of type SHT_DYNSYM).
450e01aa904Sopenharmony_ci///
451e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
452e01aa904Sopenharmony_ci///
453e01aa904Sopenharmony_ci/// @param symtab_index the index of the symbol_table, that was found.
454e01aa904Sopenharmony_ci///
455e01aa904Sopenharmony_ci/// @return true iff the symbol table section index was found.
456e01aa904Sopenharmony_cibool
457e01aa904Sopenharmony_cifind_symbol_table_section_index(Elf* elf_handle, size_t& symtab_index)
458e01aa904Sopenharmony_ci{
459e01aa904Sopenharmony_ci  Elf_Scn* section = find_symbol_table_section(elf_handle);
460e01aa904Sopenharmony_ci
461e01aa904Sopenharmony_ci  if (!section)
462e01aa904Sopenharmony_ci    return false;
463e01aa904Sopenharmony_ci
464e01aa904Sopenharmony_ci  symtab_index = elf_ndxscn(section);
465e01aa904Sopenharmony_ci  return true;
466e01aa904Sopenharmony_ci}
467e01aa904Sopenharmony_ci
468e01aa904Sopenharmony_ci/// Get the offset offset of the hash table section.
469e01aa904Sopenharmony_ci///
470e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
471e01aa904Sopenharmony_ci///
472e01aa904Sopenharmony_ci/// @param ht_section_offset this is set to the resulting offset
473e01aa904Sopenharmony_ci/// of the hash table section.  This is set iff the function returns true.
474e01aa904Sopenharmony_ci///
475e01aa904Sopenharmony_ci/// @param symtab_section_offset the offset of the section of the
476e01aa904Sopenharmony_ci/// symbol table the hash table refers to.
477e01aa904Sopenharmony_cihash_table_kind
478e01aa904Sopenharmony_cifind_hash_table_section_index(Elf*	elf_handle,
479e01aa904Sopenharmony_ci			      size_t&	ht_section_index,
480e01aa904Sopenharmony_ci			      size_t&	symtab_section_index)
481e01aa904Sopenharmony_ci{
482e01aa904Sopenharmony_ci  if (!elf_handle)
483e01aa904Sopenharmony_ci    return NO_HASH_TABLE_KIND;
484e01aa904Sopenharmony_ci
485e01aa904Sopenharmony_ci  GElf_Shdr header_mem, *section_header;
486e01aa904Sopenharmony_ci  bool found_sysv_ht = false, found_gnu_ht = false;
487e01aa904Sopenharmony_ci  for (Elf_Scn* section = elf_nextscn(elf_handle, 0);
488e01aa904Sopenharmony_ci       section != 0;
489e01aa904Sopenharmony_ci       section = elf_nextscn(elf_handle, section))
490e01aa904Sopenharmony_ci    {
491e01aa904Sopenharmony_ci      section_header= gelf_getshdr(section, &header_mem);
492e01aa904Sopenharmony_ci      if (section_header->sh_type != SHT_HASH
493e01aa904Sopenharmony_ci	  && section_header->sh_type != SHT_GNU_HASH)
494e01aa904Sopenharmony_ci	continue;
495e01aa904Sopenharmony_ci
496e01aa904Sopenharmony_ci      ht_section_index = elf_ndxscn(section);
497e01aa904Sopenharmony_ci      symtab_section_index = section_header->sh_link;
498e01aa904Sopenharmony_ci
499e01aa904Sopenharmony_ci      if (section_header->sh_type == SHT_HASH)
500e01aa904Sopenharmony_ci	found_sysv_ht = true;
501e01aa904Sopenharmony_ci      else if (section_header->sh_type == SHT_GNU_HASH)
502e01aa904Sopenharmony_ci	found_gnu_ht = true;
503e01aa904Sopenharmony_ci    }
504e01aa904Sopenharmony_ci
505e01aa904Sopenharmony_ci  if (found_gnu_ht)
506e01aa904Sopenharmony_ci    return GNU_HASH_TABLE_KIND;
507e01aa904Sopenharmony_ci  else if (found_sysv_ht)
508e01aa904Sopenharmony_ci    return SYSV_HASH_TABLE_KIND;
509e01aa904Sopenharmony_ci  else
510e01aa904Sopenharmony_ci    return NO_HASH_TABLE_KIND;
511e01aa904Sopenharmony_ci}
512e01aa904Sopenharmony_ci
513e01aa904Sopenharmony_ci/// Find and return the .text section.
514e01aa904Sopenharmony_ci///
515e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
516e01aa904Sopenharmony_ci///
517e01aa904Sopenharmony_ci/// @return the .text section found.
518e01aa904Sopenharmony_ciElf_Scn*
519e01aa904Sopenharmony_cifind_text_section(Elf* elf_handle)
520e01aa904Sopenharmony_ci{return find_section(elf_handle, ".text", SHT_PROGBITS);}
521e01aa904Sopenharmony_ci
522e01aa904Sopenharmony_ci/// Find and return the .bss section.
523e01aa904Sopenharmony_ci///
524e01aa904Sopenharmony_ci/// @param elf_handle.
525e01aa904Sopenharmony_ci///
526e01aa904Sopenharmony_ci/// @return the .bss section found.
527e01aa904Sopenharmony_ciElf_Scn*
528e01aa904Sopenharmony_cifind_bss_section(Elf* elf_handle)
529e01aa904Sopenharmony_ci{return find_section(elf_handle, ".bss", SHT_NOBITS);}
530e01aa904Sopenharmony_ci
531e01aa904Sopenharmony_ci/// Find and return the .rodata section.
532e01aa904Sopenharmony_ci///
533e01aa904Sopenharmony_ci/// @param elf_handle.
534e01aa904Sopenharmony_ci///
535e01aa904Sopenharmony_ci/// @return the .rodata section found.
536e01aa904Sopenharmony_ciElf_Scn*
537e01aa904Sopenharmony_cifind_rodata_section(Elf* elf_handle)
538e01aa904Sopenharmony_ci{return find_section(elf_handle, ".rodata", SHT_PROGBITS);}
539e01aa904Sopenharmony_ci
540e01aa904Sopenharmony_ci/// Find and return the .data section.
541e01aa904Sopenharmony_ci///
542e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
543e01aa904Sopenharmony_ci///
544e01aa904Sopenharmony_ci/// @return the .data section found.
545e01aa904Sopenharmony_ciElf_Scn*
546e01aa904Sopenharmony_cifind_data_section(Elf* elf_handle)
547e01aa904Sopenharmony_ci{return find_section(elf_handle, ".data", SHT_PROGBITS);}
548e01aa904Sopenharmony_ci
549e01aa904Sopenharmony_ci/// Find and return the .data1 section.
550e01aa904Sopenharmony_ci///
551e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
552e01aa904Sopenharmony_ci///
553e01aa904Sopenharmony_ci/// @return the .data1 section found.
554e01aa904Sopenharmony_ciElf_Scn*
555e01aa904Sopenharmony_cifind_data1_section(Elf* elf_handle)
556e01aa904Sopenharmony_ci{return find_section(elf_handle, ".data1", SHT_PROGBITS);}
557e01aa904Sopenharmony_ci
558e01aa904Sopenharmony_ci/// Return the "Official Procedure descriptors section."  This
559e01aa904Sopenharmony_ci/// section is named .opd, and is usually present only on PPC64
560e01aa904Sopenharmony_ci/// ELFv1 binaries.
561e01aa904Sopenharmony_ci///
562e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider.
563e01aa904Sopenharmony_ci///
564e01aa904Sopenharmony_ci/// @return the .opd section, if found.  Return nil otherwise.
565e01aa904Sopenharmony_ciElf_Scn*
566e01aa904Sopenharmony_cifind_opd_section(Elf* elf_handle)
567e01aa904Sopenharmony_ci{return find_section(elf_handle, ".opd", SHT_PROGBITS);}
568e01aa904Sopenharmony_ci
569e01aa904Sopenharmony_ci/// Return the SHT_GNU_versym, SHT_GNU_verdef and SHT_GNU_verneed
570e01aa904Sopenharmony_ci/// sections that are involved in symbol versionning.
571e01aa904Sopenharmony_ci///
572e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
573e01aa904Sopenharmony_ci///
574e01aa904Sopenharmony_ci/// @param versym_section the SHT_GNU_versym section found.  If the
575e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil.
576e01aa904Sopenharmony_ci///
577e01aa904Sopenharmony_ci/// @param verdef_section the SHT_GNU_verdef section found.  If the
578e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil.
579e01aa904Sopenharmony_ci///
580e01aa904Sopenharmony_ci/// @param verneed_section the SHT_GNU_verneed section found.  If the
581e01aa904Sopenharmony_ci/// section wasn't found, this is set to nil.
582e01aa904Sopenharmony_ci///
583e01aa904Sopenharmony_ci/// @return true iff at least one of the sections where found.
584e01aa904Sopenharmony_cibool
585e01aa904Sopenharmony_ciget_symbol_versionning_sections(Elf*		elf_handle,
586e01aa904Sopenharmony_ci				Elf_Scn*&	versym_section,
587e01aa904Sopenharmony_ci				Elf_Scn*&	verdef_section,
588e01aa904Sopenharmony_ci				Elf_Scn*&	verneed_section)
589e01aa904Sopenharmony_ci{
590e01aa904Sopenharmony_ci  Elf_Scn* section = NULL;
591e01aa904Sopenharmony_ci  GElf_Shdr mem;
592e01aa904Sopenharmony_ci  Elf_Scn* versym = NULL, *verdef = NULL, *verneed = NULL;
593e01aa904Sopenharmony_ci
594e01aa904Sopenharmony_ci  while ((section = elf_nextscn(elf_handle, section)) != NULL)
595e01aa904Sopenharmony_ci    {
596e01aa904Sopenharmony_ci      GElf_Shdr* h = gelf_getshdr(section, &mem);
597e01aa904Sopenharmony_ci      if (h->sh_type == SHT_GNU_versym)
598e01aa904Sopenharmony_ci	versym = section;
599e01aa904Sopenharmony_ci      else if (h->sh_type == SHT_GNU_verdef)
600e01aa904Sopenharmony_ci	verdef = section;
601e01aa904Sopenharmony_ci      else if (h->sh_type == SHT_GNU_verneed)
602e01aa904Sopenharmony_ci	verneed = section;
603e01aa904Sopenharmony_ci    }
604e01aa904Sopenharmony_ci
605e01aa904Sopenharmony_ci  if (versym || verdef || verneed)
606e01aa904Sopenharmony_ci    {
607e01aa904Sopenharmony_ci      // At least one the versionning sections was found.  Return it.
608e01aa904Sopenharmony_ci      versym_section = versym;
609e01aa904Sopenharmony_ci      verdef_section = verdef;
610e01aa904Sopenharmony_ci      verneed_section = verneed;
611e01aa904Sopenharmony_ci      return true;
612e01aa904Sopenharmony_ci    }
613e01aa904Sopenharmony_ci
614e01aa904Sopenharmony_ci  return false;
615e01aa904Sopenharmony_ci}
616e01aa904Sopenharmony_ci
617e01aa904Sopenharmony_ci/// Return the __ksymtab section of a linux kernel ELF file (either
618e01aa904Sopenharmony_ci/// a vmlinux binary or a kernel module).
619e01aa904Sopenharmony_ci///
620e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider.
621e01aa904Sopenharmony_ci///
622e01aa904Sopenharmony_ci/// @return the __ksymtab section if found, nil otherwise.
623e01aa904Sopenharmony_ciElf_Scn*
624e01aa904Sopenharmony_cifind_ksymtab_section(Elf* elf_handle)
625e01aa904Sopenharmony_ci{return find_section(elf_handle, "__ksymtab", SHT_PROGBITS);}
626e01aa904Sopenharmony_ci
627e01aa904Sopenharmony_ci/// Return the __ksymtab_gpl section of a linux kernel ELF file (either
628e01aa904Sopenharmony_ci/// a vmlinux binary or a kernel module).
629e01aa904Sopenharmony_ci///
630e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider.
631e01aa904Sopenharmony_ci///
632e01aa904Sopenharmony_ci/// @return the __ksymtab section if found, nil otherwise.
633e01aa904Sopenharmony_ciElf_Scn*
634e01aa904Sopenharmony_cifind_ksymtab_gpl_section(Elf* elf_handle)
635e01aa904Sopenharmony_ci{return find_section(elf_handle, "__ksymtab_gpl", SHT_PROGBITS);}
636e01aa904Sopenharmony_ci
637e01aa904Sopenharmony_ci/// Find the __ksymtab_strings section of a Linux kernel binary.
638e01aa904Sopenharmony_ci///
639e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
640e01aa904Sopenharmony_ci///
641e01aa904Sopenharmony_ci/// @return the find_ksymtab_strings_section of the linux kernel
642e01aa904Sopenharmony_ci/// binary denoted by @p elf_handle, or nil if such a section could
643e01aa904Sopenharmony_ci/// not be found.
644e01aa904Sopenharmony_ciElf_Scn*
645e01aa904Sopenharmony_cifind_ksymtab_strings_section(Elf *elf_handle)
646e01aa904Sopenharmony_ci{
647e01aa904Sopenharmony_ci  if (is_linux_kernel(elf_handle))
648e01aa904Sopenharmony_ci    return find_section(elf_handle, "__ksymtab_strings", SHT_PROGBITS);
649e01aa904Sopenharmony_ci  return 0;
650e01aa904Sopenharmony_ci}
651e01aa904Sopenharmony_ci
652e01aa904Sopenharmony_ci/// Return the .rel{a,} section corresponding to a given section.
653e01aa904Sopenharmony_ci///
654e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to consider.
655e01aa904Sopenharmony_ci///
656e01aa904Sopenharmony_ci/// @param target_section the section to search the relocation section for
657e01aa904Sopenharmony_ci///
658e01aa904Sopenharmony_ci/// @return the .rel{a,} section if found, null otherwise.
659e01aa904Sopenharmony_ciElf_Scn*
660e01aa904Sopenharmony_cifind_relocation_section(Elf* elf_handle, Elf_Scn* target_section)
661e01aa904Sopenharmony_ci{
662e01aa904Sopenharmony_ci  if (target_section)
663e01aa904Sopenharmony_ci    {
664e01aa904Sopenharmony_ci      // the relo section we are searching for has this index as sh_info
665e01aa904Sopenharmony_ci      size_t target_index = elf_ndxscn(target_section);
666e01aa904Sopenharmony_ci
667e01aa904Sopenharmony_ci      // now iterate over all the sections, look for relocation sections and
668e01aa904Sopenharmony_ci      // find the one that points to the section we are searching for
669e01aa904Sopenharmony_ci      Elf_Scn*	section = 0;
670e01aa904Sopenharmony_ci      GElf_Shdr header_mem, *header;
671e01aa904Sopenharmony_ci      while ((section = elf_nextscn(elf_handle, section)) != 0)
672e01aa904Sopenharmony_ci	{
673e01aa904Sopenharmony_ci	  header = gelf_getshdr(section, &header_mem);
674e01aa904Sopenharmony_ci	  if (header == NULL
675e01aa904Sopenharmony_ci	      || (header->sh_type != SHT_RELA && header->sh_type != SHT_REL))
676e01aa904Sopenharmony_ci	    continue;
677e01aa904Sopenharmony_ci
678e01aa904Sopenharmony_ci	  if (header->sh_info == target_index)
679e01aa904Sopenharmony_ci	    return section;
680e01aa904Sopenharmony_ci	}
681e01aa904Sopenharmony_ci    }
682e01aa904Sopenharmony_ci  return NULL;
683e01aa904Sopenharmony_ci}
684e01aa904Sopenharmony_ci
685e01aa904Sopenharmony_ci/// Return the string table used by the given symbol table.
686e01aa904Sopenharmony_ci///
687e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
688e01aa904Sopenharmony_ci///
689e01aa904Sopenharmony_ci/// @param symtab_section section containing a symbol table.
690e01aa904Sopenharmony_ci///
691e01aa904Sopenharmony_ci/// @return the string table linked by the symtab, if it is not NULL.
692e01aa904Sopenharmony_ciElf_Scn*
693e01aa904Sopenharmony_cifind_strtab_for_symtab_section(Elf* elf_handle, Elf_Scn* symtab_section)
694e01aa904Sopenharmony_ci{
695e01aa904Sopenharmony_ci  Elf_Scn *strtab_section = NULL;
696e01aa904Sopenharmony_ci
697e01aa904Sopenharmony_ci  if (symtab_section)
698e01aa904Sopenharmony_ci    {
699e01aa904Sopenharmony_ci      GElf_Shdr symtab_shdr_mem, *symtab_shdr;
700e01aa904Sopenharmony_ci
701e01aa904Sopenharmony_ci      symtab_shdr = gelf_getshdr(symtab_section, &symtab_shdr_mem);
702e01aa904Sopenharmony_ci      strtab_section = elf_getscn(elf_handle, symtab_shdr->sh_link);
703e01aa904Sopenharmony_ci    }
704e01aa904Sopenharmony_ci
705e01aa904Sopenharmony_ci  return strtab_section;
706e01aa904Sopenharmony_ci}
707e01aa904Sopenharmony_ci
708e01aa904Sopenharmony_ci/// Get the version definition (from the SHT_GNU_verdef section) of a
709e01aa904Sopenharmony_ci/// given symbol represented by a pointer to GElf_Versym.
710e01aa904Sopenharmony_ci///
711e01aa904Sopenharmony_ci/// @param elf_hande the elf handle to use.
712e01aa904Sopenharmony_ci///
713e01aa904Sopenharmony_ci/// @param versym the symbol to get the version definition for.
714e01aa904Sopenharmony_ci///
715e01aa904Sopenharmony_ci/// @param verdef_section the SHT_GNU_verdef section.
716e01aa904Sopenharmony_ci///
717e01aa904Sopenharmony_ci/// @param version the resulting version definition.  This is set iff
718e01aa904Sopenharmony_ci/// the function returns true.
719e01aa904Sopenharmony_ci///
720e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise.
721e01aa904Sopenharmony_cibool
722e01aa904Sopenharmony_ciget_version_definition_for_versym(Elf*			 elf_handle,
723e01aa904Sopenharmony_ci				  GElf_Versym*		 versym,
724e01aa904Sopenharmony_ci				  Elf_Scn*		 verdef_section,
725e01aa904Sopenharmony_ci				  elf_symbol::version&	 version)
726e01aa904Sopenharmony_ci{
727e01aa904Sopenharmony_ci  Elf_Data* verdef_data = elf_getdata(verdef_section, NULL);
728e01aa904Sopenharmony_ci  GElf_Verdef verdef_mem;
729e01aa904Sopenharmony_ci  GElf_Verdef* verdef = gelf_getverdef(verdef_data, 0, &verdef_mem);
730e01aa904Sopenharmony_ci  size_t vd_offset = 0;
731e01aa904Sopenharmony_ci
732e01aa904Sopenharmony_ci  for (;; vd_offset += verdef->vd_next)
733e01aa904Sopenharmony_ci    {
734e01aa904Sopenharmony_ci      for (;verdef != 0;)
735e01aa904Sopenharmony_ci	{
736e01aa904Sopenharmony_ci	  if (verdef->vd_ndx == (*versym & 0x7fff))
737e01aa904Sopenharmony_ci	    // Found the version of the symbol.
738e01aa904Sopenharmony_ci	    break;
739e01aa904Sopenharmony_ci	  vd_offset += verdef->vd_next;
740e01aa904Sopenharmony_ci	  verdef = (verdef->vd_next == 0
741e01aa904Sopenharmony_ci		    ? 0
742e01aa904Sopenharmony_ci		    : gelf_getverdef(verdef_data, vd_offset, &verdef_mem));
743e01aa904Sopenharmony_ci	}
744e01aa904Sopenharmony_ci
745e01aa904Sopenharmony_ci      if (verdef != 0)
746e01aa904Sopenharmony_ci	{
747e01aa904Sopenharmony_ci	  GElf_Verdaux verdaux_mem;
748e01aa904Sopenharmony_ci	  GElf_Verdaux *verdaux = gelf_getverdaux(verdef_data,
749e01aa904Sopenharmony_ci						  vd_offset + verdef->vd_aux,
750e01aa904Sopenharmony_ci						  &verdaux_mem);
751e01aa904Sopenharmony_ci	  GElf_Shdr header_mem;
752e01aa904Sopenharmony_ci	  GElf_Shdr* verdef_section_header = gelf_getshdr(verdef_section,
753e01aa904Sopenharmony_ci							  &header_mem);
754e01aa904Sopenharmony_ci	  size_t verdef_stridx = verdef_section_header->sh_link;
755e01aa904Sopenharmony_ci	  version.str(elf_strptr(elf_handle, verdef_stridx, verdaux->vda_name));
756e01aa904Sopenharmony_ci	  if (*versym & 0x8000)
757e01aa904Sopenharmony_ci	    version.is_default(false);
758e01aa904Sopenharmony_ci	  else
759e01aa904Sopenharmony_ci	    version.is_default(true);
760e01aa904Sopenharmony_ci	  return true;
761e01aa904Sopenharmony_ci	}
762e01aa904Sopenharmony_ci      if (!verdef || verdef->vd_next == 0)
763e01aa904Sopenharmony_ci	break;
764e01aa904Sopenharmony_ci    }
765e01aa904Sopenharmony_ci  return false;
766e01aa904Sopenharmony_ci}
767e01aa904Sopenharmony_ci
768e01aa904Sopenharmony_ci/// Get the version needed (from the SHT_GNU_verneed section) to
769e01aa904Sopenharmony_ci/// resolve an undefined symbol represented by a pointer to
770e01aa904Sopenharmony_ci/// GElf_Versym.
771e01aa904Sopenharmony_ci///
772e01aa904Sopenharmony_ci/// @param elf_hande the elf handle to use.
773e01aa904Sopenharmony_ci///
774e01aa904Sopenharmony_ci/// @param versym the symbol to get the version definition for.
775e01aa904Sopenharmony_ci///
776e01aa904Sopenharmony_ci/// @param verneed_section the SHT_GNU_verneed section.
777e01aa904Sopenharmony_ci///
778e01aa904Sopenharmony_ci/// @param version the resulting version definition.  This is set iff
779e01aa904Sopenharmony_ci/// the function returns true.
780e01aa904Sopenharmony_ci///
781e01aa904Sopenharmony_ci/// @return true upon successful completion, false otherwise.
782e01aa904Sopenharmony_cibool
783e01aa904Sopenharmony_ciget_version_needed_for_versym(Elf*			elf_handle,
784e01aa904Sopenharmony_ci			      GElf_Versym*		versym,
785e01aa904Sopenharmony_ci			      Elf_Scn*			verneed_section,
786e01aa904Sopenharmony_ci			      elf_symbol::version&	version)
787e01aa904Sopenharmony_ci{
788e01aa904Sopenharmony_ci  if (versym == 0 || elf_handle == 0 || verneed_section == 0)
789e01aa904Sopenharmony_ci    return false;
790e01aa904Sopenharmony_ci
791e01aa904Sopenharmony_ci  size_t vn_offset = 0;
792e01aa904Sopenharmony_ci  Elf_Data* verneed_data = elf_getdata(verneed_section, NULL);
793e01aa904Sopenharmony_ci  GElf_Verneed verneed_mem;
794e01aa904Sopenharmony_ci  GElf_Verneed* verneed = gelf_getverneed(verneed_data, 0, &verneed_mem);
795e01aa904Sopenharmony_ci
796e01aa904Sopenharmony_ci  for (;verneed; vn_offset += verneed->vn_next)
797e01aa904Sopenharmony_ci    {
798e01aa904Sopenharmony_ci      size_t vna_offset = vn_offset;
799e01aa904Sopenharmony_ci      GElf_Vernaux vernaux_mem;
800e01aa904Sopenharmony_ci      GElf_Vernaux *vernaux = gelf_getvernaux(verneed_data,
801e01aa904Sopenharmony_ci					      vn_offset + verneed->vn_aux,
802e01aa904Sopenharmony_ci					      &vernaux_mem);
803e01aa904Sopenharmony_ci      for (;vernaux != 0 && verneed;)
804e01aa904Sopenharmony_ci	{
805e01aa904Sopenharmony_ci	  if (vernaux->vna_other == *versym)
806e01aa904Sopenharmony_ci	    // Found the version of the symbol.
807e01aa904Sopenharmony_ci	    break;
808e01aa904Sopenharmony_ci	  vna_offset += verneed->vn_next;
809e01aa904Sopenharmony_ci	  verneed = (verneed->vn_next == 0
810e01aa904Sopenharmony_ci		     ? 0
811e01aa904Sopenharmony_ci		     : gelf_getverneed(verneed_data, vna_offset, &verneed_mem));
812e01aa904Sopenharmony_ci	}
813e01aa904Sopenharmony_ci
814e01aa904Sopenharmony_ci      if (verneed != 0 && vernaux != 0 && vernaux->vna_other == *versym)
815e01aa904Sopenharmony_ci	{
816e01aa904Sopenharmony_ci	  GElf_Shdr header_mem;
817e01aa904Sopenharmony_ci	  GElf_Shdr* verneed_section_header = gelf_getshdr(verneed_section,
818e01aa904Sopenharmony_ci							   &header_mem);
819e01aa904Sopenharmony_ci	  size_t verneed_stridx = verneed_section_header->sh_link;
820e01aa904Sopenharmony_ci	  version.str(elf_strptr(elf_handle,
821e01aa904Sopenharmony_ci				 verneed_stridx,
822e01aa904Sopenharmony_ci				 vernaux->vna_name));
823e01aa904Sopenharmony_ci	  if (*versym & 0x8000)
824e01aa904Sopenharmony_ci	    version.is_default(false);
825e01aa904Sopenharmony_ci	  else
826e01aa904Sopenharmony_ci	    version.is_default(true);
827e01aa904Sopenharmony_ci	  return true;
828e01aa904Sopenharmony_ci	}
829e01aa904Sopenharmony_ci
830e01aa904Sopenharmony_ci      if (!verneed || verneed->vn_next == 0)
831e01aa904Sopenharmony_ci	break;
832e01aa904Sopenharmony_ci    }
833e01aa904Sopenharmony_ci  return false;
834e01aa904Sopenharmony_ci}
835e01aa904Sopenharmony_ci
836e01aa904Sopenharmony_ci/// Return the version for a symbol that is at a given index in its
837e01aa904Sopenharmony_ci/// SHT_SYMTAB section.
838e01aa904Sopenharmony_ci///
839e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
840e01aa904Sopenharmony_ci///
841e01aa904Sopenharmony_ci/// @param symbol_index the index of the symbol to consider.
842e01aa904Sopenharmony_ci///
843e01aa904Sopenharmony_ci/// @param get_def_version if this is true, it means that that we want
844e01aa904Sopenharmony_ci/// the version for a defined symbol; in that case, the version is
845e01aa904Sopenharmony_ci/// looked for in a section of type SHT_GNU_verdef.  Otherwise, if
846e01aa904Sopenharmony_ci/// this parameter is false, this means that we want the version for
847e01aa904Sopenharmony_ci/// an undefined symbol; in that case, the version is the needed one
848e01aa904Sopenharmony_ci/// for the symbol to be resolved; so the version is looked fo in a
849e01aa904Sopenharmony_ci/// section of type SHT_GNU_verneed.
850e01aa904Sopenharmony_ci///
851e01aa904Sopenharmony_ci/// @param version the version found for symbol at @p symbol_index.
852e01aa904Sopenharmony_ci///
853e01aa904Sopenharmony_ci/// @return true iff a version was found for symbol at index @p
854e01aa904Sopenharmony_ci/// symbol_index.
855e01aa904Sopenharmony_cibool
856e01aa904Sopenharmony_ciget_version_for_symbol(Elf*			elf_handle,
857e01aa904Sopenharmony_ci		       size_t			symbol_index,
858e01aa904Sopenharmony_ci		       bool			get_def_version,
859e01aa904Sopenharmony_ci		       elf_symbol::version&	version)
860e01aa904Sopenharmony_ci{
861e01aa904Sopenharmony_ci  Elf_Scn *versym_section = NULL,
862e01aa904Sopenharmony_ci    *verdef_section = NULL,
863e01aa904Sopenharmony_ci    *verneed_section = NULL;
864e01aa904Sopenharmony_ci
865e01aa904Sopenharmony_ci  if (!get_symbol_versionning_sections(elf_handle,
866e01aa904Sopenharmony_ci				       versym_section,
867e01aa904Sopenharmony_ci				       verdef_section,
868e01aa904Sopenharmony_ci				       verneed_section))
869e01aa904Sopenharmony_ci    return false;
870e01aa904Sopenharmony_ci
871e01aa904Sopenharmony_ci  GElf_Versym versym_mem;
872e01aa904Sopenharmony_ci  Elf_Data* versym_data = (versym_section)
873e01aa904Sopenharmony_ci    ? elf_getdata(versym_section, NULL)
874e01aa904Sopenharmony_ci    : NULL;
875e01aa904Sopenharmony_ci  GElf_Versym* versym = (versym_data)
876e01aa904Sopenharmony_ci    ? gelf_getversym(versym_data, symbol_index, &versym_mem)
877e01aa904Sopenharmony_ci    : NULL;
878e01aa904Sopenharmony_ci
879e01aa904Sopenharmony_ci  if (versym == 0 || *versym <= 1)
880e01aa904Sopenharmony_ci    // I got these value from the code of readelf.c in elfutils.
881e01aa904Sopenharmony_ci    // Apparently, if the symbol version entry has these values, the
882e01aa904Sopenharmony_ci    // symbol must be discarded. This is not documented in the
883e01aa904Sopenharmony_ci    // official specification.
884e01aa904Sopenharmony_ci    return false;
885e01aa904Sopenharmony_ci
886e01aa904Sopenharmony_ci  if (get_def_version)
887e01aa904Sopenharmony_ci    {
888e01aa904Sopenharmony_ci      if (*versym == 0x8001)
889e01aa904Sopenharmony_ci	// I got this value from the code of readelf.c in elfutils
890e01aa904Sopenharmony_ci	// too.  It's not really documented in the official
891e01aa904Sopenharmony_ci	// specification.
892e01aa904Sopenharmony_ci	return false;
893e01aa904Sopenharmony_ci
894e01aa904Sopenharmony_ci      if (verdef_section
895e01aa904Sopenharmony_ci	  && get_version_definition_for_versym(elf_handle, versym,
896e01aa904Sopenharmony_ci					       verdef_section, version))
897e01aa904Sopenharmony_ci	return true;
898e01aa904Sopenharmony_ci    }
899e01aa904Sopenharmony_ci  else
900e01aa904Sopenharmony_ci    {
901e01aa904Sopenharmony_ci      if (verneed_section
902e01aa904Sopenharmony_ci	  && get_version_needed_for_versym(elf_handle, versym,
903e01aa904Sopenharmony_ci					   verneed_section, version))
904e01aa904Sopenharmony_ci	return true;
905e01aa904Sopenharmony_ci    }
906e01aa904Sopenharmony_ci
907e01aa904Sopenharmony_ci  return false;
908e01aa904Sopenharmony_ci}
909e01aa904Sopenharmony_ci
910e01aa904Sopenharmony_ci/// Return the CRC from the "__crc_" symbol.
911e01aa904Sopenharmony_ci///
912e01aa904Sopenharmony_ci/// @param elf_handle the elf handle to use.
913e01aa904Sopenharmony_ci///
914e01aa904Sopenharmony_ci/// @param crc_symbol symbol containing CRC value.
915e01aa904Sopenharmony_ci///
916e01aa904Sopenharmony_ci/// @param crc_value the CRC found for @p crc_symbol.
917e01aa904Sopenharmony_ci///
918e01aa904Sopenharmony_ci/// @return true iff a CRC was found for given @p crc_symbol.
919e01aa904Sopenharmony_cibool
920e01aa904Sopenharmony_ciget_crc_for_symbol(Elf* elf_handle, GElf_Sym* crc_symbol, uint32_t& crc_value)
921e01aa904Sopenharmony_ci{
922e01aa904Sopenharmony_ci  size_t crc_section_index = crc_symbol->st_shndx;
923e01aa904Sopenharmony_ci  uint64_t crc_symbol_value = crc_symbol->st_value;
924e01aa904Sopenharmony_ci  if (crc_section_index == SHN_ABS)
925e01aa904Sopenharmony_ci    {
926e01aa904Sopenharmony_ci      crc_value = crc_symbol_value;
927e01aa904Sopenharmony_ci      return true;
928e01aa904Sopenharmony_ci    }
929e01aa904Sopenharmony_ci
930e01aa904Sopenharmony_ci  Elf_Scn* kcrctab_section = elf_getscn(elf_handle, crc_section_index);
931e01aa904Sopenharmony_ci  if (kcrctab_section == NULL)
932e01aa904Sopenharmony_ci      return false;
933e01aa904Sopenharmony_ci
934e01aa904Sopenharmony_ci  GElf_Shdr sheader_mem;
935e01aa904Sopenharmony_ci  GElf_Shdr* sheader = gelf_getshdr(kcrctab_section, &sheader_mem);
936e01aa904Sopenharmony_ci  if (sheader == NULL)
937e01aa904Sopenharmony_ci    return false;
938e01aa904Sopenharmony_ci
939e01aa904Sopenharmony_ci  Elf_Data* kcrctab_data = elf_rawdata(kcrctab_section, NULL);
940e01aa904Sopenharmony_ci  if (kcrctab_data == NULL)
941e01aa904Sopenharmony_ci    return false;
942e01aa904Sopenharmony_ci
943e01aa904Sopenharmony_ci  if (crc_symbol_value < sheader->sh_addr)
944e01aa904Sopenharmony_ci    return false;
945e01aa904Sopenharmony_ci
946e01aa904Sopenharmony_ci  size_t offset = crc_symbol_value - sheader->sh_addr;
947e01aa904Sopenharmony_ci  if (offset + sizeof(uint32_t) > kcrctab_data->d_size
948e01aa904Sopenharmony_ci      || offset + sizeof(uint32_t) > sheader->sh_size)
949e01aa904Sopenharmony_ci    return false;
950e01aa904Sopenharmony_ci
951e01aa904Sopenharmony_ci  crc_value = *reinterpret_cast<uint32_t*>(
952e01aa904Sopenharmony_ci      reinterpret_cast<char*>(kcrctab_data->d_buf) + offset);
953e01aa904Sopenharmony_ci
954e01aa904Sopenharmony_ci  return true;
955e01aa904Sopenharmony_ci}
956e01aa904Sopenharmony_ci
957e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is ppc64.
958e01aa904Sopenharmony_ci///
959e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
960e01aa904Sopenharmony_ci///
961e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is ppc64.
962e01aa904Sopenharmony_cibool
963e01aa904Sopenharmony_ciarchitecture_is_ppc64(Elf* elf_handle)
964e01aa904Sopenharmony_ci{
965e01aa904Sopenharmony_ci  GElf_Ehdr  eh_mem;
966e01aa904Sopenharmony_ci  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
967e01aa904Sopenharmony_ci  return (elf_header && elf_header->e_machine == EM_PPC64);
968e01aa904Sopenharmony_ci}
969e01aa904Sopenharmony_ci
970e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is ppc32.
971e01aa904Sopenharmony_ci///
972e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
973e01aa904Sopenharmony_ci///
974e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is ppc32.
975e01aa904Sopenharmony_cibool
976e01aa904Sopenharmony_ciarchitecture_is_ppc32(Elf* elf_handle)
977e01aa904Sopenharmony_ci{
978e01aa904Sopenharmony_ci  GElf_Ehdr  eh_mem;
979e01aa904Sopenharmony_ci  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
980e01aa904Sopenharmony_ci  return (elf_header && elf_header->e_machine == EM_PPC);
981e01aa904Sopenharmony_ci}
982e01aa904Sopenharmony_ci
983e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is arm32.
984e01aa904Sopenharmony_ci///
985e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
986e01aa904Sopenharmony_ci///
987e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is arm32.
988e01aa904Sopenharmony_cibool
989e01aa904Sopenharmony_ciarchitecture_is_arm32(Elf* elf_handle)
990e01aa904Sopenharmony_ci{
991e01aa904Sopenharmony_ci  GElf_Ehdr  eh_mem;
992e01aa904Sopenharmony_ci  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
993e01aa904Sopenharmony_ci  return (elf_header && elf_header->e_machine == EM_ARM);
994e01aa904Sopenharmony_ci}
995e01aa904Sopenharmony_ci
996e01aa904Sopenharmony_ci/// Test if the architecture of the current binary is arm64.
997e01aa904Sopenharmony_ci///
998e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
999e01aa904Sopenharmony_ci///
1000e01aa904Sopenharmony_ci/// @return true iff the architecture of the current binary is arm64.
1001e01aa904Sopenharmony_cibool
1002e01aa904Sopenharmony_ciarchitecture_is_arm64(Elf* elf_handle)
1003e01aa904Sopenharmony_ci{
1004e01aa904Sopenharmony_ci#ifdef HAVE_EM_AARCH64_MACRO
1005e01aa904Sopenharmony_ci  GElf_Ehdr  eh_mem;
1006e01aa904Sopenharmony_ci  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle, &eh_mem);
1007e01aa904Sopenharmony_ci  return (elf_header && elf_header->e_machine == EM_AARCH64);
1008e01aa904Sopenharmony_ci#else
1009e01aa904Sopenharmony_ci  return false;
1010e01aa904Sopenharmony_ci#endif
1011e01aa904Sopenharmony_ci}
1012e01aa904Sopenharmony_ci
1013e01aa904Sopenharmony_ci/// Test if the endianness of the current binary is Big Endian.
1014e01aa904Sopenharmony_ci///
1015e01aa904Sopenharmony_ci/// https://en.wikipedia.org/wiki/Endianness.
1016e01aa904Sopenharmony_ci///
1017e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1018e01aa904Sopenharmony_ci///
1019e01aa904Sopenharmony_ci/// @return true iff the current binary is Big Endian.
1020e01aa904Sopenharmony_cibool
1021e01aa904Sopenharmony_ciarchitecture_is_big_endian(Elf* elf_handle)
1022e01aa904Sopenharmony_ci{
1023e01aa904Sopenharmony_ci  GElf_Ehdr  elf_header;
1024e01aa904Sopenharmony_ci  gelf_getehdr(elf_handle, &elf_header);
1025e01aa904Sopenharmony_ci
1026e01aa904Sopenharmony_ci  bool is_big_endian = (elf_header.e_ident[EI_DATA] == ELFDATA2MSB);
1027e01aa904Sopenharmony_ci
1028e01aa904Sopenharmony_ci  if (!is_big_endian)
1029e01aa904Sopenharmony_ci    ABG_ASSERT(elf_header.e_ident[EI_DATA] == ELFDATA2LSB);
1030e01aa904Sopenharmony_ci
1031e01aa904Sopenharmony_ci  return is_big_endian;
1032e01aa904Sopenharmony_ci}
1033e01aa904Sopenharmony_ci
1034e01aa904Sopenharmony_ci/// Read N bytes and convert their value into an integer type T.
1035e01aa904Sopenharmony_ci///
1036e01aa904Sopenharmony_ci/// Note that N cannot be bigger than 8 for now. The type passed needs to be at
1037e01aa904Sopenharmony_ci/// least of the size of number_of_bytes.
1038e01aa904Sopenharmony_ci///
1039e01aa904Sopenharmony_ci/// @param bytes the array of bytes to read the next 8 bytes from.
1040e01aa904Sopenharmony_ci/// Note that this array must be at least 8 bytes long.
1041e01aa904Sopenharmony_ci///
1042e01aa904Sopenharmony_ci/// @param number_of_bytes the number of bytes to read.  This number
1043e01aa904Sopenharmony_ci/// cannot be bigger than 8.
1044e01aa904Sopenharmony_ci///
1045e01aa904Sopenharmony_ci/// @param is_big_endian if true, read the 8 bytes in Big Endian
1046e01aa904Sopenharmony_ci/// mode, otherwise, read them in Little Endian.
1047e01aa904Sopenharmony_ci///
1048e01aa904Sopenharmony_ci/// @param result where to store the resuting integer that was read.
1049e01aa904Sopenharmony_ci///
1050e01aa904Sopenharmony_ci///
1051e01aa904Sopenharmony_ci/// @param true if the 8 bytes could be read, false otherwise.
1052e01aa904Sopenharmony_citemplate <typename T>
1053e01aa904Sopenharmony_cibool
1054e01aa904Sopenharmony_ciread_int_from_array_of_bytes(const uint8_t* bytes,
1055e01aa904Sopenharmony_ci			     unsigned char  number_of_bytes,
1056e01aa904Sopenharmony_ci			     bool	    is_big_endian,
1057e01aa904Sopenharmony_ci			     T&		    result)
1058e01aa904Sopenharmony_ci{
1059e01aa904Sopenharmony_ci  if (!bytes)
1060e01aa904Sopenharmony_ci    return false;
1061e01aa904Sopenharmony_ci
1062e01aa904Sopenharmony_ci  ABG_ASSERT(number_of_bytes <= 8);
1063e01aa904Sopenharmony_ci  ABG_ASSERT(number_of_bytes <= sizeof(T));
1064e01aa904Sopenharmony_ci
1065e01aa904Sopenharmony_ci  T res = 0;
1066e01aa904Sopenharmony_ci
1067e01aa904Sopenharmony_ci  const uint8_t* cur = bytes;
1068e01aa904Sopenharmony_ci  if (is_big_endian)
1069e01aa904Sopenharmony_ci    {
1070e01aa904Sopenharmony_ci      // In Big Endian, the most significant byte is at the lowest
1071e01aa904Sopenharmony_ci      // address.
1072e01aa904Sopenharmony_ci      const uint8_t* msb = cur;
1073e01aa904Sopenharmony_ci      res = *msb;
1074e01aa904Sopenharmony_ci
1075e01aa904Sopenharmony_ci      // Now read the remaining least significant bytes.
1076e01aa904Sopenharmony_ci      for (uint i = 1; i < number_of_bytes; ++i)
1077e01aa904Sopenharmony_ci	res = (res << 8) | ((T)msb[i]);
1078e01aa904Sopenharmony_ci    }
1079e01aa904Sopenharmony_ci  else
1080e01aa904Sopenharmony_ci    {
1081e01aa904Sopenharmony_ci      // In Little Endian, the least significant byte is at the
1082e01aa904Sopenharmony_ci      // lowest address.
1083e01aa904Sopenharmony_ci      const uint8_t* lsb = cur;
1084e01aa904Sopenharmony_ci      res = *lsb;
1085e01aa904Sopenharmony_ci      // Now read the remaining most significant bytes.
1086e01aa904Sopenharmony_ci      for (uint i = 1; i < number_of_bytes; ++i)
1087e01aa904Sopenharmony_ci	res = res | (((T)lsb[i]) << i * 8);
1088e01aa904Sopenharmony_ci    }
1089e01aa904Sopenharmony_ci
1090e01aa904Sopenharmony_ci  result = res;
1091e01aa904Sopenharmony_ci  return true;
1092e01aa904Sopenharmony_ci}
1093e01aa904Sopenharmony_ci
1094e01aa904Sopenharmony_ci/// Read 8 bytes and convert their value into an uint64_t.
1095e01aa904Sopenharmony_ci///
1096e01aa904Sopenharmony_ci/// @param bytes the array of bytes to read the next 8 bytes from.
1097e01aa904Sopenharmony_ci/// Note that this array must be at least 8 bytes long.
1098e01aa904Sopenharmony_ci///
1099e01aa904Sopenharmony_ci/// @param result where to store the resuting uint64_t that was read.
1100e01aa904Sopenharmony_ci///
1101e01aa904Sopenharmony_ci/// @param is_big_endian if true, read the 8 bytes in Big Endian
1102e01aa904Sopenharmony_ci/// mode, otherwise, read them in Little Endian.
1103e01aa904Sopenharmony_ci///
1104e01aa904Sopenharmony_ci/// @param true if the 8 bytes could be read, false otherwise.
1105e01aa904Sopenharmony_cibool
1106e01aa904Sopenharmony_ciread_uint64_from_array_of_bytes(const uint8_t* bytes,
1107e01aa904Sopenharmony_ci				bool	       is_big_endian,
1108e01aa904Sopenharmony_ci				uint64_t&      result)
1109e01aa904Sopenharmony_ci{
1110e01aa904Sopenharmony_ci  return read_int_from_array_of_bytes(bytes, 8, is_big_endian, result);
1111e01aa904Sopenharmony_ci}
1112e01aa904Sopenharmony_ci
1113e01aa904Sopenharmony_ci
1114e01aa904Sopenharmony_ci/// Lookup the address of the function entry point that corresponds
1115e01aa904Sopenharmony_ci/// to the address of a given function descriptor.
1116e01aa904Sopenharmony_ci///
1117e01aa904Sopenharmony_ci/// On PPC64, a function pointer is the address of a function
1118e01aa904Sopenharmony_ci/// descriptor.  Function descriptors are located in the .opd
1119e01aa904Sopenharmony_ci/// section.  Each function descriptor is a triplet of three
1120e01aa904Sopenharmony_ci/// addresses, each one on 64 bits.  Among those three address only
1121e01aa904Sopenharmony_ci/// the first one is of any interest to us: the address of the entry
1122e01aa904Sopenharmony_ci/// point of the function.
1123e01aa904Sopenharmony_ci///
1124e01aa904Sopenharmony_ci/// This function returns the address of the entry point of the
1125e01aa904Sopenharmony_ci/// function whose descriptor's address is given.
1126e01aa904Sopenharmony_ci///
1127e01aa904Sopenharmony_ci/// http://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.html#FUNC-DES
1128e01aa904Sopenharmony_ci///
1129e01aa904Sopenharmony_ci/// https://www.ibm.com/developerworks/community/blogs/5894415f-be62-4bc0-81c5-3956e82276f3/entry/deeply_understand_64_bit_powerpc_elf_abi_function_descriptors?lang=en
1130e01aa904Sopenharmony_ci///
1131e01aa904Sopenharmony_ci/// @param fn_desc_address the address of the function descriptor to
1132e01aa904Sopenharmony_ci/// consider.
1133e01aa904Sopenharmony_ci///
1134e01aa904Sopenharmony_ci/// @return the address of the entry point of the function whose
1135e01aa904Sopenharmony_ci/// descriptor has the address @p fn_desc_address.  If there is no
1136e01aa904Sopenharmony_ci/// .opd section (e.g because we are not on ppc64) or more generally
1137e01aa904Sopenharmony_ci/// if the function descriptor could not be found then this function
1138e01aa904Sopenharmony_ci/// just returns the address of the fuction descriptor.
1139e01aa904Sopenharmony_ciGElf_Addr
1140e01aa904Sopenharmony_cilookup_ppc64_elf_fn_entry_point_address(Elf* elf_handle, GElf_Addr fn_desc_address)
1141e01aa904Sopenharmony_ci{
1142e01aa904Sopenharmony_ci  if (!elf_handle)
1143e01aa904Sopenharmony_ci    return fn_desc_address;
1144e01aa904Sopenharmony_ci
1145e01aa904Sopenharmony_ci  if (!architecture_is_ppc64(elf_handle))
1146e01aa904Sopenharmony_ci    return fn_desc_address;
1147e01aa904Sopenharmony_ci
1148e01aa904Sopenharmony_ci  bool is_big_endian = architecture_is_big_endian(elf_handle);
1149e01aa904Sopenharmony_ci
1150e01aa904Sopenharmony_ci  Elf_Scn* opd_section = find_opd_section(elf_handle);
1151e01aa904Sopenharmony_ci  if (!opd_section)
1152e01aa904Sopenharmony_ci    return fn_desc_address;
1153e01aa904Sopenharmony_ci
1154e01aa904Sopenharmony_ci  GElf_Shdr header_mem;
1155e01aa904Sopenharmony_ci  // The section header of the .opd section.
1156e01aa904Sopenharmony_ci  GElf_Shdr* opd_sheader = gelf_getshdr(opd_section, &header_mem);
1157e01aa904Sopenharmony_ci
1158e01aa904Sopenharmony_ci  // The offset of the function descriptor entry, in the .opd
1159e01aa904Sopenharmony_ci  // section.
1160e01aa904Sopenharmony_ci  size_t    fn_desc_offset = fn_desc_address - opd_sheader->sh_addr;
1161e01aa904Sopenharmony_ci  Elf_Data* elf_data = elf_rawdata(opd_section, 0);
1162e01aa904Sopenharmony_ci
1163e01aa904Sopenharmony_ci  // Ensure that the opd_section has at least 8 bytes, starting from
1164e01aa904Sopenharmony_ci  // the offset we want read the data from.
1165e01aa904Sopenharmony_ci  if (elf_data->d_size <= fn_desc_offset + 8)
1166e01aa904Sopenharmony_ci    return fn_desc_address;
1167e01aa904Sopenharmony_ci
1168e01aa904Sopenharmony_ci  // A pointer to the data of the .opd section, that we can actually
1169e01aa904Sopenharmony_ci  // do something with.
1170e01aa904Sopenharmony_ci  uint8_t* bytes = (uint8_t*)elf_data->d_buf;
1171e01aa904Sopenharmony_ci
1172e01aa904Sopenharmony_ci  // The resulting address we are looking for is going to be formed
1173e01aa904Sopenharmony_ci  // in this variable.
1174e01aa904Sopenharmony_ci  GElf_Addr result = 0;
1175e01aa904Sopenharmony_ci  ABG_ASSERT(read_uint64_from_array_of_bytes(bytes + fn_desc_offset,
1176e01aa904Sopenharmony_ci					     is_big_endian, result));
1177e01aa904Sopenharmony_ci
1178e01aa904Sopenharmony_ci  return result;
1179e01aa904Sopenharmony_ci}
1180e01aa904Sopenharmony_ci
1181e01aa904Sopenharmony_ci/// Test if the ELF binary denoted by a given ELF handle is a Linux
1182e01aa904Sopenharmony_ci/// Kernel Module.
1183e01aa904Sopenharmony_ci///
1184e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1185e01aa904Sopenharmony_ci///
1186e01aa904Sopenharmony_ci/// @return true iff the binary denoted by @p elf_handle is a Linux
1187e01aa904Sopenharmony_ci/// kernel module.
1188e01aa904Sopenharmony_cibool
1189e01aa904Sopenharmony_ciis_linux_kernel_module(Elf *elf_handle)
1190e01aa904Sopenharmony_ci{
1191e01aa904Sopenharmony_ci  return (find_section(elf_handle, ".modinfo", SHT_PROGBITS)
1192e01aa904Sopenharmony_ci	  && find_section(elf_handle,
1193e01aa904Sopenharmony_ci			  ".gnu.linkonce.this_module",
1194e01aa904Sopenharmony_ci			  SHT_PROGBITS));
1195e01aa904Sopenharmony_ci}
1196e01aa904Sopenharmony_ci
1197e01aa904Sopenharmony_ci/// Test if the ELF binary denoted by a given ELF handle is a Linux
1198e01aa904Sopenharmony_ci/// Kernel binary (either vmlinux or a kernel module).
1199e01aa904Sopenharmony_ci///
1200e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1201e01aa904Sopenharmony_ci///
1202e01aa904Sopenharmony_ci/// @return true iff the binary denoted by @p elf_handle is a Linux
1203e01aa904Sopenharmony_ci/// kernel binary
1204e01aa904Sopenharmony_cibool
1205e01aa904Sopenharmony_ciis_linux_kernel(Elf *elf_handle)
1206e01aa904Sopenharmony_ci{
1207e01aa904Sopenharmony_ci  return (find_section(elf_handle,
1208e01aa904Sopenharmony_ci		       "__ksymtab_strings",
1209e01aa904Sopenharmony_ci		       SHT_PROGBITS)
1210e01aa904Sopenharmony_ci	  || is_linux_kernel_module(elf_handle));
1211e01aa904Sopenharmony_ci}
1212e01aa904Sopenharmony_ci
1213e01aa904Sopenharmony_ci/// Get the address at which a given binary is loaded in memory.
1214e01aa904Sopenharmony_ci///
1215e01aa904Sopenharmony_ci/// @param elf_handle the elf handle for the binary to consider.
1216e01aa904Sopenharmony_ci///
1217e01aa904Sopenharmony_ci/// @param load_address the address where the binary is loaded.  This
1218e01aa904Sopenharmony_ci/// is set by the function iff it returns true.
1219e01aa904Sopenharmony_ci///
1220e01aa904Sopenharmony_ci/// @return true if the function could get the binary load address
1221e01aa904Sopenharmony_ci/// and assign @p load_address to it.
1222e01aa904Sopenharmony_cibool
1223e01aa904Sopenharmony_ciget_binary_load_address(Elf* elf_handle, GElf_Addr& load_address)
1224e01aa904Sopenharmony_ci{
1225e01aa904Sopenharmony_ci  GElf_Ehdr elf_header;
1226e01aa904Sopenharmony_ci  gelf_getehdr(elf_handle, &elf_header);
1227e01aa904Sopenharmony_ci  size_t num_segments = elf_header.e_phnum;
1228e01aa904Sopenharmony_ci  GElf_Phdr *program_header = NULL;
1229e01aa904Sopenharmony_ci  GElf_Addr result;
1230e01aa904Sopenharmony_ci  bool found_loaded_segment = false;
1231e01aa904Sopenharmony_ci  GElf_Phdr ph_mem;
1232e01aa904Sopenharmony_ci
1233e01aa904Sopenharmony_ci  for (unsigned i = 0; i < num_segments; ++i)
1234e01aa904Sopenharmony_ci    {
1235e01aa904Sopenharmony_ci      program_header = gelf_getphdr(elf_handle, i, &ph_mem);
1236e01aa904Sopenharmony_ci      if (program_header && program_header->p_type == PT_LOAD)
1237e01aa904Sopenharmony_ci	{
1238e01aa904Sopenharmony_ci	  if (!found_loaded_segment)
1239e01aa904Sopenharmony_ci	    {
1240e01aa904Sopenharmony_ci	      result = program_header->p_vaddr;
1241e01aa904Sopenharmony_ci	      found_loaded_segment = true;
1242e01aa904Sopenharmony_ci	    }
1243e01aa904Sopenharmony_ci
1244e01aa904Sopenharmony_ci	  if (program_header->p_vaddr < result)
1245e01aa904Sopenharmony_ci	    // The resulting load address we want is the lowest
1246e01aa904Sopenharmony_ci	    // load address of all the loaded segments.
1247e01aa904Sopenharmony_ci	    result = program_header->p_vaddr;
1248e01aa904Sopenharmony_ci	}
1249e01aa904Sopenharmony_ci    }
1250e01aa904Sopenharmony_ci
1251e01aa904Sopenharmony_ci  if (found_loaded_segment)
1252e01aa904Sopenharmony_ci    {
1253e01aa904Sopenharmony_ci      load_address = result;
1254e01aa904Sopenharmony_ci      return true;
1255e01aa904Sopenharmony_ci    }
1256e01aa904Sopenharmony_ci  return false;
1257e01aa904Sopenharmony_ci}
1258e01aa904Sopenharmony_ci
1259e01aa904Sopenharmony_ci/// Return the size of a word for the current architecture.
1260e01aa904Sopenharmony_ci///
1261e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1262e01aa904Sopenharmony_ci///
1263e01aa904Sopenharmony_ci/// @return the size of a word.
1264e01aa904Sopenharmony_ciunsigned char
1265e01aa904Sopenharmony_ciget_architecture_word_size(Elf* elf_handle)
1266e01aa904Sopenharmony_ci{
1267e01aa904Sopenharmony_ci  unsigned char word_size = 0;
1268e01aa904Sopenharmony_ci  GElf_Ehdr	elf_header;
1269e01aa904Sopenharmony_ci  gelf_getehdr(elf_handle, &elf_header);
1270e01aa904Sopenharmony_ci  if (elf_header.e_ident[EI_CLASS] == ELFCLASS32)
1271e01aa904Sopenharmony_ci    word_size = 4;
1272e01aa904Sopenharmony_ci  else if (elf_header.e_ident[EI_CLASS] == ELFCLASS64)
1273e01aa904Sopenharmony_ci    word_size = 8;
1274e01aa904Sopenharmony_ci  else
1275e01aa904Sopenharmony_ci    ABG_ASSERT_NOT_REACHED;
1276e01aa904Sopenharmony_ci  return word_size;
1277e01aa904Sopenharmony_ci}
1278e01aa904Sopenharmony_ci
1279e01aa904Sopenharmony_ci/// Test if the elf file being read is an executable.
1280e01aa904Sopenharmony_ci///
1281e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1282e01aa904Sopenharmony_ci///
1283e01aa904Sopenharmony_ci/// @return true iff the elf file being read is an / executable.
1284e01aa904Sopenharmony_cibool
1285e01aa904Sopenharmony_ciis_executable(Elf* elf_handle)
1286e01aa904Sopenharmony_ci{
1287e01aa904Sopenharmony_ci  GElf_Ehdr  elf_header;
1288e01aa904Sopenharmony_ci  gelf_getehdr(elf_handle, &elf_header);
1289e01aa904Sopenharmony_ci  return elf_header.e_type == ET_EXEC;
1290e01aa904Sopenharmony_ci}
1291e01aa904Sopenharmony_ci
1292e01aa904Sopenharmony_ci/// Test if the elf file being read is a dynamic shared / object.
1293e01aa904Sopenharmony_ci///
1294e01aa904Sopenharmony_ci/// @param elf_handle the ELF handle to consider.
1295e01aa904Sopenharmony_ci///
1296e01aa904Sopenharmony_ci/// @return true iff the elf file being read is a / dynamic shared object.
1297e01aa904Sopenharmony_cibool
1298e01aa904Sopenharmony_ciis_dso(Elf* elf_handle)
1299e01aa904Sopenharmony_ci{
1300e01aa904Sopenharmony_ci  GElf_Ehdr  elf_header;
1301e01aa904Sopenharmony_ci  gelf_getehdr(elf_handle, &elf_header);
1302e01aa904Sopenharmony_ci  return elf_header.e_type == ET_DYN;
1303e01aa904Sopenharmony_ci}
1304e01aa904Sopenharmony_ci
1305e01aa904Sopenharmony_ci/// Translate a section-relative symbol address (i.e, symbol value)
1306e01aa904Sopenharmony_ci/// into an absolute symbol address by adding the address of the
1307e01aa904Sopenharmony_ci/// section the symbol belongs to, to the address value.
1308e01aa904Sopenharmony_ci///
1309e01aa904Sopenharmony_ci/// This is useful when looking at symbol values coming from
1310e01aa904Sopenharmony_ci/// relocatable files (of ET_REL kind).  If the binary is not
1311e01aa904Sopenharmony_ci/// ET_REL, then the function does nothing and returns the input
1312e01aa904Sopenharmony_ci/// address unchanged.
1313e01aa904Sopenharmony_ci///
1314e01aa904Sopenharmony_ci/// @param elf_handle the elf handle for the binary to consider.
1315e01aa904Sopenharmony_ci///
1316e01aa904Sopenharmony_ci/// @param sym the symbol whose address to possibly needs to be
1317e01aa904Sopenharmony_ci/// translated.
1318e01aa904Sopenharmony_ci///
1319e01aa904Sopenharmony_ci/// @return the section-relative address, translated into an
1320e01aa904Sopenharmony_ci/// absolute address, if @p sym is from an ET_REL binary.
1321e01aa904Sopenharmony_ci/// Otherwise, return the address of @p sym, unchanged.
1322e01aa904Sopenharmony_ciGElf_Addr
1323e01aa904Sopenharmony_cimaybe_adjust_et_rel_sym_addr_to_abs_addr(Elf* elf_handle, GElf_Sym* sym)
1324e01aa904Sopenharmony_ci{
1325e01aa904Sopenharmony_ci  Elf_Scn*  symbol_section = elf_getscn(elf_handle, sym->st_shndx);
1326e01aa904Sopenharmony_ci  GElf_Addr addr = sym->st_value;
1327e01aa904Sopenharmony_ci
1328e01aa904Sopenharmony_ci  if (!symbol_section)
1329e01aa904Sopenharmony_ci    return addr;
1330e01aa904Sopenharmony_ci
1331e01aa904Sopenharmony_ci  GElf_Ehdr elf_header;
1332e01aa904Sopenharmony_ci  if (!gelf_getehdr(elf_handle, &elf_header))
1333e01aa904Sopenharmony_ci    return addr;
1334e01aa904Sopenharmony_ci
1335e01aa904Sopenharmony_ci  if (elf_header.e_type != ET_REL)
1336e01aa904Sopenharmony_ci    return addr;
1337e01aa904Sopenharmony_ci
1338e01aa904Sopenharmony_ci  GElf_Shdr section_header;
1339e01aa904Sopenharmony_ci  if (!gelf_getshdr(symbol_section, &section_header))
1340e01aa904Sopenharmony_ci    return addr;
1341e01aa904Sopenharmony_ci
1342e01aa904Sopenharmony_ci  return addr + section_header.sh_addr;
1343e01aa904Sopenharmony_ci}
1344e01aa904Sopenharmony_ci
1345e01aa904Sopenharmony_ci/// Test if a given address is in a given section.
1346e01aa904Sopenharmony_ci///
1347e01aa904Sopenharmony_ci/// @param addr the address to consider.
1348e01aa904Sopenharmony_ci///
1349e01aa904Sopenharmony_ci/// @param section the section to consider.
1350e01aa904Sopenharmony_ci///
1351e01aa904Sopenharmony_ci/// @return true iff @p addr is in section @p section.
1352e01aa904Sopenharmony_cibool
1353e01aa904Sopenharmony_ciaddress_is_in_section(Dwarf_Addr addr, Elf_Scn* section)
1354e01aa904Sopenharmony_ci{
1355e01aa904Sopenharmony_ci  if (!section)
1356e01aa904Sopenharmony_ci    return false;
1357e01aa904Sopenharmony_ci
1358e01aa904Sopenharmony_ci  GElf_Shdr  sheader_mem;
1359e01aa904Sopenharmony_ci  GElf_Shdr* sheader = gelf_getshdr(section, &sheader_mem);
1360e01aa904Sopenharmony_ci
1361e01aa904Sopenharmony_ci  if (sheader->sh_addr <= addr && addr <= sheader->sh_addr + sheader->sh_size)
1362e01aa904Sopenharmony_ci    return true;
1363e01aa904Sopenharmony_ci
1364e01aa904Sopenharmony_ci  return false;
1365e01aa904Sopenharmony_ci}
1366e01aa904Sopenharmony_ci
1367e01aa904Sopenharmony_ci/// Return true if an address is in the ".opd" section that is
1368e01aa904Sopenharmony_ci/// present on the ppc64 platform.
1369e01aa904Sopenharmony_ci///
1370e01aa904Sopenharmony_ci/// @param addr the address to consider.
1371e01aa904Sopenharmony_ci///
1372e01aa904Sopenharmony_ci/// @return true iff @p addr designates a word that is in the ".opd"
1373e01aa904Sopenharmony_ci/// section.
1374e01aa904Sopenharmony_cibool
1375e01aa904Sopenharmony_ciaddress_is_in_opd_section(Elf* elf_handle, Dwarf_Addr addr)
1376e01aa904Sopenharmony_ci{
1377e01aa904Sopenharmony_ci  Elf_Scn * opd_section = find_opd_section(elf_handle);
1378e01aa904Sopenharmony_ci  if (!opd_section)
1379e01aa904Sopenharmony_ci    return false;
1380e01aa904Sopenharmony_ci  if (address_is_in_section(addr, opd_section))
1381e01aa904Sopenharmony_ci    return true;
1382e01aa904Sopenharmony_ci  return false;
1383e01aa904Sopenharmony_ci}
1384e01aa904Sopenharmony_ci
1385e01aa904Sopenharmony_ci/// Get data tag information of an ELF file by looking up into its
1386e01aa904Sopenharmony_ci/// dynamic segment
1387e01aa904Sopenharmony_ci///
1388e01aa904Sopenharmony_ci/// @param elf the elf handle to use for the query.
1389e01aa904Sopenharmony_ci///
1390e01aa904Sopenharmony_ci/// @param dt_tag data tag to look for in dynamic segment
1391e01aa904Sopenharmony_ci/// @param dt_tag_data vector of found information for a given @p data_tag
1392e01aa904Sopenharmony_ci///
1393e01aa904Sopenharmony_ci/// @return true iff data tag @p data_tag was found
1394e01aa904Sopenharmony_cibool
1395e01aa904Sopenharmony_cilookup_data_tag_from_dynamic_segment(Elf*                       elf,
1396e01aa904Sopenharmony_ci                                     Elf64_Sxword               data_tag,
1397e01aa904Sopenharmony_ci                                     vector<string>&            dt_tag_data)
1398e01aa904Sopenharmony_ci{
1399e01aa904Sopenharmony_ci  size_t num_prog_headers = 0;
1400e01aa904Sopenharmony_ci  bool found = false;
1401e01aa904Sopenharmony_ci  if (elf_getphdrnum(elf, &num_prog_headers) < 0)
1402e01aa904Sopenharmony_ci    return found;
1403e01aa904Sopenharmony_ci
1404e01aa904Sopenharmony_ci  // Cycle through each program header.
1405e01aa904Sopenharmony_ci  for (size_t i = 0; i < num_prog_headers; ++i)
1406e01aa904Sopenharmony_ci    {
1407e01aa904Sopenharmony_ci      GElf_Phdr phdr_mem;
1408e01aa904Sopenharmony_ci      GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem);
1409e01aa904Sopenharmony_ci      if (phdr == NULL || phdr->p_type != PT_DYNAMIC)
1410e01aa904Sopenharmony_ci        continue;
1411e01aa904Sopenharmony_ci
1412e01aa904Sopenharmony_ci      // Poke at the dynamic segment like a section, so that we can
1413e01aa904Sopenharmony_ci      // get its section header information; also we'd like to read
1414e01aa904Sopenharmony_ci      // the data of the segment by using elf_getdata() but that
1415e01aa904Sopenharmony_ci      // function needs a Elf_Scn data structure to act on.
1416e01aa904Sopenharmony_ci      // Elfutils doesn't really have any particular function to
1417e01aa904Sopenharmony_ci      // access segment data, other than the functions used to
1418e01aa904Sopenharmony_ci      // access section data.
1419e01aa904Sopenharmony_ci      Elf_Scn *dynamic_section = gelf_offscn(elf, phdr->p_offset);
1420e01aa904Sopenharmony_ci      GElf_Shdr  shdr_mem;
1421e01aa904Sopenharmony_ci      GElf_Shdr *dynamic_section_header = gelf_getshdr(dynamic_section,
1422e01aa904Sopenharmony_ci						       &shdr_mem);
1423e01aa904Sopenharmony_ci      if (dynamic_section_header == NULL
1424e01aa904Sopenharmony_ci          || dynamic_section_header->sh_type != SHT_DYNAMIC)
1425e01aa904Sopenharmony_ci        continue;
1426e01aa904Sopenharmony_ci
1427e01aa904Sopenharmony_ci      // Get data of the dynamic segment (seen as a section).
1428e01aa904Sopenharmony_ci      Elf_Data *data = elf_getdata(dynamic_section, NULL);
1429e01aa904Sopenharmony_ci      if (data == NULL)
1430e01aa904Sopenharmony_ci        continue;
1431e01aa904Sopenharmony_ci
1432e01aa904Sopenharmony_ci      // Get the index of the section headers string table.
1433e01aa904Sopenharmony_ci      size_t string_table_index = 0;
1434e01aa904Sopenharmony_ci      ABG_ASSERT (elf_getshdrstrndx(elf, &string_table_index) >= 0);
1435e01aa904Sopenharmony_ci
1436e01aa904Sopenharmony_ci      size_t dynamic_section_header_entry_size = gelf_fsize(elf,
1437e01aa904Sopenharmony_ci                                                            ELF_T_DYN, 1,
1438e01aa904Sopenharmony_ci                                                            EV_CURRENT);
1439e01aa904Sopenharmony_ci
1440e01aa904Sopenharmony_ci      GElf_Shdr link_mem;
1441e01aa904Sopenharmony_ci      GElf_Shdr *link =
1442e01aa904Sopenharmony_ci        gelf_getshdr(elf_getscn(elf,
1443e01aa904Sopenharmony_ci                                dynamic_section_header->sh_link),
1444e01aa904Sopenharmony_ci		     &link_mem);
1445e01aa904Sopenharmony_ci      ABG_ASSERT(link != NULL);
1446e01aa904Sopenharmony_ci
1447e01aa904Sopenharmony_ci      size_t num_dynamic_section_entries =
1448e01aa904Sopenharmony_ci        dynamic_section_header->sh_size / dynamic_section_header_entry_size;
1449e01aa904Sopenharmony_ci
1450e01aa904Sopenharmony_ci      // Now walk through all the DT_* data tags that are in the
1451e01aa904Sopenharmony_ci      // segment/section
1452e01aa904Sopenharmony_ci      for (size_t j = 0; j < num_dynamic_section_entries; ++j)
1453e01aa904Sopenharmony_ci        {
1454e01aa904Sopenharmony_ci          GElf_Dyn dynamic_section_mem;
1455e01aa904Sopenharmony_ci          GElf_Dyn *dynamic_section = gelf_getdyn(data,
1456e01aa904Sopenharmony_ci                                                  j,
1457e01aa904Sopenharmony_ci                                                  &dynamic_section_mem);
1458e01aa904Sopenharmony_ci          if (dynamic_section->d_tag == data_tag)
1459e01aa904Sopenharmony_ci            {
1460e01aa904Sopenharmony_ci              dt_tag_data.push_back(elf_strptr(elf,
1461e01aa904Sopenharmony_ci                                               dynamic_section_header->sh_link,
1462e01aa904Sopenharmony_ci					       dynamic_section->d_un.d_val));
1463e01aa904Sopenharmony_ci              found = true;
1464e01aa904Sopenharmony_ci            }
1465e01aa904Sopenharmony_ci        }
1466e01aa904Sopenharmony_ci    }
1467e01aa904Sopenharmony_ci  return found;
1468e01aa904Sopenharmony_ci}
1469e01aa904Sopenharmony_ci
1470e01aa904Sopenharmony_ciconst Dwfl_Callbacks&
1471e01aa904Sopenharmony_ciinitialize_dwfl_callbacks(Dwfl_Callbacks& cb,
1472e01aa904Sopenharmony_ci			  char** debug_info_root_path)
1473e01aa904Sopenharmony_ci{
1474e01aa904Sopenharmony_ci  cb.find_debuginfo = dwfl_standard_find_debuginfo;
1475e01aa904Sopenharmony_ci  cb.section_address = dwfl_offline_section_address;
1476e01aa904Sopenharmony_ci  cb.debuginfo_path = debug_info_root_path;
1477e01aa904Sopenharmony_ci  return cb;
1478e01aa904Sopenharmony_ci}
1479e01aa904Sopenharmony_ci
1480e01aa904Sopenharmony_cidwfl_sptr
1481e01aa904Sopenharmony_cicreate_new_dwfl_handle(Dwfl_Callbacks& cb)
1482e01aa904Sopenharmony_ci{
1483e01aa904Sopenharmony_ci  dwfl_sptr handle(dwfl_begin(&cb), dwfl_deleter());
1484e01aa904Sopenharmony_ci  return handle;
1485e01aa904Sopenharmony_ci}
1486e01aa904Sopenharmony_ci
1487e01aa904Sopenharmony_ci/// Fetch the SONAME ELF property from an ELF binary file.
1488e01aa904Sopenharmony_ci///
1489e01aa904Sopenharmony_ci/// @param path The path to the elf file to consider.
1490e01aa904Sopenharmony_ci///
1491e01aa904Sopenharmony_ci/// @param soname out parameter. Set to the SONAME property of the
1492e01aa904Sopenharmony_ci/// binary file, if it present in the ELF file.
1493e01aa904Sopenharmony_ci///
1494e01aa904Sopenharmony_ci/// return false if an error occured while looking for the SONAME
1495e01aa904Sopenharmony_ci/// property in the binary, true otherwise.
1496e01aa904Sopenharmony_cibool
1497e01aa904Sopenharmony_ciget_soname_of_elf_file(const string& path, string &soname)
1498e01aa904Sopenharmony_ci{
1499e01aa904Sopenharmony_ci
1500e01aa904Sopenharmony_ci  int fd = open(path.c_str(), O_RDONLY);
1501e01aa904Sopenharmony_ci  if (fd == -1)
1502e01aa904Sopenharmony_ci    return false;
1503e01aa904Sopenharmony_ci
1504e01aa904Sopenharmony_ci  elf_version (EV_CURRENT);
1505e01aa904Sopenharmony_ci  Elf* elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
1506e01aa904Sopenharmony_ci
1507e01aa904Sopenharmony_ci  GElf_Ehdr ehdr_mem;
1508e01aa904Sopenharmony_ci  GElf_Ehdr* ehdr = gelf_getehdr (elf, &ehdr_mem);
1509e01aa904Sopenharmony_ci  if (ehdr == NULL)
1510e01aa904Sopenharmony_ci    return false;
1511e01aa904Sopenharmony_ci
1512e01aa904Sopenharmony_ci  for (int i = 0; i < ehdr->e_phnum; ++i)
1513e01aa904Sopenharmony_ci    {
1514e01aa904Sopenharmony_ci      GElf_Phdr phdr_mem;
1515e01aa904Sopenharmony_ci      GElf_Phdr* phdr = gelf_getphdr (elf, i, &phdr_mem);
1516e01aa904Sopenharmony_ci
1517e01aa904Sopenharmony_ci      if (phdr != NULL && phdr->p_type == PT_DYNAMIC)
1518e01aa904Sopenharmony_ci        {
1519e01aa904Sopenharmony_ci          Elf_Scn* scn = gelf_offscn (elf, phdr->p_offset);
1520e01aa904Sopenharmony_ci          GElf_Shdr shdr_mem;
1521e01aa904Sopenharmony_ci          GElf_Shdr* shdr = gelf_getshdr (scn, &shdr_mem);
1522e01aa904Sopenharmony_ci          size_t entsize = (shdr != NULL && shdr->sh_entsize != 0
1523e01aa904Sopenharmony_ci                            ? shdr->sh_entsize
1524e01aa904Sopenharmony_ci                            : gelf_fsize (elf, ELF_T_DYN, 1, EV_CURRENT));
1525e01aa904Sopenharmony_ci          int maxcnt = (shdr != NULL
1526e01aa904Sopenharmony_ci                        ? shdr->sh_size / entsize : INT_MAX);
1527e01aa904Sopenharmony_ci          ABG_ASSERT (shdr == NULL || (shdr->sh_type == SHT_DYNAMIC
1528e01aa904Sopenharmony_ci				       || shdr->sh_type == SHT_PROGBITS));
1529e01aa904Sopenharmony_ci          Elf_Data* data = elf_getdata (scn, NULL);
1530e01aa904Sopenharmony_ci          if (data == NULL)
1531e01aa904Sopenharmony_ci            break;
1532e01aa904Sopenharmony_ci
1533e01aa904Sopenharmony_ci          for (int cnt = 0; cnt < maxcnt; ++cnt)
1534e01aa904Sopenharmony_ci            {
1535e01aa904Sopenharmony_ci              GElf_Dyn dynmem;
1536e01aa904Sopenharmony_ci              GElf_Dyn* dyn = gelf_getdyn (data, cnt, &dynmem);
1537e01aa904Sopenharmony_ci              if (dyn == NULL)
1538e01aa904Sopenharmony_ci                continue;
1539e01aa904Sopenharmony_ci
1540e01aa904Sopenharmony_ci              if (dyn->d_tag == DT_NULL)
1541e01aa904Sopenharmony_ci                break;
1542e01aa904Sopenharmony_ci
1543e01aa904Sopenharmony_ci              if (dyn->d_tag != DT_SONAME)
1544e01aa904Sopenharmony_ci                continue;
1545e01aa904Sopenharmony_ci
1546e01aa904Sopenharmony_ci              soname = elf_strptr (elf, shdr->sh_link, dyn->d_un.d_val);
1547e01aa904Sopenharmony_ci              break;
1548e01aa904Sopenharmony_ci            }
1549e01aa904Sopenharmony_ci          break;
1550e01aa904Sopenharmony_ci        }
1551e01aa904Sopenharmony_ci    }
1552e01aa904Sopenharmony_ci
1553e01aa904Sopenharmony_ci  elf_end(elf);
1554e01aa904Sopenharmony_ci  close(fd);
1555e01aa904Sopenharmony_ci
1556e01aa904Sopenharmony_ci  return true;
1557e01aa904Sopenharmony_ci}
1558e01aa904Sopenharmony_ci
1559e01aa904Sopenharmony_ci} // end namespace elf_helpers
1560e01aa904Sopenharmony_ci} // end namespace abigail
1561