#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <inttypes.h>
#include "symbol.h"
#include "debug.h"
#ifndef NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID 3
#endif
/**
* elf_symtab__for_each_symbol - iterate thru all the symbols
*
* @syms: struct elf_symtab instance to iterate
* @idx: uint32_t idx
* @sym: GElf_Sym iterator
*/
#define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
for (idx = 0, gelf_getsym(syms, idx, &sym);\
idx < nr_syms; \
idx++, gelf_getsym(syms, idx, &sym))
static inline uint8_t elf_sym__type(const GElf_Sym *sym)
{
return GELF_ST_TYPE(sym->st_info);
}
static inline int elf_sym__is_function(const GElf_Sym *sym)
{
return elf_sym__type(sym) == STT_FUNC &&
sym->st_name != 0 &&
sym->st_shndx != SHN_UNDEF;
}
static inline bool elf_sym__is_object(const GElf_Sym *sym)
{
return elf_sym__type(sym) == STT_OBJECT &&
sym->st_name != 0 &&
sym->st_shndx != SHN_UNDEF;
}
static inline int elf_sym__is_label(const GElf_Sym *sym)
{
return elf_sym__type(sym) == STT_NOTYPE &&
sym->st_name != 0 &&
sym->st_shndx != SHN_UNDEF &&
sym->st_shndx != SHN_ABS;
}
static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
{
switch (type) {
case MAP__FUNCTION:
return elf_sym__is_function(sym);
case MAP__VARIABLE:
return elf_sym__is_object(sym);
default:
return false;
}
}
static inline const char *elf_sym__name(const GElf_Sym *sym,
const Elf_Data *symstrs)
{
return symstrs->d_buf + sym->st_name;
}
static inline const char *elf_sec__name(const GElf_Shdr *shdr,
const Elf_Data *secstrs)
{
return secstrs->d_buf + shdr->sh_name;
}
static inline int elf_sec__is_text(const GElf_Shdr *shdr,
const Elf_Data *secstrs)
{
return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
}
static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
const Elf_Data *secstrs)
{
return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
}
static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
enum map_type type)
{
switch (type) {
case MAP__FUNCTION:
return elf_sec__is_text(shdr, secstrs);
case MAP__VARIABLE:
return elf_sec__is_data(shdr, secstrs);
default:
return false;
}
}
static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
{
Elf_Scn *sec = NULL;
GElf_Shdr shdr;
size_t cnt = 1;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
gelf_getshdr(sec, &shdr);
if ((addr >= shdr.sh_addr) &&
(addr < (shdr.sh_addr + shdr.sh_size)))
return cnt;
++cnt;
}
return -1;
}
static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
GElf_Shdr *shp, const char *name,
size_t *idx)
{
Elf_Scn *sec = NULL;
size_t cnt = 1;
/* Elf is corrupted/truncated, avoid calling elf_strptr. */
if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL))
return NULL;
while ((sec = elf_nextscn(elf, sec)) != NULL) {
char *str;
gelf_getshdr(sec, shp);
str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
if (!strcmp(name, str)) {
if (idx)
*idx = cnt;
break;
}
++cnt;
}
return sec;
}
#define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
idx < nr_entries; \
++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
#define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
idx < nr_entries; \
++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
/*
* We need to check if we have a .dynsym, so that we can handle the
* .plt, synthesizing its symbols, that aren't on the symtabs (be it
* .dynsym or .symtab).
* And always look at the original dso, not at debuginfo packages, that
* have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).
*/
int dso__synthesize_plt_symbols(struct dso *dso, struct symsrc *ss, struct map *map,
symbol_filter_t filter)
{
uint32_t nr_rel_entries, idx;
GElf_Sym sym;
u64 plt_offset;
GElf_Shdr shdr