1e01aa904Sopenharmony_ci// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2e01aa904Sopenharmony_ci// -*- Mode: C++ -*-
3e01aa904Sopenharmony_ci//
4e01aa904Sopenharmony_ci// Copyright (C) 2022 Red Hat, Inc.
5e01aa904Sopenharmony_ci//
6e01aa904Sopenharmony_ci// Author: Dodji Seketeli
7e01aa904Sopenharmony_ci
8e01aa904Sopenharmony_ci/// @file
9e01aa904Sopenharmony_ci///
10e01aa904Sopenharmony_ci/// Elf reader stuff
11e01aa904Sopenharmony_ci
12e01aa904Sopenharmony_ci#include "abg-internal.h"
13e01aa904Sopenharmony_ci
14e01aa904Sopenharmony_ci#include <fcntl.h> /* For open(3) */
15e01aa904Sopenharmony_ci#include <unistd.h>
16e01aa904Sopenharmony_ci#include <iostream>
17e01aa904Sopenharmony_ci#include <cstring>
18e01aa904Sopenharmony_ci#include <libgen.h>
19e01aa904Sopenharmony_ci#include <fcntl.h>
20e01aa904Sopenharmony_ci#include <elfutils/libdwfl.h>
21e01aa904Sopenharmony_ci
22e01aa904Sopenharmony_ci
23e01aa904Sopenharmony_ci#include "abg-symtab-reader.h"
24e01aa904Sopenharmony_ci#include "abg-suppression-priv.h"
25e01aa904Sopenharmony_ci#include "abg-elf-helpers.h"
26e01aa904Sopenharmony_ci
27e01aa904Sopenharmony_ci// <headers defining libabigail's API go under here>
28e01aa904Sopenharmony_ciABG_BEGIN_EXPORT_DECLARATIONS
29e01aa904Sopenharmony_ci#include "abg-elf-reader.h"
30e01aa904Sopenharmony_ci#include "abg-tools-utils.h"
31e01aa904Sopenharmony_ciABG_END_EXPORT_DECLARATIONS
32e01aa904Sopenharmony_ci// </headers defining libabigail's API>
33e01aa904Sopenharmony_cinamespace abigail
34e01aa904Sopenharmony_ci{
35e01aa904Sopenharmony_ci
36e01aa904Sopenharmony_ciusing namespace elf_helpers;
37e01aa904Sopenharmony_ci
38e01aa904Sopenharmony_cinamespace elf
39e01aa904Sopenharmony_ci{
40e01aa904Sopenharmony_ci
41e01aa904Sopenharmony_ci/// Find the file name of the alternate debug info file.
42e01aa904Sopenharmony_ci///
43e01aa904Sopenharmony_ci/// @param elf_module the elf module to consider.
44e01aa904Sopenharmony_ci///
45e01aa904Sopenharmony_ci/// @param out parameter.  Is set to the file name of the alternate
46e01aa904Sopenharmony_ci/// debug info file, iff this function returns true.
47e01aa904Sopenharmony_ci///
48e01aa904Sopenharmony_ci/// @return true iff the location of the alternate debug info file was
49e01aa904Sopenharmony_ci/// found.
50e01aa904Sopenharmony_cistatic bool
51e01aa904Sopenharmony_cifind_alt_dwarf_debug_info_link(Dwfl_Module *elf_module,
52e01aa904Sopenharmony_ci			       string &alt_file_name)
53e01aa904Sopenharmony_ci{
54e01aa904Sopenharmony_ci  GElf_Addr bias = 0;
55e01aa904Sopenharmony_ci  Dwarf *dwarf = dwfl_module_getdwarf(elf_module, &bias);
56e01aa904Sopenharmony_ci  Elf *elf = dwarf_getelf(dwarf);
57e01aa904Sopenharmony_ci  GElf_Ehdr ehmem, *elf_header;
58e01aa904Sopenharmony_ci  elf_header = gelf_getehdr(elf, &ehmem);
59e01aa904Sopenharmony_ci
60e01aa904Sopenharmony_ci  Elf_Scn* section = 0;
61e01aa904Sopenharmony_ci  while ((section = elf_nextscn(elf, section)) != 0)
62e01aa904Sopenharmony_ci    {
63e01aa904Sopenharmony_ci      GElf_Shdr header_mem, *header;
64e01aa904Sopenharmony_ci      header = gelf_getshdr(section, &header_mem);
65e01aa904Sopenharmony_ci      if (header->sh_type != SHT_PROGBITS)
66e01aa904Sopenharmony_ci	continue;
67e01aa904Sopenharmony_ci
68e01aa904Sopenharmony_ci      const char *section_name = elf_strptr(elf,
69e01aa904Sopenharmony_ci					    elf_header->e_shstrndx,
70e01aa904Sopenharmony_ci					    header->sh_name);
71e01aa904Sopenharmony_ci
72e01aa904Sopenharmony_ci      char *alt_name = 0;
73e01aa904Sopenharmony_ci      char *buildid = 0;
74e01aa904Sopenharmony_ci      size_t buildid_len = 0;
75e01aa904Sopenharmony_ci      if (section_name != 0
76e01aa904Sopenharmony_ci	  && strcmp(section_name, ".gnu_debugaltlink") == 0)
77e01aa904Sopenharmony_ci	{
78e01aa904Sopenharmony_ci	  Elf_Data *data = elf_getdata(section, 0);
79e01aa904Sopenharmony_ci	  if (data != 0 && data->d_size != 0)
80e01aa904Sopenharmony_ci	    {
81e01aa904Sopenharmony_ci	      alt_name = (char*) data->d_buf;
82e01aa904Sopenharmony_ci	      char *end_of_alt_name =
83e01aa904Sopenharmony_ci		(char *) memchr(alt_name, '\0', data->d_size);
84e01aa904Sopenharmony_ci	      buildid_len = data->d_size - (end_of_alt_name - alt_name + 1);
85e01aa904Sopenharmony_ci	      if (buildid_len == 0)
86e01aa904Sopenharmony_ci		return false;
87e01aa904Sopenharmony_ci	      buildid = end_of_alt_name + 1;
88e01aa904Sopenharmony_ci	    }
89e01aa904Sopenharmony_ci	}
90e01aa904Sopenharmony_ci      else
91e01aa904Sopenharmony_ci	continue;
92e01aa904Sopenharmony_ci
93e01aa904Sopenharmony_ci      if (buildid == 0 || alt_name == 0)
94e01aa904Sopenharmony_ci	return false;
95e01aa904Sopenharmony_ci
96e01aa904Sopenharmony_ci      alt_file_name = alt_name;
97e01aa904Sopenharmony_ci      return true;
98e01aa904Sopenharmony_ci    }
99e01aa904Sopenharmony_ci
100e01aa904Sopenharmony_ci  return false;
101e01aa904Sopenharmony_ci}
102e01aa904Sopenharmony_ci
103e01aa904Sopenharmony_ci/// Find alternate debuginfo file of a given "link" under a set of
104e01aa904Sopenharmony_ci/// root directories.
105e01aa904Sopenharmony_ci///
106e01aa904Sopenharmony_ci/// The link is a string that is read by the function
107e01aa904Sopenharmony_ci/// find_alt_dwarf_debug_info_link().  That link is a path that is relative
108e01aa904Sopenharmony_ci/// to a given debug info file, e.g, "../../../.dwz/something.debug".
109e01aa904Sopenharmony_ci/// It designates the alternate debug info file associated to a given
110e01aa904Sopenharmony_ci/// debug info file.
111e01aa904Sopenharmony_ci///
112e01aa904Sopenharmony_ci/// This function will thus try to find the .dwz/something.debug file
113e01aa904Sopenharmony_ci/// under some given root directories.
114e01aa904Sopenharmony_ci///
115e01aa904Sopenharmony_ci/// @param root_dirs the set of root directories to look from.
116e01aa904Sopenharmony_ci///
117e01aa904Sopenharmony_ci/// @param alt_file_name a relative path to the alternate debug info
118e01aa904Sopenharmony_ci/// file to look for.
119e01aa904Sopenharmony_ci///
120e01aa904Sopenharmony_ci/// @param alt_file_path the resulting absolute path to the alternate
121e01aa904Sopenharmony_ci/// debuginfo path denoted by @p alt_file_name and found under one of
122e01aa904Sopenharmony_ci/// the directories in @p root_dirs.  This is set iff the function
123e01aa904Sopenharmony_ci/// returns true.
124e01aa904Sopenharmony_ci///
125e01aa904Sopenharmony_ci/// @return true iff the function found the alternate debuginfo file.
126e01aa904Sopenharmony_cistatic bool
127e01aa904Sopenharmony_cifind_alt_dwarf_debug_info_path(const vector<char**> root_dirs,
128e01aa904Sopenharmony_ci			       const string &alt_file_name,
129e01aa904Sopenharmony_ci			       string &alt_file_path)
130e01aa904Sopenharmony_ci{
131e01aa904Sopenharmony_ci  if (alt_file_name.empty())
132e01aa904Sopenharmony_ci    return false;
133e01aa904Sopenharmony_ci
134e01aa904Sopenharmony_ci  string altfile_name = tools_utils::trim_leading_string(alt_file_name, "../");
135e01aa904Sopenharmony_ci
136e01aa904Sopenharmony_ci  for (vector<char**>::const_iterator i = root_dirs.begin();
137e01aa904Sopenharmony_ci       i != root_dirs.end();
138e01aa904Sopenharmony_ci       ++i)
139e01aa904Sopenharmony_ci    if (tools_utils::find_file_under_dir(**i, altfile_name, alt_file_path))
140e01aa904Sopenharmony_ci      return true;
141e01aa904Sopenharmony_ci
142e01aa904Sopenharmony_ci  return false;
143e01aa904Sopenharmony_ci}
144e01aa904Sopenharmony_ci
145e01aa904Sopenharmony_ci/// Return the alternate debug info associated to a given main debug
146e01aa904Sopenharmony_ci/// info file.
147e01aa904Sopenharmony_ci///
148e01aa904Sopenharmony_ci/// @param elf_module the elf module to consider.
149e01aa904Sopenharmony_ci///
150e01aa904Sopenharmony_ci/// @param debug_root_dirs a set of root debuginfo directories under
151e01aa904Sopenharmony_ci/// which too look for the alternate debuginfo file.
152e01aa904Sopenharmony_ci///
153e01aa904Sopenharmony_ci/// @param alt_file_name output parameter.  This is set to the file
154e01aa904Sopenharmony_ci/// path of the alternate debug info file associated to @p elf_module.
155e01aa904Sopenharmony_ci/// This is set iff the function returns a non-null result.
156e01aa904Sopenharmony_ci///
157e01aa904Sopenharmony_ci/// @param alt_fd the file descriptor used to access the alternate
158e01aa904Sopenharmony_ci/// debug info.  If this parameter is set by the function, then the
159e01aa904Sopenharmony_ci/// caller needs to fclose it, otherwise the file descriptor is going
160e01aa904Sopenharmony_ci/// to be leaked.  Note however that on recent versions of elfutils
161e01aa904Sopenharmony_ci/// where libdw.h contains the function dwarf_getalt(), this parameter
162e01aa904Sopenharmony_ci/// is set to 0, so it doesn't need to be fclosed.
163e01aa904Sopenharmony_ci///
164e01aa904Sopenharmony_ci/// Note that the alternate debug info file is a DWARF extension as of
165e01aa904Sopenharmony_ci/// DWARF 4 ans is decribed at
166e01aa904Sopenharmony_ci/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
167e01aa904Sopenharmony_ci///
168e01aa904Sopenharmony_ci/// @return the alternate debuginfo, or null.  If @p alt_fd is
169e01aa904Sopenharmony_ci/// non-zero, then the caller of this function needs to call
170e01aa904Sopenharmony_ci/// dwarf_end() on the returned alternate debuginfo pointer,
171e01aa904Sopenharmony_ci/// otherwise, it's going to be leaked.
172e01aa904Sopenharmony_cistatic Dwarf*
173e01aa904Sopenharmony_cifind_alt_dwarf_debug_info(Dwfl_Module *elf_module,
174e01aa904Sopenharmony_ci			  const vector<char**> debug_root_dirs,
175e01aa904Sopenharmony_ci			  string& alt_file_name,
176e01aa904Sopenharmony_ci			  int& alt_fd)
177e01aa904Sopenharmony_ci{
178e01aa904Sopenharmony_ci  if (elf_module == 0)
179e01aa904Sopenharmony_ci    return 0;
180e01aa904Sopenharmony_ci
181e01aa904Sopenharmony_ci  Dwarf* result = 0;
182e01aa904Sopenharmony_ci  find_alt_dwarf_debug_info_link(elf_module, alt_file_name);
183e01aa904Sopenharmony_ci
184e01aa904Sopenharmony_ci#ifdef LIBDW_HAS_DWARF_GETALT
185e01aa904Sopenharmony_ci  // We are on recent versions of elfutils where the function
186e01aa904Sopenharmony_ci  // dwarf_getalt exists, so let's use it.
187e01aa904Sopenharmony_ci  Dwarf_Addr bias = 0;
188e01aa904Sopenharmony_ci  Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
189e01aa904Sopenharmony_ci  result = dwarf_getalt(dwarf);
190e01aa904Sopenharmony_ci  alt_fd = 0;
191e01aa904Sopenharmony_ci#else
192e01aa904Sopenharmony_ci  // We are on an old version of elfutils where the function
193e01aa904Sopenharmony_ci  // dwarf_getalt doesn't exist yet, so let's open code its
194e01aa904Sopenharmony_ci  // functionality
195e01aa904Sopenharmony_ci  char *alt_name = 0;
196e01aa904Sopenharmony_ci  const char *file_name = 0;
197e01aa904Sopenharmony_ci  void **user_data = 0;
198e01aa904Sopenharmony_ci  Dwarf_Addr low_addr = 0;
199e01aa904Sopenharmony_ci  char *alt_file = 0;
200e01aa904Sopenharmony_ci
201e01aa904Sopenharmony_ci  file_name = dwfl_module_info(elf_module, &user_data,
202e01aa904Sopenharmony_ci			       &low_addr, 0, 0, 0, 0, 0);
203e01aa904Sopenharmony_ci
204e01aa904Sopenharmony_ci  alt_fd = dwfl_standard_find_debuginfo(elf_module, user_data,
205e01aa904Sopenharmony_ci					file_name, low_addr,
206e01aa904Sopenharmony_ci					alt_name, file_name,
207e01aa904Sopenharmony_ci					0, &alt_file);
208e01aa904Sopenharmony_ci
209e01aa904Sopenharmony_ci  result = dwarf_begin(alt_fd, DWARF_C_READ);
210e01aa904Sopenharmony_ci#endif
211e01aa904Sopenharmony_ci
212e01aa904Sopenharmony_ci  if (result == 0)
213e01aa904Sopenharmony_ci    {
214e01aa904Sopenharmony_ci      // So we didn't find the alternate debuginfo file from the
215e01aa904Sopenharmony_ci      // information that is in the debuginfo file associated to
216e01aa904Sopenharmony_ci      // elf_module.  Maybe the alternate debuginfo file is located
217e01aa904Sopenharmony_ci      // under one of the directories in debug_root_dirs.  So let's
218e01aa904Sopenharmony_ci      // look in there.
219e01aa904Sopenharmony_ci      string alt_file_path;
220e01aa904Sopenharmony_ci      if (!find_alt_dwarf_debug_info_path(debug_root_dirs,
221e01aa904Sopenharmony_ci					  alt_file_name,
222e01aa904Sopenharmony_ci					  alt_file_path))
223e01aa904Sopenharmony_ci	return result;
224e01aa904Sopenharmony_ci
225e01aa904Sopenharmony_ci      // If we reach this point it means we have found the path to the
226e01aa904Sopenharmony_ci      // alternate debuginfo file and it's in alt_file_path.  So let's
227e01aa904Sopenharmony_ci      // open it and read it.
228e01aa904Sopenharmony_ci      int fd = open(alt_file_path.c_str(), O_RDONLY);
229e01aa904Sopenharmony_ci      if (fd == -1)
230e01aa904Sopenharmony_ci	return result;
231e01aa904Sopenharmony_ci      result = dwarf_begin(fd, DWARF_C_READ);
232e01aa904Sopenharmony_ci
233e01aa904Sopenharmony_ci#ifdef LIBDW_HAS_DWARF_GETALT
234e01aa904Sopenharmony_ci      Dwarf_Addr bias = 0;
235e01aa904Sopenharmony_ci      Dwarf* dwarf = dwfl_module_getdwarf(elf_module, &bias);
236e01aa904Sopenharmony_ci      dwarf_setalt(dwarf, result);
237e01aa904Sopenharmony_ci#endif
238e01aa904Sopenharmony_ci    }
239e01aa904Sopenharmony_ci
240e01aa904Sopenharmony_ci  return result;
241e01aa904Sopenharmony_ci}
242e01aa904Sopenharmony_ci
243e01aa904Sopenharmony_ci/// Private data of the @ref elf::reader type.
244e01aa904Sopenharmony_cistruct reader::priv
245e01aa904Sopenharmony_ci{
246e01aa904Sopenharmony_ci  reader&				rdr;
247e01aa904Sopenharmony_ci  Elf*					elf_handle		= nullptr;
248e01aa904Sopenharmony_ci  Elf_Scn*				symtab_section		= nullptr;
249e01aa904Sopenharmony_ci  string				elf_architecture;
250e01aa904Sopenharmony_ci  vector<string>			dt_needed;
251e01aa904Sopenharmony_ci  // An abstraction of the symbol table.  This is loaded lazily, on
252e01aa904Sopenharmony_ci  // demand.
253e01aa904Sopenharmony_ci  mutable symtab_reader::symtab_sptr	symt;
254e01aa904Sopenharmony_ci  // Where split debug info is to be searched for on disk.
255e01aa904Sopenharmony_ci  vector<char**>			debug_info_root_paths;
256e01aa904Sopenharmony_ci  // Some very useful callback functions that elfutils needs to
257e01aa904Sopenharmony_ci  // perform various tasks.
258e01aa904Sopenharmony_ci  Dwfl_Callbacks			offline_callbacks;
259e01aa904Sopenharmony_ci  // A pointer to the DWARF Front End Library handle of elfutils.
260e01aa904Sopenharmony_ci  // This is useful to perform all kind of things at a higher level.
261e01aa904Sopenharmony_ci  dwfl_sptr				dwfl_handle;
262e01aa904Sopenharmony_ci  // The address range of the offline elf file we are looking at.
263e01aa904Sopenharmony_ci  Dwfl_Module*				elf_module		= nullptr;
264e01aa904Sopenharmony_ci  // A pointer to the DWARF debug info, if found by locate_dwarf_debug_info.
265e01aa904Sopenharmony_ci  Dwarf*				dwarf_handle		= nullptr;
266e01aa904Sopenharmony_ci  // A pointer to the ALT DWARF debug info, which is the debug info
267e01aa904Sopenharmony_ci  // that is constructed by the DWZ tool.  It's made of all the type
268e01aa904Sopenharmony_ci  // information that was redundant in the DWARF.  DWZ put it there
269e01aa904Sopenharmony_ci  // and make the DWARF reference it in here.
270e01aa904Sopenharmony_ci  Dwarf*				alt_dwarf_handle	= nullptr;
271e01aa904Sopenharmony_ci  string				alt_dwarf_path;
272e01aa904Sopenharmony_ci  int					alt_dwarf_fd		= 0;
273e01aa904Sopenharmony_ci  Elf_Scn*				ctf_section		= nullptr;
274e01aa904Sopenharmony_ci  Elf_Scn*				alt_ctf_section	= nullptr;
275e01aa904Sopenharmony_ci
276e01aa904Sopenharmony_ci  priv(reader& reeder, const std::string& elf_path,
277e01aa904Sopenharmony_ci       const vector<char**>& debug_info_roots)
278e01aa904Sopenharmony_ci    : rdr(reeder)
279e01aa904Sopenharmony_ci  {
280e01aa904Sopenharmony_ci    rdr.corpus_path(elf_path);
281e01aa904Sopenharmony_ci    initialize(debug_info_roots);
282e01aa904Sopenharmony_ci  }
283e01aa904Sopenharmony_ci
284e01aa904Sopenharmony_ci  /// Reset the private data of @elf elf::reader.
285e01aa904Sopenharmony_ci  ///
286e01aa904Sopenharmony_ci  /// @param debug_info_roots the vector of new directories where to
287e01aa904Sopenharmony_ci  /// look for split debug info file.
288e01aa904Sopenharmony_ci  void
289e01aa904Sopenharmony_ci  initialize(const vector<char**>& debug_info_roots)
290e01aa904Sopenharmony_ci  {
291e01aa904Sopenharmony_ci    debug_info_root_paths = debug_info_roots;
292e01aa904Sopenharmony_ci    symt.reset();
293e01aa904Sopenharmony_ci    dwfl_handle.reset();
294e01aa904Sopenharmony_ci    elf_module = nullptr;
295e01aa904Sopenharmony_ci    elf_handle = nullptr;
296e01aa904Sopenharmony_ci  }
297e01aa904Sopenharmony_ci
298e01aa904Sopenharmony_ci  /// Setup the necessary plumbing to open the ELF file and find all
299e01aa904Sopenharmony_ci  /// the associated split debug info files.
300e01aa904Sopenharmony_ci  ///
301e01aa904Sopenharmony_ci  /// This function also setup the various handles on the opened ELF
302e01aa904Sopenharmony_ci  /// file and whatnot.
303e01aa904Sopenharmony_ci  void
304e01aa904Sopenharmony_ci  crack_open_elf_file()
305e01aa904Sopenharmony_ci  {
306e01aa904Sopenharmony_ci    // Initialize the callback functions used by elfutils.
307e01aa904Sopenharmony_ci    elf_helpers::initialize_dwfl_callbacks(offline_callbacks,
308e01aa904Sopenharmony_ci					   debug_info_root_paths.empty()
309e01aa904Sopenharmony_ci					   ? nullptr
310e01aa904Sopenharmony_ci					   : debug_info_root_paths.front());
311e01aa904Sopenharmony_ci
312e01aa904Sopenharmony_ci    // Create a handle to the DWARF Front End Library that we'll need.
313e01aa904Sopenharmony_ci    dwfl_handle = elf_helpers::create_new_dwfl_handle(offline_callbacks);
314e01aa904Sopenharmony_ci
315e01aa904Sopenharmony_ci    const string& elf_path = rdr.corpus_path();
316e01aa904Sopenharmony_ci    // Get the set of addresses that make up the ELF file we are
317e01aa904Sopenharmony_ci    // looking at.
318e01aa904Sopenharmony_ci    elf_module =
319e01aa904Sopenharmony_ci      dwfl_report_offline(dwfl_handle.get(),
320e01aa904Sopenharmony_ci			  basename(const_cast<char*>(elf_path.c_str())),
321e01aa904Sopenharmony_ci			  elf_path.c_str(), -1);
322e01aa904Sopenharmony_ci    dwfl_report_end(dwfl_handle.get(), 0, 0);
323e01aa904Sopenharmony_ci    ABG_ASSERT(elf_module);
324e01aa904Sopenharmony_ci
325e01aa904Sopenharmony_ci    // Finally, get and handle at the representation of the ELF file
326e01aa904Sopenharmony_ci    // we've just cracked open.
327e01aa904Sopenharmony_ci    GElf_Addr bias = 0;
328e01aa904Sopenharmony_ci    elf_handle = dwfl_module_getelf(elf_module, &bias);
329e01aa904Sopenharmony_ci    ABG_ASSERT(elf_handle);
330e01aa904Sopenharmony_ci  }
331e01aa904Sopenharmony_ci
332e01aa904Sopenharmony_ci  /// Find the alternate debuginfo file associated to a given elf file.
333e01aa904Sopenharmony_ci  ///
334e01aa904Sopenharmony_ci  /// @param elf_module represents the elf file to consider.
335e01aa904Sopenharmony_ci  ///
336e01aa904Sopenharmony_ci  /// @param alt_file_name the resulting path to the alternate
337e01aa904Sopenharmony_ci  /// debuginfo file found.  This is set iff the function returns a
338e01aa904Sopenharmony_ci  /// non-nil value.
339e01aa904Sopenharmony_ci  Dwarf*
340e01aa904Sopenharmony_ci  find_alt_dwarf_debug_info(Dwfl_Module*	elf_module,
341e01aa904Sopenharmony_ci			    string&		alt_file_name,
342e01aa904Sopenharmony_ci			    int&		alt_fd)
343e01aa904Sopenharmony_ci  {
344e01aa904Sopenharmony_ci    Dwarf *result = 0;
345e01aa904Sopenharmony_ci    result = elf::find_alt_dwarf_debug_info(elf_module,
346e01aa904Sopenharmony_ci					    debug_info_root_paths,
347e01aa904Sopenharmony_ci					    alt_file_name, alt_fd);
348e01aa904Sopenharmony_ci    return result;
349e01aa904Sopenharmony_ci  }
350e01aa904Sopenharmony_ci
351e01aa904Sopenharmony_ci  /// Locate the DWARF debug info in the ELF file.
352e01aa904Sopenharmony_ci  ///
353e01aa904Sopenharmony_ci  /// This also knows how to locate split debug info.
354e01aa904Sopenharmony_ci  void
355e01aa904Sopenharmony_ci  locate_dwarf_debug_info()
356e01aa904Sopenharmony_ci  {
357e01aa904Sopenharmony_ci    ABG_ASSERT(dwfl_handle);
358e01aa904Sopenharmony_ci
359e01aa904Sopenharmony_ci    if (dwarf_handle)
360e01aa904Sopenharmony_ci      return;
361e01aa904Sopenharmony_ci
362e01aa904Sopenharmony_ci    // First let's see if the ELF file that was cracked open does have
363e01aa904Sopenharmony_ci    // some DWARF debug info embedded.
364e01aa904Sopenharmony_ci    Dwarf_Addr bias = 0;
365e01aa904Sopenharmony_ci    dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
366e01aa904Sopenharmony_ci
367e01aa904Sopenharmony_ci    // If no debug info was found in the binary itself, then look for
368e01aa904Sopenharmony_ci    // split debuginfo files under multiple possible debuginfo roots.
369e01aa904Sopenharmony_ci    for (vector<char**>::const_iterator i = debug_info_root_paths.begin();
370e01aa904Sopenharmony_ci	 dwarf_handle == 0 && i != debug_info_root_paths.end();
371e01aa904Sopenharmony_ci	 ++i)
372e01aa904Sopenharmony_ci      {
373e01aa904Sopenharmony_ci	offline_callbacks.debuginfo_path = *i;
374e01aa904Sopenharmony_ci	dwarf_handle = dwfl_module_getdwarf(elf_module, &bias);
375e01aa904Sopenharmony_ci      }
376e01aa904Sopenharmony_ci
377e01aa904Sopenharmony_ci    alt_dwarf_handle = find_alt_dwarf_debug_info(elf_module,
378e01aa904Sopenharmony_ci						 alt_dwarf_path,
379e01aa904Sopenharmony_ci						 alt_dwarf_fd);
380e01aa904Sopenharmony_ci  }
381e01aa904Sopenharmony_ci
382e01aa904Sopenharmony_ci  /// Locate the CTF "alternate" debug information associated with the
383e01aa904Sopenharmony_ci  /// current ELF file ( and split out somewhere else).
384e01aa904Sopenharmony_ci  ///
385e01aa904Sopenharmony_ci  /// This is a sub-routine of @ref locate_ctf_debug_info().
386e01aa904Sopenharmony_ci  void
387e01aa904Sopenharmony_ci  locate_alt_ctf_debug_info()
388e01aa904Sopenharmony_ci  {
389e01aa904Sopenharmony_ci    Elf_Scn *section =
390e01aa904Sopenharmony_ci      elf_helpers::find_section(elf_handle,
391e01aa904Sopenharmony_ci				".gnu_debuglink",
392e01aa904Sopenharmony_ci				SHT_PROGBITS);
393e01aa904Sopenharmony_ci
394e01aa904Sopenharmony_ci    std::string name;
395e01aa904Sopenharmony_ci    Elf_Data *data;
396e01aa904Sopenharmony_ci    if (section
397e01aa904Sopenharmony_ci	&& (data = elf_getdata(section, nullptr))
398e01aa904Sopenharmony_ci	&& data->d_size != 0)
399e01aa904Sopenharmony_ci      name = (char *) data->d_buf;
400e01aa904Sopenharmony_ci
401e01aa904Sopenharmony_ci    if (!name.empty())
402e01aa904Sopenharmony_ci      for (const auto& path : rdr.debug_info_root_paths())
403e01aa904Sopenharmony_ci	{
404e01aa904Sopenharmony_ci	  std::string file_path;
405e01aa904Sopenharmony_ci	  if (!tools_utils::find_file_under_dir(*path, name, file_path))
406e01aa904Sopenharmony_ci	    continue;
407e01aa904Sopenharmony_ci
408e01aa904Sopenharmony_ci	  int fd;
409e01aa904Sopenharmony_ci	  if ((fd = open(file_path.c_str(), O_RDONLY)) == -1)
410e01aa904Sopenharmony_ci	    continue;
411e01aa904Sopenharmony_ci
412e01aa904Sopenharmony_ci	  Elf *hdl;
413e01aa904Sopenharmony_ci	  if ((hdl = elf_begin(fd, ELF_C_READ, nullptr)) == nullptr)
414e01aa904Sopenharmony_ci	    {
415e01aa904Sopenharmony_ci	      close(fd);
416e01aa904Sopenharmony_ci	      continue;
417e01aa904Sopenharmony_ci	    }
418e01aa904Sopenharmony_ci
419e01aa904Sopenharmony_ci	  // unlikely .ctf was designed to be present in stripped file
420e01aa904Sopenharmony_ci	  alt_ctf_section =
421e01aa904Sopenharmony_ci	    elf_helpers::find_section(hdl, ".ctf", SHT_PROGBITS);
422e01aa904Sopenharmony_ci          break;
423e01aa904Sopenharmony_ci
424e01aa904Sopenharmony_ci	  elf_end(hdl);
425e01aa904Sopenharmony_ci	  close(fd);
426e01aa904Sopenharmony_ci	}
427e01aa904Sopenharmony_ci  }
428e01aa904Sopenharmony_ci
429e01aa904Sopenharmony_ci  /// Locate the CTF debug information associated with the current ELF
430e01aa904Sopenharmony_ci  /// file.  It also locates the CTF debug information that is split
431e01aa904Sopenharmony_ci  /// out in a separate file.
432e01aa904Sopenharmony_ci  void
433e01aa904Sopenharmony_ci  locate_ctf_debug_info()
434e01aa904Sopenharmony_ci  {
435e01aa904Sopenharmony_ci    ABG_ASSERT(elf_handle);
436e01aa904Sopenharmony_ci
437e01aa904Sopenharmony_ci    ctf_section = elf_helpers::find_section_by_name(elf_handle, ".ctf");
438e01aa904Sopenharmony_ci    if (ctf_section == nullptr)
439e01aa904Sopenharmony_ci      {
440e01aa904Sopenharmony_ci	locate_alt_ctf_debug_info();
441e01aa904Sopenharmony_ci	ctf_section = alt_ctf_section;
442e01aa904Sopenharmony_ci      }
443e01aa904Sopenharmony_ci  }
444e01aa904Sopenharmony_ci}; //end reader::priv
445e01aa904Sopenharmony_ci
446e01aa904Sopenharmony_ci/// The constructor of the @ref elf::reader type.
447e01aa904Sopenharmony_ci///
448e01aa904Sopenharmony_ci/// @param elf_path the path to the ELF file to read from.
449e01aa904Sopenharmony_ci///
450e01aa904Sopenharmony_ci/// @param debug_info_root a vector of directory paths to look into
451e01aa904Sopenharmony_ci/// for split debug information files.
452e01aa904Sopenharmony_ci///
453e01aa904Sopenharmony_ci/// @param env the environment which the reader operates in.
454e01aa904Sopenharmony_cireader::reader(const string&		elf_path,
455e01aa904Sopenharmony_ci	       const vector<char**>&	debug_info_roots,
456e01aa904Sopenharmony_ci	       ir::environment&	env)
457e01aa904Sopenharmony_ci  : fe_iface(elf_path, env),
458e01aa904Sopenharmony_ci    priv_(new priv(*this, elf_path, debug_info_roots))
459e01aa904Sopenharmony_ci{
460e01aa904Sopenharmony_ci  priv_->crack_open_elf_file();
461e01aa904Sopenharmony_ci  priv_->locate_dwarf_debug_info();
462e01aa904Sopenharmony_ci  priv_->locate_ctf_debug_info();
463e01aa904Sopenharmony_ci}
464e01aa904Sopenharmony_ci
465e01aa904Sopenharmony_ci/// The destructor of the @ref elf::reader type.
466e01aa904Sopenharmony_cireader::~reader()
467e01aa904Sopenharmony_ci{delete priv_;}
468e01aa904Sopenharmony_ci
469e01aa904Sopenharmony_ci/// Resets (erase) the resources used by the current @ref
470e01aa904Sopenharmony_ci/// elf::reader type.
471e01aa904Sopenharmony_ci///
472e01aa904Sopenharmony_ci/// This lets the reader in a state where it's ready to read from
473e01aa904Sopenharmony_ci/// another ELF file.
474e01aa904Sopenharmony_ci///
475e01aa904Sopenharmony_ci/// @param elf_path the new ELF path to read from.
476e01aa904Sopenharmony_ci///
477e01aa904Sopenharmony_ci/// @param debug_info_roots a vector of directory paths to look into
478e01aa904Sopenharmony_ci/// for split debug information files.
479e01aa904Sopenharmony_civoid
480e01aa904Sopenharmony_cireader::reset(const std::string&	elf_path,
481e01aa904Sopenharmony_ci	      const vector<char**>&	debug_info_roots)
482e01aa904Sopenharmony_ci{
483e01aa904Sopenharmony_ci  fe_iface::options_type opts = options();
484e01aa904Sopenharmony_ci  fe_iface::reset(elf_path, opts.env);
485e01aa904Sopenharmony_ci  corpus_path(elf_path);
486e01aa904Sopenharmony_ci  priv_->initialize(debug_info_roots);
487e01aa904Sopenharmony_ci  priv_->crack_open_elf_file();
488e01aa904Sopenharmony_ci  priv_->locate_dwarf_debug_info();
489e01aa904Sopenharmony_ci  priv_->locate_ctf_debug_info();
490e01aa904Sopenharmony_ci}
491e01aa904Sopenharmony_ci
492e01aa904Sopenharmony_ci/// Getter of the vector of directory paths to look into for split
493e01aa904Sopenharmony_ci/// debug information files.
494e01aa904Sopenharmony_ci///
495e01aa904Sopenharmony_ci/// @return the vector of directory paths to look into for split
496e01aa904Sopenharmony_ci/// debug information files.
497e01aa904Sopenharmony_ciconst vector<char**>&
498e01aa904Sopenharmony_cireader::debug_info_root_paths() const
499e01aa904Sopenharmony_ci{return priv_->debug_info_root_paths;}
500e01aa904Sopenharmony_ci
501e01aa904Sopenharmony_ci/// Getter of the functions used by the DWARF Front End library of
502e01aa904Sopenharmony_ci/// elfutils to locate DWARF debug information.
503e01aa904Sopenharmony_ci///
504e01aa904Sopenharmony_ci/// @return the functions used by the DWARF Front End library of
505e01aa904Sopenharmony_ciconst Dwfl_Callbacks&
506e01aa904Sopenharmony_cireader::dwfl_offline_callbacks() const
507e01aa904Sopenharmony_ci{return priv_->offline_callbacks;}
508e01aa904Sopenharmony_ci
509e01aa904Sopenharmony_ci/// Getter of the functions used by the DWARF Front End library of
510e01aa904Sopenharmony_ci/// elfutils to locate DWARF debug information.
511e01aa904Sopenharmony_ci///
512e01aa904Sopenharmony_ci/// @return the functions used by the DWARF Front End library of
513e01aa904Sopenharmony_ciDwfl_Callbacks&
514e01aa904Sopenharmony_cireader::dwfl_offline_callbacks()
515e01aa904Sopenharmony_ci{return priv_->offline_callbacks;}
516e01aa904Sopenharmony_ci
517e01aa904Sopenharmony_ci/// Getter of the handle used to access ELF information from the
518e01aa904Sopenharmony_ci/// current ELF file.
519e01aa904Sopenharmony_ci///
520e01aa904Sopenharmony_ci/// @return the handle used to access ELF information from the current
521e01aa904Sopenharmony_ci/// ELF file.
522e01aa904Sopenharmony_ciElf*
523e01aa904Sopenharmony_cireader::elf_handle() const
524e01aa904Sopenharmony_ci{return priv_->elf_handle;}
525e01aa904Sopenharmony_ci
526e01aa904Sopenharmony_ci/// Getter of the handle used to access DWARF information from the
527e01aa904Sopenharmony_ci/// current ELF file.
528e01aa904Sopenharmony_ci///
529e01aa904Sopenharmony_ci/// @return the handle used to access DWARF information from the
530e01aa904Sopenharmony_ci/// current ELF file.
531e01aa904Sopenharmony_ciconst Dwarf*
532e01aa904Sopenharmony_cireader::dwarf_debug_info() const
533e01aa904Sopenharmony_ci{return priv_->dwarf_handle;}
534e01aa904Sopenharmony_ci
535e01aa904Sopenharmony_ci/// Test if the binary has DWARF debug info.
536e01aa904Sopenharmony_ci///
537e01aa904Sopenharmony_ci/// @return true iff the binary has DWARF debug info.
538e01aa904Sopenharmony_cibool
539e01aa904Sopenharmony_cireader::has_dwarf_debug_info() const
540e01aa904Sopenharmony_ci{return ((priv_->dwarf_handle != nullptr)
541e01aa904Sopenharmony_ci	  || (priv_->alt_dwarf_handle != nullptr));}
542e01aa904Sopenharmony_ci
543e01aa904Sopenharmony_ci/// Test if the binary has CTF debug info.
544e01aa904Sopenharmony_ci///
545e01aa904Sopenharmony_ci/// @return true iff the binary has CTF debug info.
546e01aa904Sopenharmony_cibool
547e01aa904Sopenharmony_cireader::has_ctf_debug_info() const
548e01aa904Sopenharmony_ci{return (priv_->ctf_section != nullptr);}
549e01aa904Sopenharmony_ci
550e01aa904Sopenharmony_ci/// Getter of the handle use to access DWARF information from the
551e01aa904Sopenharmony_ci/// alternate split DWARF information.
552e01aa904Sopenharmony_ci///
553e01aa904Sopenharmony_ci/// In other words, this accesses the factorized DWARF information
554e01aa904Sopenharmony_ci/// that has been constructed by the DWZ tool to de-duplicate DWARF
555e01aa904Sopenharmony_ci/// information on disk.
556e01aa904Sopenharmony_ci///
557e01aa904Sopenharmony_ci/// @return the handle use to access DWARF information from the
558e01aa904Sopenharmony_ci/// alternate split DWARF information.
559e01aa904Sopenharmony_ciconst Dwarf*
560e01aa904Sopenharmony_cireader::alternate_dwarf_debug_info() const
561e01aa904Sopenharmony_ci{return priv_->alt_dwarf_handle;}
562e01aa904Sopenharmony_ci
563e01aa904Sopenharmony_ci
564e01aa904Sopenharmony_ci/// Getter of the path to the alternate split DWARF information file,
565e01aa904Sopenharmony_ci/// on disk.  In othe words, this returns the path to the factorized
566e01aa904Sopenharmony_ci/// DWARF information used by the current ELF file, created by the
567e01aa904Sopenharmony_ci/// 'DWZ' tool.
568e01aa904Sopenharmony_ci///
569e01aa904Sopenharmony_ci/// @return the path to the alternate split DWARF information file,
570e01aa904Sopenharmony_ci/// on disk.
571e01aa904Sopenharmony_ciconst string&
572e01aa904Sopenharmony_cireader::alternate_dwarf_debug_info_path() const
573e01aa904Sopenharmony_ci{return priv_->alt_dwarf_path;}
574e01aa904Sopenharmony_ci
575e01aa904Sopenharmony_ci/// Check if the underlying elf file refers to an alternate debug info
576e01aa904Sopenharmony_ci/// file associated to it.
577e01aa904Sopenharmony_ci///
578e01aa904Sopenharmony_ci/// Note that "alternate debug info sections" is a GNU extension as
579e01aa904Sopenharmony_ci/// of DWARF4 and is described at
580e01aa904Sopenharmony_ci/// http://www.dwarfstd.org/ShowIssue.php?issue=120604.1.
581e01aa904Sopenharmony_ci///
582e01aa904Sopenharmony_ci/// @param alt_di the path to the alternate debug info file.  This is
583e01aa904Sopenharmony_ci/// set iff the function returns true.
584e01aa904Sopenharmony_ci///
585e01aa904Sopenharmony_ci/// @return true if the ELF file refers to an alternate debug info
586e01aa904Sopenharmony_ci/// file.
587e01aa904Sopenharmony_cibool
588e01aa904Sopenharmony_cireader::refers_to_alt_debug_info(string& alt_di_path) const
589e01aa904Sopenharmony_ci{
590e01aa904Sopenharmony_ci  if (!alternate_dwarf_debug_info_path().empty())
591e01aa904Sopenharmony_ci    {
592e01aa904Sopenharmony_ci      alt_di_path = alternate_dwarf_debug_info_path();
593e01aa904Sopenharmony_ci      return true;
594e01aa904Sopenharmony_ci    }
595e01aa904Sopenharmony_ci  return false;
596e01aa904Sopenharmony_ci}
597e01aa904Sopenharmony_ci
598e01aa904Sopenharmony_ci/// Find and return a pointer to the ELF symbol table
599e01aa904Sopenharmony_ci/// section.
600e01aa904Sopenharmony_ci///
601e01aa904Sopenharmony_ci/// @return a pointer to the ELF symbol table section.
602e01aa904Sopenharmony_ciconst Elf_Scn*
603e01aa904Sopenharmony_cireader::find_symbol_table_section() const
604e01aa904Sopenharmony_ci{
605e01aa904Sopenharmony_ci  if (!priv_->symtab_section)
606e01aa904Sopenharmony_ci      priv_->symtab_section =
607e01aa904Sopenharmony_ci	elf_helpers::find_symbol_table_section(elf_handle());
608e01aa904Sopenharmony_ci    return priv_->symtab_section;
609e01aa904Sopenharmony_ci}
610e01aa904Sopenharmony_ci
611e01aa904Sopenharmony_ci/// Clear the pointer to the ELF symbol table section.
612e01aa904Sopenharmony_civoid
613e01aa904Sopenharmony_cireader::reset_symbol_table_section()
614e01aa904Sopenharmony_ci{priv_->symtab_section = nullptr;}
615e01aa904Sopenharmony_ci
616e01aa904Sopenharmony_ci/// Find and return a pointer to the the CTF section.
617e01aa904Sopenharmony_ci///
618e01aa904Sopenharmony_ci/// @return a pointer to the the CTF section.
619e01aa904Sopenharmony_ciconst Elf_Scn*
620e01aa904Sopenharmony_cireader::find_ctf_section() const
621e01aa904Sopenharmony_ci{
622e01aa904Sopenharmony_ci  if (priv_->ctf_section == nullptr)
623e01aa904Sopenharmony_ci    priv_->locate_ctf_debug_info();
624e01aa904Sopenharmony_ci
625e01aa904Sopenharmony_ci  if (priv_->ctf_section)
626e01aa904Sopenharmony_ci    return priv_->ctf_section;
627e01aa904Sopenharmony_ci
628e01aa904Sopenharmony_ci  return priv_->alt_ctf_section;
629e01aa904Sopenharmony_ci}
630e01aa904Sopenharmony_ci
631e01aa904Sopenharmony_ci/// Find and return a pointer to the alternate CTF section of the
632e01aa904Sopenharmony_ci/// current ELF file.
633e01aa904Sopenharmony_ci///
634e01aa904Sopenharmony_ci/// @return a pointer to the alternate CTF section of the current ELF
635e01aa904Sopenharmony_ci/// file.
636e01aa904Sopenharmony_ciconst Elf_Scn*
637e01aa904Sopenharmony_cireader::find_alternate_ctf_section() const
638e01aa904Sopenharmony_ci{
639e01aa904Sopenharmony_ci  if (priv_->alt_ctf_section == nullptr)
640e01aa904Sopenharmony_ci    priv_->locate_alt_ctf_debug_info();
641e01aa904Sopenharmony_ci
642e01aa904Sopenharmony_ci  return priv_->alt_ctf_section;
643e01aa904Sopenharmony_ci}
644e01aa904Sopenharmony_ci
645e01aa904Sopenharmony_ci/// Get the value of the DT_NEEDED property of the current ELF file.
646e01aa904Sopenharmony_ci///
647e01aa904Sopenharmony_ci/// @return the value of the DT_NEEDED property.
648e01aa904Sopenharmony_ciconst vector<string>&
649e01aa904Sopenharmony_cireader::dt_needed()const
650e01aa904Sopenharmony_ci{return priv_->dt_needed;}
651e01aa904Sopenharmony_ci
652e01aa904Sopenharmony_ci
653e01aa904Sopenharmony_ci/// Get the value of the 'ARCHITECTURE' property of the current ELF file.
654e01aa904Sopenharmony_ci///
655e01aa904Sopenharmony_ci/// @return the value of the 'ARCHITECTURE' property of the current
656e01aa904Sopenharmony_ci/// ELF file.
657e01aa904Sopenharmony_ciconst string&
658e01aa904Sopenharmony_cireader::elf_architecture() const
659e01aa904Sopenharmony_ci{return priv_->elf_architecture;}
660e01aa904Sopenharmony_ci
661e01aa904Sopenharmony_ci/// Getter of an abstract representation of the symbol table of the
662e01aa904Sopenharmony_ci/// underlying ELF file.
663e01aa904Sopenharmony_ci///
664e01aa904Sopenharmony_ci/// Note that the symbol table is loaded lazily, upon the first
665e01aa904Sopenharmony_ci/// invocation of this member function.
666e01aa904Sopenharmony_ci///
667e01aa904Sopenharmony_ci/// @returnt the symbol table.
668e01aa904Sopenharmony_cisymtab_reader::symtab_sptr&
669e01aa904Sopenharmony_cireader::symtab() const
670e01aa904Sopenharmony_ci{
671e01aa904Sopenharmony_ci  ABG_ASSERT(elf_handle());
672e01aa904Sopenharmony_ci
673e01aa904Sopenharmony_ci  if (!priv_->symt)
674e01aa904Sopenharmony_ci    priv_->symt = symtab_reader::symtab::load
675e01aa904Sopenharmony_ci      (elf_handle(), options().env,
676e01aa904Sopenharmony_ci       [&](const elf_symbol_sptr& symbol)
677e01aa904Sopenharmony_ci       {return suppr::is_elf_symbol_suppressed(*this, symbol);});
678e01aa904Sopenharmony_ci
679e01aa904Sopenharmony_ci  if (!priv_->symt)
680e01aa904Sopenharmony_ci    std::cerr << "Symbol table of '" << corpus_path()
681e01aa904Sopenharmony_ci	      << "' could not be loaded\n";
682e01aa904Sopenharmony_ci  return priv_->symt;
683e01aa904Sopenharmony_ci}
684e01aa904Sopenharmony_ci
685e01aa904Sopenharmony_ci/// Test if a given function symbol has been exported.
686e01aa904Sopenharmony_ci///
687e01aa904Sopenharmony_ci/// @param symbol_address the address of the symbol we are looking
688e01aa904Sopenharmony_ci/// for.  Note that this address must be a relative offset from the
689e01aa904Sopenharmony_ci/// beginning of the .text section, just like the kind of addresses
690e01aa904Sopenharmony_ci/// that are present in the .symtab section.
691e01aa904Sopenharmony_ci///
692e01aa904Sopenharmony_ci/// @return the elf symbol if found, or nil otherwise.
693e01aa904Sopenharmony_cielf_symbol_sptr
694e01aa904Sopenharmony_cireader::function_symbol_is_exported(GElf_Addr symbol_address) const
695e01aa904Sopenharmony_ci{
696e01aa904Sopenharmony_ci  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
697e01aa904Sopenharmony_ci  if (!symbol)
698e01aa904Sopenharmony_ci    return symbol;
699e01aa904Sopenharmony_ci
700e01aa904Sopenharmony_ci  if (!symbol->is_function() || !symbol->is_public())
701e01aa904Sopenharmony_ci    return elf_symbol_sptr();
702e01aa904Sopenharmony_ci
703e01aa904Sopenharmony_ci  address_set_sptr set;
704e01aa904Sopenharmony_ci  bool looking_at_linux_kernel_binary =
705e01aa904Sopenharmony_ci    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
706e01aa904Sopenharmony_ci
707e01aa904Sopenharmony_ci  if (looking_at_linux_kernel_binary)
708e01aa904Sopenharmony_ci    {
709e01aa904Sopenharmony_ci	if (symbol->is_in_ksymtab())
710e01aa904Sopenharmony_ci	  return symbol;
711e01aa904Sopenharmony_ci	return elf_symbol_sptr();
712e01aa904Sopenharmony_ci    }
713e01aa904Sopenharmony_ci
714e01aa904Sopenharmony_ci  return symbol;
715e01aa904Sopenharmony_ci}
716e01aa904Sopenharmony_ci
717e01aa904Sopenharmony_ci/// Test if a given variable symbol has been exported.
718e01aa904Sopenharmony_ci///
719e01aa904Sopenharmony_ci/// @param symbol_address the address of the symbol we are looking
720e01aa904Sopenharmony_ci/// for.  Note that this address must be a relative offset from the
721e01aa904Sopenharmony_ci/// beginning of the .text section, just like the kind of addresses
722e01aa904Sopenharmony_ci/// that are present in the .symtab section.
723e01aa904Sopenharmony_ci///
724e01aa904Sopenharmony_ci/// @return the elf symbol if found, or nil otherwise.
725e01aa904Sopenharmony_cielf_symbol_sptr
726e01aa904Sopenharmony_cireader::variable_symbol_is_exported(GElf_Addr symbol_address) const
727e01aa904Sopenharmony_ci{
728e01aa904Sopenharmony_ci  elf_symbol_sptr symbol = symtab()->lookup_symbol(symbol_address);
729e01aa904Sopenharmony_ci  if (!symbol)
730e01aa904Sopenharmony_ci    return symbol;
731e01aa904Sopenharmony_ci
732e01aa904Sopenharmony_ci  if (!symbol->is_variable() || !symbol->is_public())
733e01aa904Sopenharmony_ci    return elf_symbol_sptr();
734e01aa904Sopenharmony_ci
735e01aa904Sopenharmony_ci  address_set_sptr set;
736e01aa904Sopenharmony_ci  bool looking_at_linux_kernel_binary =
737e01aa904Sopenharmony_ci    load_in_linux_kernel_mode() && elf_helpers::is_linux_kernel(elf_handle());
738e01aa904Sopenharmony_ci
739e01aa904Sopenharmony_ci  if (looking_at_linux_kernel_binary)
740e01aa904Sopenharmony_ci    {
741e01aa904Sopenharmony_ci	if (symbol->is_in_ksymtab())
742e01aa904Sopenharmony_ci	  return symbol;
743e01aa904Sopenharmony_ci	return elf_symbol_sptr();
744e01aa904Sopenharmony_ci    }
745e01aa904Sopenharmony_ci
746e01aa904Sopenharmony_ci  return symbol;
747e01aa904Sopenharmony_ci}
748e01aa904Sopenharmony_ci
749e01aa904Sopenharmony_ci/// Test if a given function symbol has been exported.
750e01aa904Sopenharmony_ci///
751e01aa904Sopenharmony_ci/// @param name the name of the symbol we are looking for.
752e01aa904Sopenharmony_ci///
753e01aa904Sopenharmony_ci/// @return the elf symbol if found, or nil otherwise.
754e01aa904Sopenharmony_cielf_symbol_sptr
755e01aa904Sopenharmony_cireader::function_symbol_is_exported(const string& name) const
756e01aa904Sopenharmony_ci{
757e01aa904Sopenharmony_ci  const elf_symbols& syms = symtab()->lookup_symbol(name);
758e01aa904Sopenharmony_ci  for (auto s : syms)
759e01aa904Sopenharmony_ci    {
760e01aa904Sopenharmony_ci      if (s->is_function() && s->is_public())
761e01aa904Sopenharmony_ci	{
762e01aa904Sopenharmony_ci	  bool looking_at_linux_kernel_binary =
763e01aa904Sopenharmony_ci	    (load_in_linux_kernel_mode()
764e01aa904Sopenharmony_ci	     && elf_helpers::is_linux_kernel(elf_handle()));
765e01aa904Sopenharmony_ci
766e01aa904Sopenharmony_ci	  if (looking_at_linux_kernel_binary)
767e01aa904Sopenharmony_ci	    {
768e01aa904Sopenharmony_ci	      if (s->is_in_ksymtab())
769e01aa904Sopenharmony_ci		return s;
770e01aa904Sopenharmony_ci	    }
771e01aa904Sopenharmony_ci	  else
772e01aa904Sopenharmony_ci	    return s;
773e01aa904Sopenharmony_ci	}
774e01aa904Sopenharmony_ci    }
775e01aa904Sopenharmony_ci  return elf_symbol_sptr();
776e01aa904Sopenharmony_ci}
777e01aa904Sopenharmony_ci
778e01aa904Sopenharmony_ci/// Test if a given variable symbol has been exported.
779e01aa904Sopenharmony_ci///
780e01aa904Sopenharmony_ci/// @param name the name of the symbol we are looking
781e01aa904Sopenharmony_ci/// for.
782e01aa904Sopenharmony_ci///
783e01aa904Sopenharmony_ci/// @return the elf symbol if found, or nil otherwise.
784e01aa904Sopenharmony_cielf_symbol_sptr
785e01aa904Sopenharmony_cireader::variable_symbol_is_exported(const string& name) const
786e01aa904Sopenharmony_ci{
787e01aa904Sopenharmony_ci  const elf_symbols& syms = symtab()->lookup_symbol(name);
788e01aa904Sopenharmony_ci  for (auto s : syms)
789e01aa904Sopenharmony_ci    {
790e01aa904Sopenharmony_ci      if (s->is_variable() && s->is_public())
791e01aa904Sopenharmony_ci	{
792e01aa904Sopenharmony_ci	  bool looking_at_linux_kernel_binary =
793e01aa904Sopenharmony_ci	    (load_in_linux_kernel_mode()
794e01aa904Sopenharmony_ci	     && elf_helpers::is_linux_kernel(elf_handle()));
795e01aa904Sopenharmony_ci
796e01aa904Sopenharmony_ci	  if (looking_at_linux_kernel_binary)
797e01aa904Sopenharmony_ci	    {
798e01aa904Sopenharmony_ci	      if (s->is_in_ksymtab())
799e01aa904Sopenharmony_ci		return s;
800e01aa904Sopenharmony_ci	    }
801e01aa904Sopenharmony_ci	  else
802e01aa904Sopenharmony_ci	    return s;
803e01aa904Sopenharmony_ci	}
804e01aa904Sopenharmony_ci    }
805e01aa904Sopenharmony_ci  return elf_symbol_sptr();
806e01aa904Sopenharmony_ci}
807e01aa904Sopenharmony_ci/// Load the DT_NEEDED and DT_SONAME elf TAGS.
808e01aa904Sopenharmony_civoid
809e01aa904Sopenharmony_cireader::load_dt_soname_and_needed()
810e01aa904Sopenharmony_ci{
811e01aa904Sopenharmony_ci  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
812e01aa904Sopenharmony_ci						    DT_NEEDED,
813e01aa904Sopenharmony_ci						    priv_->dt_needed);
814e01aa904Sopenharmony_ci
815e01aa904Sopenharmony_ci  vector<string> dt_tag_data;
816e01aa904Sopenharmony_ci  elf_helpers::lookup_data_tag_from_dynamic_segment(elf_handle(),
817e01aa904Sopenharmony_ci						    DT_SONAME,
818e01aa904Sopenharmony_ci						    dt_tag_data);
819e01aa904Sopenharmony_ci  if (!dt_tag_data.empty())
820e01aa904Sopenharmony_ci    dt_soname(dt_tag_data[0]);
821e01aa904Sopenharmony_ci}
822e01aa904Sopenharmony_ci
823e01aa904Sopenharmony_ci/// Read the string representing the architecture of the current ELF
824e01aa904Sopenharmony_ci/// file.
825e01aa904Sopenharmony_civoid
826e01aa904Sopenharmony_cireader::load_elf_architecture()
827e01aa904Sopenharmony_ci{
828e01aa904Sopenharmony_ci  if (!elf_handle())
829e01aa904Sopenharmony_ci    return;
830e01aa904Sopenharmony_ci
831e01aa904Sopenharmony_ci  GElf_Ehdr eh_mem;
832e01aa904Sopenharmony_ci  GElf_Ehdr* elf_header = gelf_getehdr(elf_handle(), &eh_mem);
833e01aa904Sopenharmony_ci
834e01aa904Sopenharmony_ci  priv_->elf_architecture =
835e01aa904Sopenharmony_ci    elf_helpers::e_machine_to_string(elf_header->e_machine);
836e01aa904Sopenharmony_ci}
837e01aa904Sopenharmony_ci
838e01aa904Sopenharmony_ci/// Load various ELF data.
839e01aa904Sopenharmony_ci///
840e01aa904Sopenharmony_ci/// This function loads ELF data that are not symbol maps or debug
841e01aa904Sopenharmony_ci/// info.  That is, things like various tags, elf architecture and
842e01aa904Sopenharmony_ci/// so on.
843e01aa904Sopenharmony_civoid
844e01aa904Sopenharmony_cireader::load_elf_properties()
845e01aa904Sopenharmony_ci{
846e01aa904Sopenharmony_ci  // Note that we don't load the symbol table as it's loaded lazily,
847e01aa904Sopenharmony_ci  // on demand.
848e01aa904Sopenharmony_ci
849e01aa904Sopenharmony_ci  load_dt_soname_and_needed();
850e01aa904Sopenharmony_ci  load_elf_architecture();
851e01aa904Sopenharmony_ci}
852e01aa904Sopenharmony_ci
853e01aa904Sopenharmony_ci/// Read the ELF information associated to the current ELF file and
854e01aa904Sopenharmony_ci/// construct an ABI representation from it.
855e01aa904Sopenharmony_ci///
856e01aa904Sopenharmony_ci/// Note that this reader doesn't know how to interpret any debug
857e01aa904Sopenharmony_ci/// information so the resulting ABI corpus won't have any type
858e01aa904Sopenharmony_ci/// information.  Rather, it will only have ELF symbol representation.
859e01aa904Sopenharmony_ci///
860e01aa904Sopenharmony_ci/// To have type information, consider using readers that know how to
861e01aa904Sopenharmony_ci/// interpret the symbolic type information comprised in DWARF, CTF or
862e01aa904Sopenharmony_ci/// other symbolic debug information format, like the @ref or
863e01aa904Sopenharmony_ci/// abigail::dwarf_reader::reader, @ref abigail::ctf_reader::reader
864e01aa904Sopenharmony_ci/// readers.
865e01aa904Sopenharmony_ci///
866e01aa904Sopenharmony_ci/// @return the resulting ABI corpus.
867e01aa904Sopenharmony_ciir::corpus_sptr
868e01aa904Sopenharmony_cireader::read_corpus(status& status)
869e01aa904Sopenharmony_ci{
870e01aa904Sopenharmony_ci  status = STATUS_UNKNOWN;
871e01aa904Sopenharmony_ci
872e01aa904Sopenharmony_ci  corpus::origin origin = corpus()->get_origin();
873e01aa904Sopenharmony_ci  origin |= corpus::ELF_ORIGIN;
874e01aa904Sopenharmony_ci  if (is_linux_kernel(elf_handle()))
875e01aa904Sopenharmony_ci    origin |= corpus::LINUX_KERNEL_BINARY_ORIGIN;
876e01aa904Sopenharmony_ci  corpus()->set_origin(origin);
877e01aa904Sopenharmony_ci
878e01aa904Sopenharmony_ci  load_elf_properties(); // DT_SONAME, DT_NEEDED, architecture
879e01aa904Sopenharmony_ci  corpus()->set_soname(dt_soname());
880e01aa904Sopenharmony_ci  corpus()->set_needed(dt_needed());
881e01aa904Sopenharmony_ci  corpus()->set_architecture_name(elf_architecture());
882e01aa904Sopenharmony_ci
883e01aa904Sopenharmony_ci  // See if we could find symbol tables.
884e01aa904Sopenharmony_ci  if (!symtab() || !symtab()->has_symbols())
885e01aa904Sopenharmony_ci    {
886e01aa904Sopenharmony_ci      status |= STATUS_NO_SYMBOLS_FOUND;
887e01aa904Sopenharmony_ci      // We found no ELF symbol, so we can't handle the binary.
888e01aa904Sopenharmony_ci      return corpus_sptr();
889e01aa904Sopenharmony_ci    }
890e01aa904Sopenharmony_ci
891e01aa904Sopenharmony_ci  // Set symbols information to the corpus.
892e01aa904Sopenharmony_ci  corpus()->set_symtab(symtab());
893e01aa904Sopenharmony_ci
894e01aa904Sopenharmony_ci  // If we couldn't load debug info from the elf path, then say it.
895e01aa904Sopenharmony_ci  if ((origin & abigail::ir::corpus::DWARF_ORIGIN)
896e01aa904Sopenharmony_ci        && !has_dwarf_debug_info())
897e01aa904Sopenharmony_ci    status |= STATUS_DEBUG_INFO_NOT_FOUND;
898e01aa904Sopenharmony_ci  else if ((origin & abigail::ir::corpus::CTF_ORIGIN)
899e01aa904Sopenharmony_ci             && !has_ctf_debug_info())
900e01aa904Sopenharmony_ci    status |= STATUS_DEBUG_INFO_NOT_FOUND;
901e01aa904Sopenharmony_ci
902e01aa904Sopenharmony_ci  status |= STATUS_OK;
903e01aa904Sopenharmony_ci  return corpus();
904e01aa904Sopenharmony_ci}
905e01aa904Sopenharmony_ci
906e01aa904Sopenharmony_ci/// Get the SONAME property of a designated ELF file.
907e01aa904Sopenharmony_ci///
908e01aa904Sopenharmony_ci/// @param path the path to the ELF file to consider.
909e01aa904Sopenharmony_ci///
910e01aa904Sopenharmony_ci/// @param soname output parameter.  This is set to the SONAME of the
911e01aa904Sopenharmony_ci/// file located at @p path, iff this function return true.
912e01aa904Sopenharmony_ci///
913e01aa904Sopenharmony_ci/// @return true iff the SONAME property was found in the ELF file
914e01aa904Sopenharmony_ci/// located at @p path and set into the argument of the parameter @p
915e01aa904Sopenharmony_ci/// soname.
916e01aa904Sopenharmony_cibool
917e01aa904Sopenharmony_ciget_soname_of_elf_file(const string& path, string &soname)
918e01aa904Sopenharmony_ci{return elf_helpers::get_soname_of_elf_file(path, soname);}
919e01aa904Sopenharmony_ci
920e01aa904Sopenharmony_ci/// Convert the type of ELF file into @ref elf_type.
921e01aa904Sopenharmony_ci///
922e01aa904Sopenharmony_ci/// @param elf the elf handle to use for the query.
923e01aa904Sopenharmony_ci///
924e01aa904Sopenharmony_ci/// @return the @ref elf_type for a given elf type.
925e01aa904Sopenharmony_cistatic elf::elf_type
926e01aa904Sopenharmony_cielf_file_type(Elf* elf)
927e01aa904Sopenharmony_ci{
928e01aa904Sopenharmony_ci  GElf_Ehdr ehdr_mem;
929e01aa904Sopenharmony_ci  GElf_Ehdr *header = gelf_getehdr (elf, &ehdr_mem);
930e01aa904Sopenharmony_ci  vector<string> dt_debug_data;
931e01aa904Sopenharmony_ci
932e01aa904Sopenharmony_ci  switch (header->e_type)
933e01aa904Sopenharmony_ci    {
934e01aa904Sopenharmony_ci    case ET_DYN:
935e01aa904Sopenharmony_ci      if (lookup_data_tag_from_dynamic_segment(elf, DT_DEBUG, dt_debug_data))
936e01aa904Sopenharmony_ci	return elf::ELF_TYPE_PI_EXEC;
937e01aa904Sopenharmony_ci      else
938e01aa904Sopenharmony_ci	return elf::ELF_TYPE_DSO;
939e01aa904Sopenharmony_ci    case ET_EXEC:
940e01aa904Sopenharmony_ci      return elf::ELF_TYPE_EXEC;
941e01aa904Sopenharmony_ci    case ET_REL:
942e01aa904Sopenharmony_ci      return elf::ELF_TYPE_RELOCATABLE;
943e01aa904Sopenharmony_ci    default:
944e01aa904Sopenharmony_ci      return elf::ELF_TYPE_UNKNOWN;
945e01aa904Sopenharmony_ci    }
946e01aa904Sopenharmony_ci}
947e01aa904Sopenharmony_ci
948e01aa904Sopenharmony_ci/// Get the type of a given elf type.
949e01aa904Sopenharmony_ci///
950e01aa904Sopenharmony_ci/// @param path the absolute path to the ELF file to analyzed.
951e01aa904Sopenharmony_ci///
952e01aa904Sopenharmony_ci/// @param type the kind of the ELF file designated by @p path.
953e01aa904Sopenharmony_ci///
954e01aa904Sopenharmony_ci/// @param out parameter.  Is set to the type of ELF file of @p path.
955e01aa904Sopenharmony_ci/// This parameter is set iff the function returns true.
956e01aa904Sopenharmony_ci///
957e01aa904Sopenharmony_ci/// @return true iff the file could be opened and analyzed.
958e01aa904Sopenharmony_cibool
959e01aa904Sopenharmony_ciget_type_of_elf_file(const string& path, elf::elf_type& type)
960e01aa904Sopenharmony_ci{
961e01aa904Sopenharmony_ci  int fd = open(path.c_str(), O_RDONLY);
962e01aa904Sopenharmony_ci  if (fd == -1)
963e01aa904Sopenharmony_ci    return false;
964e01aa904Sopenharmony_ci
965e01aa904Sopenharmony_ci  elf_version (EV_CURRENT);
966e01aa904Sopenharmony_ci  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
967e01aa904Sopenharmony_ci  type = elf_file_type(elf);
968e01aa904Sopenharmony_ci  elf_end(elf);
969e01aa904Sopenharmony_ci  close(fd);
970e01aa904Sopenharmony_ci
971e01aa904Sopenharmony_ci  return true;
972e01aa904Sopenharmony_ci}
973e01aa904Sopenharmony_ci
974e01aa904Sopenharmony_ci}// end namespace elf
975e01aa904Sopenharmony_ci} // end namespace abigail
976