From f4faaf86acd0fe9d410c16c8ec44664ef92559ef Mon Sep 17 00:00:00 2001
From: Josh Stone <jistone@redhat.com>
Date: Wed, 13 Nov 2013 17:04:19 -0800
Subject: [PATCH] PR16162: Support .plt probes on prelinked libraries
There were a few bias issues in how plt addresses were handled, which
broke in the face of prelink offsets. This patch tries to standardize
how these addresses are handled.
* tapsets.cxx (query_plt_statement): New function to fix plt addresses,
both adding dwfl's elf bias and subtracting the dw bias, so it will
work with dwflpp::relocate_address like everything else.
(base_query::base_query): Leave session::consult_symtab alone!
(dwarf_query::query_module_symtab): PLT doesn't fake a path through
the symbol table anymore.
(dwarf_query::handle_query_module): Direct PLT to query_plt_statement.
(dwarf_query::add_probe_point): Remove the relocate exemption for plt.
* testsuite/systemtap.base/plt.exp: Update with a prelink test, and
refactor a lot of the test on the way.
---
tapsets.cxx | 52 ++++++++-----
testsuite/systemtap.base/plt.exp | 163 ++++++++++++++++-----------------------
testsuite/systemtap.base/plt.stp | 9 +++
3 files changed, 109 insertions(+), 115 deletions(-)
create mode 100644 testsuite/systemtap.base/plt.stp
diff --git a/tapsets.cxx b/tapsets.cxx
index 49740b0..f7947ca 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -405,6 +405,7 @@ static const string TOK_CLASS("class");;
static int query_cu (Dwarf_Die * cudie, void * arg);
static void query_addr(Dwarf_Addr addr, dwarf_query *q);
+static void query_plt_statement(dwarf_query *q);
// Can we handle this query with just symbol-table info?
enum dbinfo_reqt
@@ -665,8 +666,6 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params):
if ((has_plt = has_null_param (params, TOK_PLT)))
plt_val = "*";
else has_plt = get_string_param (params, TOK_PLT, plt_val);
- if (has_plt)
- sess.consult_symtab = true;
has_statement = get_number_param(params, TOK_STATEMENT, statement_num_val);
if (has_process)
@@ -1049,14 +1048,7 @@ dwarf_query::query_module_symtab()
// Find the "function" in which the indicated address resides.
Dwarf_Addr addr =
(has_function_num ? function_num_val : statement_num_val);
- if (has_plt)
- {
- // Use the raw address from the .plt
- fi = sym_table->get_first_func();
- fi->addr = addr;
- }
- else
- fi = sym_table->get_func_containing_address(addr);
+ fi = sym_table->get_func_containing_address(addr);
if (!fi)
{
@@ -1081,6 +1073,12 @@ dwarf_query::query_module_symtab()
void
dwarf_query::handle_query_module()
{
+ if (has_plt && has_statement_num)
+ {
+ query_plt_statement (this);
+ return;
+ }
+
bool report = dbinfo_reqt == dbr_need_dwarf || !sess.consult_symtab;
dw.get_module_dwarf(false, report);
@@ -1250,14 +1248,7 @@ dwarf_query::add_probe_point(const string& dw_funcname,
assert (! has_absolute); // already handled in dwarf_builder::build()
- if (!has_plt)
- reloc_addr = dw.relocate_address(addr, reloc_section);
- else
- {
- // Set the reloc_section but use the plt entry for reloc_addr
- dw.relocate_address(addr, reloc_section);
- reloc_addr = addr;
- }
+ reloc_addr = dw.relocate_address(addr, reloc_section);
// If we originally used the linkage name, then let's call it that way
const char* linkage_name;
@@ -1515,6 +1506,29 @@ query_addr(Dwarf_Addr addr, dwarf_query *q)
}
static void
+query_plt_statement(dwarf_query *q)
+{
+ assert (q->has_plt && q->has_statement_num);
+
+ Dwarf_Addr addr = q->statement_num_val;
+ if (q->sess.verbose > 2)
+ clog << "query_plt_statement 0x" << hex << addr << dec << endl;
+
+ // First adjust the raw address to dwfl's elf bias.
+ Dwarf_Addr elf_bias;
+ Elf *elf = dwfl_module_getelf (q->dw.module, &elf_bias);
+ assert(elf);
+ addr += elf_bias;
+
+ // Now compensate for the dw bias
+ q->dw.get_module_dwarf(false, false);
+ addr -= q->dw.module_bias;
+
+ // Build a probe at this point
+ query_statement(q->plt_val, NULL, -1, NULL, addr, q);
+}
+
+static void
query_label (string const & func,
char const * label,
char const * file,
@@ -2233,8 +2247,6 @@ query_one_plt (const char *entry, long addr, dwflpp & dw,
if (dw.sess.verbose > 2)
clog << _F("plt entry=%s\n", entry);
- // query_module_symtab requires .plt to recognize that it can set the probe at
- // a plt entry so we convert process.plt to process.plt.statement
vector<probe_point::component*>::iterator it;
for (it = specific_loc->components.begin();
it != specific_loc->components.end(); ++it)
diff --git a/testsuite/systemtap.base/plt.exp b/testsuite/systemtap.base/plt.exp
index 71b7987..a6d2a86 100644
--- a/testsuite/systemtap.base/plt.exp
+++ b/testsuite/systemtap.base/plt.exp
@@ -1,4 +1,5 @@
set test "plt"
+set script "$srcdir/$subdir/$test.stp"
proc cleanup_handler { verbose } {
if { $verbose == 0 } {
@@ -20,127 +21,99 @@ proc error_handler { res test message } {
}
}
+set ::result_string \
+{__cxa_finalize 2
+__libc_start_main 1
+__xpg_basename 1
+asctime 1
+asprintf 3
+basename2 1
+bsearch 3
+critters 1
+datetime 1
+find_critter 3
+fprintf 3
+fputs 3
+free 4
+localtime 1
+malloc 3
+memcpy 1
+open 2
+open2 1
+open3 1
+print_critter 32
+printf 38
+qsort 1
+register_printf_function 1
+savestring 1
+stpcpy 4
+strcmp 51
+strftime 2
+strlen 4
+time 1
+widgets 1
+xmalloc 2
+zenme 1}
+
if {![installtest_p]} { untested $test; return }
if {![plt_probes_p]} { untested $test; return }
-set stap_path $env(SYSTEMTAP_PATH)/stap
-
set exepath "./plt.x"
+
set F additional_flags
-set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT1 $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format"
+set common_flags "$F=-g $F=-Wno-deprecated-declarations $F=-Wno-format $F=-fno-builtin"
+set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT1 $common_flags"
set res [target_compile $srcdir/$subdir/plt.c ./libplt1.so executable $flags ]
if { [error_handler [expr {$res == ""}] "target_compile libplt1.so" ""] } { return }
-set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT2 $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format"
+set flags "$F=-I. $F=-shared $F=-fPIC $F=-DLIBPLT2 $common_flags"
set res [target_compile $srcdir/$subdir/plt.c ./libplt2.so executable $flags ]
if { [error_handler [expr {$res == ""}] "target_compile libplt2.so" ""] } { return }
-set flags "$F=-Wl,-rpath,[pwd] $F=-L[pwd] $F=-lplt1 $F=-lplt2 $F=-DONLY_MAIN $F=-g $F=-Wno-deprecated-declarations $F=-Wno-format"
+set flags "$F=-Wl,-rpath,[pwd] $F=-L[pwd] $F=-lplt1 $F=-lplt2 $F=-DONLY_MAIN $common_flags"
set res [target_compile $srcdir/$subdir/plt.c $exepath executable $flags ]
if { [error_handler [expr {$res == ""}] "target_compile plt.x" ""] } { return }
# test process.plt
-set ok 0
-spawn $stap_path -c $exepath -e "global calls probe process(\"./plt.x\").plt {calls\[\$\$name\] += 1} probe process(\"./libplt1.so\").plt {calls\[\$\$name\] += 1} probe process(\"./libplt2.so\").plt {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}"
-
-expect {
- -timeout 180
- -re {__libc_start_main 1\r\n} { incr ok; exp_continue }
- -re {xmalloc 2\r\n} { incr ok; exp_continue }
- -re {savestring 1\r\n} { incr ok; exp_continue }
- -re {memcpy 1\r\n} { incr ok; exp_continue }
- -re {open2 1\r\n} { incr ok; exp_continue }
- -re {stpcpy 4\r\n} { incr ok; exp_continue }
- -re {open 2\r\n} { incr ok; exp_continue }
- -re {open3 1\r\n} { incr ok; exp_continue }
- -re {basename2 1\r\n} { incr ok; exp_continue }
- -re {__xpg_basename 1\r\n} { incr ok; exp_continue }
- -re {critters 1\r\n} { incr ok; exp_continue }
- -re {print_critter 32\r\n} { incr ok; exp_continue }
- -re {printf 36\r\n} { incr ok; exp_continue }
- -re {putchar 2\r\n} { incr ok; exp_continue }
- -re {qsort 1\r\n} { incr ok; exp_continue }
- -re {strcmp 51\r\n} { incr ok; exp_continue }
- -re {find_critter 3\r\n} { incr ok; exp_continue }
- -re {bsearch 3\r\n} { incr ok; exp_continue }
- -re {widgets 1\r\n} { incr ok; exp_continue }
- -re {register_printf_function 1\r\n} { incr ok; exp_continue }
- -re {asprintf 3\r\n} { incr ok; exp_continue }
- -re {fprintf 3\r\n} { incr ok; exp_continue }
- -re {datetime 1\r\n} { incr ok; exp_continue }
- -re {time 1\r\n} { incr ok; exp_continue }
- -re {localtime 1\r\n} { incr ok; exp_continue }
- -re {asctime 1\r\n} { incr ok; exp_continue }
- -re {fputs 3\r\n} { incr ok; exp_continue }
- -re {strftime 2\r\n} { incr ok; exp_continue }
- timeout { fail "$test (timeout)" }
- eof { }
-}
-
-catch { close}; catch { wait}
-
-error_handler [expr {$ok == 28}] "plt" "($ok != 28)"
+set pp {process("./plt.x").plt, process("./libplt1.so").plt, process("./libplt2.so").plt}
+stap_run3 "plt" "$script" "$pp" -c "$exepath >/dev/null"
# test process.library.plt
-set ok 0
-spawn $stap_path -c $exepath -e "global calls probe process(\"./plt.x\").plt {calls\[\$\$name\] += 1} probe process(\"./plt.x\").library(\"*\").plt {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}"
+set pp {process("./plt.x").plt, process("./plt.x").library("libplt*").plt}
+stap_run3 "plt library" "$script" "$pp" -c "$exepath >/dev/null"
-expect {
- -timeout 180
- -re {__libc_start_main 1\r\n} { incr ok; exp_continue }
- -re {xmalloc 2\r\n} { incr ok; exp_continue }
- -re {savestring 1\r\n} { incr ok; exp_continue }
- -re {memcpy 1\r\n} { incr ok; exp_continue }
- -re {open2 1\r\n} { incr ok; exp_continue }
- -re {stpcpy 4\r\n} { incr ok; exp_continue }
- -re {open 2\r\n} { incr ok; exp_continue }
- -re {open3 1\r\n} { incr ok; exp_continue }
- -re {basename2 1\r\n} { incr ok; exp_continue }
- -re {__xpg_basename 1\r\n} { incr ok; exp_continue }
- -re {critters 1\r\n} { incr ok; exp_continue }
- -re {print_critter 32\r\n} { incr ok; exp_continue }
- -re {printf 36\r\n} { incr ok; exp_continue }
- -re {putchar 2\r\n} { incr ok; exp_continue }
- -re {qsort 1\r\n} { incr ok; exp_continue }
- -re {strcmp 51\r\n} { incr ok; exp_continue }
- -re {find_critter 3\r\n} { incr ok; exp_continue }
- -re {bsearch 3\r\n} { incr ok; exp_continue }
- -re {widgets 1\r\n} { incr ok; exp_continue }
- -re {register_printf_function 1\r\n} { incr ok; exp_continue }
- -re {asprintf 3\r\n} { incr ok; exp_continue }
- -re {fprintf 3\r\n} { incr ok; exp_continue }
- -re {datetime 1\r\n} { incr ok; exp_continue }
- -re {time 1\r\n} { incr ok; exp_continue }
- -re {localtime 1\r\n} { incr ok; exp_continue }
- -re {asctime 1\r\n} { incr ok; exp_continue }
- -re {fputs 3\r\n} { incr ok; exp_continue }
- -re {strftime 2\r\n} { incr ok; exp_continue }
- timeout { fail "$test (timeout)" }
- eof { }
+# test process.library.plt prelinked
+
+set prelink_bin "/usr/sbin/prelink"
+if {[file exists $prelink_bin]} {
+ set addr "-r 0x6400000"
+ set prelink_cmd [concat $prelink_bin -vfNR $addr libplt1.so]
+ send_log "Executing: $prelink_cmd\n"
+ catch {eval exec $prelink_cmd} result
+ if { $result != "" } {
+ verbose -log "prelink failed: $result"
+ fail "plt prelink libplt1.so"
+ untested "plt prelinked library"
+ } else {
+ pass "plt prelink libplt1.so"
+
+ set pp {process("./plt.x").plt, process("./plt.x").library("libplt*").plt}
+ stap_run3 "plt prelinked library" "$script" "$pp" -c "$exepath >/dev/null"
+ }
+} else {
+ untested "plt prelink libplt1.so"
+ untested "plt prelinked library"
}
-catch { close}; catch { wait}
-
-error_handler [expr {$ok == 28}] "plt library" "($ok != 28)"
-
# test process.plt("glob")
set ok 0
-spawn $stap_path -c $exepath -e "global calls probe process(\"./libplt2.so\").plt(\"strcmp\") {calls\[\$\$name\] += 1} probe end {foreach (x in calls) printf (\"%s %d\\n\", x, calls\[x\])}"
+set ::result_string {strcmp 51}
+set pp {process("./libplt2.so").plt("strcmp")}
+stap_run3 "plt glob" "$script" "$pp" -c "$exepath >/dev/null"
-expect {
- -timeout 180
- -re {strcmp 51\r\n} { incr ok; exp_continue }
- -re {printf 36\r\n} { incr ok; exp_continue }
- timeout { fail "$test (timeout)" }
- eof { }
-}
-
-catch { close}; catch { wait}
-
-error_handler [expr {$ok == 1}] "plt glob" "($ok != 1)"
cleanup_handler $verbose
diff --git a/testsuite/systemtap.base/plt.stp b/testsuite/systemtap.base/plt.stp
new file mode 100644
index 0000000..286c4e9
--- /dev/null
+++ b/testsuite/systemtap.base/plt.stp
@@ -0,0 +1,9 @@
+global calls
+probe $1 {
+ calls[$$name] += 1
+}
+probe end {
+ foreach (x+ in calls)
+ printf ("%s %d\n", x, calls[x])
+}
+
--
1.8.3.1