summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Brolley <brolley@redhat.com>2009-11-03 16:22:36 -0500
committerDave Brolley <brolley@redhat.com>2009-11-03 16:22:36 -0500
commit899b66209b0146560f0efc33efe58a4be3577df3 (patch)
tree7b64764b917c359a99d0adcf6c68a2d73cd52be7
parentd4ad7984018ff769cbb662342be7e501632c0bea (diff)
parent89651893a8ec51ee4d77ddfd57019e350ad7b169 (diff)
downloadsystemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.tar.gz
systemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.tar.xz
systemtap-steved-899b66209b0146560f0efc33efe58a4be3577df3.zip
Merge branch 'master' of ssh://sources.redhat.com/git/systemtap
Conflicts: Makefile.in configure doc/Makefile.in doc/SystemTap_Tapset_Reference/Makefile.in grapher/Makefile.in testsuite/configure
-rw-r--r--.mailmap1
-rw-r--r--NEWS16
-rw-r--r--buildrun.cxx5
-rwxr-xr-xconfigure2
-rw-r--r--configure.ac2
-rw-r--r--doc/SystemTap_Tapset_Reference/tapsets.tmpl9
-rwxr-xr-xdtrace.in5
-rw-r--r--dwflpp.cxx7
-rw-r--r--elaborate.cxx24
-rw-r--r--elaborate.h2
-rw-r--r--grapher/GraphData.hxx13
-rw-r--r--grapher/StapParser.cxx68
-rw-r--r--grapher/StapParser.hxx14
-rw-r--r--grapher/grapher.cxx454
-rw-r--r--includes/sys/sdt.h2
-rw-r--r--runtime/probe_lock.h68
-rw-r--r--runtime/staprun/mainloop.c26
-rw-r--r--runtime/staprun/staprun.h2
-rw-r--r--runtime/stat-common.c2
-rw-r--r--runtime/string.c6
-rw-r--r--runtime/task_finder.c4
-rw-r--r--runtime/transport/transport.c38
-rw-r--r--runtime/transport/transport.h3
-rw-r--r--runtime/unwind.c43
-rw-r--r--runtime/unwind/unwind.h6
-rwxr-xr-xstap-gen-cert26
-rw-r--r--tapset-utrace.cxx2
-rw-r--r--tapset/aux_syscalls.stp80
-rw-r--r--tapset/syscalls.stp22
-rw-r--r--tapset/task.stp14
-rw-r--r--tapset/tty.stp189
-rw-r--r--tapsets.cxx40
-rw-r--r--testsuite/Makefile.am4
-rw-r--r--testsuite/Makefile.in4
-rwxr-xr-xtestsuite/buildok/tty.stp51
-rwxr-xr-xtestsuite/configure22
-rw-r--r--testsuite/configure.ac12
-rw-r--r--testsuite/systemtap.apps/mysql.exp (renamed from testsuite/systemtap.base/mysql.exp)2
-rw-r--r--testsuite/systemtap.apps/postgres.exp (renamed from testsuite/systemtap.base/postgres.exp)2
-rw-r--r--testsuite/systemtap.apps/stap-tcl.sh25
-rw-r--r--testsuite/systemtap.apps/stap-tcl.stp30
-rw-r--r--testsuite/systemtap.apps/tcl.exp67
-rw-r--r--testsuite/systemtap.apps/xulrunner.exp133
-rw-r--r--testsuite/systemtap.base/onoffprobe.exp20
-rw-r--r--testsuite/systemtap.base/pr10854.exp32
-rw-r--r--testsuite/systemtap.base/pr10854.stp20
-rw-r--r--testsuite/systemtap.context/args.tcl3
-rw-r--r--testsuite/systemtap.context/backtrace.tcl2
-rw-r--r--testsuite/systemtap.context/num_args.tcl3
-rw-r--r--testsuite/systemtap.context/pid.tcl2
-rw-r--r--testsuite/systemtap.examples/index.html3
-rw-r--r--testsuite/systemtap.examples/index.txt7
-rwxr-xr-xtestsuite/systemtap.examples/io/traceio2.stp2
-rw-r--r--testsuite/systemtap.examples/keyword-index.html3
-rw-r--r--testsuite/systemtap.examples/keyword-index.txt7
-rw-r--r--testsuite/systemtap.examples/process/plimit.meta7
-rwxr-xr-xtestsuite/systemtap.examples/process/plimit.stp78
-rw-r--r--testsuite/systemtap.syscall/README3
-rw-r--r--testsuite/systemtap.syscall/chmod.c2
-rw-r--r--testsuite/systemtap.syscall/dir.c4
-rw-r--r--testsuite/systemtap.syscall/mmap.c4
-rw-r--r--testsuite/systemtap.syscall/net1.c2
-rw-r--r--testsuite/systemtap.syscall/openclose.c18
-rw-r--r--testsuite/systemtap.syscall/readwrite.c4
-rw-r--r--testsuite/systemtap.syscall/stat.c2
-rwxr-xr-xtestsuite/systemtap.syscall/sys.stp10
-rwxr-xr-xtestsuite/systemtap.syscall/test-debug.tcl11
-rwxr-xr-xtestsuite/systemtap.syscall/test.tcl6
-rwxr-xr-xtestsuite/transko/varargs.stp10
-rwxr-xr-xtestsuite/transok/varargs.stp9
-rw-r--r--translate.cxx149
71 files changed, 1501 insertions, 469 deletions
diff --git a/.mailmap b/.mailmap
index 6d8d9e71..3f50d654 100644
--- a/.mailmap
+++ b/.mailmap
@@ -48,6 +48,7 @@ Zhaolei <zhaolei>
# Normalize a few git commit names too
Anithra Janakiraman <anithra@linux.vnet.ibm.com>
+Breno Leitao <leitao@linux.vnet.ibm.com>
Dave Nomura <dcn@vervainp2.rchland.ibm.com>
Don Domingo <ddomingo@redhat.com>
K.Prasad <prasad@linux.vnet.ibm.com>
diff --git a/NEWS b/NEWS
index d13e81af..21ab8e41 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,21 @@
* What's new
+- Any output line that starts with "ERROR", as in error("foo"), will
+ promote a "Pass 5: run failed", and the return code is 1.
+
+- Systemtap now warns about global variables being referenced from other
+ script files. This aims to protect against unintended local-vs-global
+ namespace collisions such as:
+
+ % cat some_tapset.stp
+ probe baz.one = bar { foo = $foo; bar = $bar }
+ % cat end_user_script.stp
+ global foo # intended to be private variable
+ probe timer.s(1) { foo ++ }
+ probe baz.* { println(foo, pp()) }
+ % stap end_user_script.stp
+ WARNING: cross-file global variable reference to foo from some_tapset.stp
+
- Preprocessor conditional for kernel configuration testing:
%( CONFIG_foo == "y" %? ... %)
diff --git a/buildrun.cxx b/buildrun.cxx
index c5c44f13..b6063e36 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -201,6 +201,11 @@ compile_pass (systemtap_session& s)
// o << "CFLAGS += -fno-unit-at-a-time" << endl;
+ // 512 bytes should be enough for anybody
+ // XXX but it's not enough for unwind_frame -- PR10821
+ // XXX temporarily bumping to 600 bytes
+ o << "EXTRA_CFLAGS += $(call cc-option,-Wframe-larger-than=600)" << endl;
+
// Assumes linux 2.6 kbuild
o << "EXTRA_CFLAGS += -Wno-unused -Werror" << endl;
#if CHECK_POINTER_ARITH_PR5947
diff --git a/configure b/configure
index 0a81bb9f..d72c6c52 100755
--- a/configure
+++ b/configure
@@ -2349,6 +2349,8 @@ fi
+
+
mkdir_p="$MKDIR_P"
case $mkdir_p in
[\\/$]* | ?:[\\/]*) ;;
diff --git a/configure.ac b/configure.ac
index 010026dc..7c4a15e8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -8,6 +8,8 @@ AC_PREREQ(2.59)
AM_INIT_AUTOMAKE
AM_MAINTAINER_MODE
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
AM_PROG_MKDIR_P
AC_SUBST(MKDIR_P)
AC_PROG_LN_S
diff --git a/doc/SystemTap_Tapset_Reference/tapsets.tmpl b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
index c8c5ed72..21577eb1 100644
--- a/doc/SystemTap_Tapset_Reference/tapsets.tmpl
+++ b/doc/SystemTap_Tapset_Reference/tapsets.tmpl
@@ -174,6 +174,15 @@
!Itapset/scsi.stp
</chapter>
+ <chapter id="tty.stp">
+ <title>TTY Tapset</title>
+ <para>
+ This family of probe points is used to probe TTY (Teletype) activities.
+ It contains the following probe points:
+ </para>
+!Itapset/tty.stp
+ </chapter>
+
<chapter id="networking.stp">
<title>Networking Tapset</title>
<para>
diff --git a/dtrace.in b/dtrace.in
index 976ba0cf..74d70e77 100755
--- a/dtrace.in
+++ b/dtrace.in
@@ -46,7 +46,7 @@ class provider:
self.f = open(provider)
self.h = open(header,mode='w')
self.h.write("/* Generated by the Systemtap dtrace wrapper */\n")
- self.h.write("\n#define STAP_HAS_SEMAPHORES 1\n\n")
+ # self.h.write("\n#define STAP_HAS_SEMAPHORES 1\n\n")
self.h.write("\n#include <sys/sdt.h>\n\n")
in_comment = False
typedefs = ""
@@ -106,7 +106,8 @@ class provider:
stap_str = stap_str + ",arg%s" % (i);
i += 1
self.h.write ('/* %s (%s) */\n' % (this_probe_canon,args_string))
- self.h.write ('#define %s_ENABLED() %s_semaphore\n' % (this_probe_canon,this_probe))
+ # XXX Enable this when .so semaphores work properly
+ self.h.write ('#define %s_ENABLED() 1 /*%s_semaphore*/\n' % (this_probe_canon,this_probe))
# NB: unsigned short is fixed in ABI
self.h.write ("__extension__ extern unsigned short %s_semaphore __attribute__ ((unused)) __attribute__ ((section (\".probes\")));\n" % (this_probe))
self.h.write (define_str + ") \\\n")
diff --git a/dwflpp.cxx b/dwflpp.cxx
index b1d9a32b..0c45eb7d 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -2182,8 +2182,15 @@ dwflpp::express_as_string (string prelude,
fprintf(memstream, "{\n");
fprintf(memstream, "%s", prelude.c_str());
+
unsigned int stack_depth;
bool deref = c_emit_location (memstream, head, 1, &stack_depth);
+
+ // Ensure that DWARF keeps loc2c to a "reasonable" stack size
+ // 32 intptr_t leads to max 256 bytes on the stack
+ if (stack_depth > 32)
+ throw semantic_error("oversized DWARF stack");
+
fprintf(memstream, "%s", postlude.c_str());
fprintf(memstream, " goto out;\n");
diff --git a/elaborate.cxx b/elaborate.cxx
index 2446e4f8..626db280 100644
--- a/elaborate.cxx
+++ b/elaborate.cxx
@@ -157,7 +157,9 @@ derived_probe::emit_process_owner_assertion (translator_output* o)
o->newline() << " \"Internal Error: Process %d does not belong to user %d in probe %s in --unprivileged mode\",";
o->newline() << " current->tgid, _stp_uid, c->probe_point);";
o->newline() << "c->last_error = c->error_buffer;";
- o->newline() << "goto out;";
+ // NB: since this check occurs before probe locking, its exit should
+ // not be a "goto out", which would attempt unlocking.
+ o->newline() << "return;";
o->newline(-1) << "}";
o->newline(-1) << "#endif";
}
@@ -1711,7 +1713,7 @@ symresolution_info::visit_foreach_loop (foreach_loop* e)
{
if (!array->referent)
{
- vardecl* d = find_var (array->name, e->indexes.size ());
+ vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
if (d)
array->referent = d;
else
@@ -1760,7 +1762,7 @@ delete_statement_symresolution_info:
if (e->referent)
return;
- vardecl* d = parent->find_var (e->name, -1);
+ vardecl* d = parent->find_var (e->name, -1, e->tok);
if (d)
e->referent = d;
else
@@ -1782,7 +1784,7 @@ symresolution_info::visit_symbol (symbol* e)
if (e->referent)
return;
- vardecl* d = find_var (e->name, 0);
+ vardecl* d = find_var (e->name, 0, e->tok);
if (d)
e->referent = d;
else
@@ -1818,7 +1820,7 @@ symresolution_info::visit_arrayindex (arrayindex* e)
if (array->referent)
return;
- vardecl* d = find_var (array->name, e->indexes.size ());
+ vardecl* d = find_var (array->name, e->indexes.size (), array->tok);
if (d)
array->referent = d;
else
@@ -1877,7 +1879,7 @@ symresolution_info::visit_functioncall (functioncall* e)
vardecl*
-symresolution_info::find_var (const string& name, int arity)
+symresolution_info::find_var (const string& name, int arity, const token* tok)
{
if (current_function || current_probe)
{
@@ -1912,6 +1914,16 @@ symresolution_info::find_var (const string& name, int arity)
&& session.globals[i]->compatible_arity(arity))
{
session.globals[i]->set_arity (arity);
+ if (! session.suppress_warnings)
+ {
+ vardecl* v = session.globals[i];
+ // clog << "resolved " << *tok << " to global " << *v->tok << endl;
+ if (v->tok->location.file != tok->location.file)
+ {
+ session.print_warning ("cross-file global variable reference to " + lex_cast (*v->tok) + " from",
+ tok);
+ }
+ }
return session.globals[i];
}
diff --git a/elaborate.h b/elaborate.h
index bee71a50..fec62d59 100644
--- a/elaborate.h
+++ b/elaborate.h
@@ -37,7 +37,7 @@ public:
derived_probe* current_probe;
symresolution_info (systemtap_session& s);
- vardecl* find_var (const std::string& name, int arity);
+ vardecl* find_var (const std::string& name, int arity, const token *tok);
functiondecl* find_function (const std::string& name, unsigned arity);
void visit_block (block *s);
diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx
index e4c08cfd..0e26fb4d 100644
--- a/grapher/GraphData.hxx
+++ b/grapher/GraphData.hxx
@@ -6,6 +6,8 @@
#include <vector>
#include <tr1/memory>
+#include <boost/circular_buffer.hpp>
+
namespace systemtap
{
struct GraphDataBase
@@ -16,11 +18,12 @@ namespace systemtap
DOT,
EVENT
};
- GraphDataBase() : scale(1.0), style(BAR)
+ typedef boost::circular_buffer<double> TimeList;
+ GraphDataBase(TimeList::capacity_type cap = 50000)
+ : scale(1.0), style(BAR), times(cap)
{
color[0] = 0.0; color[1] = 1.0; color[2] = 0.0;
}
- typedef std::vector<double> TimeList;
// size of grid square at "normal" viewing
double scale;
double color[3];
@@ -36,7 +39,11 @@ namespace systemtap
{
public:
typedef T data_type;
- typedef std::vector<data_type> DataList;
+ typedef boost::circular_buffer<data_type> DataList;
+ GraphData(typename DataList::capacity_type cap = 50000)
+ : GraphDataBase(cap), data(cap)
+ {
+ }
DataList data;
};
struct CSVData
diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx
index 9bb9b9c9..9e42dab6 100644
--- a/grapher/StapParser.cxx
+++ b/grapher/StapParser.cxx
@@ -63,17 +63,17 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
using namespace boost;
if (ioCondition & Glib::IO_HUP)
{
- _win.hide();
+ _win->hide();
return true;
}
if ((ioCondition & Glib::IO_IN) == 0)
return true;
char buf[256];
ssize_t bytes_read = 0;
- bytes_read = read(STDIN_FILENO, buf, sizeof(buf) - 1);
+ bytes_read = read(_inFd, buf, sizeof(buf) - 1);
if (bytes_read <= 0)
{
- _win.hide();
+ _win->hide();
return true;
}
buf[bytes_read] = '\0';
@@ -108,7 +108,7 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
dataSet->color[2] = (hexColor & 0xff) / 255.0;
dataSet->scale = scale;
_dataSets.insert(std::make_pair(setName, dataSet));
- _widget.addGraphData(dataSet);
+ _widget->addGraphData(dataSet);
}
else if (style == "discreet")
{
@@ -120,7 +120,7 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
dataSet->color[2] = (hexColor & 0xff) / 255.0;
dataSet->scale = scale;
_dataSets.insert(std::make_pair(setName, dataSet));
- _widget.addGraphData(dataSet);
+ _widget->addGraphData(dataSet);
}
}
else if ((found = find_first(dataString, "%CSV:")))
@@ -156,18 +156,15 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
shared_ptr<GraphDataBase> gdata = itr->second;
string decl;
// Hack: scan from the beginning of dataString again
- if (findTaggedValue(dataString, "%Title:", decl)
- != string::npos)
+ if (findTaggedValue(dataString, "%Title:", decl))
{
gdata->title = decl;
}
- else if (findTaggedValue(dataString, "%XAxisTitle:", decl)
- != string::npos)
+ else if (findTaggedValue(dataString, "%XAxisTitle:", decl))
{
gdata->xAxisText = decl;
}
- else if (findTaggedValue(dataString, "%YAxisTitle:", decl)
- != string::npos)
+ else if (findTaggedValue(dataString, "%YAxisTitle:", decl))
{
gdata->yAxisText = decl;
}
@@ -179,29 +176,32 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
stream >> ymax;
gdata->scale = ymax;
}
-
- if (!_csv.elements.empty())
- {
- vector<string> tokens = commaSplit(dataString);
- int i = 0;
- double time;
- vector<string>::iterator tokIter = tokens.begin();
- std::istringstream timeStream(*tokIter++);
- timeStream >> time;
- for (vector<string>::iterator e = tokens.end();
- tokIter != e;
- ++tokIter, ++i)
- {
- parseData(_csv.elements[i].second, time, *tokIter);
- }
- }
else
- {
- double time;
- string data;
- stream >> time >> data;
- parseData(itr->second, time, data);
- }
+ {
+ if (!_csv.elements.empty())
+ {
+ vector<string> tokens = commaSplit(dataString);
+ int i = 0;
+ double time;
+ vector<string>::iterator tokIter = tokens.begin();
+ std::istringstream timeStream(*tokIter++);
+ timeStream >> time;
+ for (vector<string>::iterator e = tokens.end();
+ tokIter != e;
+ ++tokIter, ++i)
+ {
+ parseData(_csv.elements[i].second, time,
+ *tokIter);
+ }
+ }
+ else
+ {
+ double time;
+ string data;
+ stream >> time >> data;
+ parseData(itr->second, time, data);
+ }
+ }
}
}
_buffer.erase(0, ret + 1);
@@ -219,7 +219,7 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
bytes_read = read(_errFd, buf, sizeof(buf) - 1);
if (bytes_read <= 0)
{
- _win.hide();
+ _win->hide();
return true;
}
if (write(STDOUT_FILENO, buf, bytes_read) < 0)
diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx
index f4f6bdef..40add9fd 100644
--- a/grapher/StapParser.hxx
+++ b/grapher/StapParser.hxx
@@ -10,17 +10,23 @@ class StapParser
typedef std::map<std::string, std::tr1::shared_ptr<GraphDataBase> > DataMap;
DataMap _dataSets;
CSVData _csv;
- Gtk::Window& _win;
- GraphWidget& _widget;
+ Gtk::Window* _win;
+ GraphWidget* _widget;
int _errFd;
+ int _inFd;
public:
- StapParser(Gtk::Window& win,
- GraphWidget& widget) : _win(win), _widget(widget), _errFd(-1) {}
+ StapParser(Gtk::Window* win,
+ GraphWidget* widget) : _win(win), _widget(widget), _errFd(-1),
+ _inFd(-1)
+ {
+ }
void parseData(std::tr1::shared_ptr<GraphDataBase> gdata,
double time, const std::string& dataString);
bool ioCallback(Glib::IOCondition ioCondition);
bool errIoCallback(Glib::IOCondition ioCondition);
int getErrFd() { return _errFd; }
void setErrFd(int fd) { _errFd = fd; }
+ int getInFd() { return _inFd; }
+ void setInFd(int fd) { _inFd = fd; }
};
}
diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx
index 429d0537..fe9880b2 100644
--- a/grapher/grapher.cxx
+++ b/grapher/grapher.cxx
@@ -10,10 +10,13 @@
#include <sstream>
#include <string>
#include <map>
+#include <memory>
#include <vector>
#include <signal.h>
+#include <boost/bind.hpp>
+
#include <gtkmm.h>
#include <gtkmm/button.h>
#include <gtkmm/stock.h>
@@ -31,6 +34,20 @@ using namespace std;
using namespace systemtap;
+// magic for noticing that the child stap process has died.
+int signalPipe[2] = {-1, -1};
+
+extern "C"
+{
+ void handleChild(int signum, siginfo_t* info, void* context)
+ {
+ char buf[1];
+ ssize_t err;
+ buf[0] = 1;
+ err = write(signalPipe[1], buf, 1);
+ }
+}
+
// Waits for a gtk I/O signal, indicating that a child has died, then
// performs an action
@@ -46,6 +63,20 @@ public:
ChildDeathReader(int sigfd_) : sigfd(sigfd_) {}
int getSigfd() { return sigfd; }
void setSigfd(int sigfd_) { sigfd = sigfd_; }
+ virtual pid_t reap()
+ {
+ pid_t pid;
+ int status;
+ if ((pid = waitpid(-1, &status, WNOHANG)) == -1)
+ {
+ std::perror("waitpid");
+ return -1;
+ }
+ else
+ {
+ return pid;
+ }
+ }
bool ioCallback(Glib::IOCondition ioCondition)
{
if ((ioCondition & Glib::IO_IN) == 0)
@@ -54,152 +85,26 @@ public:
if (read(sigfd, &buf, 1) <= 0)
return true;
- int status;
- while (wait(&status) != -1)
- ;
+ reap();
return true;
}
private:
int sigfd;
};
-class StapLauncher;
-
-class GraphicalStapLauncher
-{
-public:
- GraphicalStapLauncher(StapLauncher* launcher);
- bool runDialog();
- void onLaunch();
- void onLaunchCancel();
-private:
- Glib::RefPtr<Gnome::Glade::Xml> _launchStapDialog;
- Gtk::Window* _scriptWindow;
- Gtk::FileChooserButton* _chooserButton;
- Gtk::Entry* _stapArgEntry;
- Gtk::Entry* _scriptArgEntry;
- StapLauncher* _launcher;
-};
-
-class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback
-{
-public:
- GrapherWindow();
- virtual ~GrapherWindow() {}
- Gtk::VBox m_Box;
- Gtk::ScrolledWindow scrolled;
- GraphWidget w;
- void childDied(int pid);
- void setGraphicalLauncher(GraphicalStapLauncher* launcher)
- {
- _graphicalLauncher = launcher;
- }
- GraphicalStapLauncher* getGraphicalLauncher() { return _graphicalLauncher; }
-protected:
- virtual void on_menu_file_quit();
- virtual void on_menu_script_start();
- void addGraph();
- // menu support
- Glib::RefPtr<Gtk::UIManager> m_refUIManager;
- Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
- GraphicalStapLauncher* _graphicalLauncher;
-
-};
-
-GrapherWindow::GrapherWindow()
-{
- set_title("systemtap grapher");
- add(m_Box);
-
-
- //Create actions for menus and toolbars:
- m_refActionGroup = Gtk::ActionGroup::create();
- //File menu:
- m_refActionGroup->add(Gtk::Action::create("FileMenu", "File"));
- m_refActionGroup->add(Gtk::Action::create("StartScript", "Start script"),
- sigc::mem_fun(*this,
- &GrapherWindow::on_menu_script_start));
- m_refActionGroup->add(Gtk::Action::create("AddGraph", "Add graph"),
- sigc::mem_fun(*this, &GrapherWindow::addGraph));
- m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
- sigc::mem_fun(*this,
- &GrapherWindow::on_menu_file_quit));
- m_refUIManager = Gtk::UIManager::create();
- m_refUIManager->insert_action_group(m_refActionGroup);
-
- add_accel_group(m_refUIManager->get_accel_group());
- //Layout the actions in a menubar and toolbar:
- Glib::ustring ui_info =
- "<ui>"
- " <menubar name='MenuBar'>"
- " <menu action='FileMenu'>"
- " <menuitem action='StartScript'/>"
- " <menuitem action='AddGraph'/>"
- " <menuitem action='FileQuit'/>"
- " </menu>"
- " </menubar>"
- "</ui>";
- try
- {
- m_refUIManager->add_ui_from_string(ui_info);
- }
- catch(const Glib::Error& ex)
- {
- std::cerr << "building menus failed: " << ex.what();
- }
- Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar");
- scrolled.add(w);
- if(pMenubar)
- m_Box.pack_start(*pMenubar, Gtk::PACK_SHRINK);
- m_Box.pack_start(scrolled, Gtk::PACK_EXPAND_WIDGET);
- scrolled.show();
-
- show_all_children();
-
-}
-
-void GrapherWindow::on_menu_file_quit()
-{
- hide();
-}
-
-void GrapherWindow::on_menu_script_start()
-{
- _graphicalLauncher->runDialog();
-}
-
-void GrapherWindow::childDied(int pid)
-{
- hide();
-}
-
-// magic for noticing that the child stap process has died.
-int signalPipe[2] = {-1, -1};
-
-extern "C"
-{
- void handleChild(int signum, siginfo_t* info, void* context)
- {
- char buf[1];
- ssize_t err;
- buf[0] = 1;
- err = write(signalPipe[1], buf, 1);
- }
-}
-
// Depending on how args are passed, either launch stap directly or
// use the shell to parse arguments
class StapLauncher : public ChildDeathReader
{
public:
- StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0), _stapParser(0) {}
+ StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0) {}
StapLauncher(char** argv)
- : _argv(argv), _childPid(-1), _deathCallback(0), _stapParser(0)
+ : _argv(argv), _childPid(-1), _deathCallback(0)
{
}
StapLauncher(const string& stapArgs, const string& script,
const string& scriptArgs)
- : _childPid(-1), _deathCallback(0), _stapParser(0)
+ : _childPid(-1), _deathCallback(0), _win(0), _widget(0)
{
setArgs(stapArgs, script, scriptArgs);
}
@@ -239,12 +144,41 @@ public:
{
_deathCallback = callback;
}
- void setStapParser(StapParser *parser)
+ void setWinParams(Gtk::Window* win, GraphWidget* widget)
{
- _stapParser = parser;
+ _win = win;
+ _widget = widget;
}
int launch();
void cleanUp();
+ tr1::shared_ptr<StapParser> makeStapParser()
+ {
+ tr1::shared_ptr<StapParser> result(new StapParser(_win, _widget));
+ _parsers.push_back(ParserInstance(-1, result));
+ return result;
+ }
+ pid_t reap()
+ {
+ pid_t pid = ChildDeathReader::reap();
+ if (pid < 0)
+ return pid;
+ ParserList::iterator itr
+ = find_if(_parsers.begin(), _parsers.end(),
+ boost::bind(&ParserInstance::childPid, _1) == pid);
+ if (itr != _parsers.end())
+ itr->childPid = -1;
+ return pid;
+ }
+ void killAll()
+ {
+ for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end();
+ itr != end;
+ ++itr)
+ {
+ if (itr->childPid >= 0)
+ kill(itr->childPid, SIGTERM);
+ }
+ }
protected:
char** _argv;
string _stapArgs;
@@ -252,17 +186,39 @@ protected:
string _scriptArgs;
int _childPid;
ChildDeathReader::Callback* _deathCallback;
- StapParser* _stapParser;
+ Gtk::Window* _win;
+ GraphWidget* _widget;
+ struct ParserInstance
+ {
+ ParserInstance() : childPid(-1) {}
+ ParserInstance(int childPid_, tr1::shared_ptr<StapParser> stapParser_)
+ : childPid(childPid_), stapParser(stapParser_)
+ {
+ }
+ pid_t childPid;
+ tr1::shared_ptr<StapParser> stapParser;
+ };
+ typedef vector<ParserInstance> ParserList;
+ ParserList _parsers;
};
int StapLauncher::launch()
{
- int stapErrFd = -1;
-
- if (pipe(&signalPipe[0]) < 0)
+ int childPid = -1;
+ if (signalPipe[0] < 0)
{
- std::perror("pipe");
- exit(1);
+ if (pipe(&signalPipe[0]) < 0)
+ {
+ std::perror("pipe");
+ exit(1);
+ }
+ setSigfd(signalPipe[0]);
+ if (signalPipe[0] >= 0)
+ {
+ Glib::signal_io().connect(sigc::mem_fun(*this,
+ &ChildDeathReader::ioCallback),
+ signalPipe[0], Glib::IO_IN);
+ }
}
struct sigaction action;
action.sa_sigaction = handleChild;
@@ -280,15 +236,12 @@ int StapLauncher::launch()
std::perror("pipe");
exit(1);
}
- if ((_childPid = fork()) == -1)
+ if ((childPid = fork()) == -1)
{
exit(1);
}
- else if (_childPid)
+ else if (childPid)
{
- dup2(pipefd[0], STDIN_FILENO);
- stapErrFd = pipefd[2];
- close(pipefd[0]);
close(pipefd[1]);
close(pipefd[3]);
}
@@ -296,8 +249,8 @@ int StapLauncher::launch()
{
dup2(pipefd[1], STDOUT_FILENO);
dup2(pipefd[3], STDERR_FILENO);
- for (int i = 0; i < 4; ++i)
- close(pipefd[i]);
+ for_each(&pipefd[0], &pipefd[4], close);
+ for_each(&signalPipe[0], &signalPipe[2], close);
if (_argv)
{
char argv0[] = "stap";
@@ -318,70 +271,192 @@ int StapLauncher::launch()
}
_exit(1);
}
- if (stapErrFd >= 0)
- {
- _stapParser->setErrFd(stapErrFd);
- Glib::signal_io().connect(sigc::mem_fun(*_stapParser,
- &StapParser::errIoCallback),
- stapErrFd,
- Glib::IO_IN);
- }
- setSigfd(signalPipe[0]);
- if (signalPipe[0] >= 0)
- {
- Glib::signal_io().connect(sigc::mem_fun(*this,
- &ChildDeathReader::ioCallback),
- signalPipe[0], Glib::IO_IN);
- }
- Glib::signal_io().connect(sigc::mem_fun(*_stapParser,
+ tr1::shared_ptr<StapParser> sp(new StapParser(_win, _widget));
+ _parsers.push_back(ParserInstance(childPid, sp));
+ sp->setErrFd(pipefd[2]);
+ sp->setInFd(pipefd[0]);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
+ &StapParser::errIoCallback),
+ pipefd[2],
+ Glib::IO_IN);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
&StapParser::ioCallback),
- STDIN_FILENO,
+ pipefd[0],
Glib::IO_IN | Glib::IO_HUP);
- return _childPid;
+ return childPid;
}
void StapLauncher::cleanUp()
{
- if (_childPid > 0)
- kill(_childPid, SIGTERM);
- int status;
- while (wait(&status) != -1)
- ;
- if (_deathCallback)
+ struct sigaction action;
+ action.sa_handler = SIG_DFL;
+ sigemptyset(&action.sa_mask);
+ action.sa_flags = 0;
+ sigaction(SIGCLD, &action, 0);
+ // Drain any outstanding signals
+ close(signalPipe[1]);
+ char buf;
+ while (read(signalPipe[0], &buf, 1) > 0)
+ reap();
+ for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end();
+ itr != end;
+ ++itr)
{
- _deathCallback->childDied(_childPid);
- _childPid = -1;
+ if (itr->childPid > 0)
+ kill(itr->childPid, SIGTERM);
+ int status;
+ pid_t killedPid = -1;
+ if ((killedPid = wait(&status)) == -1)
+ {
+ std::perror("wait");
+ }
+ else if (killedPid != itr->childPid)
+ {
+ std::cerr << "wait: killed Pid " << killedPid << " != child Pid "
+ << itr->childPid << "\n";
+ }
+ else if (_deathCallback)
+ _deathCallback->childDied(itr->childPid);
}
}
-StapLauncher launcher;
+class GraphicalStapLauncher : public StapLauncher
+{
+public:
+ GraphicalStapLauncher();
+ bool runDialog();
+ void onLaunch();
+ void onLaunchCancel();
+private:
+ Glib::RefPtr<Gnome::Glade::Xml> _launchStapDialog;
+ Gtk::Window* _scriptWindow;
+ Gtk::FileChooserButton* _chooserButton;
+ Gtk::Entry* _stapArgEntry;
+ Gtk::Entry* _scriptArgEntry;
+};
+
+class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback
+{
+public:
+ GrapherWindow();
+ virtual ~GrapherWindow() {}
+ Gtk::VBox m_Box;
+ Gtk::ScrolledWindow scrolled;
+ GraphWidget w;
+ void childDied(int pid);
+ void setGraphicalLauncher(GraphicalStapLauncher* launcher)
+ {
+ _graphicalLauncher = launcher;
+ }
+ GraphicalStapLauncher* getGraphicalLauncher() { return _graphicalLauncher; }
+protected:
+ virtual void on_menu_file_quit();
+ virtual void on_menu_script_start();
+ void addGraph();
+ // menu support
+ Glib::RefPtr<Gtk::UIManager> m_refUIManager;
+ Glib::RefPtr<Gtk::ActionGroup> m_refActionGroup;
+ GraphicalStapLauncher* _graphicalLauncher;
+
+};
+
+GrapherWindow::GrapherWindow()
+{
+ set_title("systemtap grapher");
+ add(m_Box);
+
+
+ //Create actions for menus and toolbars:
+ m_refActionGroup = Gtk::ActionGroup::create();
+ //File menu:
+ m_refActionGroup->add(Gtk::Action::create("FileMenu", "File"));
+ m_refActionGroup->add(Gtk::Action::create("StartScript", "Start script"),
+ sigc::mem_fun(*this,
+ &GrapherWindow::on_menu_script_start));
+ m_refActionGroup->add(Gtk::Action::create("AddGraph", "Add graph"),
+ sigc::mem_fun(*this, &GrapherWindow::addGraph));
+ m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT),
+ sigc::mem_fun(*this,
+ &GrapherWindow::on_menu_file_quit));
+ m_refUIManager = Gtk::UIManager::create();
+ m_refUIManager->insert_action_group(m_refActionGroup);
+
+ add_accel_group(m_refUIManager->get_accel_group());
+ //Layout the actions in a menubar and toolbar:
+ Glib::ustring ui_info =
+ "<ui>"
+ " <menubar name='MenuBar'>"
+ " <menu action='FileMenu'>"
+ " <menuitem action='StartScript'/>"
+ " <menuitem action='AddGraph'/>"
+ " <menuitem action='FileQuit'/>"
+ " </menu>"
+ " </menubar>"
+ "</ui>";
+ try
+ {
+ m_refUIManager->add_ui_from_string(ui_info);
+ }
+ catch(const Glib::Error& ex)
+ {
+ std::cerr << "building menus failed: " << ex.what();
+ }
+ Gtk::Widget* pMenubar = m_refUIManager->get_widget("/MenuBar");
+ scrolled.add(w);
+ if(pMenubar)
+ m_Box.pack_start(*pMenubar, Gtk::PACK_SHRINK);
+ m_Box.pack_start(scrolled, Gtk::PACK_EXPAND_WIDGET);
+ scrolled.show();
+
+ show_all_children();
+
+}
+
+void GrapherWindow::on_menu_file_quit()
+{
+ hide();
+}
+
+void GrapherWindow::on_menu_script_start()
+{
+ _graphicalLauncher->runDialog();
+}
+
+void GrapherWindow::childDied(int pid)
+{
+ hide();
+}
+
+
+
int main(int argc, char** argv)
{
Gtk::Main app(argc, argv);
-
+ GraphicalStapLauncher launcher;
GrapherWindow win;
win.set_title("Grapher");
win.set_default_size(600, 200);
+ launcher.setWinParams(&win, &win.w);
- StapParser stapParser(win, win.w);
- launcher.setStapParser(&stapParser);
- GraphicalStapLauncher graphicalLauncher(&launcher);
- win.setGraphicalLauncher(&graphicalLauncher);
- if (argc > 1)
- {
- launcher.setArgv(argv + 1);
- launcher.setDeathCallback(&win);
- launcher.launch();
- }
- else
+ win.setGraphicalLauncher(&launcher);
+
+ if (argc == 2 && !std::strcmp(argv[1], "-"))
{
- Glib::signal_io().connect(sigc::mem_fun(stapParser,
+ tr1::shared_ptr<StapParser> sp = launcher.makeStapParser();
+ sp->setInFd(STDIN_FILENO);
+ Glib::signal_io().connect(sigc::mem_fun(sp.get(),
&StapParser::ioCallback),
STDIN_FILENO,
Glib::IO_IN | Glib::IO_HUP);
}
+ else if (argc > 1)
+ {
+ launcher.setArgv(argv + 1);
+ launcher.setDeathCallback(&win);
+ launcher.launch();
+ }
Gtk::Main::run(win);
launcher.cleanUp();
return 0;
@@ -393,8 +468,7 @@ void GrapherWindow::addGraph()
}
-GraphicalStapLauncher::GraphicalStapLauncher(StapLauncher* launcher)
- : _launcher(launcher)
+GraphicalStapLauncher::GraphicalStapLauncher()
{
try
{
@@ -428,10 +502,10 @@ bool GraphicalStapLauncher::runDialog()
void GraphicalStapLauncher::onLaunch()
{
- _launcher->setArgs(_stapArgEntry->get_text(), _chooserButton->get_filename(),
- _scriptArgEntry->get_text());
+ setArgs(_stapArgEntry->get_text(), _chooserButton->get_filename(),
+ _scriptArgEntry->get_text());
_scriptWindow->hide();
- _launcher->launch();
+ launch();
}
void GraphicalStapLauncher::onLaunchCancel()
diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h
index d31d7326..3847c497 100644
--- a/includes/sys/sdt.h
+++ b/includes/sys/sdt.h
@@ -42,7 +42,7 @@
#if defined STAP_HAS_SEMAPHORES && defined EXPERIMENTAL_UTRACE_SDT
#define STAP_SEMAPHORE(probe) \
- if ( probe ## _semaphore )
+ if (__builtin_expect ( probe ## _semaphore , 0))
#else
#define STAP_SEMAPHORE(probe)
#endif
diff --git a/runtime/probe_lock.h b/runtime/probe_lock.h
new file mode 100644
index 00000000..1915d4ff
--- /dev/null
+++ b/runtime/probe_lock.h
@@ -0,0 +1,68 @@
+/* probe locking header file
+ * Copyright (C) 2009 Red Hat Inc.
+ *
+ * This file is part of systemtap, and is free software. You can
+ * redistribute it and/or modify it under the terms of the GNU General
+ * Public License (GPL); either version 2, or (at your option) any
+ * later version.
+ */
+
+#ifndef _PROBE_LOCK_H
+#define _PROBE_LOCK_H
+
+#include <linux/spinlock.h>
+
+// XXX: old 2.6 kernel hack
+#ifndef read_trylock
+#define read_trylock(x) ({ read_lock(x); 1; })
+#endif
+
+struct stp_probe_lock {
+ #ifdef STP_TIMING
+ atomic_t *skipped;
+ #endif
+ rwlock_t *lock;
+ unsigned write_p;
+};
+
+
+static void
+stp_unlock_probe(const struct stp_probe_lock *locks, unsigned num_locks)
+{
+ unsigned i;
+ for (i = num_locks; i-- > 0;) {
+ if (locks[i].write_p)
+ write_unlock(locks[i].lock);
+ else
+ read_unlock(locks[i].lock);
+ }
+}
+
+
+static unsigned
+stp_lock_probe(const struct stp_probe_lock *locks, unsigned num_locks)
+{
+ unsigned i, numtrylock = 0;
+ for (i = 0; i < num_locks; ++i) {
+ if (locks[i].write_p)
+ while (!write_trylock(locks[i].lock) &&
+ (++numtrylock < MAXTRYLOCK))
+ ndelay (TRYLOCKDELAY);
+ else
+ while (!read_trylock(locks[i].lock) &&
+ (++numtrylock < MAXTRYLOCK))
+ ndelay (TRYLOCKDELAY);
+ if (unlikely(numtrylock >= MAXTRYLOCK)) {
+ atomic_inc(&skipped_count);
+ #ifdef STP_TIMING
+ atomic_inc(locks[i].skipped);
+ #endif
+ stp_unlock_probe(locks, i);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+#endif /* _PROBE_LOCK_H */
diff --git a/runtime/staprun/mainloop.c b/runtime/staprun/mainloop.c
index cf8bef9a..ab228937 100644
--- a/runtime/staprun/mainloop.c
+++ b/runtime/staprun/mainloop.c
@@ -38,7 +38,7 @@ static void *signal_thread(void *arg)
}
dbug(2, "sigproc %d (%s)\n", signum, strsignal(signum));
if (signum == SIGQUIT)
- cleanup_and_exit(1);
+ cleanup_and_exit(1, 0);
else if (signum == SIGINT || signum == SIGHUP || signum == SIGTERM) {
// send STP_EXIT
rc = write(control_channel, &btype, sizeof(btype));
@@ -383,7 +383,7 @@ int init_stapio(void)
/* cleanup_and_exit() closed channels, frees memory,
* removes the module (if necessary) and exits. */
-void cleanup_and_exit(int detach)
+void cleanup_and_exit(int detach, int rc)
{
static int exiting = 0;
const char *staprun;
@@ -467,7 +467,7 @@ void cleanup_and_exit(int detach)
}
if (WIFEXITED(rstatus)) {
- _exit(WEXITSTATUS(rstatus)); /* only possibility for rc=0 exit */
+ _exit(rc ?: WEXITSTATUS(rstatus));
}
_exit(-1);
}
@@ -484,8 +484,9 @@ int stp_main_loop(void)
uint32_t type;
FILE *ofp = stdout;
char recvbuf[8196];
+ int error_detected = 0;
- setvbuf(ofp, (char *)NULL, _IOLBF, 0);
+ setvbuf(ofp, (char *)NULL, _IONBF, 0);
setup_main_signals();
dbug(2, "in main loop\n");
@@ -511,18 +512,21 @@ int stp_main_loop(void)
case STP_REALTIME_DATA:
if (write_realtime_data(data, nb)) {
_perr("write error (nb=%ld)", (long)nb);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
break;
#endif
case STP_OOB_DATA:
eprintf("%s", (char *)data);
+ if (strncmp(data, "ERROR:", 5) == 0){
+ error_detected = 1;
+ }
break;
case STP_EXIT:
{
/* module asks us to unload it and exit */
dbug(2, "got STP_EXIT\n");
- cleanup_and_exit(0);
+ cleanup_and_exit(0, error_detected);
break;
}
case STP_REQUEST_EXIT:
@@ -540,7 +544,7 @@ int stp_main_loop(void)
if (t->res < 0) {
if (target_cmd)
kill(target_pid, SIGKILL);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
} else if (target_cmd) {
dbug(1, "detaching pid %d\n", target_pid);
#if WORKAROUND_BZ467568
@@ -555,7 +559,7 @@ int stp_main_loop(void)
perror ("ptrace detach");
if (target_cmd)
kill(target_pid, SIGKILL);
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
#endif
}
@@ -573,15 +577,15 @@ int stp_main_loop(void)
struct _stp_msg_start ts;
if (use_old_transport) {
if (init_oldrelayfs() < 0)
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
} else {
if (init_relayfs() < 0)
- cleanup_and_exit(0);
+ cleanup_and_exit(0, 1);
}
ts.target = target_pid;
send_request(STP_START, &ts, sizeof(ts));
if (load_only)
- cleanup_and_exit(1);
+ cleanup_and_exit(1, 0);
break;
}
default:
diff --git a/runtime/staprun/staprun.h b/runtime/staprun/staprun.h
index f9f01003..9cdbc861 100644
--- a/runtime/staprun/staprun.h
+++ b/runtime/staprun/staprun.h
@@ -114,7 +114,7 @@ int init_staprun(void);
int init_stapio(void);
int stp_main_loop(void);
int send_request(int type, void *data, int len);
-void cleanup_and_exit (int);
+void cleanup_and_exit (int, int);
int init_ctl_channel(const char *name, int verb);
void close_ctl_channel(void);
int init_relayfs(void);
diff --git a/runtime/stat-common.c b/runtime/stat-common.c
index e6fd3a11..7123dc8e 100644
--- a/runtime/stat-common.c
+++ b/runtime/stat-common.c
@@ -270,7 +270,7 @@ static void _stp_stat_print_histogram_buf(char *buf, size_t size, Hist st, stat
for (j = 0; j < v; ++j)
HIST_PRINTF("@");
- HIST_PRINTF("%*lld\n", HIST_WIDTH - v + 1 + cnt_space, sd->histogram[i]);
+ HIST_PRINTF("%*lld\n", (int)(HIST_WIDTH - v + 1 + cnt_space), sd->histogram[i]);
}
HIST_PRINTF("\n");
#undef HIST_PRINTF
diff --git a/runtime/string.c b/runtime/string.c
index cdafbf64..b3f81f0e 100644
--- a/runtime/string.c
+++ b/runtime/string.c
@@ -21,7 +21,11 @@
*/
/** Sprintf into a string.
- * Like printf, except output goes into a string.
+ * Like printf, except output goes into a string.
+ *
+ * NB: these are script language printf formatting directives, where
+ * %d ints are 64-bits etc, so we can't use gcc level attribute printf
+ * to type-check the arguments.
*
* @param str string
* @param fmt A printf-style format string followed by a
diff --git a/runtime/task_finder.c b/runtime/task_finder.c
index 6b50f1b9..e89ac8ee 100644
--- a/runtime/task_finder.c
+++ b/runtime/task_finder.c
@@ -87,15 +87,15 @@ struct stap_task_finder_target {
struct list_head callback_list_head;
struct list_head callback_list;
struct utrace_engine_ops ops;
+ size_t pathlen;
unsigned engine_attached:1;
unsigned mmap_events:1;
unsigned munmap_events:1;
unsigned mprotect_events:1;
- size_t pathlen;
/* public: */
- const char *procname;
pid_t pid;
+ const char *procname;
stap_task_finder_callback callback;
stap_task_finder_mmap_callback mmap_callback;
stap_task_finder_munmap_callback munmap_callback;
diff --git a/runtime/transport/transport.c b/runtime/transport/transport.c
index f5efce9f..bab5efa9 100644
--- a/runtime/transport/transport.c
+++ b/runtime/transport/transport.c
@@ -19,6 +19,7 @@
#include <linux/namei.h>
#include <linux/workqueue.h>
#include <linux/delay.h>
+#include <linux/mutex.h>
static int _stp_exit_flag = 0;
@@ -30,6 +31,9 @@ static int _stp_ctl_attached = 0;
static pid_t _stp_target = 0;
static int _stp_probes_started = 0;
+static int _stp_exit_called = 0;
+static DEFINE_MUTEX(_stp_transport_mutex);
+
// For now, disable transport version 3 (unless STP_USE_RING_BUFFER is
// defined).
@@ -81,22 +85,26 @@ static struct workqueue_struct *_stp_wq;
static void _stp_handle_start(struct _stp_msg_start *st)
{
- dbug_trans(1, "stp_handle_start\n");
+ mutex_lock(&_stp_transport_mutex);
+ if (!_stp_exit_called) {
+ dbug_trans(1, "stp_handle_start\n");
#ifdef STAPCONF_VM_AREA
- { /* PR9740: workaround for kernel valloc bug. */
- void *dummy;
- dummy = alloc_vm_area (PAGE_SIZE);
- free_vm_area (dummy);
- }
+ { /* PR9740: workaround for kernel valloc bug. */
+ void *dummy;
+ dummy = alloc_vm_area (PAGE_SIZE);
+ free_vm_area (dummy);
+ }
#endif
- _stp_target = st->target;
- st->res = probe_start();
- if (st->res >= 0)
- _stp_probes_started = 1;
+ _stp_target = st->target;
+ st->res = probe_start();
+ if (st->res >= 0)
+ _stp_probes_started = 1;
- _stp_ctl_send(STP_START, st, sizeof(*st));
+ _stp_ctl_send(STP_START, st, sizeof(*st));
+ }
+ mutex_unlock(&_stp_transport_mutex);
}
/* common cleanup code. */
@@ -106,8 +114,7 @@ static void _stp_handle_start(struct _stp_msg_start *st)
/* when someone does /sbin/rmmod on a loaded systemtap module. */
static void _stp_cleanup_and_exit(int send_exit)
{
- static int _stp_exit_called = 0;
-
+ mutex_lock(&_stp_transport_mutex);
if (!_stp_exit_called) {
int failures;
@@ -135,6 +142,7 @@ static void _stp_cleanup_and_exit(int send_exit)
_stp_ctl_send(STP_EXIT, NULL, 0);
dbug_trans(1, "done with ctl_send STP_EXIT\n");
}
+ mutex_unlock(&_stp_transport_mutex);
}
static void _stp_request_exit(void)
@@ -293,7 +301,7 @@ err0:
static inline void _stp_lock_inode(struct inode *inode)
{
-#ifdef DEFINE_MUTEX
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
mutex_lock(&inode->i_mutex);
#else
down(&inode->i_sem);
@@ -302,7 +310,7 @@ static inline void _stp_lock_inode(struct inode *inode)
static inline void _stp_unlock_inode(struct inode *inode)
{
-#ifdef DEFINE_MUTEX
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
mutex_unlock(&inode->i_mutex);
#else
up(&inode->i_sem);
diff --git a/runtime/transport/transport.h b/runtime/transport/transport.h
index 871e37b3..ddd85495 100644
--- a/runtime/transport/transport.h
+++ b/runtime/transport/transport.h
@@ -13,9 +13,6 @@
static int _stp_ctl_write(int type, void *data, unsigned len);
-static int _stp_transport_init(void);
-static void _stp_transport_close(void);
-
/* STP_CTL_BUFFER_SIZE is the maximum size of a message */
/* exchanged on the control channel. */
#if STP_TRANSPORT_VERSION == 1
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 00108a39..7607770e 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -88,7 +88,7 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
/* given an FDE, find its CIE */
static const u32 *cie_for_fde(const u32 *fde, void *unwind_data,
- int is_ehframe)
+ uint32_t table_len, int is_ehframe)
{
const u32 *cie;
@@ -118,6 +118,11 @@ static const u32 *cie_for_fde(const u32 *fde, void *unwind_data,
else
cie = unwind_data + fde[1];
+ /* Make sure address falls in the table */
+ if (((void *)cie) < ((void*)unwind_data)
+ || ((void*)cie) > ((void*)(unwind_data + table_len)))
+ return NULL;
+
if (*cie <= sizeof(*cie) + 4 || *cie >= fde[1] - sizeof(*fde)
|| (*cie & (sizeof(*cie) - 1))
|| (cie[1] != 0xffffffff && cie[1] != 0)) {
@@ -200,7 +205,8 @@ static unsigned long read_pointer(const u8 **pLoc, const void *end, signed ptrTy
return value;
}
-static signed fde_pointer_type(const u32 *cie)
+static signed fde_pointer_type(const u32 *cie, void *unwind_data,
+ uint32_t table_len)
{
const u8 *ptr = (const u8 *)(cie + 2);
unsigned version = *ptr;
@@ -212,11 +218,16 @@ static signed fde_pointer_type(const u32 *cie)
const u8 *end = (const u8 *)(cie + 1) + *cie;
uleb128_t len;
+ /* end of cie should fall within unwind table. */
+ if (((void*)end) < ((void *)unwind_data)
+ || ((void *)end) > ((void *)(unwind_data + table_len)))
+ return -1;
+
/* check if augmentation size is first (and thus present) */
if (*ptr != 'z')
return -1;
/* check if augmentation string is nul-terminated */
- if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
+ if ((ptr = memchr(aug = (const void *)ptr, 0, end - ptr)) == NULL)
return -1;
++ptr; /* skip terminator */
get_uleb128(&ptr, end); /* skip code alignment */
@@ -267,6 +278,10 @@ static void set_rule(uleb128_t reg, enum item_location where, uleb128_t value, s
}
}
+/* Limit the number of instructions we process. Arbitrary limit.
+ 512 should be enough for anybody... */
+#define MAX_CFI 512
+
static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, signed ptrType, struct unwind_state *state)
{
union {
@@ -276,6 +291,9 @@ static int processCFI(const u8 *start, const u8 *end, unsigned long targetLoc, s
} ptr;
int result = 1;
+ if (end - start > MAX_CFI)
+ return 0;
+
dbug_unwind(1, "targetLoc=%lx state->loc=%lx\n", targetLoc, state->loc);
if (start != state->cieStart) {
state->loc = state->org;
@@ -606,10 +624,10 @@ static int unwind_frame(struct unwind_frame_info *frame,
/* found the fde, now set startLoc and endLoc */
if (fde != NULL) {
- cie = cie_for_fde(fde, table, is_ehframe);
+ cie = cie_for_fde(fde, table, table_len, is_ehframe);
if (likely(cie != NULL && cie != &bad_cie && cie != &not_fde)) {
ptr = (const u8 *)(fde + 2);
- ptrType = fde_pointer_type(cie);
+ ptrType = fde_pointer_type(cie, table, table_len);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
@@ -632,12 +650,12 @@ static int unwind_frame(struct unwind_frame_info *frame,
for (fde = table, tableSize = table_len; cie = NULL, tableSize > sizeof(*fde)
&& tableSize - sizeof(*fde) >= *fde; tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
dbug_unwind(3, "fde=%lx tableSize=%d\n", (long)*fde, (int)tableSize);
- cie = cie_for_fde(fde, table, is_ehframe);
+ cie = cie_for_fde(fde, table, table_len, is_ehframe);
if (cie == &bad_cie) {
cie = NULL;
break;
}
- if (cie == NULL || cie == &not_fde || (ptrType = fde_pointer_type(cie)) < 0)
+ if (cie == NULL || cie == &not_fde || (ptrType = fde_pointer_type(cie, table, table_len)) < 0)
continue;
ptr = (const u8 *)(fde + 2);
@@ -666,6 +684,12 @@ static int unwind_frame(struct unwind_frame_info *frame,
state.cieEnd = ptr; /* keep here temporarily */
ptr = (const u8 *)(cie + 2);
end = (const u8 *)(cie + 1) + *cie;
+
+ /* end should fall within unwind table. */
+ if (((void *)end) < table
+ || ((void *)end) > ((void *)(table + table_len)))
+ goto err;
+
frame->call_frame = 1;
if ((state.version = *ptr) != 1) {
dbug_unwind(1, "CIE version number is %d. 1 is supported.\n", state.version);
@@ -723,6 +747,11 @@ static int unwind_frame(struct unwind_frame_info *frame,
state.cieEnd = end;
end = (const u8 *)(fde + 1) + *fde;
+ /* end should fall within unwind table. */
+ if (((void*)end) < table
+ || ((void *)end) > ((void *)(table + table_len)))
+ goto err;
+
/* skip augmentation */
if (((const char *)(cie + 2))[1] == 'z') {
uleb128_t augSize = get_uleb128(&ptr, end);
diff --git a/runtime/unwind/unwind.h b/runtime/unwind/unwind.h
index 285a3a34..023ea603 100644
--- a/runtime/unwind/unwind.h
+++ b/runtime/unwind/unwind.h
@@ -143,8 +143,10 @@ static unsigned long read_pointer(const u8 **pLoc,
const void *end,
signed ptrType);
static const u32 bad_cie, not_fde;
-static const u32 *cie_for_fde(const u32 *fde, void *table, int is_ehframe);
-static signed fde_pointer_type(const u32 *cie);
+static const u32 *cie_for_fde(const u32 *fde, void *table,
+ uint32_t table_len, int is_ehframe);
+static signed fde_pointer_type(const u32 *cie,
+ void *table, uint32_t table_len);
#endif /* STP_USE_DWARF_UNWINDER */
diff --git a/stap-gen-cert b/stap-gen-cert
index 54195187..ffd7f6f1 100755
--- a/stap-gen-cert
+++ b/stap-gen-cert
@@ -13,30 +13,6 @@
# Initialize the environment
. `dirname $0`/stap-env
-# Obtain a password from stdin and echo it.
-function user_enter_password
-{
- while true
- do
- while true
- do
- read -sp "Enter new password for systemtap server certificate/key database:" pw1 junk
- echo "" >&2
- test "X$pw1" != "X" && break
- done
- while true
- do
- read -sp "Reenter new password:" pw2 junk
- echo "" >&2
- test "X$pw2" != "X" && break
- done
- test "$pw1" = "$pw2" && break
- echo "Passwords do not match" >&2
- done
-
- echo $pw1
-}
-
# Obtain the certificate database directory name.
serverdb=$1
if test "X$serverdb" = "X"; then
@@ -60,7 +36,7 @@ fi
# Generate a random password.
mkpasswd -l 20 > $serverdb/pw 2>/dev/null || \
apg -a 1 -n 1 -m 20 -x 20 > $serverdb/pw 2>/dev/null || \
-user_enter_password > $serverdb/pw
+(read -n20 password </dev/urandom; echo "$password" > $serverdb/pw)
# Generate the server certificate database
if ! certutil -N -d $serverdb -f $serverdb/pw > /dev/null; then
diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx
index abc9759f..4bd4ecc1 100644
--- a/tapset-utrace.cxx
+++ b/tapset-utrace.cxx
@@ -785,10 +785,10 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "struct stap_task_finder_target tgt;";
s.op->newline() << "const char *pp;";
s.op->newline() << "void (*ph) (struct context*);";
+ s.op->newline() << "int engine_attached;";
s.op->newline() << "enum utrace_derived_probe_flags flags;";
s.op->newline() << "struct utrace_engine_ops ops;";
s.op->newline() << "unsigned long events;";
- s.op->newline() << "int engine_attached;";
s.op->newline() << "struct task_struct *tsk;";
s.op->newline() << "unsigned long sdt_sem_address;";
s.op->newline(-1) << "};";
diff --git a/tapset/aux_syscalls.stp b/tapset/aux_syscalls.stp
index 9347e46f..2f19ab16 100644
--- a/tapset/aux_syscalls.stp
+++ b/tapset/aux_syscalls.stp
@@ -1302,16 +1302,76 @@ function _sock_family_str(f) {
return sprintf("UNKNOWN VALUE: %d", f)
}
-function _sock_type_str(t) {
- if(t==1) return "SOCK_STREAM"
- if(t==2) return "SOCK_DGRAM"
- if(t==5) return "SOCK_SEQPACKET"
- if(t==3) return "SOCK_RAW"
- if(t==4) return "SOCK_RDM"
- if(t==6) return "SOCK_DCCP"
- if(t==10) return "SOCK_PACKET"
- return sprintf("UNKNOWN VALUE: %d", t)
-}
+function _sock_type_str:string(type:long)
+%{ /* pure */
+#ifdef SOCK_TYPE_MASK
+ int flags = (int)THIS->type & ~SOCK_TYPE_MASK;
+ int t = (int)THIS->type & SOCK_TYPE_MASK;
+#else
+ int t = (int)THIS->type;
+#endif
+
+ switch (t) {
+ case SOCK_STREAM:
+ strlcpy (THIS->__retvalue, "SOCK_STREAM", MAXSTRINGLEN);
+ break;
+ case SOCK_DGRAM:
+ strlcpy (THIS->__retvalue, "SOCK_DGRAM", MAXSTRINGLEN);
+ break;
+ case SOCK_RAW:
+ strlcpy (THIS->__retvalue, "SOCK_RAW", MAXSTRINGLEN);
+ break;
+ case SOCK_RDM:
+ strlcpy (THIS->__retvalue, "SOCK_RDM", MAXSTRINGLEN);
+ break;
+ case SOCK_SEQPACKET:
+ strlcpy (THIS->__retvalue, "SOCK_SEQPACKET", MAXSTRINGLEN);
+ break;
+#ifdef SOL_DCCP
+ case SOCK_DCCP:
+ strlcpy (THIS->__retvalue, "SOCK_DCCP", MAXSTRINGLEN);
+ break;
+#endif
+ case SOCK_PACKET:
+ strlcpy (THIS->__retvalue, "SOCK_PACKET", MAXSTRINGLEN);
+ break;
+ default:
+ strlcpy (THIS->__retvalue, "UNKNOWN VALUE: %d", t);
+ break;
+ }
+
+#ifdef SOCK_TYPE_MASK
+ if (flags & SOCK_CLOEXEC) {
+ strlcat (THIS->__retvalue, "|SOCK_CLOEXEC", MAXSTRINGLEN);
+ }
+ if (flags & SOCK_NONBLOCK) {
+ strlcat (THIS->__retvalue, "|SOCK_NONBLOCK", MAXSTRINGLEN);
+ }
+#endif
+%}
+
+function _sock_flags_str:string(f:long)
+%{ /* pure */
+#ifdef SOCK_TYPE_MASK
+ int flags = (int)THIS->f;
+ int len;
+
+ THIS->__retvalue[0] = '\0';
+ if (flags & SOCK_CLOEXEC) {
+ strlcat (THIS->__retvalue, "SOCK_CLOEXEC|", MAXSTRINGLEN);
+ }
+ if (flags & SOCK_NONBLOCK) {
+ strlcat (THIS->__retvalue, "SOCK_NONBLOCK|", MAXSTRINGLEN);
+ }
+ len = strlen(THIS->__retvalue);
+ if (len) {
+ THIS->__retvalue[len - 1] = '\0';
+ }
+ else {
+ strlcat (THIS->__retvalue, "0", MAXSTRINGLEN);
+ }
+#endif
+%}
function _opoll_op_str(o) {
if(o==1) return "EPOLL_CTL_ADD"
diff --git a/tapset/syscalls.stp b/tapset/syscalls.stp
index 825842a6..dde0ca9f 100644
--- a/tapset/syscalls.stp
+++ b/tapset/syscalls.stp
@@ -27,17 +27,29 @@
# accept _____________________________________________________
# long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
-# int __user *upeer_addrlen)
-probe syscall.accept = kernel.function("SyS_accept").call !,
- kernel.function("sys_accept").call ?
+# int __user *upeer_addrlen, int flags)
+probe syscall.accept = _syscall.accept4 !, _syscall.accept
{
name = "accept"
sockfd = $fd
addr_uaddr = $upeer_sockaddr
addrlen_uaddr = $upeer_addrlen
- argstr = sprintf("%d, %p, %p", $fd, $upeer_sockaddr, $upeer_addrlen)
+ argstr = sprintf("%d, %p, %p, %s", $fd, $upeer_sockaddr,
+ $upeer_addrlen, flags_str)
}
-probe syscall.accept.return = kernel.function("SyS_accept").return !,
+probe _syscall.accept4 = kernel.function("sys_accept4").call
+{
+ flags = $flags
+ flags_str = _sock_flags_str($flags)
+}
+probe _syscall.accept = kernel.function("SyS_accept").call !,
+ kernel.function("sys_accept").call ?
+{
+ flags = 0
+ flags_str = "0"
+}
+probe syscall.accept.return = kernel.function("sys_accept4").return !,
+ kernel.function("SyS_accept").return !,
kernel.function("sys_accept").return ?
{
name = "accept"
diff --git a/tapset/task.stp b/tapset/task.stp
index 3bb65413..90579d5d 100644
--- a/tapset/task.stp
+++ b/tapset/task.stp
@@ -45,21 +45,21 @@ function task_parent:long (task:long) %{ /* pure */
// EXIT_DEAD 32
function task_state:long (task:long)
{
- return @cast(task, "task_struct", "kernel")->state
+ return @cast(task, "task_struct", "kernel<linux/sched.h>")->state
}
// Return the name of the given task
function task_execname:string (task:long)
{
- return kernel_string(@cast(task, "task_struct", "kernel")->comm)
+ return kernel_string(@cast(task, "task_struct", "kernel<linux/sched.h>")->comm)
}
// Return the process id of the given task
function task_pid:long (task:long)
{
- return @cast(task, "task_struct", "kernel")->tgid
+ return @cast(task, "task_struct", "kernel<linux/sched.h>")->tgid
}
@@ -95,7 +95,7 @@ function pid2execname:string (pid:long) {
// Return the thread id of the given task
function task_tid:long (task:long)
{
- return @cast(task, "task_struct", "kernel")->pid
+ return @cast(task, "task_struct", "kernel<linux/sched.h>")->pid
}
@@ -181,11 +181,11 @@ function task_nice:long (task:long) %{ /* pure */
function task_cpu:long (task:long)
{
%( kernel_v >= "2.6.22" %?
- ti = @cast(task, "task_struct", "kernel")->stack
+ ti = @cast(task, "task_struct", "kernel<linux/sched.h>")->stack
%:
- ti = @cast(task, "task_struct", "kernel")->thread_info
+ ti = @cast(task, "task_struct", "kernel<linux/sched.h>")->thread_info
%)
- return @cast(ti, "thread_info", "kernel")->cpu
+ return @cast(ti, "thread_info", "kernel<linux/sched.h>")->cpu
}
// Return the number of open file handlers for the given task
diff --git a/tapset/tty.stp b/tapset/tty.stp
new file mode 100644
index 00000000..f6ce8ea9
--- /dev/null
+++ b/tapset/tty.stp
@@ -0,0 +1,189 @@
+// tty tapset
+// Copyright (C) 2009 IBM Corp.
+//
+// Author: Breno Leitao <leitao@linux.vnet.ibm.com>
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+/**
+ * probe tty.open - Called when a tty is opened
+ * @inode_number: the inode number
+ * @inode_state: the inode state
+ * @inode_flags: the inode flags
+ * @file_name: the file name
+ * @file_mode: the file mode
+ * @file_flags: the file flags
+ */
+probe tty.open = kernel.function("tty_open") {
+ inode_number= $inode->i_ino
+ inode_state = $inode->i_state
+ inode_flags = $inode->i_flags
+
+ file_name = d_name($filp->f_path->dentry)
+ file_mode = $filp->f_mode
+ file_flags = $filp->f_flags
+}
+
+/**
+ * probe tty.release - Called when the tty is closed
+ * @inode_number: the inode number
+ * @inode_state: the inode state
+ * @inode_flags: the inode flags
+ * @file_name: the file name
+ * @file_mode: the file mode
+ * @file_flags: the file flags
+ */
+probe tty.release = kernel.function("tty_release") {
+ inode_number= $inode->i_ino
+ inode_state = $inode->i_state
+ inode_flags = $inode->i_flags
+
+ file_name = d_name($filp->f_path->dentry)
+ file_mode = $filp->f_mode
+ file_flags = $filp->f_flags
+}
+
+/**
+ * probe tty.resize - Called when a terminal resize happens
+ * @name: the tty name
+ * @old_row: the old row value
+ * @old_col: the old col value
+ * @old_ypixel: the old ypixel
+ * @old_xpixel: the old xpixel
+ * @new_row: the new row value
+ * @new_col: the new col value
+ * @new_ypixel: the new ypixel value
+ * @new_xpixel: the new xpixel value
+*/
+probe tty.resize = kernel.function("tty_do_resize"){
+ name = kernel_string($tty->name)
+ old_row = $tty->winsize->ws_row
+ old_col = $tty->winsize->ws_col
+ old_ypixel = $tty->winsize->ws_ypixel
+ old_xpixel = $tty->winsize->ws_xpixel
+
+ new_row = $ws->ws_row
+ new_col = $ws->ws_col
+ new_ypixel = $ws->ws_ypixel
+ new_xpixel = $ws->ws_xpixel
+}
+
+/**
+ * probe tty.ioctl - called when a ioctl is request to the tty
+ * @name: the file name
+ * @cmd: the ioctl command
+ * @arg: the ioctl argument
+ */
+probe tty.ioctl = kernel.function("tty_ioctl"){
+ name = kernel_string($file->f_path->dentry->d_iname)
+
+ cmd = $cmd
+ arg = $arg
+}
+
+/**
+ * probe tty.init - Called when a tty is being initalized
+ * @driver_name: the driver name
+ * @name: the driver .dev_name name
+ * @module: the module name
+ */
+probe tty.init = kernel.function("tty_init_dev"){
+ driver_name = kernel_string($driver->driver_name)
+ name = kernel_string($driver->name)
+ module = kernel_string($driver->owner->name)
+}
+
+/**
+ * probe tty.register - Called when a tty device is registred
+ * @driver_name: the driver name
+ * @name: the driver .dev_name name
+ * @module: the module name
+ * @index: the tty index requested
+ */
+probe tty.register = kernel.function("tty_register_device"){
+ driver_name = kernel_string($driver->driver_name)
+ name = kernel_string($driver->name)
+ module = kernel_string($driver->owner->name)
+ index = $index
+}
+
+/**
+ * probe tty.unregister - Called when a tty device is being unregistered
+ * @driver_name: the driver name
+ * @name: the driver .dev_name name
+ * @module: the module name
+ * @index: the tty index requested
+ */
+probe tty.unregister = kernel.function("tty_unregister_device"){
+ driver_name = kernel_string($driver->driver_name)
+ name = kernel_string($driver->name)
+ module = kernel_string($driver->owner->name)
+ index = $index
+}
+
+/**
+ * probe tty.poll - Called when a tty device is being polled
+ * @file_name: the tty file name
+ * @wait_key: the wait queue key
+ */
+probe tty.poll = kernel.function("tty_poll"){
+ file_name = d_name($filp->f_path->dentry)
+
+ if ($wait)
+ wait_key = $wait->key
+ else
+ wait_key = 0
+}
+
+/**
+ * probe tty.receive - called when a tty receives a message
+ * @cp: the buffer that was received
+ * @fp: The flag buffer
+ * @count: The amount of characters received
+ * @driver_name: the driver name
+ * @name: the name of the module file
+ * @index: The tty Index
+ * @id: the tty id
+ */
+probe tty.receive = kernel.function("n_tty_receive_buf"){
+ cp = kernel_string($cp)
+ fp = kernel_string($fp)
+ count = $count
+
+ driver_name = kernel_string($tty->driver->driver_name)
+ name = kernel_string($tty->driver->name)
+ index = $tty->index
+ id = $tty->magic
+}
+
+/**
+ * probe tty.write - write to the tty line
+ * @buffer: the buffer that will be written
+ * @nr: The amount of characters
+ * @driver_name: the driver name
+ * @file_name: the file name lreated to the tty
+ */
+probe tty.write = kernel.function("n_tty_write"){
+ buffer = kernel_string($buf)
+ nr = $nr
+
+ file_name = d_name($file->f_path->dentry)
+ driver_name = kernel_string($tty->driver->driver_name)
+}
+
+/**
+ * probe tty.read - called when a tty line will be read
+ * @buffer: the buffer that will receive the characters
+ * @nr: The amount of characters to be read
+ * @driver_name: the driver name
+ * @file_name: the file name lreated to the tty
+ */
+probe tty.read = kernel.function("n_tty_read"){
+ buffer = kernel_string($buf)
+ nr = $nr
+ file_name = d_name($file->f_path->dentry)
+ driver_name = kernel_string($tty->driver->driver_name)
+}
diff --git a/tapsets.cxx b/tapsets.cxx
index 113395e3..324237fa 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -228,8 +228,8 @@ common_probe_entryfn_epilogue (translator_output* o,
// Check for excessive skip counts.
o->newline() << "if (unlikely (atomic_read (& skipped_count) > MAXSKIPPED)) {";
- o->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- o->newline() << "_stp_exit ();";
+ o->newline(1) << "if (unlikely (atomic_cmpxchg(& session_state, STAP_SESSION_RUNNING, STAP_SESSION_ERROR) == STAP_SESSION_RUNNING))";
+ o->newline() << "_stp_error (\"Skipped too many probes, check MAXSKIPPED or try again with stap -t for more details.\");";
o->newline(-1) << "}";
o->newline() << "#if INTERRUPTIBLE";
@@ -326,6 +326,7 @@ function_spec_type
struct dwarf_builder;
+struct dwarf_var_expanding_visitor;
// XXX: This class is a candidate for subclassing to separate
@@ -377,7 +378,7 @@ protected:
private:
string args;
- void saveargs(dwarf_query& q, Dwarf_Die* scope_die);
+ void saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_expanding_visitor& v);
};
@@ -2317,6 +2318,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
// quietly.
provide (e);
semantic_error* saveme = new semantic_error (er); // copy it
+ if (! saveme->tok1) { saveme->tok1 = e->tok; } // fill in token if needed
// NB: we can have multiple errors, since a $target variable
// may be expanded in several different contexts:
// function ("*") { $var }
@@ -2812,12 +2814,13 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
q.has_call = false;
q.base_probe->body = old_body;
}
+ // Save the local variables for listing mode
+ if (q.sess.listing_mode_vars)
+ saveargs(q, scope_die, v);
}
// else - null scope_die - $target variables will produce an error during translate phase
- // Save the local variables for listing mode
- if (q.sess.listing_mode_vars)
- saveargs(q, scope_die);
+ // PR10820: null scope die, local variables aren't accessible, not necessary to invoke saveargs
// Reset the sole element of the "locations" vector as a
// "reverse-engineered" form of the incoming (q.base_loc) probe
@@ -2884,7 +2887,7 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname,
void
-dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die)
+dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die, dwarf_var_expanding_visitor& v)
{
if (null_die(scope_die))
return;
@@ -2922,7 +2925,18 @@ dwarf_derived_probe::saveargs(dwarf_query& q, Dwarf_Die* scope_die)
!dwarf_type_name(&type_die, type_name))
continue;
- argstream << " $" << arg_name << ":" << type_name;
+ /* trick from visit_target_symbol_context */
+ target_symbol *tsym = new target_symbol;
+ token *t = new token;
+ tsym->tok = t;
+ tsym->base_name = "$";
+ tsym->base_name += arg_name;
+
+ /* Ignore any variable that isn't accessible */
+ tsym->saved_conversion_error = 0;
+ v.require (tsym);
+ if (!tsym->saved_conversion_error)
+ argstream << " $" << arg_name << ":" << type_name;
}
while (dwarf_siblingof (&arg, &arg) == 0);
@@ -3033,7 +3047,7 @@ dwarf_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "#ifndef KRETACTIVE";
- s.op->newline() << "#define KRETACTIVE (max(15,6*NR_CPUS))";
+ s.op->newline() << "#define KRETACTIVE (max(15,6*(int)num_possible_cpus()))";
s.op->newline() << "#endif";
// Forward declare the master entry functions
@@ -4432,11 +4446,11 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "static const struct stap_uprobe_spec {"; // NB: read-only structure
s.op->newline(1) << "unsigned tfi;"; // index into stap_uprobe_finders[]
+ s.op->newline() << "unsigned return_p:1;";
s.op->newline() << "unsigned long address;";
s.op->newline() << "const char *pp;";
s.op->newline() << "void (*ph) (struct context*);";
s.op->newline() << "unsigned long sdt_sem_address;";
- s.op->newline() << "unsigned return_p:1;";
s.op->newline(-1) << "} stap_uprobe_specs [] = {"; // NB: read-only structure
s.op->indent(1);
for (unsigned i =0; i<probes.size(); i++)
@@ -4620,8 +4634,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline() << "#endif";
// NB: duplicates common_entryfn_epilogue, but then this is not a probe entry fn epilogue.
s.op->newline() << "if (unlikely (atomic_inc_return (& skipped_count) > MAXSKIPPED)) {";
- s.op->newline(1) << "atomic_set (& session_state, STAP_SESSION_ERROR);";
- s.op->newline() << "_stp_exit ();";
+ s.op->newline(1) << "if (unlikely (atomic_cmpxchg(& session_state, STAP_SESSION_RUNNING, STAP_SESSION_ERROR) == STAP_SESSION_RUNNING))";
+ s.op->newline() << "_stp_error (\"Skipped too many probes, check MAXSKIPPED or try again with stap -t for more details.\");";
s.op->newline(-1) << "}";
s.op->newline(-1) << "}";
@@ -5022,7 +5036,7 @@ kprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
s.op->newline();
s.op->newline() << "#ifndef KRETACTIVE";
- s.op->newline() << "#define KRETACTIVE (max(15,6*NR_CPUS))";
+ s.op->newline() << "#define KRETACTIVE (max(15,6*(int)num_possible_cpus()))";
s.op->newline() << "#endif";
// Forward declare the master entry functions
diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am
index 9607ebe3..248a0fb3 100644
--- a/testsuite/Makefile.am
+++ b/testsuite/Makefile.am
@@ -12,7 +12,7 @@ clean-local:
-rm -rf .systemtap* .cache_test* 2>/dev/null
DEJAZILLA=@dejazilla@
-
+TESTAPPS=@enable_testapps@
TOOL_OPTS=
# automake's dejagnu library already runs check-DEJAGNU before check-local
@@ -37,4 +37,4 @@ SYSTEMTAP_INCLUDES=$(DESTDIR)$(includedir)
RUNTESTDEFAULTFLAGS = --tool $$tool --tool_opts \'$(TOOL_OPTS)\' --srcdir $$srcdir
EXPECT = expect
-RUNTEST="env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH SYSTEMTAP_PATH=$(SYSTEMTAP_PATH) SYSTEMTAP_INCLUDES=$(SYSTEMTAP_INCLUDES) $(srcdir)/execrc runtest"
+RUNTEST="env SYSTEMTAP_TESTAPPS=$(TESTAPPS) SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH SYSTEMTAP_PATH=$(SYSTEMTAP_PATH) SYSTEMTAP_INCLUDES=$(SYSTEMTAP_INCLUDES) $(srcdir)/execrc runtest"
diff --git a/testsuite/Makefile.in b/testsuite/Makefile.in
index c0f0b19c..3068dea3 100644
--- a/testsuite/Makefile.in
+++ b/testsuite/Makefile.in
@@ -92,6 +92,7 @@ datarootdir = @datarootdir@
dejazilla = @dejazilla@
docdir = @docdir@
dvidir = @dvidir@
+enable_testapps = @enable_testapps@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
@@ -118,6 +119,7 @@ top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = dejagnu no-dist
DEJAZILLA = @dejazilla@
+TESTAPPS = @enable_testapps@
TOOL_OPTS =
# $(srcdir)/These values point the test suite to the install tree, and
@@ -130,7 +132,7 @@ SYSTEMTAP_PATH = $(DESTDIR)$(bindir)
SYSTEMTAP_INCLUDES = $(DESTDIR)$(includedir)
RUNTESTDEFAULTFLAGS = --tool $$tool --tool_opts \'$(TOOL_OPTS)\' --srcdir $$srcdir
EXPECT = expect
-RUNTEST = "env SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH SYSTEMTAP_PATH=$(SYSTEMTAP_PATH) SYSTEMTAP_INCLUDES=$(SYSTEMTAP_INCLUDES) $(srcdir)/execrc runtest"
+RUNTEST = "env SYSTEMTAP_TESTAPPS=$(TESTAPPS) SYSTEMTAP_RUNTIME=$(SYSTEMTAP_RUNTIME) SYSTEMTAP_TAPSET=$(SYSTEMTAP_TAPSET) LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) CRASH_LIBDIR=$(CRASH_LIBDIR) PATH=$(SYSTEMTAP_PATH):$$PATH SYSTEMTAP_PATH=$(SYSTEMTAP_PATH) SYSTEMTAP_INCLUDES=$(SYSTEMTAP_INCLUDES) $(srcdir)/execrc runtest"
all: all-am
.SUFFIXES:
diff --git a/testsuite/buildok/tty.stp b/testsuite/buildok/tty.stp
new file mode 100755
index 00000000..0b5018d9
--- /dev/null
+++ b/testsuite/buildok/tty.stp
@@ -0,0 +1,51 @@
+#! stap -wp4
+
+probe tty.poll{
+ printf("Pooling tty %s for wait queue key %d\n", file_name, wait_key);
+}
+
+probe tty.register {
+ printf("Device registered using index %d using driver %s(%s/%s)\n", index, driver_name, name, module)
+}
+
+probe tty.unregister {
+ printf("Device registered using index %d using driver %s(%s/%s)\n", index, driver_name, name, module)
+}
+
+probe tty.release {
+ printf("Closing file %s\n", file_name)
+ printf("INODE: number %d\nState: %d\nFlag: %d\n", inode_number, inode_state, inode_flags)
+ printf("File: %s (mode %x flags %x)\n", file_name, file_mode, file_flags)
+}
+
+probe tty.open {
+ printf("Opening tty file %s\n", file_name)
+ printf("INODE: number %d\nState: %d\nFlag: %d\n", inode_number, inode_state, inode_flags)
+ printf("File: %s mode %x flags %x\n", file_name, file_mode, file_flags)
+}
+
+probe tty.resize {
+ printf("Resizing %s from %dx%d (%d/%d) to %dx%d (%d/%d)\n", name, old_row, old_col, old_xpixel, old_ypixel,
+ new_row, new_col, new_xpixel, new_ypixel)
+}
+
+probe tty.ioctl {
+ printf("Ioctling file %s with %d %d\n", name, cmd, arg)
+}
+
+probe tty.init {
+ printf("new tty with name %s from driver %s and module %s\nn", driver_name, name, module)
+}
+
+probe tty.receive {
+ printf("Driver %s/%s (%d/%d) received %s (%s) with len %d\n", name, driver_name, index, id, cp, fp, count)
+}
+
+
+probe tty.write {
+ printf("Buffer %s (len %d) wrote on file %s (driver %s)\n", buffer, nr, file_name, driver_name)
+}
+
+probe tty.read {
+ printf("Reading tty file %s (driver %s) to a buffer with size %d containing %s\n", file_name, driver_name, nr, buffer)
+}
diff --git a/testsuite/configure b/testsuite/configure
index 716d8b50..8a9503cd 100755
--- a/testsuite/configure
+++ b/testsuite/configure
@@ -641,6 +641,7 @@ MAINTAINER_MODE_TRUE
MAINTAINER_MODE_FALSE
MAINT
dejazilla
+enable_testapps
LIBOBJS
LTLIBOBJS'
ac_subst_files=''
@@ -1229,6 +1230,9 @@ Optional Features:
results to a central public collection point
(default is disabled). Optional EMAIL overrides the
default email address.
+ --enable-testapps=foo bar or all
+ enable rebuilding of large external apps for testing
+ <sdt.h> markers
Report bugs to <systemtap@sources.redhat.com>.
_ACEOF
@@ -2182,6 +2186,21 @@ echo "$as_me: A \"make *check\" will email results to $dejazilla" >&6;}
fi
+apps=
+for exp in $srcdir/systemtap.apps/*.exp
+do
+ app=`basename $exp .exp`
+ apps="$app $apps"
+done
+# Check whether --enable-testapps was given.
+if test "${enable_testapps+set}" = set; then
+ enableval=$enable_testapps;
+fi
+
+{ echo "$as_me:$LINENO: Will test ${enable_testapps-no} apps from: $apps" >&5
+echo "$as_me: Will test ${enable_testapps-no} apps from: $apps" >&6;}
+
+
ac_config_files="$ac_config_files Makefile"
cat >confcache <<\_ACEOF
@@ -2884,11 +2903,12 @@ MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim
MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim
MAINT!$MAINT$ac_delim
dejazilla!$dejazilla$ac_delim
+enable_testapps!$enable_testapps$ac_delim
LIBOBJS!$LIBOBJS$ac_delim
LTLIBOBJS!$LTLIBOBJS$ac_delim
_ACEOF
- if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 65; then
+ if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 66; then
break
elif $ac_last_try; then
{ { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/testsuite/configure.ac b/testsuite/configure.ac
index 5166d226..33e06752 100644
--- a/testsuite/configure.ac
+++ b/testsuite/configure.ac
@@ -23,5 +23,17 @@ if test -n "$dejazilla"; then
fi
AC_SUBST(dejazilla)
+apps=
+for exp in $srcdir/systemtap.apps/*.exp
+do
+ app=`basename $exp .exp`
+ apps="$app $apps"
+done
+AC_ARG_ENABLE([testapps],
+ AC_HELP_STRING([--enable-testapps=foo bar or all],
+ [enable rebuilding of large external apps for testing <sdt.h> markers]))
+AC_MSG_NOTICE([Will test ${enable_testapps-no} apps from: $apps])
+AC_SUBST(enable_testapps)
+
AC_CONFIG_FILES(Makefile)
AC_OUTPUT
diff --git a/testsuite/systemtap.base/mysql.exp b/testsuite/systemtap.apps/mysql.exp
index 44b30cf4..efeffbae 100644
--- a/testsuite/systemtap.base/mysql.exp
+++ b/testsuite/systemtap.apps/mysql.exp
@@ -244,7 +244,7 @@ $mysqldir/bin/mysql_install_db --basedir=$mysqldir --datadir=$msdata
(cd $mysqldir/mysql-test
# wait until mysql is running
MOD=stapsdt_\$(date +%j%k%M%N | sed 's/ //')
-/usr/local/bin/stap -m \$MOD -c \"$mysqldir/libexec/mysqld --basedir=$mysqldir --datadir=$msdata --log-error=$msdata/mysql.log --pid-file=$msdata/mysql.pid --socket=$msdata/mysql.sock\" $testsuite/stap-mysql.stp $mysqldir/libexec/mysqld >$testsuite/stap-mysql-markers.log 2>&1 &
+$env(SYSTEMTAP_PATH)/stap -m \$MOD -c \"$mysqldir/libexec/mysqld --basedir=$mysqldir --datadir=$msdata --log-error=$msdata/mysql.log --pid-file=$msdata/mysql.pid --socket=$msdata/mysql.sock\" $testsuite/stap-mysql.stp $mysqldir/libexec/mysqld >$testsuite/stap-mysql-markers.log 2>&1 &
STAPPID=\$!
for i in \$(seq 0 10) ; do
diff --git a/testsuite/systemtap.base/postgres.exp b/testsuite/systemtap.apps/postgres.exp
index ceef9437..2d58a54f 100644
--- a/testsuite/systemtap.base/postgres.exp
+++ b/testsuite/systemtap.apps/postgres.exp
@@ -69,7 +69,7 @@ function run_tests \{
$postgresdir/bin/initdb $pgdata
which stap
-stap -m \$(date +stapsdt_%j%k%M%N | sed 's/ //') -c \"$postgresdir/bin/postgres -D $pgdata\" $pgdata.stp >$pgdata-markers.log 2>&1 &
+$env(SYSTEMTAP_PATH)/stap -m \$(date +stapsdt_%j%k%M%N | sed 's/ //') -c \"$postgresdir/bin/postgres -D $pgdata\" $pgdata.stp >$pgdata-markers.log 2>&1 &
STAPPID=\$!
# wait until postgres is running
diff --git a/testsuite/systemtap.apps/stap-tcl.sh b/testsuite/systemtap.apps/stap-tcl.sh
new file mode 100644
index 00000000..919f632d
--- /dev/null
+++ b/testsuite/systemtap.apps/stap-tcl.sh
@@ -0,0 +1,25 @@
+#! /bin/sh
+
+set -e
+
+tclreleasemajor="8.6"
+tclrelease="8.6b1"
+tcldir=`pwd`/tcl/install/
+
+mkdir -p tcl
+
+if [ ! -r tcl$tclrelease-src.tar.gz ] ; then
+ wget http://sourceforge.net/projects/tcl/files/Tcl/$tclrelease/tcl$tclrelease-src.tar.gz/download
+fi
+
+if [ ! -d tcl/src ] ; then
+ tar -x -z -f tcl$tclrelease-src.tar.gz
+ mv tcl$tclrelease tcl/src
+fi
+
+cd tcl/src/unix
+env CPPFLAGS="-I$SYSTEMTAP_INCLUDES" CFLAGS="-g -O2" ./configure --prefix=$tcldir --enable-dtrace
+make -j2
+make install
+
+exit 0
diff --git a/testsuite/systemtap.apps/stap-tcl.stp b/testsuite/systemtap.apps/stap-tcl.stp
new file mode 100644
index 00000000..d3293b09
--- /dev/null
+++ b/testsuite/systemtap.apps/stap-tcl.stp
@@ -0,0 +1,30 @@
+global counts
+
+probe process(@1).mark("*") {
+ counts[$$name]<<<1 # PR10878; check also $$parms length
+}
+
+function judge(name, minvalue) {
+ value = @count(counts[name])
+ printf("%s %s %d %d\n", ((value>=minvalue)?"OK":"KO"), name, value, minvalue)
+}
+
+probe end,error {
+ /* foreach (name in counts-) {
+ printf("== %s %d\n", name, @count(counts[name]))
+ } */
+ judge("proc__entry", 9000)
+ judge("proc__return", 9000)
+ judge("proc__result", 9000)
+ judge("proc__args", 9000)
+ judge("proc__info", 9000)
+ judge("cmd__entry", 37000)
+ judge("cmd__return", 37000)
+ judge("cmd__result", 37000)
+ judge("cmd__args", 3700 /* not 37000? */)
+ judge("cmd__info", 37000)
+ judge("inst__start", 542000)
+ judge("inst__done", 542000)
+ judge("obj__create", 723000)
+ judge("obj__free", 704000)
+}
diff --git a/testsuite/systemtap.apps/tcl.exp b/testsuite/systemtap.apps/tcl.exp
new file mode 100644
index 00000000..bfcf2239
--- /dev/null
+++ b/testsuite/systemtap.apps/tcl.exp
@@ -0,0 +1,67 @@
+set test "tcl"
+
+# Test sdt support in tcl.
+
+global env
+
+if {! [info exists env(SYSTEMTAP_TESTAPPS)] || (
+ ! [string match "tcl" $env(SYSTEMTAP_TESTAPPS)] &&
+ ! [string match "all" $env(SYSTEMTAP_TESTAPPS)])} {
+ untested "$test sdt app"
+ return
+}
+
+########## Create /tmp/stap-tcl.stp ##########
+set tclreleasemajor "8.6"
+set tclrelease "8.6b1"
+set tcldir "[pwd]/tcl/install/"
+set testsuite "[pwd]"
+
+verbose -log "Building tcl"
+set test "tcl${tclreleasemajor} build"
+set rc [catch {exec sh $srcdir/$subdir/stap-tcl.sh 2>@ stdout} out]
+if {$rc != 0} {
+ clone_output $out
+ fail $test
+ return
+} else {
+ pass $test
+}
+
+set test "stap-tcl.stp compilation"
+set rc [catch {exec stap -DMAXSKIPPED=8024 -t -p4 $srcdir/$subdir/stap-tcl.stp tcl/install/lib/libtcl${tclreleasemajor}.so} out]
+clone_output $out
+if {$rc != 0} {
+ fail $test
+ return
+} else {
+ pass $test
+}
+
+set test "stap-tcl.stp execution"
+if {![installtest_p]} {
+ untested $test
+ return
+}
+
+set ok 0
+set ko 0
+set lines 0
+spawn stap -DMAXSKIPPED=8024 -t -c "tcl/install/bin/tclsh${tclreleasemajor} tcl/src/tests/all.tcl > tcl-test.out" $srcdir/$subdir/stap-tcl.stp tcl/install/lib/libtcl${tclreleasemajor}.so
+expect {
+ -timeout 1000
+ -re {^OK [^\r\n]*[\r\n]} { incr ok; exp_continue }
+ -re {^KO [^\r\n]*[\r\n]} { incr ko; exp_continue }
+ -re {^ERROR[^\r\n]*[\r\n]} { incr ko; exp_continue }
+ -re {^[^\r\n]*[\r\n]} { incr lines; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+catch {close}; catch {wait}
+
+if {$ok == 14 && $ko == 0} {
+ pass "$test ($ok $ko $lines)"
+} else {
+ fail "$test ($ok $ko $lines)"
+}
+
diff --git a/testsuite/systemtap.apps/xulrunner.exp b/testsuite/systemtap.apps/xulrunner.exp
new file mode 100644
index 00000000..be2db0c7
--- /dev/null
+++ b/testsuite/systemtap.apps/xulrunner.exp
@@ -0,0 +1,133 @@
+set test "xulrunner"
+
+# Test sdt support in xulrunner.
+
+global env
+
+if {! [info exists env(SYSTEMTAP_TEST_SDT)]} {
+ unsupported "xulrunner (\"SYSTEMTAP_TEST_SDT\" not in env)"
+ return
+}
+
+########## Create /tmp/stap-xul.stp ##########
+set xulrelease "1.9.1.3"
+set xuldir "[pwd]/xul/"
+set testsuite "[pwd]"
+
+set fp [open "$testsuite/stap-xul.stp" "w"]
+puts $fp "
+global funcinfo
+global objinfo
+
+probe process(@1).mark(\"function__info\")
+{
+ file = user_string (\$arg1)
+ func = user_string (\$arg3)
+ funcinfo\[file,func\] <<< 1
+}
+
+probe process(@1).mark(\"object__create\")
+{
+ file = user_string (\$arg1)
+ class = user_string (\$arg2)
+ objinfo\[file,class\] <<< 1
+}
+
+probe end
+{
+ foreach (\[i,j\] in funcinfo+)
+ {
+ printf (\"probes: %-20s %-25s %d\\n\", substr(i,strlen(i)-20,strlen(i)), j, @count(funcinfo\[i,j\]))
+ }
+ foreach (\[i,j\] in objinfo+)
+ {
+ printf (\"probes: %-20s %-25s %d\\n\", substr(i,strlen(i)-20,strlen(i)), j, @count(funcinfo\[i,j\]))
+ }
+}
+"
+close $fp
+
+########## Begin /tmp/stap-xul.sh ##########
+set fp [open "$testsuite/stap-xul.sh" "w"]
+puts $fp "
+##### begin run_tests #####
+function run_tests \{
+cd $testsuite/xul/bld/js/src
+pwd
+for i in call trace-test math-trace-tests ; do
+$env(SYSTEMTAP_PATH)/stap -c \"./js $xuldir/src/js/src/\$i.js\" $testsuite/stap-xul.stp ./js
+done | tee $testsuite/stap-xul-markers.log
+PROBES=\$(grep 'probes: ' $testsuite/stap-xul-markers.log | wc -l)
+TESTS=\$(grep '-FAIL' $testsuite/stap-xul-markers.log)
+echo PROBES=\$PROBES TESTS=\$TESTS
+
+if \[ \$PROBES -gt 400 \] ; then
+ echo PASS: xulrunner javascript markers \$1
+else
+ echo FAIL: xulrunner javascript markers \$1
+fi
+
+if \[ -z \$TESTS \] ; then
+ echo PASS: xulrunner javascript testsuite \$1
+else
+ echo FAIL: xulrunner javascript testsuite \$1
+fi
+
+\}
+##### end run_tests #####
+
+if \[ ! -r xulrunner-$xulrelease-source.tar \] ; then
+wget ftp://ftp.mozilla.org/pub/mozilla.org/xul/releases/$xulrelease/source/xulrunner-$xulrelease-source.tar.bz2
+bunzip2 xulrunner-$xulrelease-source.tar.bz2
+fi
+
+if \[ ! -d xul/src \] ; then
+tar -x -f xulrunner-$xulrelease-source.tar
+mkdir xul
+xulrelease=$xulrelease
+mv mozilla-\${xulrelease%.\[0-9\]} xul/src
+fi
+
+if \[ ! -f xul/bld/js/src/js \] ; then
+mkdir xul/bld
+cd xul/bld
+if rpm -q java-1.6.0-openjdk ; then :
+else
+ echo FAIL: Need java-1.6.0-openjdk-devel
+ exit
+fi
+JAVA_HOME=/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64 \
+CXXFLAGS='-g -I$env(SYSTEMTAP_INCLUDES)' \
+CFLAGS='-g -I$env(SYSTEMTAP_INCLUDES)' \
+PATH=$env(SYSTEMTAP_PATH)/:\$PATH \
+../src/configure --prefix=$xuldir --enable-dtrace --enable-application=xulrunner
+J=\$(getconf _NPROCESSORS_CONF)
+make -j \$J
+fi
+
+run_tests uprobe
+"
+########## End /tmp/stap-xul.sh ##########
+close $fp
+
+########## /tmp/stap-xul.sh does most of the work ##########
+verbose -log Running xul testsuite
+spawn sh stap-xul.sh 2>&1
+expect {
+ -timeout 10000
+ -re {FAIL: [a-z_ ]+} { regexp " .*$" $expect_out(0,string) s;
+ fail "$s"; exp_continue }
+ -re {PASS: [a-z_ ]+} { regexp " .*$" $expect_out(0,string) s;
+ pass "$s"; exp_continue }
+ -re {UNSUPPORTED: [a-zA-Z_/: ]+} { regexp " .*$" $expect_out(0,string) s;
+ verbose -log "$s"
+ unsupported "$s"; exp_continue }
+ timeout { fail "$test (timeout)" }
+ eof { }
+}
+
+if { $verbose == 0 } {
+catch {exec rm -rf $testsuite/stap-xul.stp xulrunner-$xulrelease-source.tar \
+ $testsuite/stap-xul-markers.log $testsuite/stap-xul.sh }
+catch {exec rm -rf xul}
+}
diff --git a/testsuite/systemtap.base/onoffprobe.exp b/testsuite/systemtap.base/onoffprobe.exp
index 1b39dab5..c6d83d5d 100644
--- a/testsuite/systemtap.base/onoffprobe.exp
+++ b/testsuite/systemtap.base/onoffprobe.exp
@@ -10,9 +10,27 @@ proc advance {} {
global expect_out
global ok
global modname
+ set procfs_file "/proc/systemtap/$modname/switch"
+
pass "$test $expect_out(1,string)"
+
+ # If this is the first time, wait until the procfs file exists
+ # (for up to 10 seconds).
+ if {$ok == 0} {
+ set i 0
+ while {![file exists $procfs_file]} {
+ sleep 1
+ incr i
+ if {$i >= 10} { break }
+ }
+ # If the procfs file still doesn't exist, fail.
+ if {![file exists $procfs_file]} {
+ fail "$test (missing procfs file)"
+ }
+ }
+
incr ok
- exec echo $ok > /proc/systemtap/$modname/switch
+ if {[file exists $procfs_file]} { exec echo $ok > $procfs_file }
exec echo dummy > /dev/null
exp_continue
}
diff --git a/testsuite/systemtap.base/pr10854.exp b/testsuite/systemtap.base/pr10854.exp
new file mode 100644
index 00000000..9173c8b4
--- /dev/null
+++ b/testsuite/systemtap.base/pr10854.exp
@@ -0,0 +1,32 @@
+# This test is to make sure that we've resolved PR10854's race between probe
+# initialization and shutdown. Here we load a module and then kill the stapio
+# process as soon as we can to try to make the init and shutdown overlap.
+
+set test "pr10854"
+
+# precompile the script module
+set compile { exec stap $srcdir/$subdir/$test.stp sys_read *@fs/*.c -p4 }
+if { [catch { set module [eval $compile] } msg ] } {
+ fail "compiling $test.stp: $msg"
+ untested "$test runloop"
+ continue
+} else {
+ pass "compiling $test.stp"
+}
+
+if {![installtest_p]} {
+ untested "$test runloop"
+ continue
+}
+
+# run & kill the module 10 times
+# (this was usually enough to trigger the fault)
+for {set i 0} {$i < 10} {incr i} {
+ spawn staprun $module -o /dev/null
+ while { [catch { exec pkill stapio -P [pid] } msg ] } { }
+ catch { close }
+ wait
+}
+
+# if we're still alive, we pass :)
+pass "$test runloop"
diff --git a/testsuite/systemtap.base/pr10854.stp b/testsuite/systemtap.base/pr10854.stp
new file mode 100644
index 00000000..55f027f2
--- /dev/null
+++ b/testsuite/systemtap.base/pr10854.stp
@@ -0,0 +1,20 @@
+function trace(entry_p) {
+ if(tid() in trace)
+ printf("%s%s%s\n",thread_indent(entry_p),
+ (entry_p>0?"->":"<-"),
+ probefunc())
+}
+
+global trace
+probe kernel.function(@1).call {
+ if (execname() == "staprun") next # skip our own helper process
+ trace[tid()] = 1
+ trace(1)
+}
+probe kernel.function(@1).return {
+ trace(-1)
+ delete trace[tid()]
+}
+
+probe kernel.function(@2).call { trace(1) }
+probe kernel.function(@2).return { trace(-1) }
diff --git a/testsuite/systemtap.context/args.tcl b/testsuite/systemtap.context/args.tcl
index fb8aecb4..c5aed203 100644
--- a/testsuite/systemtap.context/args.tcl
+++ b/testsuite/systemtap.context/args.tcl
@@ -1,6 +1,6 @@
spawn stap $srcdir/$subdir/args.stp
expect {
- -timeout 60
+ -timeout 120
"READY" {
exec echo 1 > /proc/stap_test_cmd
expect {
@@ -51,6 +51,7 @@ expect {
timeout {fail "string function arguments"}
}
}
+ timeout {fail "all args tests - timeout"}
eof {fail "function arguments: unexpected timeout"}
}
exec kill -INT -[exp_pid]
diff --git a/testsuite/systemtap.context/backtrace.tcl b/testsuite/systemtap.context/backtrace.tcl
index 5e7b1536..d436ab5c 100644
--- a/testsuite/systemtap.context/backtrace.tcl
+++ b/testsuite/systemtap.context/backtrace.tcl
@@ -9,7 +9,7 @@ set m6 0
spawn stap $srcdir/$subdir/backtrace.stp
#exp_internal 1
expect {
- -timeout 60
+ -timeout 120
"Systemtap probe: begin\r\n" {
pass "backtrace of begin probe"
exec echo 0 > /proc/stap_test_cmd
diff --git a/testsuite/systemtap.context/num_args.tcl b/testsuite/systemtap.context/num_args.tcl
index 62ac8dd3..d677f849 100644
--- a/testsuite/systemtap.context/num_args.tcl
+++ b/testsuite/systemtap.context/num_args.tcl
@@ -3,7 +3,7 @@ foreach arglist $arglists {
set tag [concat numeric $arglist]
eval spawn stap $arglist $srcdir/$subdir/num_args.stp
expect {
- -timeout 60
+ -timeout 120
"READY" {
exec echo 1 > /proc/stap_test_cmd
expect {
@@ -57,6 +57,7 @@ expect {
-re "semantic error:" {
fail "function arguments -- $tag: compilation failed"
}
+ timeout {fail "all function arguments tests - timeout"}
eof {fail "function arguments -- $tag: unexpected timeout"}
}
exec kill -INT -[exp_pid]
diff --git a/testsuite/systemtap.context/pid.tcl b/testsuite/systemtap.context/pid.tcl
index 70a87345..350a05b2 100644
--- a/testsuite/systemtap.context/pid.tcl
+++ b/testsuite/systemtap.context/pid.tcl
@@ -2,7 +2,7 @@ set tests [list execname pexecname pid ppid tid uid euid gid egid]
spawn stap $srcdir/$subdir/pid.stp
#exp_internal 1
expect {
- -timeout 60
+ -timeout 120
"READY" {
set pid [exec echo 1 > /proc/stap_test_cmd &]
set ppid {[0-9]*}
diff --git a/testsuite/systemtap.examples/index.html b/testsuite/systemtap.examples/index.html
index f2b7066f..55fea0fb 100644
--- a/testsuite/systemtap.examples/index.html
+++ b/testsuite/systemtap.examples/index.html
@@ -169,6 +169,9 @@ keywords: <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <br>
<li><a href="process/pf2.stp">process/pf2.stp</a> - Profile kernel functions<br>
keywords: <a href="keyword-index.html#PROFILING">PROFILING</a> <br>
<p>The pf2.stp script sets up time-based sampling. Every five seconds it prints out a sorted list with the top ten kernel functions with samples.</p></li>
+<li><a href="process/plimit.stp">process/plimit.stp</a> - print resource limits<br>
+keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <br>
+<p>The script prints a variety of resource limits for a given pid, like /proc/$$/limits on recent kernels.</p></li>
<li><a href="process/schedtimes.stp">process/schedtimes.stp</a> - Track Time Processes Spend in Various States using Tracepoints<br>
keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <a href="keyword-index.html#TIME">TIME</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <br>
<p>The schedtimes.stp script instruments the scheduler to track the amount of time that each process spends running, sleeping, queued, and waiting for io. On exit the script prints out the accumulated time for each state of processes observed. Optionally, this script can be used with the '-c' or '-x' options to focus on a specific PID.</p></li>
diff --git a/testsuite/systemtap.examples/index.txt b/testsuite/systemtap.examples/index.txt
index e880c746..16b45aac 100644
--- a/testsuite/systemtap.examples/index.txt
+++ b/testsuite/systemtap.examples/index.txt
@@ -407,6 +407,13 @@ keywords: profiling
samples.
+process/plimit.stp - print resource limits
+keywords: process
+
+ The script prints a variety of resource limits for a given pid, like
+ /proc/$$/limits on recent kernels.
+
+
process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints
keywords: process scheduler time tracepoint
diff --git a/testsuite/systemtap.examples/io/traceio2.stp b/testsuite/systemtap.examples/io/traceio2.stp
index 1abea45d..797f3062 100755
--- a/testsuite/systemtap.examples/io/traceio2.stp
+++ b/testsuite/systemtap.examples/io/traceio2.stp
@@ -1,6 +1,6 @@
#! /usr/bin/env stap
-global device_of_interest, dev
+global device_of_interest
probe begin {
/* The following is not the most efficient way to do this.
diff --git a/testsuite/systemtap.examples/keyword-index.html b/testsuite/systemtap.examples/keyword-index.html
index f09a20b3..1a2855e1 100644
--- a/testsuite/systemtap.examples/keyword-index.html
+++ b/testsuite/systemtap.examples/keyword-index.html
@@ -297,6 +297,9 @@ keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-inde
<li><a href="process/forktracker.stp">process/forktracker.stp</a> - Trace Creation of Processes<br>
keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <br>
<p>The forktracker.stp script prints out a time-stamped entry showing each fork and exec operation on the machine. This can be useful for determine what process is creating a flurry of short-lived processes.</p></li>
+<li><a href="process/plimit.stp">process/plimit.stp</a> - print resource limits<br>
+keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <br>
+<p>The script prints a variety of resource limits for a given pid, like /proc/$$/limits on recent kernels.</p></li>
<li><a href="process/schedtimes.stp">process/schedtimes.stp</a> - Track Time Processes Spend in Various States using Tracepoints<br>
keywords: <a href="keyword-index.html#PROCESS">PROCESS</a> <a href="keyword-index.html#SCHEDULER">SCHEDULER</a> <a href="keyword-index.html#TIME">TIME</a> <a href="keyword-index.html#TRACEPOINT">TRACEPOINT</a> <br>
<p>The schedtimes.stp script instruments the scheduler to track the amount of time that each process spends running, sleeping, queued, and waiting for io. On exit the script prints out the accumulated time for each state of processes observed. Optionally, this script can be used with the '-c' or '-x' options to focus on a specific PID.</p></li>
diff --git a/testsuite/systemtap.examples/keyword-index.txt b/testsuite/systemtap.examples/keyword-index.txt
index 853198d3..6de9c330 100644
--- a/testsuite/systemtap.examples/keyword-index.txt
+++ b/testsuite/systemtap.examples/keyword-index.txt
@@ -605,6 +605,13 @@ keywords: process scheduler
determine what process is creating a flurry of short-lived processes.
+process/plimit.stp - print resource limits
+keywords: process
+
+ The script prints a variety of resource limits for a given pid, like
+ /proc/$$/limits on recent kernels.
+
+
process/schedtimes.stp - Track Time Processes Spend in Various States using Tracepoints
keywords: process scheduler time tracepoint
diff --git a/testsuite/systemtap.examples/process/plimit.meta b/testsuite/systemtap.examples/process/plimit.meta
new file mode 100644
index 00000000..d5cd4e8b
--- /dev/null
+++ b/testsuite/systemtap.examples/process/plimit.meta
@@ -0,0 +1,7 @@
+title: print resource limits
+name: plimit.stp
+keywords: process
+subsystem: general
+description: The script prints a variety of resource limits for a given pid, like /proc/$$/limits on recent kernels.
+test_check: stap -gp4 plimit.stp $$
+test_installcheck: stap -g plimit.stp $$
diff --git a/testsuite/systemtap.examples/process/plimit.stp b/testsuite/systemtap.examples/process/plimit.stp
new file mode 100755
index 00000000..1a389468
--- /dev/null
+++ b/testsuite/systemtap.examples/process/plimit.stp
@@ -0,0 +1,78 @@
+#!/usr/bin/env stap
+# plimit.stp
+# Copyright (C) 2006 Red Hat, Inc., Eugene Teo <eteo@redhat.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+
+%{
+ #include <linux/sched.h>
+ #include <linux/list.h>
+%}
+
+function getrlimit:string (rlim:long, pid:long) %{ /* pure */
+ struct task_struct *p;
+ struct list_head *_p, *_n;
+ static char cur_buf[24], max_buf[24];
+ long int cur, max;
+
+ list_for_each_safe(_p, _n, &current->tasks) {
+ p = list_entry(_p, struct task_struct, tasks);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,12)
+ cur = p->signal->rlim[THIS->rlim].rlim_cur;
+ max = p->signal->rlim[THIS->rlim].rlim_max;
+#else
+ cur = p->rlim[THIS->rlim].rlim_cur;
+ max = p->rlim[THIS->rlim].rlim_max;
+#endif
+ if (p->pid == (int)THIS->pid) {
+ if (cur == -1 && max == -1)
+ strcat(THIS->__retvalue, "unlimited unlimited");
+ else if (cur == -1)
+ snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9s %-9ld",
+ "unlimited", max);
+ else if (max == -1)
+ snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9ld %-9s",
+ cur, "unlimited");
+ else
+ snprintf(THIS->__retvalue, MAXSTRINGLEN, "%-9ld %-9ld",
+ cur, max);
+ }
+ }
+%}
+
+function task_execname_by_pid:string (pid:long) %{ /* pure */
+ struct task_struct *p;
+ struct list_head *_p, *_n;
+ list_for_each_safe(_p, _n, &current->tasks) {
+ p = list_entry(_p, struct task_struct, tasks);
+ if (p->pid == (int)THIS->pid)
+ snprintf(THIS->__retvalue, MAXSTRINGLEN, "%s", p->comm);
+ }
+%}
+
+probe begin
+{
+ printf("%d: -%s\n", $1, task_execname_by_pid($1))
+ /* include/asm-generic/resource.h */
+ printf(" resource current maximum\n")
+ printf("coredump(blocks) %s\n", getrlimit(4, $1))
+ printf("data(bytes) %s\n", getrlimit(2, $1))
+ printf("max nice %s\n", getrlimit(13, $1))
+ printf("file size(blocks) %s\n", getrlimit(1, $1))
+ printf("pending signals %s\n", getrlimit(11, $1))
+ printf("max locked memory(bytes) %s\n", getrlimit(8, $1))
+ printf("max memory size(bytes) %s\n", getrlimit(5, $1))
+ printf("open files %s\n", getrlimit(7, $1))
+ printf("POSIX message queues(bytes) %s\n", getrlimit(12, $1))
+ printf("max rt priority %s\n", getrlimit(14, $1))
+ printf("stack size(bytes) %s\n", getrlimit(3, $1))
+ printf("cpu time(seconds) %s\n", getrlimit(0, $1))
+ printf("max user processes %s\n", getrlimit(6, $1))
+ printf("virtual memory(bytes) %s\n", getrlimit(9, $1))
+ printf("file locks %s\n", getrlimit(10, $1))
+
+ exit()
+}
diff --git a/testsuite/systemtap.syscall/README b/testsuite/systemtap.syscall/README
index 480bd8cd..836ac747 100644
--- a/testsuite/systemtap.syscall/README
+++ b/testsuite/systemtap.syscall/README
@@ -18,6 +18,9 @@ is expected, put "NNNN" (for decimal) or "XXXX" (for hex). Or you can
just write regular expressions. The "NNNN" and "XXXX" are just shorthand to
aid readability and are converted to regular expressions in test.tcl.
+Normally opening and closing parentheses ('(' and ')') get quoted. If
+you want unquoted parentheses, use '[[[[' (for '(') or ']]]]' (for ')').
+
3. Somewhere is your test program puts a comment line like this:
/* COVERAGE: syscall1 syscall2 ... */
where you list the systemcalls that are tested. Then you can run
diff --git a/testsuite/systemtap.syscall/chmod.c b/testsuite/systemtap.syscall/chmod.c
index 724b86c4..ce18b3d0 100644
--- a/testsuite/systemtap.syscall/chmod.c
+++ b/testsuite/systemtap.syscall/chmod.c
@@ -11,7 +11,7 @@ int main()
int fd;
fd = open("foobar",O_WRONLY|O_CREAT, 0666);
- //staptest// open ("foobar", O_WRONLY|O_CREAT, 0666) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?, 0666) = NNNN
chmod("foobar", 0644);
//staptest// chmod ("foobar", 0644)
diff --git a/testsuite/systemtap.syscall/dir.c b/testsuite/systemtap.syscall/dir.c
index 3eda8175..f5b9f320 100644
--- a/testsuite/systemtap.syscall/dir.c
+++ b/testsuite/systemtap.syscall/dir.c
@@ -20,7 +20,7 @@ int main()
//staptest// chdir ("..") = 0
fd = open("foobar", O_RDONLY);
- //staptest// open ("foobar", O_RDONLY) = NNNN
+ //staptest// open ("foobar", O_RDONLY[[[[.O_LARGEFILE]]]]?) = NNNN
fchdir(fd);
//staptest// fchdir (NNNN) = 0
@@ -35,7 +35,7 @@ int main()
//staptest// rmdir ("foobar") = 0
fd = open(".", O_RDONLY);
- //staptest// open (".", O_RDONLY) = NNNN
+ //staptest// open (".", O_RDONLY[[[[.O_LARGEFILE]]]]?) = NNNN
#ifdef SYS_mkdirat
mkdirat(fd, "xyzzy", 0765);
diff --git a/testsuite/systemtap.syscall/mmap.c b/testsuite/systemtap.syscall/mmap.c
index 13145fb2..a09888b4 100644
--- a/testsuite/systemtap.syscall/mmap.c
+++ b/testsuite/systemtap.syscall/mmap.c
@@ -13,14 +13,14 @@ int main()
/* create a file with something in it */
fd = open("foobar",O_WRONLY|O_CREAT|O_TRUNC, 0600);
- //staptest// open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?|O_TRUNC, 0600) = NNNN
lseek(fd, 1024, SEEK_SET);
write(fd, "abcdef", 6);
close(fd);
//staptest// close (NNNN) = 0
fd = open("foobar", O_RDONLY);
- //staptest// open ("foobar", O_RDONLY) = NNNN
+ //staptest// open ("foobar", O_RDONLY[[[[.O_LARGEFILE]]]]?) = NNNN
/* stat for file size */
ret = fstat(fd, &fs);
diff --git a/testsuite/systemtap.syscall/net1.c b/testsuite/systemtap.syscall/net1.c
index f8079ffd..b7f1d6cb 100644
--- a/testsuite/systemtap.syscall/net1.c
+++ b/testsuite/systemtap.syscall/net1.c
@@ -32,7 +32,7 @@ int main()
//staptest// listen (NNNN, 7) = 0
cfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
- //staptest// accept (NNNN, 0x[0]+, 0x[0]+) = -NNNN (EAGAIN)
+ //staptest// accept (NNNN, 0x[0]+, 0x[0]+, 0) = -NNNN (EAGAIN)
close(cfd);
close(listenfd);
diff --git a/testsuite/systemtap.syscall/openclose.c b/testsuite/systemtap.syscall/openclose.c
index cb003a9e..aeabbe19 100644
--- a/testsuite/systemtap.syscall/openclose.c
+++ b/testsuite/systemtap.syscall/openclose.c
@@ -13,46 +13,46 @@ int main()
int fd1, fd2;
fd2 = creat("foobar1",S_IREAD|S_IWRITE);
- //staptest// open ("foobar1", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar1", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?|O_TRUNC, 0600) = NNNN
fd1 = open("foobar2",O_WRONLY|O_CREAT, S_IRWXU);
- //staptest// open ("foobar2", O_WRONLY|O_CREAT, 0700) = NNNN
+ //staptest// open ("foobar2", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?, 0700) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
fd1 = open("foobar2",O_RDONLY);
- //staptest// open ("foobar2", O_RDONLY) = NNNN
+ //staptest// open ("foobar2", O_RDONLY[[[[.O_LARGEFILE]]]]?) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
fd1 = open("foobar2",O_RDWR);
- //staptest// open ("foobar2", O_RDWR) = NNNN
+ //staptest// open ("foobar2", O_RDWR[[[[.O_LARGEFILE]]]]?) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
fd1 = open("foobar2",O_APPEND|O_WRONLY);
- //staptest// open ("foobar2", O_WRONLY|O_APPEND) = NNNN
+ //staptest// open ("foobar2", O_WRONLY|O_APPEND[[[[.O_LARGEFILE]]]]?) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
fd1 = open("foobar2",O_DIRECT|O_RDWR);
- //staptest// open ("foobar2", O_RDWR|O_DIRECT) = NNNN
+ //staptest// open ("foobar2", O_RDWR|O_DIRECT[[[[.O_LARGEFILE]]]]?) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
fd1 = open("foobar2",O_NOATIME|O_SYNC|O_RDWR);
- //staptest// open ("foobar2", O_RDWR|O_NOATIME|O_SYNC) = NNNN
+ //staptest// open ("foobar2", O_RDWR[[[[.O_LARGEFILE]]]]?|O_NOATIME|O_SYNC) = NNNN
close(fd1);
//staptest// close (NNNN) = 0
/* Now test some bad opens */
fd1 = open("/",O_WRONLY);
- //staptest// open ("/", O_WRONLY) = -NNNN (EISDIR)
+ //staptest// open ("/", O_WRONLY[[[[.O_LARGEFILE]]]]?) = -NNNN (EISDIR)
close (fd1);
//staptest// close (NNNN) = -NNNN (EBADF)
fd1 = open("foobar2",O_WRONLY|O_CREAT|O_EXCL, S_IRWXU);
- //staptest// open ("foobar2", O_WRONLY|O_CREAT|O_EXCL, 0700) = -NNNN (EEXIST)
+ //staptest// open ("foobar2", O_WRONLY|O_CREAT|O_EXCL[[[[.O_LARGEFILE]]]]?, 0700) = -NNNN (EEXIST)
return 0;
}
diff --git a/testsuite/systemtap.syscall/readwrite.c b/testsuite/systemtap.syscall/readwrite.c
index bd0914cc..d966c0a8 100644
--- a/testsuite/systemtap.syscall/readwrite.c
+++ b/testsuite/systemtap.syscall/readwrite.c
@@ -26,7 +26,7 @@ int main()
v[2].iov_len = sizeof(STRING3);
fd = open("foobar1",O_WRONLY|O_CREAT, 0666);
- //staptest// open ("foobar1", O_WRONLY|O_CREAT, 0666) = NNNN
+ //staptest// open ("foobar1", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?, 0666) = NNNN
write(fd,"Hello world", 11);
//staptest// write (NNNN, "Hello world", 11) = 11
@@ -66,7 +66,7 @@ int main()
close (fd);
fd = open("foobar1",O_RDONLY);
- //staptest// open ("foobar1", O_RDONLY) = NNNN
+ //staptest// open ("foobar1", O_RDONLY[[[[.O_LARGEFILE]]]]?) = NNNN
read(fd, buf, 11);
//staptest// read (NNNN, XXXX, 11) = 11
diff --git a/testsuite/systemtap.syscall/stat.c b/testsuite/systemtap.syscall/stat.c
index d47c1440..20a66b09 100644
--- a/testsuite/systemtap.syscall/stat.c
+++ b/testsuite/systemtap.syscall/stat.c
@@ -20,7 +20,7 @@ int main()
//staptest// getcwd (XXXX, 128) = NNNN
fd = creat("foobar",S_IREAD|S_IWRITE);
- //staptest// open ("foobar", O_WRONLY|O_CREAT|O_TRUNC, 0600) = NNNN
+ //staptest// open ("foobar", O_WRONLY|O_CREAT[[[[.O_LARGEFILE]]]]?|O_TRUNC, 0600) = NNNN
fstat(fd, &sbuf);
//staptest// fstat (NNNN, XXXX) = 0
diff --git a/testsuite/systemtap.syscall/sys.stp b/testsuite/systemtap.syscall/sys.stp
index e3564a15..79c7ff57 100755
--- a/testsuite/systemtap.syscall/sys.stp
+++ b/testsuite/systemtap.syscall/sys.stp
@@ -1,4 +1,4 @@
-global indent, indent_str, entry
+global indent, indent_str, entry_p
probe begin {
indent = 0
@@ -13,22 +13,22 @@ probe begin {
probe syscall.* ? {
if (pid() == target()) {
- if (entry) printf("\n")
+ if (entry_p) printf("\n")
printf("%s%s: %s (%s) = ", indent_str[indent], execname(), name, argstr)
# printf("%s%s: %s (%s) = ", indent_str[indent], execname(), probefunc(), argstr)
indent++
- entry = 1
+ entry_p = 1
}
}
probe syscall.*.return ? {
if (pid() == target()) {
if (indent) indent--
- if (entry)
+ if (entry_p)
printf("%s\n", retstr)
else
printf("%s%s\n", indent_str[indent],retstr)
- entry = 0
+ entry_p = 0
}
}
diff --git a/testsuite/systemtap.syscall/test-debug.tcl b/testsuite/systemtap.syscall/test-debug.tcl
index eb730459..3eb6bbf0 100755
--- a/testsuite/systemtap.syscall/test-debug.tcl
+++ b/testsuite/systemtap.syscall/test-debug.tcl
@@ -50,9 +50,20 @@ foreach line [split $output "\n"] {
if {[regsub {//} $line {} line]} {
set line "$testname: [string trimleft $line]"
+ # We need to quote all these metacharacters
regsub -all {\(} $line {\\(} line
regsub -all {\)} $line {\\)} line
regsub -all {\|} $line {\|} line
+ # + and * are metacharacters, but should always be used
+ # as metacharacters in the expressions, don't escape them.
+ #regsub -all {\+} $line {\\+} line
+ #regsub -all {\*} $line {\\*} line
+
+ # Turn '[[[[' and ']]]]' into '(' and ')' respectively.
+ # Because normally parens get quoted, this allows us to
+ # have non-quoted parens.
+ regsub -all {\[\[\[\[} $line {(} line
+ regsub -all {\]\]\]\]} $line {)} line
regsub -all NNNN $line {[\-0-9]+} line
regsub -all XXXX $line {[x0-9a-fA-F]+} line
diff --git a/testsuite/systemtap.syscall/test.tcl b/testsuite/systemtap.syscall/test.tcl
index b9d3c0d9..e640db66 100755
--- a/testsuite/systemtap.syscall/test.tcl
+++ b/testsuite/systemtap.syscall/test.tcl
@@ -67,6 +67,12 @@ proc run_one_test {filename flags bits} {
#regsub -all {\+} $line {\\+} line
#regsub -all {\*} $line {\\*} line
+ # Turn '[[[[' and ']]]]' into '(' and ')' respectively.
+ # Because normally parens get quoted, this allows us to
+ # have non-quoted parens.
+ regsub -all {\[\[\[\[} $line {(} line
+ regsub -all {\]\]\]\]} $line {)} line
+
regsub -all NNNN $line {[\-0-9]+} line
regsub -all XXXX $line {[x0-9a-fA-F]+} line
diff --git a/testsuite/transko/varargs.stp b/testsuite/transko/varargs.stp
new file mode 100755
index 00000000..f38309ad
--- /dev/null
+++ b/testsuite/transko/varargs.stp
@@ -0,0 +1,10 @@
+#! stap -p3
+
+probe begin {
+ // PR10750 enforces at most 32 print args
+ println(1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32,
+ 33)
+}
diff --git a/testsuite/transok/varargs.stp b/testsuite/transok/varargs.stp
new file mode 100755
index 00000000..216166f6
--- /dev/null
+++ b/testsuite/transok/varargs.stp
@@ -0,0 +1,9 @@
+#! stap -p3
+
+probe begin {
+ // PR10750 enforces at most 32 print args
+ println(1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32)
+}
diff --git a/translate.cxx b/translate.cxx
index bc5d6158..ed415abb 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -29,6 +29,11 @@ extern "C" {
#include <elfutils/libdwfl.h>
}
+// Max unwind table size (debug or eh) per module. Somewhat arbitrary
+// limit (a bit more than twice the .debug_frame size of my local
+// vmlinux for 2.6.31.4-83.fc12.x86_64)
+#define MAX_UNWIND_TABLE_SIZE (3 * 1024 * 1024)
+
using namespace std;
struct var;
@@ -68,6 +73,7 @@ struct c_unparser: public unparser, public visitor
void emit_module_init ();
void emit_module_exit ();
void emit_function (functiondecl* v);
+ void emit_lock_decls (const varuse_collecting_visitor& v);
void emit_locks (const varuse_collecting_visitor& v);
void emit_probe (derived_probe* v);
void emit_unlocks (const varuse_collecting_visitor& v);
@@ -1617,6 +1623,14 @@ c_unparser::emit_probe (derived_probe* v)
probe_contents[oss.str()] = v->name;
+ // emit static read/write lock decls for global variables
+ varuse_collecting_visitor vut(*session);
+ if (v->needs_global_locks ())
+ {
+ v->body->visit (& vut);
+ emit_lock_decls (vut);
+ }
+
// initialize frame pointer
o->newline() << "struct " << v->name << "_locals * __restrict__ l =";
o->newline(1) << "& c->probe_locals." << v->name << ";";
@@ -1633,12 +1647,8 @@ c_unparser::emit_probe (derived_probe* v)
v->emit_probe_local_init(o);
// emit all read/write locks for global variables
- varuse_collecting_visitor vut(*session);
if (v->needs_global_locks ())
- {
- v->body->visit (& vut);
emit_locks (vut);
- }
// initialize locals
for (unsigned j=0; j<v->locals.size(); j++)
@@ -1689,13 +1699,16 @@ c_unparser::emit_probe (derived_probe* v)
void
-c_unparser::emit_locks(const varuse_collecting_visitor& vut)
+c_unparser::emit_lock_decls(const varuse_collecting_visitor& vut)
{
- o->newline() << "{";
- o->newline(1) << "unsigned numtrylock = 0;";
- o->newline() << "(void) numtrylock;";
+ unsigned numvars = 0;
+
+ if (session->verbose > 1)
+ clog << current_probe->name << " locks ";
+
+ o->newline() << "static const struct stp_probe_lock locks[] = {";
+ o->indent(1);
- string last_locked_var;
for (unsigned i = 0; i < session->globals.size(); i++)
{
vardecl* v = session->globals[i];
@@ -1727,94 +1740,44 @@ c_unparser::emit_locks(const varuse_collecting_visitor& vut)
continue;
}
- string lockcall =
- string (write_p ? "write" : "read") +
- "_trylock (& global.s_" + v->name + "_lock)";
-
- o->newline() << "while (! " << lockcall
- << "&& (++numtrylock < MAXTRYLOCK))";
- o->newline(1) << "ndelay (TRYLOCKDELAY);";
- o->newline(-1) << "if (unlikely (numtrylock >= MAXTRYLOCK)) {";
- o->newline(1) << "atomic_inc (& skipped_count);";
+ o->newline() << "{";
+ o->newline(1) << ".lock = &global.s_" + v->name + "_lock,";
+ o->newline() << ".write_p = " << (write_p ? 1 : 0) << ",";
o->newline() << "#ifdef STP_TIMING";
- o->newline() << "atomic_inc (& global.s_" << c_varname (v->name) << "_lock_skip_count);";
+ o->newline() << ".skipped = &global.s_" << c_varname (v->name) << "_lock_skip_count,";
o->newline() << "#endif";
- // The following works even if i==0. Note that using
- // globals[i-1]->name is wrong since that global may not have
- // been lockworthy by this probe.
- o->newline() << "goto unlock_" << last_locked_var << ";";
- o->newline(-1) << "}";
+ o->newline(-1) << "},";
- last_locked_var = v->name;
+ numvars ++;
+ if (session->verbose > 1)
+ clog << v->name << "[" << (read_p ? "r" : "")
+ << (write_p ? "w" : "") << "] ";
}
- o->newline() << "if (0) goto unlock_;";
+ o->newline(-1) << "};";
- o->newline(-1) << "}";
+ if (session->verbose > 1)
+ {
+ if (!numvars)
+ clog << "nothing";
+ clog << endl;
+ }
}
void
-c_unparser::emit_unlocks(const varuse_collecting_visitor& vut)
+c_unparser::emit_locks(const varuse_collecting_visitor&)
{
- unsigned numvars = 0;
-
- if (session->verbose>1)
- clog << current_probe->name << " locks ";
-
- for (int i = session->globals.size()-1; i>=0; i--) // in reverse order!
- {
- vardecl* v = session->globals[i];
- bool read_p = vut.read.find(v) != vut.read.end();
- bool write_p = vut.written.find(v) != vut.written.end();
- if (!read_p && !write_p) continue;
-
- // Duplicate lock flipping logic from above
- if (v->type == pe_stats)
- {
- if (write_p && !read_p) { read_p = true; write_p = false; }
- else if (read_p && !write_p) { read_p = false; write_p = true; }
- }
-
- // Duplicate "read-mostly" global variable logic from above.
- if (read_p && !write_p)
- {
- if (vcv_needs_global_locks.written.find(v)
- == vcv_needs_global_locks.written.end())
- continue;
- }
-
- numvars ++;
- o->newline(-1) << "unlock_" << v->name << ":";
- o->indent(1);
-
- if (session->verbose>1)
- clog << v->name << "[" << (read_p ? "r" : "")
- << (write_p ? "w" : "") << "] ";
-
- if (write_p) // emit write lock
- o->newline() << "write_unlock (& global.s_" << v->name << "_lock);";
- else // (read_p && !write_p) : emit read lock
- o->newline() << "read_unlock (& global.s_" << v->name << "_lock);";
-
- // fall through to next variable; thus the reverse ordering
- }
-
- // emit plain "unlock" label, used if the very first lock failed.
- o->newline(-1) << "unlock_: ;";
- o->indent(1);
+ o->newline() << "if (!stp_lock_probe(locks, ARRAY_SIZE(locks)))";
+ o->newline(1) << "return;";
+ o->indent(-1);
+}
- if (numvars) // is there a chance that any lock attempt failed?
- {
- // Formerly, we checked skipped_count > MAXSKIPPED here, and set
- // SYSTEMTAP_SESSION_ERROR if so. But now, this check is shared
- // via common_probe_entryfn_epilogue().
- if (session->verbose>1)
- clog << endl;
- }
- else if (session->verbose>1)
- clog << "nothing" << endl;
+void
+c_unparser::emit_unlocks(const varuse_collecting_visitor& vut)
+{
+ o->newline() << "stp_unlock_probe(locks, ARRAY_SIZE(locks));";
}
@@ -4173,6 +4136,11 @@ c_unparser::visit_print_format (print_format* e)
{
stmt_expr block(*this);
+ // PR10750: Enforce a reasonable limit on # of varargs
+ // 32 varargs leads to max 256 bytes on the stack
+ if (e->args.size() > 32)
+ throw semantic_error("too many arguments to print", e->tok);
+
// Compute actual arguments
vector<tmpvar> tmp;
@@ -4785,6 +4753,9 @@ dump_unwindsyms (Dwfl_Module *m,
get_unwind_data (m, &debug_frame, &eh_frame, &debug_len, &eh_len, &eh_addr);
if (debug_frame != NULL && debug_len > 0)
{
+ if (debug_len > MAX_UNWIND_TABLE_SIZE)
+ throw semantic_error ("module debug unwind table size too big");
+
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
c->output << "static uint8_t _stp_module_" << stpmod_idx
<< "_debug_frame[] = \n";
@@ -4802,6 +4773,9 @@ dump_unwindsyms (Dwfl_Module *m,
if (eh_frame != NULL && eh_len > 0)
{
+ if (eh_len > MAX_UNWIND_TABLE_SIZE)
+ throw semantic_error ("module eh unwind table size too big");
+
c->output << "#if defined(STP_USE_DWARF_UNWINDER) && defined(STP_NEED_UNWIND_DATA)\n";
c->output << "static uint8_t _stp_module_" << stpmod_idx
<< "_eh_frame[] = \n";
@@ -5217,13 +5191,10 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#include \"loc2c-runtime.h\" ";
s.op->newline() << "#include \"access_process_vm.h\" ";
- // XXX: old 2.6 kernel hack
- s.op->newline() << "#ifndef read_trylock";
- s.op->newline() << "#define read_trylock(x) ({ read_lock(x); 1; })";
- s.op->newline() << "#endif";
-
s.up->emit_common_header (); // context etc.
+ s.op->newline() << "#include \"probe_lock.h\" ";
+
for (unsigned i=0; i<s.embeds.size(); i++)
{
s.op->newline() << s.embeds[i]->code << "\n";