From 91bb9081f0f2342d2e7df985d448ea9c9ebd34b5 Mon Sep 17 00:00:00 2001 From: Lukas Berk Date: Fri, 29 Nov 2013 16:34:11 -0500 Subject: [PATCH] PR10208 Support probing weak symbols *tapsets.cxx - Now always query the symtab (unless there is a pending interrupt or dwarf callback error) on a function probe. We need to be careful to check probe point's we've already resolved which will already have full debug information and to not place another probe there. We've removed the case of probing the symbol table on a statement probe, as that code was written specifically for the kernel without userspace in mind and was resolving the function the statement resided in (causing errors in some cases). *list.exp - Added testcase for weak symbols *last_100_frees.stp - we use @defined($mem) here because on 64 bit systems, the wildcard search takes us through both 64 bit and 32 bit libc (which doesn't have debuginfo), this means the probe point resolved from the 32 bit library has no context info *mutex-contention.stp - ditto but for @defined($mutex) and @defined($rwlock) --- tapsets.cxx | 94 ++++++++++++---------- testsuite/systemtap.base/list.exp | 4 + .../systemtap.examples/memory/last_100_frees.stp | 12 ++- .../process/mutex-contention.stp | 14 +++- 4 files changed, 74 insertions(+), 50 deletions(-) diff --git a/tapsets.cxx b/tapsets.cxx index 7927106..4e05d4a 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -989,6 +989,40 @@ dwarf_query::query_module_dwarf() static void query_func_info (Dwarf_Addr entrypc, func_info & fi, dwarf_query * q); +static void +query_symtab_func_info (func_info & fi, dwarf_query * q) +{ + assert(null_die(&fi.die)); + + Dwarf_Addr addr = fi.addr; + + // Now compensate for the dw bias because the addresses come + // from dwfl_module_symtab, so fi->addr is NOT a normal dw address. + q->dw.get_module_dwarf(false, false); + addr -= q->dw.module_bias; + + // If there are already probes in this module, lets not duplicate. + // This can come from other weak symbols/aliases or existing + // matches from Dwarf DIE functions. + if (q->alias_dupes.size() > 0) + { + for (set::iterator it=q->alias_dupes.begin(); it!=q->alias_dupes.end(); ++it) + { + // If we've already got a probe at that pc, skip it + if (*it == addr) + return; + if (*it != addr && ++it==q->alias_dupes.end()) + { + // Build a probe at this point + query_func_info(addr, fi, q); + return; + } + } + } + else + query_func_info(addr,fi,q); +} + void dwarf_query::query_module_symtab() { @@ -1014,15 +1048,6 @@ dwarf_query::query_module_symtab() assert(spec_type == function_alone); if (dw.name_has_wildcard(function_str_val)) { - // Until we augment the blacklist sufficently... - if ((function_str_val.find_first_not_of("*?") == string::npos) && !dw.has_gnu_debugdata()) - { - // e.g., kernel.function("*") - cerr << _F("Error: Pattern '%s' matches every single " - "instruction address in the symbol table,\n" - "some of which aren't even functions.\n", function_str_val.c_str()) << endl; - return; - } symbol_table::iterator_t iter; for (iter = sym_table->map_by_addr.begin(); iter != sym_table->map_by_addr.end(); @@ -1032,42 +1057,16 @@ dwarf_query::query_module_symtab() if (!null_die(&fi->die)) continue; // already handled in query_module_dwarf() if (dw.function_name_matches_pattern(fi->name, function_str_val)) - query_func_info(fi->addr, *fi, this); + query_symtab_func_info(*fi, this); } } else { fi = sym_table->lookup_symbol(function_str_val); if (fi && !fi->descriptor && null_die(&fi->die)) - query_func_info(fi->addr, *fi, this); + query_symtab_func_info(*fi, this); } } - else - { - assert(has_function_num || has_statement_num); - // Find the "function" in which the indicated address resides. - Dwarf_Addr addr = - (has_function_num ? function_num_val : statement_num_val); - fi = sym_table->get_func_containing_address(addr); - - if (!fi) - { - sess.print_warning(_F("address %#" PRIx64 " out of range for module %s", - addr, dw.module_name.c_str())); - return; - } - if (!null_die(&fi->die)) - { - // addr looks like it's in the compilation unit containing - // the indicated function, but query_module_dwarf() didn't - // match addr to any compilation unit, so addr must be - // above that cu's address range. - sess.print_warning(_F("address %#" PRIx64 " maps to no known compilation unit in module %s", - addr, dw.module_name.c_str())); - return; - } - query_func_info(fi->addr, *fi, this); - } } void @@ -1092,10 +1091,11 @@ dwarf_query::handle_query_module() if (dw.mod_info->dwarf_status == info_present) query_module_dwarf(); - // Consult the symbol table if we haven't found all we're looking for. - // asm functions can show up in the symbol table but not in dwarf, - // or if we want to check the .gnu_debugdata section - if ((sess.consult_symtab || dw.has_gnu_debugdata()) && !query_done) + // Consult the symbol table, asm and weak functions can show up + // in the symbol table but not in dwarf and minidebuginfo is + // located in the gnu_debugdata section, alias_dupes checking + // is done before adding any probe points + if (!query_done && !pending_interrupts) query_module_symtab(); } @@ -1252,7 +1252,7 @@ dwarf_query::add_probe_point(const string& dw_funcname, // If we originally used the linkage name, then let's call it that way const char* linkage_name; - if (scope_die && startswith (this->function, "_Z") + if (!null_die(scope_die) && startswith (this->function, "_Z") && (linkage_name = dwarf_linkage_name (scope_die))) funcname = linkage_name; @@ -1954,8 +1954,14 @@ dwarf_query::query_module_functions () inline_dupes.clear(); // Run the query again on the individual CUs - for (vector::iterator i = cus.begin(); i != cus.end(); ++i) - query_cu(&*i, this); + for (vector::iterator i = cus.begin(); i != cus.end(); ++i){ + rc = query_cu(&*i, this); + if (rc != DWARF_CB_OK) + { + query_done = true; + return; + } + } } catch (const semantic_error& e) { diff --git a/testsuite/systemtap.base/list.exp b/testsuite/systemtap.base/list.exp index 1aa97f8..bae7e0e 100644 --- a/testsuite/systemtap.base/list.exp +++ b/testsuite/systemtap.base/list.exp @@ -81,3 +81,7 @@ test_list copy_flags-inline {kernel.function("copy_flags@kernel/fork.c").inline} # PR15587: make sure we have line numbers on statements of an inline function test_list copy_flags-statement {kernel.statement("copy_flags@kernel/fork.c:*")} \ {kernel.statement."copy_flags@kernel/fork.c:\d+".\r\n} + +# PR10208: ensure we can probe weak symbols +test_uprobes_list function-weak {process("/lib*/libc.so.*").function("chmod")} \ + {process.*.function."chmod".\r\n} diff --git a/testsuite/systemtap.examples/memory/last_100_frees.stp b/testsuite/systemtap.examples/memory/last_100_frees.stp index 06d7acf..4ca43b5 100755 --- a/testsuite/systemtap.examples/memory/last_100_frees.stp +++ b/testsuite/systemtap.examples/memory/last_100_frees.stp @@ -1,10 +1,16 @@ -#! /usr/bin/env stap +#! /usr/bin/env stap global bt%[100] probe process("/lib*/libc.so.*").function("free") { - bt[execname(),tid(),$mem,sprint_ubacktrace()] - <<< local_clock_ns() + // we use @defined($mem) here because on 64 bit systems, the + // wildcard search takes us through both 64 bit and 32 bit + // libc (which doesn't have debuginfo), this means the probe + // point resolved from the 32 bit library has no context info + if (@defined($mem)) { + bt[execname(),tid(),$mem,sprint_ubacktrace()] + <<< local_clock_ns() + } // Any monotonically increasing expression would do. // With some arbitrary expression or constant instead, // at worst we get the last 100ish results out of order. diff --git a/testsuite/systemtap.examples/process/mutex-contention.stp b/testsuite/systemtap.examples/process/mutex-contention.stp index 669618e..f418754 100755 --- a/testsuite/systemtap.examples/process/mutex-contention.stp +++ b/testsuite/systemtap.examples/process/mutex-contention.stp @@ -71,17 +71,25 @@ function show_contention(mutex, stack, type) } } +// we use @defined($muex) and @defined($rwlock) here because +// on 64 bit systems, the wildcard search takes us through +// both 64 bit and 32 bit libc (which doesn't have debuginfo), +// this means the probe point resolved from the 32 bit library +// has no context info probe process("/lib*/libc.so*").function("pthread_mutex_init") { - process_mutex_init($mutex, probefunc()) + if(@defined($mutex)) + process_mutex_init($mutex, probefunc()) } probe process("/lib*/libpthread.so*").function("__pthread_mutex_init") { - process_mutex_init($mutex, probefunc()) + if(@defined($mutex)) + process_mutex_init($mutex, probefunc()) } probe process("/lib*/libpthread.so*").function("__pthread_rwlock_init") { - process_mutex_init($rwlock, probefunc()) + if(@defined($rwlock)) + process_mutex_init($rwlock, probefunc()) } probe syscall.futex.return -- 1.8.3.1