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