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(©.root), false); @@ -1956,7 +1959,7 @@ TEST_EQ(filter->start, 0x5000UL); TEST_EQ(filter->end, 0x5000UL + 0x1000UL); - uftrace_cleanup_filter(©.root); + uftrace_cleanup_filter(©); TEST_EQ(RB_EMPTY_ROOT(©.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 {
