From 81330b4317c855d46c9cb0667c4a591ab36c924b Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 29 Oct 2023 16:10:02 -0700 Subject: [PATCH 1/2] mcount: Update debug message for GOT updates When it sets up PLT hooking, it'd overwrite GOT entries for each library functions at offset + 3. But the plt entry/exit functions print the original symbol table index. This can be confusing so let's make it explicit by printing "+ 3" part. Before: plthook: overwrite GOT[415] to 0x7f460c9db500 (__cyg_profile_func_exit) After: plthook: overwrite GOT[412 + 3] to 0x7f460c9db500 (__cyg_profile_func_exit) So not it matches the later messages like: plthook: [idx: 412] enter 56304c2019f0: __cyg_profile_func_exit@plt (mod: 7f6a2a51b180) Signed-off-by: Namhyung Kim --- libmcount/plthook.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libmcount/plthook.c b/libmcount/plthook.c index b3a0cd96b..6371bf5b8 100644 --- a/libmcount/plthook.c +++ b/libmcount/plthook.c @@ -149,7 +149,7 @@ static void restore_plt_functions(struct plthook_data *pd) continue; overwrite_pltgot(pd, got_idx, skip_sym->addr); - pr_dbg2("overwrite GOT[%d] to %p (%s)\n", got_idx, skip_sym->addr, + pr_dbg2("overwrite GOT[%d + 3] to %p (%s)\n", i, skip_sym->addr, skip_sym->name); skipped = true; @@ -171,7 +171,7 @@ static void restore_plt_functions(struct plthook_data *pd) continue; symname = demangle(sym->name); - pr_dbg2("restore GOT[%d] from \"%s\"(%#lx) to PLT(base + %#lx)\n", got_idx, + pr_dbg2("restore GOT[%d + 3] from \"%s\"(%#lx) to PLT(base + %#lx)\n", i, symname, resolved_addr, plthook_addr - pd->base_addr); free(symname); } From a9e878277b4025a7107fdee8885aa30142923730 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 25 Oct 2023 21:45:14 -0700 Subject: [PATCH 2/2] mcount: Ignore unpaired __cyg_profile_func_exit() For some reason, sometimes compilers might generate unpaired __cyg_profile_func_exit() without its _enter() counterpart. Although it's a compiler bug, uftrace can protect it from breakage by ignoring such unpaired ones. Add MCOUNT_FL_CYGPROF flag to check if it's set at the __cyg_profile_func_entry(). Signed-off-by: Namhyung Kim --- libmcount/mcount.c | 18 ++++++++++++++++-- libmcount/mcount.h | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/libmcount/mcount.c b/libmcount/mcount.c index 6347fab3f..5f31a9950 100644 --- a/libmcount/mcount.c +++ b/libmcount/mcount.c @@ -1539,11 +1539,11 @@ static int __cygprof_entry(unsigned long parent, unsigned long child) if (filtered == FILTER_IN) { rstack->start_time = mcount_gettime(); - rstack->flags = 0; + rstack->flags = MCOUNT_FL_CYGPROF; } else { rstack->start_time = 0; - rstack->flags = MCOUNT_FL_NORECORD; + rstack->flags = MCOUNT_FL_CYGPROF | MCOUNT_FL_NORECORD; } mcount_entry_filter_record(mtdp, rstack, &tr, NULL); @@ -1560,6 +1560,11 @@ static int cygprof_entry(unsigned long parent, unsigned long child) return ret; } +static void warn_unpaired_cygprof(void) +{ + pr_warn("unpaired cygprof exit: dropping...\n"); +} + static void __cygprof_exit(unsigned long parent, unsigned long child) { struct mcount_thread_data *mtdp; @@ -1582,6 +1587,15 @@ static void __cygprof_exit(unsigned long parent, unsigned long child) rstack = &mtdp->rstack[mtdp->idx - 1]; + /* discard unpaired cygprof exit (due to compiler bug?) */ + if (unlikely(!(rstack->flags & MCOUNT_FL_CYGPROF))) { + static pthread_once_t warn_once = PTHREAD_ONCE_INIT; + + pthread_once(&warn_once, warn_unpaired_cygprof); + mcount_unguard_recursion(mtdp); + return; + } + if (!(rstack->flags & MCOUNT_FL_NORECORD)) rstack->end_time = mcount_gettime(); diff --git a/libmcount/mcount.h b/libmcount/mcount.h index 920f99dee..78d85358d 100644 --- a/libmcount/mcount.h +++ b/libmcount/mcount.h @@ -38,6 +38,7 @@ enum mcount_rstack_flag { MCOUNT_FL_ARGUMENT = (1U << 11), MCOUNT_FL_READ = (1U << 12), MCOUNT_FL_CALLER = (1U << 13), + MCOUNT_FL_CYGPROF = (1U << 14), }; struct plthook_data;