return 0;
 }
 
-static int parse_lib_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
+static int parse_vma_segs(int pid, const char *lib_path, struct elf_seg **segs, size_t *seg_cnt)
 {
        char path[PATH_MAX], line[PATH_MAX], mode[16];
        size_t seg_start, seg_end, seg_off;
        return err;
 }
 
-static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long addr, bool relative)
+static struct elf_seg *find_elf_seg(struct elf_seg *segs, size_t seg_cnt, long virtaddr)
 {
        struct elf_seg *seg;
        int i;
 
-       if (relative) {
-               /* for shared libraries, address is relative offset and thus
-                * should be fall within logical offset-based range of
-                * [offset_start, offset_end)
-                */
-               for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
-                       if (seg->offset <= addr && addr < seg->offset + (seg->end - seg->start))
-                               return seg;
-               }
-       } else {
-               /* for binaries, address is absolute and thus should be within
-                * absolute address range of [seg_start, seg_end)
-                */
-               for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
-                       if (seg->start <= addr && addr < seg->end)
-                               return seg;
-               }
+       /* for ELF binaries (both executables and shared libraries), we are
+        * given virtual address (absolute for executables, relative for
+        * libraries) which should match address range of [seg_start, seg_end)
+        */
+       for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
+               if (seg->start <= virtaddr && virtaddr < seg->end)
+                       return seg;
        }
+       return NULL;
+}
 
+static struct elf_seg *find_vma_seg(struct elf_seg *segs, size_t seg_cnt, long offset)
+{
+       struct elf_seg *seg;
+       int i;
+
+       /* for VMA segments from /proc/<pid>/maps file, provided "address" is
+        * actually a file offset, so should be fall within logical
+        * offset-based range of [offset_start, offset_end)
+        */
+       for (i = 0, seg = segs; i < seg_cnt; i++, seg++) {
+               if (seg->offset <= offset && offset < seg->offset + (seg->end - seg->start))
+                       return seg;
+       }
        return NULL;
 }
 
-static int parse_usdt_note(Elf *elf, const char *path, long base_addr,
-                          GElf_Nhdr *nhdr, const char *data, size_t name_off, size_t desc_off,
+static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
+                          const char *data, size_t name_off, size_t desc_off,
                           struct usdt_note *usdt_note);
 
 static int parse_usdt_spec(struct usdt_spec *spec, const struct usdt_note *note, __u64 usdt_cookie);
                                const char *usdt_provider, const char *usdt_name, __u64 usdt_cookie,
                                struct usdt_target **out_targets, size_t *out_target_cnt)
 {
-       size_t off, name_off, desc_off, seg_cnt = 0, lib_seg_cnt = 0, target_cnt = 0;
-       struct elf_seg *segs = NULL, *lib_segs = NULL;
+       size_t off, name_off, desc_off, seg_cnt = 0, vma_seg_cnt = 0, target_cnt = 0;
+       struct elf_seg *segs = NULL, *vma_segs = NULL;
        struct usdt_target *targets = NULL, *target;
        long base_addr = 0;
        Elf_Scn *notes_scn, *base_scn;
                struct elf_seg *seg = NULL;
                void *tmp;
 
-               err = parse_usdt_note(elf, path, base_addr, &nhdr,
-                                     data->d_buf, name_off, desc_off, ¬e);
+               err = parse_usdt_note(elf, path, &nhdr, data->d_buf, name_off, desc_off, ¬e);
                if (err)
                        goto err_out;
 
                        usdt_rel_ip += base_addr - note.base_addr;
                }
 
-               if (ehdr.e_type == ET_EXEC) {
-                       /* When attaching uprobes (which what USDTs basically
-                        * are) kernel expects a relative IP to be specified,
-                        * so if we are attaching to an executable ELF binary
-                        * (i.e., not a shared library), we need to calculate
-                        * proper relative IP based on ELF's load address
-                        */
-                       seg = find_elf_seg(segs, seg_cnt, usdt_abs_ip, false /* relative */);
-                       if (!seg) {
-                               err = -ESRCH;
-                               pr_warn("usdt: failed to find ELF program segment for '%s:%s' in '%s' at IP 0x%lx\n",
-                                       usdt_provider, usdt_name, path, usdt_abs_ip);
-                               goto err_out;
-                       }
-                       if (!seg->is_exec) {
-                               err = -ESRCH;
-                               pr_warn("usdt: matched ELF binary '%s' segment [0x%lx, 0x%lx) for '%s:%s' at IP 0x%lx is not executable\n",
-                                       path, seg->start, seg->end, usdt_provider, usdt_name,
-                                       usdt_abs_ip);
-                               goto err_out;
-                       }
+               /* When attaching uprobes (which is what USDTs basically are)
+                * kernel expects file offset to be specified, not a relative
+                * virtual address, so we need to translate virtual address to
+                * file offset, for both ET_EXEC and ET_DYN binaries.
+                */
+               seg = find_elf_seg(segs, seg_cnt, usdt_abs_ip);
+               if (!seg) {
+                       err = -ESRCH;
+                       pr_warn("usdt: failed to find ELF program segment for '%s:%s' in '%s' at IP 0x%lx\n",
+                               usdt_provider, usdt_name, path, usdt_abs_ip);
+                       goto err_out;
+               }
+               if (!seg->is_exec) {
+                       err = -ESRCH;
+                       pr_warn("usdt: matched ELF binary '%s' segment [0x%lx, 0x%lx) for '%s:%s' at IP 0x%lx is not executable\n",
+                               path, seg->start, seg->end, usdt_provider, usdt_name,
+                               usdt_abs_ip);
+                       goto err_out;
+               }
+               /* translate from virtual address to file offset */
+               usdt_rel_ip = usdt_abs_ip - seg->start + seg->offset;
 
-                       usdt_rel_ip = usdt_abs_ip - (seg->start - seg->offset);
-               } else if (!man->has_bpf_cookie) { /* ehdr.e_type == ET_DYN */
+               if (ehdr.e_type == ET_DYN && !man->has_bpf_cookie) {
                        /* If we don't have BPF cookie support but need to
                         * attach to a shared library, we'll need to know and
                         * record absolute addresses of attach points due to
                                goto err_out;
                        }
 
-                       /* lib_segs are lazily initialized only if necessary */
-                       if (lib_seg_cnt == 0) {
-                               err = parse_lib_segs(pid, path, &lib_segs, &lib_seg_cnt);
+                       /* vma_segs are lazily initialized only if necessary */
+                       if (vma_seg_cnt == 0) {
+                               err = parse_vma_segs(pid, path, &vma_segs, &vma_seg_cnt);
                                if (err) {
                                        pr_warn("usdt: failed to get memory segments in PID %d for shared library '%s': %d\n",
                                                pid, path, err);
                                }
                        }
 
-                       seg = find_elf_seg(lib_segs, lib_seg_cnt, usdt_rel_ip, true /* relative */);
+                       seg = find_vma_seg(vma_segs, vma_seg_cnt, usdt_rel_ip);
                        if (!seg) {
                                err = -ESRCH;
                                pr_warn("usdt: failed to find shared lib memory segment for '%s:%s' in '%s' at relative IP 0x%lx\n",
                                goto err_out;
                        }
 
-                       usdt_abs_ip = seg->start + (usdt_rel_ip - seg->offset);
+                       usdt_abs_ip = seg->start - seg->offset + usdt_rel_ip;
                }
 
                pr_debug("usdt: probe for '%s:%s' in %s '%s': addr 0x%lx base 0x%lx (resolved abs_ip 0x%lx rel_ip 0x%lx) args '%s' in segment [0x%lx, 0x%lx) at offset 0x%lx\n",
                         note.loc_addr, note.base_addr, usdt_abs_ip, usdt_rel_ip, note.args,
                         seg ? seg->start : 0, seg ? seg->end : 0, seg ? seg->offset : 0);
 
-               /* Adjust semaphore address to be a relative offset */
+               /* Adjust semaphore address to be a file offset */
                if (note.sema_addr) {
                        if (!man->has_sema_refcnt) {
                                pr_warn("usdt: kernel doesn't support USDT semaphore refcounting for '%s:%s' in '%s'\n",
                                goto err_out;
                        }
 
-                       seg = find_elf_seg(segs, seg_cnt, note.sema_addr, false /* relative */);
+                       seg = find_elf_seg(segs, seg_cnt, note.sema_addr);
                        if (!seg) {
                                err = -ESRCH;
                                pr_warn("usdt: failed to find ELF loadable segment with semaphore of '%s:%s' in '%s' at 0x%lx\n",
                                goto err_out;
                        }
 
-                       usdt_sema_off = note.sema_addr - (seg->start - seg->offset);
+                       usdt_sema_off = note.sema_addr - seg->start + seg->offset;
 
                        pr_debug("usdt: sema  for '%s:%s' in %s '%s': addr 0x%lx base 0x%lx (resolved 0x%lx) in segment [0x%lx, 0x%lx] at offset 0x%lx\n",
                                 usdt_provider, usdt_name, ehdr.e_type == ET_EXEC ? "exec" : "lib ",
                target->rel_ip = usdt_rel_ip;
                target->sema_off = usdt_sema_off;
 
-               /* notes->args references strings from Elf itself, so they can
+               /* notes.args references strings from Elf itself, so they can
                 * be referenced safely until elf_end() call
                 */
                target->spec_str = note.args;
 
 err_out:
        free(segs);
-       free(lib_segs);
+       free(vma_segs);
        if (err < 0)
                free(targets);
        return err;
 /* Parse out USDT ELF note from '.note.stapsdt' section.
  * Logic inspired by perf's code.
  */
-static int parse_usdt_note(Elf *elf, const char *path, long base_addr,
-                          GElf_Nhdr *nhdr, const char *data, size_t name_off, size_t desc_off,
+static int parse_usdt_note(Elf *elf, const char *path, GElf_Nhdr *nhdr,
+                          const char *data, size_t name_off, size_t desc_off,
                           struct usdt_note *note)
 {
        const char *provider, *name, *args;