#include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 #include <asm/unistd.h>
 #include <linux/bpf.h>
+#include <libelf.h>
+#include <gelf.h>
 
 #include "libbpf.h"
 
        __pr_info = info;
        __pr_debug = debug;
 }
+
+/* Copied from tools/perf/util/util.h */
+#ifndef zfree
+# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+#endif
+
+#ifndef zclose
+# define zclose(fd) ({                 \
+       int ___err = 0;                 \
+       if ((fd) >= 0)                  \
+               ___err = close((fd));   \
+       fd = -1;                        \
+       ___err; })
+#endif
+
+#ifdef HAVE_LIBELF_MMAP_SUPPORT
+# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP
+#else
+# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
+#endif
+
+struct bpf_object {
+       /*
+        * Information when doing elf related work. Only valid if fd
+        * is valid.
+        */
+       struct {
+               int fd;
+               Elf *elf;
+               GElf_Ehdr ehdr;
+       } efile;
+       char path[];
+};
+#define obj_elf_valid(o)       ((o)->efile.elf)
+
+static struct bpf_object *bpf_object__new(const char *path)
+{
+       struct bpf_object *obj;
+
+       obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
+       if (!obj) {
+               pr_warning("alloc memory failed for %s\n", path);
+               return NULL;
+       }
+
+       strcpy(obj->path, path);
+       obj->efile.fd = -1;
+       return obj;
+}
+
+static void bpf_object__elf_finish(struct bpf_object *obj)
+{
+       if (!obj_elf_valid(obj))
+               return;
+
+       if (obj->efile.elf) {
+               elf_end(obj->efile.elf);
+               obj->efile.elf = NULL;
+       }
+       zclose(obj->efile.fd);
+}
+
+static int bpf_object__elf_init(struct bpf_object *obj)
+{
+       int err = 0;
+       GElf_Ehdr *ep;
+
+       if (obj_elf_valid(obj)) {
+               pr_warning("elf init: internal error\n");
+               return -EEXIST;
+       }
+
+       obj->efile.fd = open(obj->path, O_RDONLY);
+       if (obj->efile.fd < 0) {
+               pr_warning("failed to open %s: %s\n", obj->path,
+                               strerror(errno));
+               return -errno;
+       }
+
+       obj->efile.elf = elf_begin(obj->efile.fd,
+                                LIBBPF_ELF_C_READ_MMAP,
+                                NULL);
+       if (!obj->efile.elf) {
+               pr_warning("failed to open %s as ELF file\n",
+                               obj->path);
+               err = -EINVAL;
+               goto errout;
+       }
+
+       if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
+               pr_warning("failed to get EHDR from %s\n",
+                               obj->path);
+               err = -EINVAL;
+               goto errout;
+       }
+       ep = &obj->efile.ehdr;
+
+       if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
+               pr_warning("%s is not an eBPF object file\n",
+                       obj->path);
+               err = -EINVAL;
+               goto errout;
+       }
+
+       return 0;
+errout:
+       bpf_object__elf_finish(obj);
+       return err;
+}
+
+static struct bpf_object *
+__bpf_object__open(const char *path)
+{
+       struct bpf_object *obj;
+
+       if (elf_version(EV_CURRENT) == EV_NONE) {
+               pr_warning("failed to init libelf for %s\n", path);
+               return NULL;
+       }
+
+       obj = bpf_object__new(path);
+       if (!obj)
+               return NULL;
+
+       if (bpf_object__elf_init(obj))
+               goto out;
+
+       bpf_object__elf_finish(obj);
+       return obj;
+out:
+       bpf_object__close(obj);
+       return NULL;
+}
+
+struct bpf_object *bpf_object__open(const char *path)
+{
+       /* param validation */
+       if (!path)
+               return NULL;
+
+       pr_debug("loading %s\n", path);
+
+       return __bpf_object__open(path);
+}
+
+void bpf_object__close(struct bpf_object *obj)
+{
+       if (!obj)
+               return;
+
+       bpf_object__elf_finish(obj);
+
+       free(obj);
+}