Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package uftrace for openSUSE:Factory checked 
in at 2026-03-25 21:18:43
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/uftrace (Old)
 and      /work/SRC/openSUSE:Factory/.uftrace.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "uftrace"

Wed Mar 25 21:18:43 2026 rev:2 rq:1342330 version:0.19

Changes:
--------
--- /work/SRC/openSUSE:Factory/uftrace/uftrace.changes  2025-09-12 
21:11:51.597121793 +0200
+++ /work/SRC/openSUSE:Factory/.uftrace.new.8177/uftrace.changes        
2026-03-27 06:52:03.676289182 +0100
@@ -1,0 +2,11 @@
+Tue Mar 24 22:59:09 UTC 2026 - Dirk Müller <[email protected]>
+
+- update to 0.19:
+  * Add func-percentile.py script for latency percentiles (#1982)
+  * Support srcline info in the chrome dump output
+  * Convert timestamp to real time (UTC) in the chrome dump
+    output
+  * Fix segfaults on binaries built with mold linker (#1951)
+  * Update some C++ exception test cases
+
+-------------------------------------------------------------------

Old:
----
  uftrace-0.18.1.tar.gz

New:
----
  uftrace-0.19.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ uftrace.spec ++++++
--- /var/tmp/diff_new_pack.YxlUn4/_old  2026-03-27 06:52:05.560366956 +0100
+++ /var/tmp/diff_new_pack.YxlUn4/_new  2026-03-27 06:52:05.588368112 +0100
@@ -18,7 +18,7 @@
 Name:           uftrace
 Summary:        A function call graph tracer for C, C++, Rust and Python 
programs
 Group:          Development/Tools/Debuggers
-Version:        0.18.1
+Version:        0.19
 Release:        1
 License:        GPL-2.0-only
 URL:            https://github.com/namhyung/uftrace

++++++ uftrace-0.18.1.tar.gz -> uftrace-0.19.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/.clang-format 
new/uftrace-0.19/.clang-format
--- old/uftrace-0.18.1/.clang-format    2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/.clang-format      2026-03-02 06:32:16.000000000 +0100
@@ -68,6 +68,7 @@
 #   | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$,  - '\1'," \
 #   | LC_ALL=C sort -u
 ForEachMacros:
+  - 'elf_for_each_comment'
   - 'elf_for_each_dynamic'
   - 'elf_for_each_dynamic_symbol'
   - 'elf_for_each_note'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/.gitignore new/uftrace-0.19/.gitignore
--- old/uftrace-0.18.1/.gitignore       2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/.gitignore 2026-03-02 06:32:16.000000000 +0100
@@ -1,3 +1,4 @@
+*.a
 *.o
 *.op
 *.ot
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/Makefile new/uftrace-0.19/Makefile
--- old/uftrace-0.18.1/Makefile 2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/Makefile   2026-03-02 06:32:16.000000000 +0100
@@ -1,4 +1,4 @@
-VERSION := 0.18
+VERSION := 0.19
 
 # Makefiles suck: This macro sets a default value of $(2) for the
 # variable named by $(1), unless the variable has been set by
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/NEWS new/uftrace-0.19/NEWS
--- old/uftrace-0.18.1/NEWS     2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/NEWS       2026-03-02 06:32:16.000000000 +0100
@@ -1,3 +1,18 @@
+uftrace v0.19
+=============
+* New features
+  Add func-percentile.py script for latency percentiles (#1982)
+  Support srcline info in the chrome dump output
+  Convert timestamp to real time (UTC) in the chrome dump output
+
+* Bug fixes
+  Fix segfaults on binaries built with mold linker (#1951)
+  Update some C++ exception test cases
+
+And some other fixes and improvements.  Thanks all contributors:
+  Kaveh Shahedi, Kwangjin Ko, Seunghyeok Park, SoJin Jang
+
+
 uftrace v0.18
 =============
 * New features
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/check-deps/__have_libelf.c 
new/uftrace-0.19/check-deps/__have_libelf.c
--- old/uftrace-0.18.1/check-deps/__have_libelf.c       2025-07-07 
00:47:42.000000000 +0200
+++ new/uftrace-0.19/check-deps/__have_libelf.c 2026-03-02 06:32:16.000000000 
+0100
@@ -3,8 +3,14 @@
 
 int main(void)
 {
-       GElf_Ehdr ehdr;
+       Elf *elf;
 
        elf_version(EV_CURRENT);
+
+       /* check that the gelf function */
+       elf = elf_begin(0, ELF_C_READ, (Elf *)0);
+       gelf_checksum(elf);
+       elf_end(elf);
+
        return 0;
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/cmds/dump.c 
new/uftrace-0.19/cmds/dump.c
--- old/uftrace-0.18.1/cmds/dump.c      2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/cmds/dump.c        2026-03-02 06:32:16.000000000 +0100
@@ -68,6 +68,7 @@
        struct uftrace_dump_ops ops;
        unsigned lost_event_cnt;
        bool last_comma;
+       struct uftrace_opts *opts;
 };
 
 struct uftrace_flame_dump {
@@ -877,6 +878,21 @@
        char *p = name_buf;
        size_t len = sizeof(name_buf) - 1;
        size_t i;
+       struct uftrace_dbg_loc *loc = NULL;
+       uint64_t timestamp;
+       static uint64_t utc_offset_ns = 0;
+
+       /* Initialize the UTC offset */
+       if (utc_offset_ns == 0 && task->h->info.utc_offset) {
+               long offset_sec = strtol(task->h->info.utc_offset, NULL, 10);
+               utc_offset_ns = (uint64_t)offset_sec * 1000000000ULL;
+       }
+
+       timestamp = frs->time + utc_offset_ns;
+
+       if (chrome->opts && chrome->opts->srcline) {
+               loc = task_find_loc_addr(&task->h->sessions, task, frs->time, 
frs->addr);
+       }
 
        if (rec_type == UFTRACE_EVENT) {
                switch (frs->addr) {
@@ -911,44 +927,70 @@
                if (is_process) {
                        /* no need to add "tid" field */
                        pr_out("{\"ts\":%" PRIu64 
".%03d,\"ph\":\"%c\",\"pid\":%d,\"name\":\"%s\"",
-                              frs->time / 1000, (int)(frs->time % 1000), ph, 
task->tid, name_buf);
+                              timestamp / 1000, (int)(timestamp % 1000), ph, 
task->tid, name_buf);
                }
                else {
                        pr_out("{\"ts\":%" PRIu64
                               
".%03d,\"ph\":\"%c\",\"pid\":%d,\"tid\":%d,\"name\":\"%s\"",
-                              frs->time / 1000, (int)(frs->time % 1000), ph, 
task->t->pid,
+                              timestamp / 1000, (int)(timestamp % 1000), ph, 
task->t->pid,
                               task->tid, name_buf);
                }
 
-               if (frs->more && show_args) {
-                       str_mode |= NEEDS_PAREN | HAS_MORE;
-                       get_argspec_string(task, spec_buf, sizeof(spec_buf), 
str_mode);
-                       pr_out(",\"args\":{\"arguments\":\"%s\"}}", spec_buf);
+               if ((loc != NULL) || (frs->more && show_args)) {
+                       pr_out(",\"args\":{");
+
+                       if ((loc != NULL)) {
+                               pr_out("\"srcline\":\"%s:%d\"", 
loc->file->name, loc->line);
+                               if ((frs->more && show_args))
+                                       pr_out(",");
+                       }
+
+                       if ((frs->more && show_args)) {
+                               str_mode |= NEEDS_PAREN | HAS_MORE;
+                               get_argspec_string(task, spec_buf, 
sizeof(spec_buf), str_mode);
+                               pr_out("\"arguments\":\"%s\"", spec_buf);
+                       }
+
+                       pr_out("}}");
                }
-               else
+               else {
                        pr_out("}");
+               }
        }
        else if (rec_type == UFTRACE_EXIT) {
                ph = 'E';
                if (is_process) {
                        /* no need to add "tid" field */
                        pr_out("{\"ts\":%" PRIu64 
".%03d,\"ph\":\"%c\",\"pid\":%d,\"name\":\"%s\"",
-                              frs->time / 1000, (int)(frs->time % 1000), ph, 
task->tid, name_buf);
+                              timestamp / 1000, (int)(timestamp % 1000), ph, 
task->tid, name_buf);
                }
                else {
                        pr_out("{\"ts\":%" PRIu64
                               
".%03d,\"ph\":\"%c\",\"pid\":%d,\"tid\":%d,\"name\":\"%s\"",
-                              frs->time / 1000, (int)(frs->time % 1000), ph, 
task->t->pid,
+                              timestamp / 1000, (int)(timestamp % 1000), ph, 
task->t->pid,
                               task->tid, name_buf);
                }
 
-               if (frs->more && show_args) {
-                       str_mode |= IS_RETVAL | HAS_MORE;
-                       get_argspec_string(task, spec_buf, sizeof(spec_buf), 
str_mode);
-                       pr_out(",\"args\":{\"retval\":\"%s\"}}", spec_buf);
+               if ((loc != NULL) || (frs->more && show_args)) {
+                       pr_out(",\"args\":{");
+
+                       if ((loc != NULL)) {
+                               pr_out("\"srcline\":\"%s:%d\"", 
loc->file->name, loc->line);
+                               if ((frs->more && show_args))
+                                       pr_out(",");
+                       }
+
+                       if ((frs->more && show_args)) {
+                               str_mode |= IS_RETVAL | HAS_MORE;
+                               get_argspec_string(task, spec_buf, 
sizeof(spec_buf), str_mode);
+                               pr_out("\"retval\":\"%s\"", spec_buf);
+                       }
+
+                       pr_out("}}");
                }
-               else
+               else {
                        pr_out("}");
+               }
        }
        else if (rec_type == UFTRACE_LOST)
                chrome->lost_event_cnt++;
@@ -1752,6 +1794,7 @@
                                .perf_event     = dump_chrome_perf_event,
                                .footer         = dump_chrome_footer,
                        },
+                       .opts = opts,
                };
 
                do_dump_replay(&dump.ops, opts, &handle);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/cmds/info.c 
new/uftrace-0.19/cmds/info.c
--- old/uftrace-0.18.1/cmds/info.c      2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/cmds/info.c        2026-03-02 06:32:16.000000000 +0100
@@ -544,15 +544,23 @@
 
                        while (*endp != '\n') {
                                int tid = strtol(tids_str, &endp, 10);
-                               tids[nr_tid++] = tid;
-
-                               if (*endp != ',' && *endp != '\n') {
+                               if (tid && (nr_tid < info->nr_tid) &&
+                                   (*endp == ',' || *endp == '\n')) {
+                                       tids[nr_tid++] = tid;
+                               }
+                               else {
                                        free(tids);
                                        goto out;
                                }
 
                                tids_str = endp + 1;
                        }
+
+                       if (nr_tid < info->nr_tid) {
+                               free(tids);
+                               goto out;
+                       }
+
                        info->tids = tids;
 
                        ASSERT(nr_tid == info->nr_tid);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/libmcount/mcount.c 
new/uftrace-0.19/libmcount/mcount.c
--- old/uftrace-0.18.1/libmcount/mcount.c       2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/libmcount/mcount.c 2026-03-02 06:32:16.000000000 +0100
@@ -1017,12 +1017,12 @@
        if (mtdp->filter.out_count > 0)
                return FILTER_OUT;
 
-       uftrace_match_filter(child, &mcount_triggers->root, tr);
+       uftrace_match_filter(child, mcount_triggers, tr);
 
        pr_dbg3(" tr->flags: %x, filter mode: %d, count: %d/%d, depth: %d\n", 
tr->flags, tr->fmode,
                mtdp->filter.in_count, mtdp->filter.out_count, 
mtdp->filter.depth);
 
-       if (tr->flags & TRIGGER_FL_FILTER && tr->cond.idx && regs) {
+       if ((tr->flags & TRIGGER_FL_CONDITION) && regs) {
                struct mcount_arg_context ctx;
                struct uftrace_arg_spec spec = {
                        .idx = tr->cond.idx,
@@ -1336,7 +1336,7 @@
                        struct uftrace_trigger tr;
 
                        /* update args as trigger might be updated due to 
dlopen() */
-                       uftrace_match_filter(rstack->child_ip, 
&mcount_triggers->root, &tr);
+                       uftrace_match_filter(rstack->child_ip, mcount_triggers, 
&tr);
                        rstack->pargs = tr.pargs;
                }
                else {
@@ -1347,7 +1347,7 @@
                        struct uftrace_trigger tr;
 
                        /* there's a possibility of overwriting by return value 
*/
-                       uftrace_match_filter(rstack->child_ip, 
&mcount_triggers->root, &tr);
+                       uftrace_match_filter(rstack->child_ip, mcount_triggers, 
&tr);
                        save_trigger_read(mtdp, rstack, tr.read, true);
                }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/libmcount/plthook.c 
new/uftrace-0.19/libmcount/plthook.c
--- old/uftrace-0.18.1/libmcount/plthook.c      2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/libmcount/plthook.c        2026-03-02 06:32:16.000000000 
+0100
@@ -157,7 +157,7 @@
  * The `mcount` (and its friends) are part of uftrace itself,
  * so no need to use PLT hook for them.
  */
-static void restore_plt_functions(struct plthook_data *pd)
+static void restore_plt_functions(struct plthook_data *pd, unsigned long flags)
 {
        unsigned i, k;
        struct uftrace_symtab *dsymtab = &pd->dsymtab;
@@ -213,7 +213,7 @@
 
                resolved_addr = pd->pltgot_ptr[got_idx];
                plthook_addr = mcount_plthook_addr(pd, i);
-               if (resolved_addr != plthook_addr) {
+               if (resolved_addr != plthook_addr && !(flags & 
SYMTAB_FL_MOLD_PLT)) {
                        char *symname;
 
                        /* save already resolved address and hook it */
@@ -248,6 +248,7 @@
        size_t jmprel_ent_size = 0;
        struct plthook_data *pd;
        const char *fname;
+       unsigned long symtab_flags = 0;
 
        elf_for_each_shdr(elf, iter) {
                if (iter->shdr.sh_type == SHT_DYNAMIC)
@@ -296,6 +297,23 @@
                }
        }
 
+       /* MOLD linker has a different PLT format */
+       elf_for_each_shdr(elf, &sec_iter) {
+               typeof(sec_iter.shdr) *shdr = &sec_iter.shdr;
+               const char *shstr = elf_get_name(elf, &sec_iter, shdr->sh_name);
+
+               if (strcmp(shstr, ".comment"))
+                       continue;
+
+               elf_for_each_comment(elf, &sec_iter) {
+                       if (!strncmp(sec_iter.comment, "mold ", 5)) {
+                               symtab_flags |= SYMTAB_FL_MOLD_PLT;
+                               break;
+                       }
+               }
+               break;
+       }
+
        elf_for_each_shdr(elf, &sec_iter) {
                if (sec_iter.shdr.sh_type == SHT_DYNSYM) {
                        elf_get_strtab(elf, &sec_iter, sec_iter.shdr.sh_link);
@@ -365,7 +383,7 @@
 
        memset(&pd->dsymtab, 0, sizeof(pd->dsymtab));
        /* do not demangle symbol names since it might call dlsym() */
-       load_elf_dynsymtab(&pd->dsymtab, elf, pd->base_addr, 0);
+       load_elf_dynsymtab(&pd->dsymtab, elf, pd->base_addr, symtab_flags);
 
        pd->resolved_addr = xcalloc(pd->dsymtab.nr_sym, sizeof(long));
        pd->special_funcs = NULL;
@@ -395,7 +413,7 @@
                (unsigned long)pd->pltgot_ptr - pd->base_addr);
        pr_dbg2("module id = %#lx, PLT resolver = %#lx\n", pd->module_id, 
plthook_resolver_addr);
 
-       restore_plt_functions(pd);
+       restore_plt_functions(pd, symtab_flags);
 
        overwrite_pltgot(pd, ARCH_PLTGOT_RESOLVE, 
mcount_arch_ops.entry[UFT_ARCH_OPS_PLTHOOK]);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/misc/prototypes.h 
new/uftrace-0.19/misc/prototypes.h
--- old/uftrace-0.18.1/misc/prototypes.h        2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/misc/prototypes.h  2026-03-02 06:32:16.000000000 +0100
@@ -40,6 +40,7 @@
 enum uft_mmap_flag {
        MAP_SHARED      = 0x1,
        MAP_PRIVATE     = 0x2,
+       MAP_SHARED_VALIDATE = 0x3,
        MAP_FIXED       = 0x10,
        MAP_ANON        = 0x20,
        MAP_GROWSDOWN   = 0x100,
@@ -51,6 +52,8 @@
        MAP_NONBLOCK    = 0x10000,
        MAP_STACK       = 0x20000,
        MAP_HUGETLB     = 0x40000,
+       MAP_SYNC        = 0x80000,
+       MAP_FIXED_NOREPLACE = 0x100000,
 };
 void *mmap(void *addr, size_t length, enum uft_mmap_prot prot, enum 
uft_mmap_flag flags, int fd, off_t offset);
 void *mmap64(void *addr, size_t length, enum uft_mmap_prot prot, enum 
uft_mmap_flag flags, int fd, off64_t offset);
@@ -73,6 +76,14 @@
     MADV_NOHUGEPAGE  = 15,
     MADV_DONTDUMP    = 16,
     MADV_DODUMP      = 17,
+    MADV_WIPEONFORK  = 18,
+    MADV_KEEPONFORK  = 19,
+    MADV_COLD        = 20,
+    MADV_PAGEOUT     = 21,
+    MADV_POPULATE_READ   = 22,
+    MADV_POPULATE_WRITE  = 23,
+    MADV_POPULATE_LOCKED = 24,
+    MADV_COLLAPSE    = 25,
     MADV_HWPOISON    = 100,
 };
 int madvise(void *addr, size_t length, enum uft_madvise advice);
@@ -207,6 +218,7 @@
        O_CLOEXEC   = 02000000,
        O_SYNC      = 04010000,
        O_PATH      = 010000000,
+       O_TMPFILE   = 020200000,
 };
 int open(const char* pathname, enum uft_open_flag flags);
 int open64(const char* pathname, enum uft_open_flag flags);
@@ -220,6 +232,11 @@
        F_SETOWN, F_GETOWN, F_SEGSIG, F_GETSIG,
        F_GETLK64, F_SETLK64, F_SETLKW64,
        F_SETOWN_EX, F_GETOWN_EX,
+       F_SETLEASE = 1024, F_GETLEASE, F_NOTIFY,
+       F_DUPFD_CLOEXEC = 1030,
+       F_SETPIPE_SZ = 1031, F_GETPIPE_SZ, F_ADD_SEALS, F_GET_SEALS,
+       F_GET_RW_HINT = 1035, F_SET_RW_HINT,
+       F_GET_FILE_RW_HINT = 1037, F_SET_FILE_RW_HINT,
 };
 int fcntl(int fd, enum uft_fcntl_cmd);
 int fcntl64(int fd, enum uft_fcntl_cmd);
@@ -366,7 +383,7 @@
        AF_NETLINK = 16, AF_PACKET, AF_ASH, AF_ECONET, AF_ATMSVC, AF_RDS, 
AF_SNA, AF_IRDA,
        AF_PPPOX = 24, AF_WANPIPE, AF_LLC, AF_IB, AF_MPLS, AF_CAN, AF_TPIC, 
AF_BLUETOOTH,
        AF_IUCV = 32, AF_RXRPC, AF_ISDN, AF_PHONET, AF_IEEE802154, AF_CAIF, 
AF_ALG, AF_NFC,
-       AF_VSOCK = 40, AF_KCM, AF_QIPCRTR, AF_SMC,
+       AF_VSOCK = 40, AF_KCM, AF_QIPCRTR, AF_SMC, AF_XDP, AF_MCTP,
 };
 enum uft_socket_type {
        SOCK_STREAM = 1, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, SOCK_SEQPACKET, 
SOCK_DCCP,
@@ -447,6 +464,19 @@
        PR_SET_THP_DISABLE = 41, PR_GET_THP_DISABLE,
        PR_MPX_ENABLE_MANAGEMENT = 43, PR_MPX_DISABLE_MANAGEMENT,
        PR_SET_FP_MODE = 45, PR_GET_FP_MODE, PR_CAP_AMBIENT,
+       PR_SVE_SET_VL = 50, PR_SVE_GET_VL,
+       PR_GET_SPECULATION_CTRL = 52, PR_SET_SPECULATION_CTRL, 
PR_PAC_RESET_KEYS,
+       PR_SET_TAGGED_ADDR_CTRL = 55, PR_GET_TAGGED_ADDR_CTRL,
+       PR_SET_IO_FLUSHER = 57, PR_GET_IO_FLUSHER, PR_SET_SYSCALL_USER_DISPATCH,
+       PR_PAC_SET_ENABLED_KEYS = 60, PR_PAC_GET_ENABLED_KEYS, PR_SCHED_CORE,
+       PR_SME_SET_VL = 63, PR_SME_GET_VL, PR_SET_MDWE, PR_GET_MDWE,
+       PR_SET_MEMORY_MERGE = 67, PR_GET_MEMORY_MERGE,
+       PR_RISCV_V_SET_CONTROL = 69, PR_RISCV_V_GET_CONTROL, 
PR_RISCV_SET_ICACHE_FLUSH_CTX,
+       PR_PPC_GET_DEXCR = 72, PR_PPC_SET_DEXCR,
+       PR_GET_SHADOW_STACK_STATUS = 74, PR_SET_SHADOW_STACK_STATUS, 
PR_LOCK_SHADOW_STACK_STATUS,
+       PR_TIMER_CREATE_RESTORE_IDS = 77,
+       PR_GET_AUXV = 0x41555856,
+       PR_SET_VMA = 0x53564d41,
 };
 int prctl(enum uft_prctl_op option, unsigned long arg2, unsigned long arg3, 
unsigned long arg4, unsigned long arg5);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/scripts/func-percentile.py 
new/uftrace-0.19/scripts/func-percentile.py
--- old/uftrace-0.18.1/scripts/func-percentile.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/uftrace-0.19/scripts/func-percentile.py 2026-03-02 06:32:16.000000000 
+0100
@@ -0,0 +1,128 @@
+# Copyright (c) 2025 SK hynix, Inc.
+# SPDX-License-Identifier: GPL-2.0
+#
+# func-percentile.py: print P90, P95, P99 percentiles and min, avg, max of a
+# given function's total execution time
+#
+#  Usage: func-percentile.py [-- -u <unit>] <function>
+#    Unit is one of ns, us, ms, s, m, h or auto (default)
+#
+#  $ uftrace script -S scripts/func-percentile.py foobar
+#  P90:     1.052 ms
+#  P95:     1.052 ms
+#  P99:     1.053 ms
+#  MIN:     5.600 us
+#  AVG:   329.921 us
+#  MAX:     1.058 ms
+
+func = ''
+unit = 'auto'
+unit_opts = [ 'us', 'ms', 's', 'm', 'h', 'auto' ]
+durations = []
+
+RESET = "\033[0m"
+RED = "\033[91m"
+GREEN = "\033[32m"
+YELLOW = "\033[33m"
+
+unit_us = f"{RESET}us{RESET}"
+unit_ms = f"{GREEN}ms{RESET}"
+unit_s = f"{YELLOW} s{RESET}"
+unit_m = f"{RED} m{RESET}"
+unit_h = f"{RED} h{RESET}"
+units = [ unit_us, unit_ms, unit_s, unit_m, unit_h ]
+
+INT_MAX = 2**31 - 1
+limit = [ 1000, 1000, 1000, 60, 24, INT_MAX ]
+
+def time_with_unit(time_ns, selected_unit):
+    delta = time_ns
+    unit_idx = 0
+
+    for idx in range(len(limit) - 1):
+        divider = limit[idx]
+        unit_idx = idx
+        delta_small = int(delta % divider)
+        delta = int(delta / limit[idx])
+        if selected_unit is not None:
+            if idx == selected_unit:
+                break
+        elif delta < limit[idx + 1]:
+            break
+
+    return f"{delta:>5}.{delta_small:03d} {units[unit_idx]}"
+
+def percentile(data, p):
+    n = len(data)
+    index = (n - 1) * (p / 100)
+    lower = int(index)
+    upper = min(lower + 1, n - 1)
+
+    if lower == upper:
+        return data[lower]
+
+    # linear interpolation
+    return data[lower] + ((data[upper] - data[lower]) * (index - lower))
+
+def print_percentile():
+    if len(durations) == 0:
+        print("No trace")
+        return
+
+    sorted_durations = sorted(durations)
+
+    selected_unit = None
+    if unit != 'auto' and unit in unit_opts:
+        selected_unit = unit_opts.index(unit)
+
+    p90 = time_with_unit(percentile(sorted_durations, 90), selected_unit)
+    p95 = time_with_unit(percentile(sorted_durations, 95), selected_unit)
+    p99 = time_with_unit(percentile(sorted_durations, 99), selected_unit)
+    minimum = time_with_unit(sorted_durations[0], selected_unit)
+    maximum = time_with_unit(sorted_durations[-1], selected_unit)
+    avg = time_with_unit(sum(durations) / len(durations), selected_unit)
+
+    print(f"P90: {p90}")
+    print(f"P95: {p95}")
+    print(f"P99: {p99}")
+    print(f"MIN: {minimum}")
+    print(f"AVG: {avg}")
+    print(f"MAX: {maximum}")
+
+def parse_args(args):
+    global func, unit
+
+    if args[0] == '-u' or args[0] == '--unit':
+        unit = args[1]
+        func = args[2]
+    else:
+        func = args[0]
+
+#
+# uftrace interface functions
+#
+def uftrace_begin(ctx):
+    args = ctx["cmds"]
+    if len(args) == 0:
+        print("Usage: func-percentile.py [-- -u <unit>] <function>")
+        print("  Unit is one of ns, us, ms, s, m, h or auto (dufault)")
+        return
+    parse_args(ctx["cmds"])
+    if unit not in unit_opts:
+        print(f"WARN: invalid unit: {unit}. fallback to default unit: auto.")
+        return
+
+def uftrace_entry(ctx):
+    pass
+
+def uftrace_exit(ctx):
+    if ctx["name"] != func:
+        return
+    if "duration" not in ctx:
+        return
+
+    duration = int(ctx["duration"])
+    durations.append(duration)
+
+def uftrace_end():
+    print_percentile()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/tests/t124_exception1.py 
new/uftrace-0.19/tests/t124_exception1.py
--- old/uftrace-0.18.1/tests/t124_exception1.py 2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/tests/t124_exception1.py   2026-03-02 06:32:16.000000000 
+0100
@@ -26,11 +26,5 @@
 """)
 
     def setup(self):
-        self.option = '-N personality_v.'
-
-    def fixup(self, cflags, result):
-        r = result.replace("} /* oops */", """} /* oops */
-   0.088 us [10827] |     std::exception::~exception();""")
-        r = r.replace("} /* main */", """} /* main */
- 108.818 us [10827] | std::ios_base::Init::~Init();""")
-        return r
+        # Destructors are non-deterministric, let's skip them.
+        self.option = '-N personality_v. -N "~Init$" -N "~exception$"'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/tests/t251_exception4.py 
new/uftrace-0.19/tests/t251_exception4.py
--- old/uftrace-0.18.1/tests/t251_exception4.py 2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/tests/t251_exception4.py   2026-03-02 06:32:16.000000000 
+0100
@@ -23,6 +23,6 @@
         return TestBase.build_libmain(self, name, 's-libexcept-main.cpp', 
['libexcept.so'],
                                       cflags, ldflags)
 
-    def fixup(self, cflags, result):
-        return result.replace("""   6.353 us [423633] |   
std::runtime_error:~runtime_error();
-""", '')
+    def setup(self):
+        # Destructor is non-deterministric, let's skip it.
+        self.option = '-N "~runtime_error$"'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/tests/t297_plt_mold.py 
new/uftrace-0.19/tests/t297_plt_mold.py
--- old/uftrace-0.18.1/tests/t297_plt_mold.py   1970-01-01 01:00:00.000000000 
+0100
+++ new/uftrace-0.19/tests/t297_plt_mold.py     2026-03-02 06:32:16.000000000 
+0100
@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+
+import shutil
+
+from runtest import TestBase
+
+class TestCase(TestBase):
+    def __init__(self):
+        TestBase.__init__(self, 'pltarg', result="""
+# DURATION     TID     FUNCTION
+   1.237 us [ 203479] | __monstartup();
+   0.897 us [ 203479] | __cxa_atexit();
+            [ 203479] | main() {
+   4.886 us [ 203479] |   getenv();
+   2.139 us [ 203479] |   malloc();
+   1.017 us [ 203479] |   free();
+  12.233 us [ 203479] | } /* main */
+""")
+
+    def build(self, name, cflags='', ldflags=''):
+        # test only if 'mold' linker is available
+        if shutil.which('mold') is None:
+            return TestBase.TEST_SKIP
+
+        ldflags += " -fuse-ld=mold"
+        return TestBase.build(self, name, cflags, ldflags)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/uftrace.h new/uftrace-0.19/uftrace.h
--- old/uftrace-0.18.1/uftrace.h        2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/uftrace.h  2026-03-02 06:32:16.000000000 +0100
@@ -365,8 +365,8 @@
        uint64_t start_time;
        int pid, tid;
        struct uftrace_sym_info sym_info;
-       struct rb_root filters;
-       struct rb_root fixups;
+       struct uftrace_triggers_info filter_info;
+       struct uftrace_triggers_info fixups;
        struct list_head dlopen_libs;
        int namelen;
        char exename[];
@@ -383,7 +383,7 @@
        uint64_t time;
        unsigned long base;
        struct uftrace_module *mod;
-       struct rb_root filters;
+       struct uftrace_triggers_info filter_info;
 };
 
 struct uftrace_task {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/auto-args.h 
new/uftrace-0.19/utils/auto-args.h
--- old/uftrace-0.18.1/utils/auto-args.h        2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/utils/auto-args.h  2026-03-02 06:32:16.000000000 +0100
@@ -8,22 +8,22 @@
 
 static char *auto_enum_list =
        "enum uft_mmap_prot { PROT_NONE, PROT_READ, PROT_WRITE, PROT_EXEC = 4, 
};"
-       "enum uft_mmap_flag {MAP_SHARED = 0x1,MAP_PRIVATE = 0x2,MAP_FIXED = 
0x10,MAP_ANON = 0x20,MAP_GROWSDOWN = 0x100,MAP_DENYWRITE = 0x800,MAP_EXECUTABLE 
= 0x1000,MAP_LOCKED = 0x2000,MAP_NORESERVE = 0x4000,MAP_POPULATE = 
0x8000,MAP_NONBLOCK = 0x10000,MAP_STACK = 0x20000,MAP_HUGETLB = 0x40000,};"
-       "enum uft_madvise {MADV_NORMAL = 0,MADV_RANDOM = 1,MADV_SEQUENTIAL = 
2,MADV_WILLNEED = 3,MADV_DONTNEED = 4,MADV_FREE = 8,MADV_REMOVE = 
9,MADV_DONTFORK = 10,MADV_DOFORK = 11,MADV_MERGEABLE = 12,MADV_UNMERGEABLE = 
13,MADV_HUGEPAGE = 14,MADV_NOHUGEPAGE = 15,MADV_DONTDUMP = 16,MADV_DODUMP = 
17,MADV_HWPOISON = 100,};"
+       "enum uft_mmap_flag {MAP_SHARED = 0x1,MAP_PRIVATE = 
0x2,MAP_SHARED_VALIDATE = 0x3,MAP_FIXED = 0x10,MAP_ANON = 0x20,MAP_GROWSDOWN = 
0x100,MAP_DENYWRITE = 0x800,MAP_EXECUTABLE = 0x1000,MAP_LOCKED = 
0x2000,MAP_NORESERVE = 0x4000,MAP_POPULATE = 0x8000,MAP_NONBLOCK = 
0x10000,MAP_STACK = 0x20000,MAP_HUGETLB = 0x40000,MAP_SYNC = 
0x80000,MAP_FIXED_NOREPLACE = 0x100000,};"
+       "enum uft_madvise {MADV_NORMAL = 0,MADV_RANDOM = 1,MADV_SEQUENTIAL = 
2,MADV_WILLNEED = 3,MADV_DONTNEED = 4,MADV_FREE = 8,MADV_REMOVE = 
9,MADV_DONTFORK = 10,MADV_DOFORK = 11,MADV_MERGEABLE = 12,MADV_UNMERGEABLE = 
13,MADV_HUGEPAGE = 14,MADV_NOHUGEPAGE = 15,MADV_DONTDUMP = 16,MADV_DODUMP = 
17,MADV_WIPEONFORK = 18,MADV_KEEPONFORK = 19,MADV_COLD = 20,MADV_PAGEOUT = 
21,MADV_POPULATE_READ = 22,MADV_POPULATE_WRITE = 23,MADV_POPULATE_LOCKED = 
24,MADV_COLLAPSE = 25,MADV_HWPOISON = 100,};"
        "enum uft_posix_madvise {POSIX_MADV_NORMAL = 0,POSIX_MADV_RANDOM = 
1,POSIX_MADV_SEQUENTIAL = 2,POSIX_MADV_WILLNEED = 3,POSIX_MADV_DONTNEED = 4,};"
        "enum uft_posix_fadvise {POSIX_FADV_NORMAL = 0,POSIX_FADV_RANDOM = 
1,POSIX_FADV_SEQUENTIAL = 2,POSIX_FADV_WILLNEED = 3,POSIX_FADV_DONTNEED = 
4,POSIX_FADV_NOREUSE = 5,};"
-       "enum uft_open_flag {O_RDONLY = 00,O_WRONLY = 01,O_RDWR = 02,O_CREAT = 
0100,O_EXCL = 0200,O_NOCTTY = 0400,O_TRUNC = 01000,O_APPEND = 02000,O_NONBLOCK 
= 04000,O_DSYNC = 010000,O_ASYNC = 020000,O_DIRECT = 040000,O_LARGEFILE = 
0100000,O_DIRECTORY = 0200000,O_NOFOLLOW = 0400000,O_NOATIME = 
01000000,O_CLOEXEC = 02000000,O_SYNC = 04010000,O_PATH = 010000000,};"
-       "enum uft_fcntl_cmd {F_DUPFD, F_GETFD, F_SETFD, F_GETFL, 
F_SETFL,F_GETLK, F_SETLK, F_SETLKW,F_SETOWN, F_GETOWN, F_SEGSIG, 
F_GETSIG,F_GETLK64, F_SETLK64, F_SETLKW64,F_SETOWN_EX, F_GETOWN_EX,};"
+       "enum uft_open_flag {O_RDONLY = 00,O_WRONLY = 01,O_RDWR = 02,O_CREAT = 
0100,O_EXCL = 0200,O_NOCTTY = 0400,O_TRUNC = 01000,O_APPEND = 02000,O_NONBLOCK 
= 04000,O_DSYNC = 010000,O_ASYNC = 020000,O_DIRECT = 040000,O_LARGEFILE = 
0100000,O_DIRECTORY = 0200000,O_NOFOLLOW = 0400000,O_NOATIME = 
01000000,O_CLOEXEC = 02000000,O_SYNC = 04010000,O_PATH = 010000000,O_TMPFILE = 
020200000,};"
+       "enum uft_fcntl_cmd {F_DUPFD, F_GETFD, F_SETFD, F_GETFL, 
F_SETFL,F_GETLK, F_SETLK, F_SETLKW,F_SETOWN, F_GETOWN, F_SEGSIG, 
F_GETSIG,F_GETLK64, F_SETLK64, F_SETLKW64,F_SETOWN_EX, F_GETOWN_EX,F_SETLEASE = 
1024, F_GETLEASE, F_NOTIFY,F_DUPFD_CLOEXEC = 1030,F_SETPIPE_SZ = 1031, 
F_GETPIPE_SZ, F_ADD_SEALS, F_GET_SEALS,F_GET_RW_HINT = 1035, 
F_SET_RW_HINT,F_GET_FILE_RW_HINT = 1037, F_SET_FILE_RW_HINT,};"
        "enum uft_seek_whence { SEEK_SET, SEEK_CUR, SEEK_END, SEEK_DATA, 
SEEK_HOLE, };"
        "enum uft_falloc_mde {FALLOC_FL_KEEP_SIZE = 1,FALLOC_FL_PUNCH_HOLE = 
2,FALLOC_FL_NO_HIDE_STALE = 4,FALLOC_FL_COLLAPSE_RANGE = 8,FALLOC_FL_ZERO_RANGE 
= 16,FALLOC_FL_INSERT_RANGE = 32,FALLOC_FL_UNSHARE_RANGE = 64,};"
        "enum uft_access_flag {F_OK = 0, X_OK = 1, W_OK = 2, R_OK = 4,};"
        "enum uft_dlopen_flag {RTLD_LOCAL = 0,RTLD_LAZY = 1,RTLD_NOW = 
2,RTLD_NOLOAD = 4,RTLD_DEEPBIND = 8,RTLD_GLOBAL = 0x100,RTLD_NODELETE = 
0x1000,};"
-       "enum uft_socket_domain {AF_UNSPEC = 0, AF_UNIX, AF_INET, AF_AX25, 
AF_IPX, AF_APPLETALK, AF_NETROM, AF_BRIDGE,AF_ATMPVC = 8, AF_X25, AF_INET6, 
AF_ROSE, AF_DECnet, AF_NETBEUI, AF_SECURITY, AF_KEY,AF_NETLINK = 16, AF_PACKET, 
AF_ASH, AF_ECONET, AF_ATMSVC, AF_RDS, AF_SNA, AF_IRDA,AF_PPPOX = 24, 
AF_WANPIPE, AF_LLC, AF_IB, AF_MPLS, AF_CAN, AF_TPIC, AF_BLUETOOTH,AF_IUCV = 32, 
AF_RXRPC, AF_ISDN, AF_PHONET, AF_IEEE802154, AF_CAIF, AF_ALG, AF_NFC,AF_VSOCK = 
40, AF_KCM, AF_QIPCRTR, AF_SMC,};"
+       "enum uft_socket_domain {AF_UNSPEC = 0, AF_UNIX, AF_INET, AF_AX25, 
AF_IPX, AF_APPLETALK, AF_NETROM, AF_BRIDGE,AF_ATMPVC = 8, AF_X25, AF_INET6, 
AF_ROSE, AF_DECnet, AF_NETBEUI, AF_SECURITY, AF_KEY,AF_NETLINK = 16, AF_PACKET, 
AF_ASH, AF_ECONET, AF_ATMSVC, AF_RDS, AF_SNA, AF_IRDA,AF_PPPOX = 24, 
AF_WANPIPE, AF_LLC, AF_IB, AF_MPLS, AF_CAN, AF_TPIC, AF_BLUETOOTH,AF_IUCV = 32, 
AF_RXRPC, AF_ISDN, AF_PHONET, AF_IEEE802154, AF_CAIF, AF_ALG, AF_NFC,AF_VSOCK = 
40, AF_KCM, AF_QIPCRTR, AF_SMC, AF_XDP, AF_MCTP,};"
        "enum uft_socket_type {SOCK_STREAM = 1, SOCK_DGRAM, SOCK_RAW, SOCK_RDM, 
SOCK_SEQPACKET, SOCK_DCCP,SOCK_PACKET = 10,SOCK_NONBLOCK = 04000, SOCK_CLOEXEC 
= 02000000,};"
        "enum uft_socket_flag {SOCK_NONBLOCK = 04000, SOCK_CLOEXEC = 
02000000,};"
        "enum uft_signal {SIGNULL = 0, SIGHUP, SIGINT, SIGQUIT, SIGILL, 
SIGTRAP, SIGABRT, SIGBUS, SIGFPE,SIGKILL = 9, SIGUSR1, SIGSEGV, SIGUSR2, 
SIGPIPE, SIGALRM, SIGTERM, SIGSTKFLT,SIGCHLD = 17, SIGCONT, SIGSTOP, SIGTSTP, 
SIGTTIN, SIGTTOU, SIGURG, SIGXCPU,SIGXFSZ = 25, SIGVTALRM, SIGPROF, SIGWINCH, 
SIGPOLL, SIGPWR, SIGSYS,SIGRTMIN = 32, SIGRTMAX = 64,};"
        "enum uft_sigmask { SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK };"
-       "enum uft_prctl_op {PR_SET_PDEATHSIG = 1, PR_GET_PDEATHSIG, 
PR_GET_DUMPABLE, PR_SET_DUMPABLE,PR_GET_UNALIGN = 5, PR_SET_UNALIGN, 
PR_GET_KEEPCAPS, PR_SET_KEEPCAPS,PR_GET_FPEMU = 9, PR_SET_FPEMU, PR_GET_FPEXC, 
PR_SET_FPEXC,PR_GET_TIMING = 13, PR_SET_TIMING, PR_SET_NAME, 
PR_GET_NAME,PR_GET_ENDIAN = 19, PR_SET_ENDIAN, PR_GET_SECCOMP, 
PR_SET_SECCOMP,PR_CAPBSET_READ = 23, PR_CAPBSET_DROP, PR_GET_TSC, 
PR_SET_TSC,PR_GET_SECUREBITS = 27, PR_SET_SECUREBITS, PR_SET_TIMERSLACK, 
PR_GET_TIMERSLACK,PR_TASK_PERF_EVENTS_DISABLE = 31, 
PR_TASK_PERF_EVENTS_ENABLE,PR_MCE_KILL = 33, PR_MCE_KILL_GET, 
PR_SET_MM,PR_SET_CHILD_SUBREAPER = 36, 
PR_GET_CHILD_SUBREAPER,PR_SET_NO_NEW_PRIVS = 38, PR_GET_NO_NEW_PRIVS, 
PR_GET_TID_ADDRESS,PR_SET_THP_DISABLE = 41, 
PR_GET_THP_DISABLE,PR_MPX_ENABLE_MANAGEMENT = 43, 
PR_MPX_DISABLE_MANAGEMENT,PR_SET_FP_MODE = 45, PR_GET_FP_MODE, 
PR_CAP_AMBIENT,};"
+       "enum uft_prctl_op {PR_SET_PDEATHSIG = 1, PR_GET_PDEATHSIG, 
PR_GET_DUMPABLE, PR_SET_DUMPABLE,PR_GET_UNALIGN = 5, PR_SET_UNALIGN, 
PR_GET_KEEPCAPS, PR_SET_KEEPCAPS,PR_GET_FPEMU = 9, PR_SET_FPEMU, PR_GET_FPEXC, 
PR_SET_FPEXC,PR_GET_TIMING = 13, PR_SET_TIMING, PR_SET_NAME, 
PR_GET_NAME,PR_GET_ENDIAN = 19, PR_SET_ENDIAN, PR_GET_SECCOMP, 
PR_SET_SECCOMP,PR_CAPBSET_READ = 23, PR_CAPBSET_DROP, PR_GET_TSC, 
PR_SET_TSC,PR_GET_SECUREBITS = 27, PR_SET_SECUREBITS, PR_SET_TIMERSLACK, 
PR_GET_TIMERSLACK,PR_TASK_PERF_EVENTS_DISABLE = 31, 
PR_TASK_PERF_EVENTS_ENABLE,PR_MCE_KILL = 33, PR_MCE_KILL_GET, 
PR_SET_MM,PR_SET_CHILD_SUBREAPER = 36, 
PR_GET_CHILD_SUBREAPER,PR_SET_NO_NEW_PRIVS = 38, PR_GET_NO_NEW_PRIVS, 
PR_GET_TID_ADDRESS,PR_SET_THP_DISABLE = 41, 
PR_GET_THP_DISABLE,PR_MPX_ENABLE_MANAGEMENT = 43, 
PR_MPX_DISABLE_MANAGEMENT,PR_SET_FP_MODE = 45, PR_GET_FP_MODE, 
PR_CAP_AMBIENT,PR_SVE_SET_VL = 50, PR_SVE_GET_VL,PR_GET_SPECULATION_CTRL = 52, 
PR_SET_SPECULATION_CTRL, PR_PAC_RESET_KEYS,PR_SET_TAGGED_ADDR_CTRL
  = 55, PR_GET_TAGGED_ADDR_CTRL,PR_SET_IO_FLUSHER = 57, PR_GET_IO_FLUSHER, 
PR_SET_SYSCALL_USER_DISPATCH,PR_PAC_SET_ENABLED_KEYS = 60, 
PR_PAC_GET_ENABLED_KEYS, PR_SCHED_CORE,PR_SME_SET_VL = 63, PR_SME_GET_VL, 
PR_SET_MDWE, PR_GET_MDWE,PR_SET_MEMORY_MERGE = 67, 
PR_GET_MEMORY_MERGE,PR_RISCV_V_SET_CONTROL = 69, PR_RISCV_V_GET_CONTROL, 
PR_RISCV_SET_ICACHE_FLUSH_CTX,PR_PPC_GET_DEXCR = 72, 
PR_PPC_SET_DEXCR,PR_GET_SHADOW_STACK_STATUS = 74, PR_SET_SHADOW_STACK_STATUS, 
PR_LOCK_SHADOW_STACK_STATUS,PR_TIMER_CREATE_RESTORE_IDS = 77,PR_GET_AUXV = 
0x41555856,PR_SET_VMA = 0x53564d41,};"
        "enum uft_epoll_op { EPOLL_CTL_ADD = 1, EPOLL_CTL_DEL, EPOLL_CTL_MOD };"
        "enum uft_locale {LC_TYPE = 0, LC_NUMERIC, LC_TIME, LC_COLLATE, 
LC_MONETARY, LC_MESSAGES,LC_ALL, LC_PAPER, LC_NAME, LC_ADDRESS, LC_TELEPHONE, 
LC_MEASUREMENT,LC_IDENTIFICATION,};"
        "enum uft_clockid_t {CLOCK_REALTIME = 
0,CLOCK_MONOTONIC,CLOCK_PROCESS_CPUTIME_ID,CLOCK_THREAD_CPUTIME_ID,CLOCK_MONOTONIC_RAW,CLOCK_REALTIME_COARSE,CLOCK_MONOTONIC_COARSE,CLOCK_BOOTTIME,CLOCK_REALTIME_ALARM,CLOCK_BOOTTIME_ALARM,CLOCK_TAI
 = 11,};"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/filter.c 
new/uftrace-0.19/utils/filter.c
--- old/uftrace-0.18.1/utils/filter.c   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/filter.c     2026-03-02 06:32:16.000000000 +0100
@@ -55,7 +55,7 @@
                else if (tr->fmode == FILTER_MODE_OUT)
                        pr_dbg("\ttrigger: filter OUT");
 
-               if (tr->cond.idx) {
+               if (tr->flags & TRIGGER_FL_CONDITION) {
                        char buf[64];
 
                        snprintf_trigger_cond(buf, sizeof(buf), &tr->cond);
@@ -124,16 +124,16 @@
 
 /**
  * uftrace_count_filter - count matching filters in @root
- * @root - root of rbtree which has filters
+ * @filters - filter information
  * @flag - filter flag to match
  */
-int uftrace_count_filter(struct rb_root *root, unsigned long flag)
+int uftrace_count_filter(struct uftrace_triggers_info *filters, unsigned long 
flag)
 {
        struct rb_node *entry;
        struct uftrace_filter *iter;
        int count = 0;
 
-       entry = rb_first(root);
+       entry = rb_first(&filters->root);
        while (entry) {
                iter = rb_entry(entry, struct uftrace_filter, node);
 
@@ -153,14 +153,14 @@
 /**
  * uftrace_match_filter - try to match @ip with filters in @root
  * @addr - instruction address to match
- * @root - root of rbtree which has filters
+ * @filters - filter information
  * @tr   - trigger data
  */
-struct uftrace_filter *uftrace_match_filter(uint64_t addr, struct rb_root 
*root,
+struct uftrace_filter *uftrace_match_filter(uint64_t addr, struct 
uftrace_triggers_info *filters,
                                            struct uftrace_trigger *tr)
 {
        struct rb_node *parent = NULL;
-       struct rb_node **p = &root->rb_node;
+       struct rb_node **p = &filters->root.rb_node;
        struct uftrace_filter *iter;
 
        while (*p) {
@@ -272,16 +272,19 @@
                filter->trigger.flags &= ~tr->clear_flags;
                if (tr->clear_flags & TRIGGER_FL_FILTER) {
                        tr->fmode = filter->trigger.fmode; /* read from tree 
before deleting */
-                       memset(&filter->trigger.cond, 0, sizeof(tr->cond));
+                       /* updating filter also updates condition */
+                       tr->clear_flags |= TRIGGER_FL_CONDITION;
                }
+               if (tr->clear_flags & TRIGGER_FL_CONDITION)
+                       memset(&filter->trigger.cond, 0, sizeof(tr->cond));
        }
 
        if (tr->flags & TRIGGER_FL_DEPTH)
                filter->trigger.depth = tr->depth;
-       if (tr->flags & TRIGGER_FL_FILTER) {
+       if (tr->flags & TRIGGER_FL_FILTER)
                filter->trigger.fmode = tr->fmode;
+       if (tr->flags & TRIGGER_FL_CONDITION)
                memcpy(&filter->trigger.cond, &tr->cond, sizeof(tr->cond));
-       }
        if (tr->flags & TRIGGER_FL_LOC)
                filter->trigger.lmode = tr->lmode;
 
@@ -830,6 +833,7 @@
        tr->cond.idx = idx;
        tr->cond.op = op;
        tr->cond.val = val;
+       tr->flags |= TRIGGER_FL_CONDITION;
 
        return 0;
 }
@@ -884,6 +888,8 @@
                        tr->clear_flags |= TRIGGER_FL_BACKTRACE;
                else if (!strcmp(pos, "recover"))
                        tr->clear_flags |= TRIGGER_FL_RECOVER;
+               else if (!strcmp(pos, "if"))
+                       tr->clear_flags |= TRIGGER_FL_CONDITION;
                else
                        pr_use("skipping invalid clear argument: %s\n", pos);
        }
@@ -1106,7 +1112,7 @@
  * @flags      - trigger flags to apply
  * @setting    - filter settings
  */
-static void setup_trigger(char *filter_str, struct uftrace_sym_info *sinfo,
+static void setup_trigger(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                          struct uftrace_triggers_info *triggers, unsigned long 
flags,
                          struct uftrace_filter_setting *setting)
 {
@@ -1242,11 +1248,10 @@
  * uftrace_setup_filter - construct rbtree of filters
  * @filter_str - CSV of filter string
  * @sinfo      - symbol information to find symbol address
- * @root       - root of filters rbtree
- * @count      - opt-in filter count
+ * @triggers   - root of filters rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_filter(char *filter_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                          struct uftrace_triggers_info *triggers,
                          struct uftrace_filter_setting *setting)
 {
@@ -1257,11 +1262,10 @@
  * uftrace_setup_trigger - construct rbtree of triggers
  * @trigger_str - CSV of trigger string (FUNC @ act)
  * @sinfo       - symbol information to find symbol address
- * @root        - root of resulting rbtree
- * @count       - registered opt-in filter count
+ * @triggers    - root of resulting rbtree
  * @setting     - filter settings
  */
-void uftrace_setup_trigger(char *trigger_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_trigger(const char *trigger_str, struct uftrace_sym_info 
*sinfo,
                           struct uftrace_triggers_info *triggers,
                           struct uftrace_filter_setting *setting)
 {
@@ -1272,10 +1276,10 @@
  * uftrace_setup_argument - construct rbtree of argument
  * @args_str   - CSV of argument string (FUNC @ arg)
  * @sinfo      - symbol information to find symbol address
- * @root       - root of resulting rbtree
+ * @triggers   - root of resulting rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_argument(char *args_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_argument(const char *args_str, struct uftrace_sym_info 
*sinfo,
                            struct uftrace_triggers_info *triggers,
                            struct uftrace_filter_setting *setting)
 {
@@ -1291,10 +1295,10 @@
  * uftrace_setup_retval - construct rbtree of retval
  * @retval_str - CSV of return value string (FUNC @ arg)
  * @sinfo      - symbol information to find symbol address
- * @root       - root of resulting rbtree
+ * @triggers   - root of resulting rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_retval(char *retval_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_retval(const char *retval_str, struct uftrace_sym_info 
*sinfo,
                          struct uftrace_triggers_info *triggers,
                          struct uftrace_filter_setting *setting)
 {
@@ -1310,11 +1314,10 @@
  * uftrace_setup_caller_filter - add caller filters to rbtree
  * @filter_str - CSV of filter string
  * @sinfo      - symbol information to find symbol address
- * @root       - root of resulting rbtree
- * @count      - counter for registered caller filters
+ * @triggers   - root of resulting rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_caller_filter(char *filter_str, struct uftrace_sym_info 
*sinfo,
+void uftrace_setup_caller_filter(const char *filter_str, struct 
uftrace_sym_info *sinfo,
                                 struct uftrace_triggers_info *triggers,
                                 struct uftrace_filter_setting *setting)
 {
@@ -1325,10 +1328,10 @@
  * uftrace_setup_hide_filter - add hide filters to rbtree
  * @filter_str - CSV of filter string
  * @sinfo      - symbol information to find symbol address
- * @root       - root of resulting rbtree
+ * @triggers   - root of resulting rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_hide_filter(char *filter_str, struct uftrace_sym_info 
*sinfo,
+void uftrace_setup_hide_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                               struct uftrace_triggers_info *triggers,
                               struct uftrace_filter_setting *setting)
 {
@@ -1339,11 +1342,10 @@
  * uftrace_setup_loc_filter - add source location filters to rbtree
  * @filter_str - CSV of filter string
  * @sinfo      - symbol information to find symbol address
- * @root       - root of resulting rbtree
- * @count      - opt-in loc filter count
+ * @triggers   - root of resulting rbtree
  * @setting    - filter settings
  */
-void uftrace_setup_loc_filter(char *filter_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_loc_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                              struct uftrace_triggers_info *triggers,
                              struct uftrace_filter_setting *setting)
 {
@@ -1427,10 +1429,11 @@
 
 /**
  * uftrace_cleanup_filter - delete filters in rbtree
- * @root - root of the filter rbtree
+ * @filters - filter information
  */
-void uftrace_cleanup_filter(struct rb_root *root)
+void uftrace_cleanup_filter(struct uftrace_triggers_info *filters)
 {
+       struct rb_root *root = &filters->root;
        struct rb_node *node;
        struct uftrace_filter *filter;
        struct uftrace_arg_spec *arg, *tmp;
@@ -1455,7 +1458,7 @@
  */
 void uftrace_cleanup_triggers(struct uftrace_triggers_info *triggers)
 {
-       uftrace_cleanup_filter(&triggers->root);
+       uftrace_cleanup_filter(triggers);
        triggers->filter_count = 0;
        triggers->caller_count = 0;
        triggers->loc_count = 0;
@@ -1463,14 +1466,14 @@
 
 /**
  * uftrace_print_filter - print all filters in rbtree
- * @root - root of the filter rbtree
+ * @filters - filter information
  */
-void uftrace_print_filter(struct rb_root *root)
+void uftrace_print_filter(struct uftrace_triggers_info *filters)
 {
        struct rb_node *node;
        struct uftrace_filter *filter;
 
-       node = rb_first(root);
+       node = rb_first(&filters->root);
        while (node) {
                filter = rb_entry(node, struct uftrace_filter, node);
                pr_dbg("%lx-%lx: %s\n", filter->start, filter->end, 
filter->name);
@@ -1572,7 +1575,7 @@
        TEST_EQ(filter->start, 0x2000UL);
        TEST_EQ(filter->end, 0x2000UL + 0x1000UL);
 
-       uftrace_cleanup_filter(&triggers.root);
+       uftrace_cleanup_filter(&triggers);
        TEST_EQ(RB_EMPTY_ROOT(&triggers.root), true);
 
        pr_dbg("checking destructor match\n");
@@ -1768,22 +1771,22 @@
 
        pr_dbg("check addresses inside the symbol\n");
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x1000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x1000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_IN);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x1fff, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x1fff, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_IN);
 
        pr_dbg("addresses out of the symbol should not have FILTER flags\n");
        memset(&tr, 0, sizeof(tr));
-       TEST_EQ(uftrace_match_filter(0xfff, &triggers.root, &tr), NULL);
+       TEST_EQ(uftrace_match_filter(0xfff, &triggers, &tr), NULL);
        TEST_NE(tr.flags, TRIGGER_FL_FILTER);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_EQ(uftrace_match_filter(0x2000, &triggers.root, &tr), NULL);
+       TEST_EQ(uftrace_match_filter(0x2000, &triggers, &tr), NULL);
        TEST_NE(tr.flags, TRIGGER_FL_FILTER);
 
        uftrace_cleanup_triggers(&triggers);
@@ -1813,33 +1816,33 @@
        TEST_EQ(RB_EMPTY_ROOT(&triggers.root), false);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2500, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2500, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_DEPTH);
        TEST_EQ(tr.depth, 2);
 
        pr_dbg("checking backtrace trigger\n");
        uftrace_setup_trigger("foo::bar@backtrace", &sinfo, &triggers, 
&setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2500, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2500, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_DEPTH | TRIGGER_FL_BACKTRACE);
 
        pr_dbg("checking trace-on trigger\n");
        uftrace_setup_trigger("foo::baz1@traceon", &sinfo, &triggers, &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x3000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x3000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_TRACE_ON);
 
        pr_dbg("checking trace-off trigger and overwrite the depth\n");
        uftrace_setup_trigger("foo::baz3@trace_off,depth=1", &sinfo, &triggers, 
&setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x5000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x5000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_TRACE_OFF | TRIGGER_FL_DEPTH);
        TEST_EQ(tr.depth, 1);
 
        pr_dbg("checking caller trigger\n");
        uftrace_setup_trigger("foo::baz2@caller", &sinfo, &triggers, &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x4200, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x4200, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_CALLER);
 
        uftrace_cleanup_triggers(&triggers);
@@ -1871,7 +1874,7 @@
        TEST_EQ(get_filter_mode(triggers.filter_count), FILTER_MODE_OUT);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2500, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2500, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_DEPTH | TRIGGER_FL_FILTER);
        TEST_EQ(tr.depth, 2);
        TEST_EQ(tr.fmode, FILTER_MODE_OUT);
@@ -1881,7 +1884,7 @@
        TEST_EQ(get_filter_mode(triggers.filter_count), FILTER_MODE_IN);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x3000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x3000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_IN);
 
@@ -1889,14 +1892,14 @@
        TEST_EQ(get_filter_mode(triggers.filter_count), FILTER_MODE_IN);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x4100, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x4100, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_OUT);
 
        pr_dbg("check caller filter setting\n");
        uftrace_setup_caller_filter("foo::baz3", &sinfo, &triggers, &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x5000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x5000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_CALLER);
 
        uftrace_cleanup_triggers(&triggers);
@@ -1928,7 +1931,7 @@
        uftrace_setup_filter("foo::b*", &sinfo, &orig, &setting);
        pr_dbg("checking filter deep copy\n");
        copy = uftrace_deep_copy_triggers(&orig);
-       uftrace_cleanup_filter(&orig.root);
+       uftrace_cleanup_filter(&orig);
 
        TEST_EQ(RB_EMPTY_ROOT(&copy.root), false);
 
@@ -1956,7 +1959,7 @@
        TEST_EQ(filter->start, 0x5000UL);
        TEST_EQ(filter->end, 0x5000UL + 0x1000UL);
 
-       uftrace_cleanup_filter(&copy.root);
+       uftrace_cleanup_filter(&copy);
        TEST_EQ(RB_EMPTY_ROOT(&copy.root), true);
 
        return TEST_OK;
@@ -1986,14 +1989,14 @@
        TEST_EQ(RB_EMPTY_ROOT(&triggers.root), false);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2500, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2500, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_ARGUMENT);
        TEST_NE(tr.pargs, NULL);
 
        pr_dbg("compare argument setting via trigger\n");
        uftrace_setup_trigger("foo::bar@arg2/s", &sinfo, &triggers, &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2500, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2500, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_ARGUMENT);
        TEST_NE(tr.pargs, NULL);
 
@@ -2019,7 +2022,7 @@
        uftrace_setup_argument("foo::baz1@arg1/i32,arg2/x64,fparg1/32,fparg2", 
&sinfo, &triggers,
                               &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x3999, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x3999, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_ARGUMENT);
 
        count = 0;
@@ -2064,7 +2067,7 @@
        
uftrace_setup_trigger("foo::baz2@arg1/c,arg2/x32%rdi,arg3%stack+4,retval/f64", 
&sinfo,
                              &triggers, &setting);
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x4000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x4000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_ARGUMENT | TRIGGER_FL_RETVAL);
 
        count = 0;
@@ -2641,22 +2644,22 @@
 
        pr_dbg("check addresses inside the symbol\n");
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2000, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2000, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_IN);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_NE(uftrace_match_filter(0x2fff, &triggers.root, &tr), NULL);
+       TEST_NE(uftrace_match_filter(0x2fff, &triggers, &tr), NULL);
        TEST_EQ(tr.flags, TRIGGER_FL_FILTER);
        TEST_EQ(tr.fmode, FILTER_MODE_IN);
 
        pr_dbg("addresses out of the symbol should not have FILTER flags\n");
        memset(&tr, 0, sizeof(tr));
-       TEST_EQ(uftrace_match_filter(0x1fff, &triggers.root, &tr), NULL);
+       TEST_EQ(uftrace_match_filter(0x1fff, &triggers, &tr), NULL);
        TEST_NE(tr.flags, TRIGGER_FL_FILTER);
 
        memset(&tr, 0, sizeof(tr));
-       TEST_EQ(uftrace_match_filter(0xa000, &triggers.root, &tr), NULL);
+       TEST_EQ(uftrace_match_filter(0xa000, &triggers, &tr), NULL);
        TEST_NE(tr.flags, TRIGGER_FL_FILTER);
 
        uftrace_cleanup_triggers(&triggers);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/filter.h 
new/uftrace-0.19/utils/filter.h
--- old/uftrace-0.18.1/utils/filter.h   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/filter.h     2026-03-02 06:32:16.000000000 +0100
@@ -38,7 +38,9 @@
        TRIGGER_FL_HIDE = (1U << 17),
        TRIGGER_FL_LOC = (1U << 18),
        TRIGGER_FL_SIZE_FILTER = (1U << 19),
-       TRIGGER_FL_CLEAR = (1U << 20), /* Reverse other flags when set */
+       TRIGGER_FL_CONDITION = (1U << 20),
+
+       TRIGGER_FL_CLEAR = (1U << 30), /* Reverse other flags when set */
 };
 
 /**
@@ -150,35 +152,35 @@
 
 struct uftrace_sym_info;
 
-void uftrace_setup_filter(char *filter_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                          struct uftrace_triggers_info *triggers,
                          struct uftrace_filter_setting *setting);
-void uftrace_setup_trigger(char *trigger_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_trigger(const char *trigger_str, struct uftrace_sym_info 
*sinfo,
                           struct uftrace_triggers_info *triggers,
                           struct uftrace_filter_setting *setting);
-void uftrace_setup_argument(char *args_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_argument(const char *args_str, struct uftrace_sym_info 
*sinfo,
                            struct uftrace_triggers_info *triggers,
                            struct uftrace_filter_setting *setting);
-void uftrace_setup_retval(char *retval_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_retval(const char *retval_str, struct uftrace_sym_info 
*sinfo,
                          struct uftrace_triggers_info *triggers,
                          struct uftrace_filter_setting *setting);
-void uftrace_setup_caller_filter(char *filter_str, struct uftrace_sym_info 
*sinfo,
+void uftrace_setup_caller_filter(const char *filter_str, struct 
uftrace_sym_info *sinfo,
                                 struct uftrace_triggers_info *triggers,
                                 struct uftrace_filter_setting *setting);
-void uftrace_setup_hide_filter(char *filter_str, struct uftrace_sym_info 
*sinfo,
+void uftrace_setup_hide_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                               struct uftrace_triggers_info *triggers,
                               struct uftrace_filter_setting *setting);
-void uftrace_setup_loc_filter(char *filter_str, struct uftrace_sym_info *sinfo,
+void uftrace_setup_loc_filter(const char *filter_str, struct uftrace_sym_info 
*sinfo,
                              struct uftrace_triggers_info *triggers,
                              struct uftrace_filter_setting *setting);
 
 struct uftrace_triggers_info uftrace_deep_copy_triggers(struct 
uftrace_triggers_info *src);
-struct uftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root,
+struct uftrace_filter *uftrace_match_filter(uint64_t ip, struct 
uftrace_triggers_info *filters,
                                            struct uftrace_trigger *tr);
-void uftrace_cleanup_filter(struct rb_root *root);
+void uftrace_cleanup_filter(struct uftrace_triggers_info *filters);
 void uftrace_cleanup_triggers(struct uftrace_triggers_info *triggers);
-void uftrace_print_filter(struct rb_root *root);
-int uftrace_count_filter(struct rb_root *root, unsigned long flag);
+void uftrace_print_filter(struct uftrace_triggers_info *filters);
+int uftrace_count_filter(struct uftrace_triggers_info *filters, unsigned long 
flag);
 
 bool uftrace_eval_cond(struct uftrace_filter_cond *cond, long val);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/fstack.c 
new/uftrace-0.19/utils/fstack.c
--- old/uftrace-0.18.1/utils/fstack.c   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/fstack.c     2026-03-02 06:32:16.000000000 +0100
@@ -229,9 +229,9 @@
 {
        struct uftrace_filter_setting *setting = arg;
 
-       fstack_triggers.root = s->filters;
+       fstack_triggers.root = s->filter_info.root;
        uftrace_setup_filter(setting->info_str, &s->sym_info, &fstack_triggers, 
setting);
-       s->filters = fstack_triggers.root;
+       s->filter_info.root = fstack_triggers.root;
        return 0;
 }
 
@@ -239,9 +239,9 @@
 {
        struct uftrace_filter_setting *setting = arg;
 
-       fstack_triggers.root = s->filters;
+       fstack_triggers.root = s->filter_info.root;
        uftrace_setup_trigger(setting->info_str, &s->sym_info, 
&fstack_triggers, setting);
-       s->filters = fstack_triggers.root;
+       s->filter_info.root = fstack_triggers.root;
        return 0;
 }
 
@@ -249,9 +249,9 @@
 {
        struct uftrace_filter_setting *setting = arg;
 
-       fstack_triggers.root = s->filters;
+       fstack_triggers.root = s->filter_info.root;
        uftrace_setup_caller_filter(setting->info_str, &s->sym_info, 
&fstack_triggers, setting);
-       s->filters = fstack_triggers.root;
+       s->filter_info.root = fstack_triggers.root;
        return 0;
 }
 
@@ -259,9 +259,9 @@
 {
        struct uftrace_filter_setting *setting = arg;
 
-       fstack_triggers.root = s->filters;
+       fstack_triggers.root = s->filter_info.root;
        uftrace_setup_hide_filter(setting->info_str, &s->sym_info, 
&fstack_triggers, setting);
-       s->filters = fstack_triggers.root;
+       s->filter_info.root = fstack_triggers.root;
        return 0;
 }
 
@@ -269,16 +269,16 @@
 {
        struct uftrace_filter_setting *setting = arg;
 
-       fstack_triggers.root = s->filters;
+       fstack_triggers.root = s->filter_info.root;
        uftrace_setup_loc_filter(setting->info_str, &s->sym_info, 
&fstack_triggers, setting);
-       s->filters = fstack_triggers.root;
+       s->filter_info.root = fstack_triggers.root;
        return 0;
 }
 
 static int count_filters(struct uftrace_session *s, void *arg)
 {
        int *count = arg;
-       struct rb_node *node = rb_first(&s->filters);
+       struct rb_node *node = rb_first(&s->filter_info.root);
 
        while (node) {
                (*count)++;
@@ -289,19 +289,19 @@
 
 static int count_callers(struct uftrace_session *s, void *arg)
 {
-       *(int *)arg += uftrace_count_filter(&s->filters, TRIGGER_FL_CALLER);
+       *(int *)arg += uftrace_count_filter(&s->filter_info, TRIGGER_FL_CALLER);
        return 0;
 }
 
 static int count_hides(struct uftrace_session *s, void *arg)
 {
-       *(int *)arg += uftrace_count_filter(&s->filters, TRIGGER_FL_HIDE);
+       *(int *)arg += uftrace_count_filter(&s->filter_info, TRIGGER_FL_HIDE);
        return 0;
 }
 
 static int count_locs(struct uftrace_session *s, void *arg)
 {
-       *(int *)arg += uftrace_count_filter(&s->filters, TRIGGER_FL_LOC);
+       *(int *)arg += uftrace_count_filter(&s->filter_info, TRIGGER_FL_LOC);
        return 0;
 }
 
@@ -411,16 +411,12 @@
                .ptype = PATT_SIMPLE,
                .auto_args = false,
        };
-       struct uftrace_triggers_info fixups = {
-               .root = s->fixups,
-       };
 
        pr_dbg("fixup for some special functions\n");
 
        for (i = 0; i < ARRAY_SIZE(fixup_syms); i++) {
-               uftrace_setup_trigger((char *)fixup_syms[i], &s->sym_info, 
&fixups, &setting);
+               uftrace_setup_trigger(fixup_syms[i], &s->sym_info, &s->fixups, 
&setting);
        }
-       s->fixups = fixups.root;
        return 0;
 }
 
@@ -439,13 +435,9 @@
 static int build_arg_spec(struct uftrace_session *s, void *arg)
 {
        struct uftrace_filter_setting *setting = arg;
-       struct uftrace_triggers_info triggers = {
-               .root = s->filters,
-       };
 
        if (setting->info_str) {
-               uftrace_setup_argument(setting->info_str, &s->sym_info, 
&triggers, setting);
-               s->filters = triggers.root;
+               uftrace_setup_argument(setting->info_str, &s->sym_info, 
&s->filter_info, setting);
        }
 
        session_setup_dlopen_argspec(s, setting, false);
@@ -455,13 +447,9 @@
 static int build_ret_spec(struct uftrace_session *s, void *arg)
 {
        struct uftrace_filter_setting *setting = arg;
-       struct uftrace_triggers_info triggers = {
-               .root = s->filters,
-       };
 
        if (setting->info_str) {
-               uftrace_setup_retval(setting->info_str, &s->sym_info, 
&triggers, setting);
-               s->filters = triggers.root;
+               uftrace_setup_retval(setting->info_str, &s->sym_info, 
&s->filter_info, setting);
        }
 
        session_setup_dlopen_argspec(s, setting, true);
@@ -654,9 +642,9 @@
                        }
                }
 
-               uftrace_match_filter(addr, &sess->filters, tr);
+               uftrace_match_filter(addr, &sess->filter_info, tr);
 
-               if (tr->flags & TRIGGER_FL_FILTER && tr->cond.idx && 
task->args.args &&
+               if ((tr->flags & TRIGGER_FL_CONDITION) && task->args.args &&
                    !list_empty(task->args.args)) {
                        struct list_head *arg_list = task->args.args;
                        struct uftrace_arg_spec *spec;
@@ -888,7 +876,7 @@
                addr = get_kernel_address(&fsess->sym_info, addr);
        }
 
-       uftrace_match_filter(addr, &sess->filters, &tr);
+       uftrace_match_filter(addr, &sess->filter_info, &tr);
 
        if (tr.flags & TRIGGER_FL_FILTER) {
                if (tr.fmode == FILTER_MODE_OUT)
@@ -1681,7 +1669,7 @@
                sess = find_task_session(sessions, task->t, curr->time);
 
                if (sess && (curr->type == UFTRACE_ENTRY || curr->type == 
UFTRACE_EXIT))
-                       uftrace_match_filter(curr->addr, &sess->filters, &tr);
+                       uftrace_match_filter(curr->addr, &sess->filter_info, 
&tr);
 
                if (task->filter.stack) {
                        time_filter = task->filter.stack->threshold;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/hashmap.h 
new/uftrace-0.19/utils/hashmap.h
--- old/uftrace-0.18.1/utils/hashmap.h  2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/hashmap.h    2026-03-02 06:32:16.000000000 +0100
@@ -21,7 +21,7 @@
 #include <stdint.h>
 #include <stdlib.h>
 
-#if defined(__amd64__) || defined(__aarch64__)
+#if __SIZEOF_POINTER__ >= 8
 #define ARCH64
 #else
 #define ARCH32
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/kernel.c 
new/uftrace-0.19/utils/kernel.c
--- old/uftrace-0.18.1/utils/kernel.c   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/kernel.c     2026-03-02 06:32:16.000000000 +0100
@@ -1228,7 +1228,7 @@
                 * it might set TRACE trigger, which shows
                 * function even if it's less than the time filter.
                 */
-               uftrace_match_filter(real_addr, &sess->filters, &tr);
+               uftrace_match_filter(real_addr, &sess->filter_info, &tr);
 
                if (curr->type == UFTRACE_ENTRY) {
                        if (size_filter) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/session.c 
new/uftrace-0.19/utils/session.c
--- old/uftrace-0.18.1/utils/session.c  2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/session.c    2026-03-02 06:32:16.000000000 +0100
@@ -225,7 +225,6 @@
        s->namelen = msg->namelen;
        memcpy(s->exename, exename, s->namelen);
        s->exename[s->namelen] = 0;
-       s->filters = RB_ROOT;
        INIT_LIST_HEAD(&s->dlopen_libs);
 
        pr_dbg2("new session: pid = %d, session = %.*s\n", s->pid, 
SESSION_ID_LEN, s->sid);
@@ -360,7 +359,7 @@
        udl->mod = load_module_symtab(&sess->sym_info, libname, build_id);
        load_module_debug_info(udl->mod, sess->sym_info.symdir, needs_srcline);
 
-       udl->filters = RB_ROOT;
+       udl->filter_info.root = RB_ROOT;
 
        list_for_each_entry(pos, &sess->dlopen_libs, list) {
                if (pos->time > timestamp)
@@ -427,13 +426,13 @@
 
        list_for_each_entry_safe(udl, tmp, &sess->dlopen_libs, list) {
                list_del(&udl->list);
-               uftrace_cleanup_filter(&udl->filters);
+               uftrace_cleanup_filter(&udl->filter_info);
                free(udl);
        }
 
        finish_debug_info(&sess->sym_info);
        delete_session_map(&sess->sym_info);
-       uftrace_cleanup_filter(&sess->filters);
+       uftrace_cleanup_filter(&sess->filter_info);
        uftrace_cleanup_filter(&sess->fixups);
        free(sess);
 }
@@ -826,9 +825,6 @@
                                  struct uftrace_filter_setting *setting, bool 
is_retval)
 {
        struct uftrace_dlopen_list *udl;
-       struct uftrace_triggers_info triggers = {
-               .root = RB_ROOT,
-       };
 
        list_for_each_entry(udl, &sess->dlopen_libs, list) {
                struct uftrace_sym_info dl_info;
@@ -840,12 +836,14 @@
                dl_info = sess->sym_info;
                dl_info.maps = &dl_map;
 
-               triggers.root = udl->filters;
-               if (is_retval)
-                       uftrace_setup_retval(setting->info_str, &dl_info, 
&triggers, setting);
-               else
-                       uftrace_setup_argument(setting->info_str, &dl_info, 
&triggers, setting);
-               udl->filters = triggers.root;
+               if (is_retval) {
+                       uftrace_setup_retval(setting->info_str, &dl_info, 
&udl->filter_info,
+                                            setting);
+               }
+               else {
+                       uftrace_setup_argument(setting->info_str, &dl_info, 
&udl->filter_info,
+                                              setting);
+               }
        }
 }
 
@@ -855,7 +853,7 @@
        struct uftrace_filter *ret;
        struct uftrace_dlopen_list *udl;
 
-       ret = uftrace_match_filter(rec->addr, &sess->filters, tr);
+       ret = uftrace_match_filter(rec->addr, &sess->filter_info, tr);
        if (ret)
                return ret;
 
@@ -863,7 +861,7 @@
        if (udl == NULL)
                return NULL;
 
-       return uftrace_match_filter(rec->addr, &udl->filters, tr);
+       return uftrace_match_filter(rec->addr, &udl->filter_info, tr);
 }
 
 #ifdef UNIT_TEST
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/symbol-libelf.h 
new/uftrace-0.19/utils/symbol-libelf.h
--- old/uftrace-0.18.1/utils/symbol-libelf.h    2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/utils/symbol-libelf.h      2026-03-02 06:32:16.000000000 
+0100
@@ -22,6 +22,7 @@
                GElf_Dyn dyn;
                GElf_Rel rel;
                GElf_Rela rela;
+               const char *comment;
        };
 
        void *note_name;
@@ -111,6 +112,13 @@
             ((iter)->note_desc = (iter)->data->d_buf + 
(size_t)(iter)->note_desc);                \
             (iter)->i = (iter)->nr)
 
+/* iter->sec and iter->shdr must point ".comment" section */
+#define elf_for_each_comment(elf, iter)                                        
                    \
+       for ((iter)->i = 0, (iter)->data = elf_getdata((iter)->scn, NULL),      
                   \
+           (iter)->nr = (iter)->shdr.sh_size, (iter)->comment = 
(iter)->data->d_buf;              \
+            (iter)->i < (iter)->nr; (iter)->i += strlen((iter)->comment) + 1,  
                   \
+           (iter)->comment = (iter)->data->d_buf + (iter)->i)
+
 int elf_init(const char *filename, struct uftrace_elf_data *elf);
 void elf_finish(struct uftrace_elf_data *elf);
 int elf_retry(const char *filename, struct uftrace_elf_data *elf);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/symbol-rawelf.h 
new/uftrace-0.19/utils/symbol-rawelf.h
--- old/uftrace-0.18.1/utils/symbol-rawelf.h    2025-07-07 00:47:42.000000000 
+0200
+++ new/uftrace-0.19/utils/symbol-rawelf.h      2026-03-02 06:32:16.000000000 
+0100
@@ -65,6 +65,7 @@
                Elf_Dyn dyn;
                Elf_Rel rel;
                Elf_Rela rela;
+               const char *comment;
        };
 
        void *note_name;
@@ -161,6 +162,13 @@
             (iter)->i += sizeof((iter)->nhdr) + ALIGN((iter)->nhdr.n_namesz, 
4) +                 \
                          ALIGN((iter)->nhdr.n_descsz, 4))
 
+/* iter->shdr must point ".comment" section */
+#define elf_for_each_comment(elf, iter)                                        
                    \
+       for (elf_get_secdata((elf), (iter)), (iter)->i = 0, (iter)->nr = 
(iter)->shdr.sh_size,     \
+                                            (iter)->comment = (iter)->data;    
                   \
+            (iter)->i < (iter)->nr;                                            
                   \
+            (iter)->i += strcmp((iter)->comment) + 1, (iter)->comment = 
(iter)->data + (iter)->i)
+
 int elf_init(const char *filename, struct uftrace_elf_data *elf);
 void elf_finish(struct uftrace_elf_data *elf);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/symbol.c 
new/uftrace-0.19/utils/symbol.c
--- old/uftrace-0.18.1/utils/symbol.c   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/symbol.c     2026-03-02 06:32:16.000000000 +0100
@@ -601,6 +601,8 @@
                plt_entsize += 12;
        }
        else if (elf->ehdr.e_machine == EM_X86_64) {
+               if (flags & SYMTAB_FL_MOLD_PLT)
+                       plt_addr += 16;
                plt_entsize = 16; /* lld (of LLVM) seems to miss setting it */
        }
        else if (elf->ehdr.e_machine == EM_RISCV) {
@@ -711,6 +713,7 @@
                          unsigned long offset, unsigned long flags)
 {
        struct uftrace_elf_data elf;
+       struct uftrace_elf_iter sec_iter;
 
        if (elf_init(filename, &elf) < 0) {
                pr_dbg("error during open symbol file: %s: %m\n", filename);
@@ -718,6 +721,21 @@
        }
 
        pr_dbg3("loading dynamic symbols from %s (offset: %#lx)\n", filename, 
offset);
+       /* MOLD linker has a different PLT format */
+       elf_for_each_shdr(&elf, &sec_iter) {
+               typeof(sec_iter.shdr) *shdr = &sec_iter.shdr;
+               const char *shstr = elf_get_name(&elf, &sec_iter, 
shdr->sh_name);
+
+               if (!strcmp(shstr, ".comment")) {
+                       elf_for_each_comment(&elf, &sec_iter) {
+                               if (!strncmp(sec_iter.comment, "mold ", 5)) {
+                                       flags |= SYMTAB_FL_MOLD_PLT;
+                                       break;
+                               }
+                       }
+                       break;
+               }
+       }
        load_elf_dynsymtab(dsymtab, &elf, offset, flags);
        if (uftrace_arch_ops.load_dynsymtab) {
                struct uftrace_symtab dsymtab_noplt = {};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/uftrace-0.18.1/utils/symbol.h 
new/uftrace-0.19/utils/symbol.h
--- old/uftrace-0.18.1/utils/symbol.h   2025-07-07 00:47:42.000000000 +0200
+++ new/uftrace-0.19/utils/symbol.h     2026-03-02 06:32:16.000000000 +0100
@@ -104,6 +104,7 @@
        SYMTAB_FL_SKIP_NORMAL = (1U << 3),
        SYMTAB_FL_SKIP_DYNAMIC = (1U << 4),
        SYMTAB_FL_SYMS_DIR = (1U << 5),
+       SYMTAB_FL_MOLD_PLT = (1U << 6),
 };
 
 struct uftrace_sym_info {

Reply via email to