MAJOR=4
MINOR=4
DEVNAME=tty4
     �_’I|¥‰ÓMjqØ‚¦ð¬÷ÂÁ      File not found.
  +   	ˆl–Ü4ý( ©³( 	Å€fàB¦-ÿÀ„/ _†I|¥�+ÄÃ 5è    	// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <libelf.h>
#include <gelf.h>
#include <fcntl.h>
#include <linux/kernel.h>

#include "libbpf_internal.h"
#include "str_error.h"

/* A SHT_GNU_versym section holds 16-bit words. This bit is set if
 * the symbol is hidden and can only be seen when referenced using an
 * explicit version number. This is a GNU extension.
 */
#define VERSYM_HIDDEN	0x8000

/* This is the mask for the rest of the data in a word read from a
 * SHT_GNU_versym section.
 */
#define VERSYM_VERSION	0x7fff

int elf_open(const char *binary_path, struct elf_fd *elf_fd)
{
	char errmsg[STRERR_BUFSIZE];
	int fd, ret;
	Elf *elf;

	elf_fd->elf = NULL;
	elf_fd->fd = -1;

	if (elf_version(EV_CURRENT) == EV_NONE) {
		pr_warn("elf: failed to init libelf for %s\n", binary_path);
		return -LIBBPF_ERRNO__LIBELF;
	}
	fd = open(binary_path, O_RDONLY | O_CLOEXEC);
	if (fd < 0) {
		ret = -errno;
		pr_warn("elf: failed to open %s: %s\n", binary_path,
			libbpf_strerror_r(ret, errmsg, sizeof(errmsg)));
		return ret;
	}
	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
	if (!elf) {
		pr_warn("elf: could not read elf from %s: %s\n", binary_path, elf_errmsg(-1));
		close(fd);
		return -LIBBPF_ERRNO__FORMAT;
	}
	elf_fd->fd = fd;
	elf_fd->elf = elf;
	return 0;
}

void elf_close(struct elf_fd *elf_fd)
{
	if (!elf_fd)
		return;
	elf_end(elf_fd->elf);
	close(elf_fd->fd);
}

/* Return next ELF section of sh_type after scn, or first of that type if scn is NULL. */
static Elf_Scn *elf_find_next_scn_by_type(Elf *elf, int sh_type, Elf_Scn *scn)
{
	while ((scn = elf_nextscn(elf, scn)) != NULL) {
		GElf_Shdr sh;

		if (!gelf_getshdr(scn, &sh))
			continue;
		if (sh.sh_type == sh_type)
			return scn;
	}
	return NULL;
}

struct elf_sym {
	const char *name;
	GElf_Sym sym;
	GElf_Shdr sh;
	int ver;
	bool hidden;
};

struct elf_sym_iter {
	Elf *elf;
	Elf_Data *syms;
	Elf_Data *versyms;
	Elf_Data *verdefs;
	size_t nr_syms;
	size_t strtabidx;
	size_t verdef_strtabidx;
	size_t next_sym_idx;
	struct elf_sym sym;
	int st_type;
};

static int elf_sym_iter_new(struct elf_sym_iter *iter,
			    Elf *elf, const char *binary_path,
			    int sh_type, int st_type)
{
	Elf_Scn *scn = NULL;
	GElf_Ehdr ehdr;
	GElf_Shdr sh;

	memset(iter, 0, sizeof(*iter));

	if (!gelf_getehdr(elf, &ehdr)) {
		pr_warn("elf: failed to get ehdr from %s: %s\n", binary_path, elf_errmsg(-1));
		return -EINVAL;
	}

	scn = elf_find_next_scn_by_type(elf, sh_type, NULL);
	if (!scn) {
		pr_debug("elf: failed to find symbol table ELF sections in '%s'\n",
			 binary_path);
		return -ENOENT;
	}

	if (!gelf_getshdr(scn, &sh))
		return -EINVAL;

	iter->strtabidx = sh.sh_link;
	iter->syms = elf_getdata(scn, 0);
	if (!iter->syms) {
		pr_warn("elf: failed to get symbols for symtab section in '%s': %s\n",
			binary_path, elf_errmsg(-1));
		return -EINVAL;
	}
	iter->nr_syms = iter->syms->d_size / sh.sh_entsize;
	iter->elf = elf;
	iter->st_type = st_type;

	/* Version symbol table is meaningful to dynsym only */
	if (sh_type != SHT_DYNSYM)
		return 0;

	scn = elf_find_next_scn_by_type(elf, SHT_GNU_versym, NULL);
	if (!scn)
		return 0;
	iter->versyms = elf_getdata(scn, 0);

	scn = elf_find_next_scn_by_type(elf, SHT_GNU_verdef, NULL);
	if (!scn)
		return 0;

	iter->verdefs = elf_getdata(scn, 0);
	if (!iter->verdefs || !gelf_getshdr(scn, &sh)) {
		pr_warn("elf: failed to get verdef ELF section in '%s'\n", binary_path);
		return -EINVAL;
	}
	iter->verdef_strtabidx = sh.sh_link;

	return 0;
}

static struct elf_sym *elf_sym_iter_next(struct elf_sym_iter *iter)
{
	struct elf_sym *ret = &iter->sym;
	GElf_Sym *sym = &ret->sym;
	const char *name = NULL;
	GElf_Versym versym;
	Elf_Scn *sym_scn;
	size_t idx;

	for (idx = iter->next_sym_idx; idx < iter->nr_syms; idx++) {
		if (!gelf_getsym(iter->syms, idx, sym))
			continue;
		if (GELF_ST_TYPE(sym->st_info) != iter->st_type)
			continue;
		name = elf_strptr(i