commit d04fcfc174d0b459e9a3a0685ae64302fb928f04 Author: lijunlong Date: Thu Jun 5 07:20:21 2025 +0800 bugfix: buildid check failed because the Offset does not equal to the VirtAddr. $readelf -l -W envoy Elf file type is DYN (Position-Independent Executable file) Entry point 0x192e000 There are 12 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0002a0 0x0002a0 R 0x8 INTERP 0x0002e0 0x00000000000002e0 0x00000000000002e0 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x192cdec 0x192cdec R 0x1000 LOAD 0x192d000 0x000000000192e000 0x000000000192e000 0x2c95710 0x2c95710 R E 0x1000 LOAD 0x45c2740 0x00000000045c4740 0x00000000045c4740 0x267830 0x2678c0 RW 0x1000 LOAD 0x4829f70 0x000000000482cf70 0x000000000482cf70 0x0b6f70 0xc332b0 RW 0x1000 TLS 0x45c2740 0x00000000045c4740 0x00000000045c4740 0x000110 0x0026e0 R 0x40 DYNAMIC 0x48226b8 0x00000000048246b8 0x00000000048246b8 0x000200 0x000200 RW 0x8 GNU_RELRO 0x45c2740 0x00000000045c4740 0x00000000045c4740 0x267830 0x2678c0 R 0x1 GNU_EH_FRAME 0x110ae58 0x000000000110ae58 0x000000000110ae58 0x15c30c 0x15c30c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0 NOTE 0x0002fc 0x00000000000002fc 0x00000000000002fc 0x000044 0x000044 R 0x4 diff --git a/dwflpp.h b/dwflpp.h index d90ce9436..04c00dffe 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -124,6 +124,12 @@ typedef std::vector func_info_map_t; typedef std::vector inline_instance_map_t; +struct elf_hdr { + Dwarf_Addr offset; // file offset + Dwarf_Addr vaddr; // virtual address + size_t memsz; // memory size of this section +}; + struct module_info { @@ -139,6 +145,7 @@ module_info std::set inlined_funcs; std::set plt_funcs; std::set > marks; /* */ + std::vector hdrs; void get_symtab(); void update_symtab(cu_function_cache_t *funcs); diff --git a/runtime/linux/task_finder2.c b/runtime/linux/task_finder2.c index 9c2f5ad88..951720d21 100644 --- a/runtime/linux/task_finder2.c +++ b/runtime/linux/task_finder2.c @@ -784,6 +784,22 @@ __stp_find_file_based_vma(struct mm_struct *mm, unsigned long addr) return vma; } +static unsigned long +__stp_find_elf_base_addr(struct mm_struct *mm, struct vm_area_struct *target_vma) +{ + unsigned long base_addr = target_vma->vm_start; + struct vm_area_struct *vma; + + VMA_ITERATOR(vmi, mm, 0); + for_each_vma(vmi, vma) { + if (vma->vm_file == target_vma->vm_file || vma == target_vma) { + base_addr = vma->vm_start; + break; + } + } + + return base_addr; +} static void __stp_call_mmap_callbacks_with_addr(struct stap_task_finder_target *tgt, @@ -798,6 +814,7 @@ __stp_call_mmap_callbacks_with_addr(struct stap_task_finder_target *tgt, unsigned long length = 0; unsigned long offset = 0; unsigned long vm_flags = 0; + unsigned long base_addr = 0; // __stp_call_mmap_callbacks_with_addr() is only called when // tsk is current, so there isn't any danger of mm going @@ -816,7 +833,9 @@ __stp_call_mmap_callbacks_with_addr(struct stap_task_finder_target *tgt, // Cache information we need from the vma addr = vma->vm_start; length = vma->vm_end - vma->vm_start; - offset = (vma->vm_pgoff << PAGE_SHIFT); + base_addr = __stp_find_elf_base_addr(mm, vma); + //offset = (vma->vm_pgoff << PAGE_SHIFT); + offset = addr - base_addr; vm_flags = vma->vm_flags; #ifdef STAPCONF_DPATH_PATH dentry = vma->vm_file->f_path.dentry; @@ -1268,6 +1287,8 @@ __stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, }; struct vma_cache_t *vma_cache = NULL; struct vma_cache_t *vma_cache_p; + struct file *mm_file = NULL; + unsigned long base_addr = 0; // Call the mmap_callback for every vma associated with // a file. @@ -1331,9 +1352,15 @@ __stp_call_mmap_callbacks_for_task(struct stap_task_finder_target *tgt, mntget(vma_cache_p->f_vfsmnt); vma_cache_p->dentry = vma->vm_file->f_dentry; #endif + if (mm_file == NULL || mm_file != vma->vm_file) { + mm_file = vma->vm_file; + base_addr = vma->vm_start; + } + vma_cache_p->addr = vma->vm_start; vma_cache_p->length = vma->vm_end - vma->vm_start; - vma_cache_p->offset = (vma->vm_pgoff << PAGE_SHIFT); + //vma_cache_p->offset = (vma->vm_pgoff << PAGE_SHIFT); + vma_cache_p->offset = vma->vm_start - base_addr; vma_cache_p->vm_flags = vma->vm_flags; vma_cache_p++; } diff --git a/tapsets.cxx b/tapsets.cxx index 01fec29e3..37e452499 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -2664,6 +2664,30 @@ query_module (Dwfl_Module *mod, { mi->dwarf_status = info_absent; } + + { + Dwarf_Addr load_addr; + Elf* elf = dwfl_module_getelf (mod, &load_addr); + + // Get the load address, readelf -l -W elf | grep LOAD + for (int i = 0; ; i++) + { + GElf_Phdr mem; + GElf_Phdr *phdr; + phdr = gelf_getphdr (elf, i, &mem); + if (phdr == NULL) + break; + + if (phdr->p_type == PT_LOAD) + { + struct elf_hdr hdr; + hdr.memsz = phdr->p_memsz; + hdr.offset = phdr->p_offset; + hdr.vaddr = phdr->p_vaddr; + mi->hdrs.push_back(hdr); + } + } + } } // OK, enough of that module_info caching business. @@ -5610,9 +5634,19 @@ dwarf_derived_probe::dwarf_derived_probe(interned_string funcname, // inode-uprobes needs an offset rather than an absolute VM address. // ditto for userspace runtimes (dyninst) if ((kernel_supports_inode_uprobes(q.dw.sess) || q.dw.sess.runtime_usermode_p()) && - section == ".absolute" && addr == dwfl_addr && - addr >= q.dw.module_start && addr < q.dw.module_end) - this->addr = addr - q.dw.module_start; + section == ".absolute" && addr == dwfl_addr) + { + // An ELF file maybe loaded into multiple non-contiguous memory addresses, + for (auto it = q.dw.mod_info->hdrs.begin(); + it != q.dw.mod_info->hdrs.end(); ++it) + { + if (it->vaddr < addr && addr < it->vaddr + it->memsz) + { + this->addr = addr - (it->vaddr - it->offset); + break; + } + } + } } else {