From 03ebf81c360e429ef1e4f8bae48fe524f712589a Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 3 Dec 2009 19:31:08 +0100 Subject: Hover text for event-style graphs Don't draw the data value for an event; only display it in hover text. * grapher/Graph.hxx (window2GraphCoords): new function * grapher/Graph.cxx (window2GraphCoords): ditto * grapher/GraphStyle.cxx (GraphStyleEvent::dataIndexAtPoint): new function implementation. --- grapher/Graph.cxx | 7 +++++++ grapher/Graph.hxx | 1 + grapher/GraphStyle.cxx | 48 +++++++++++++++++++++++++++++++++++------------- grapher/GraphStyle.hxx | 4 ++++ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx index 55ffcdf2..57f1dc9a 100644 --- a/grapher/Graph.cxx +++ b/grapher/Graph.cxx @@ -205,4 +205,11 @@ namespace systemtap return (_left + (_right - _left) * ((x - _xOffset)/(_zoomFactor * _graphWidth))); } + + void Graph::window2GraphCoords(double x, double y, + double& xgraph, double& ygraph) + { + xgraph = x -_xOffset; + ygraph = -y + _yOffset + _graphHeight; + } } diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx index b9efb2a2..044a66d3 100644 --- a/grapher/Graph.hxx +++ b/grapher/Graph.hxx @@ -41,6 +41,7 @@ namespace systemtap std::tr1::shared_ptr _playButton; DatasetList& getDatasets() { return _datasets; } int64_t getTimeAtPoint(double x); + void window2GraphCoords(double x, double y, double& xgraph, double& ygraph); protected: DatasetList _datasets; int64_t _left; diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx index 55fc73f4..cf3855e3 100644 --- a/grapher/GraphStyle.cxx +++ b/grapher/GraphStyle.cxx @@ -132,20 +132,9 @@ namespace systemtap ditr != de; ++ditr) { - size_t dataIndex = ditr - graphData->times.begin(); + // size_t dataIndex = ditr - graphData->times.begin(); double eventHeight = graph->_graphHeight * (graphData->scale / 100.0); cr->save(); - cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, - Cairo::FONT_WEIGHT_NORMAL); - cr->set_font_size(12.0); - cr->set_source_rgba(graphData->color[0], graphData->color[1], - graphData->color[2], 1.0); - cr->save(); - cr->scale(1.0, -1.0); - cr->move_to((*ditr - left) * horizScale, - -eventHeight - 3.0 * graph->_lineWidth - 2.0); - cr->show_text(stringData->data[dataIndex]); - cr->restore(); cr->rectangle((*ditr - left) * horizScale - 1.5 * graph->_lineWidth, eventHeight - 1.5 * graph->_lineWidth, 3.0 * graph->_lineWidth, 3.0 * graph->_lineWidth); @@ -153,5 +142,38 @@ namespace systemtap cr->restore(); } } - + + ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y, + shared_ptr graphData, + shared_ptr graph) + { + shared_ptr > stringData + = dynamic_pointer_cast >(graphData); + if (!stringData) + return -1; + int64_t left, right; + double top, bottom; + graph->getExtents(left, right, top, bottom); + double horizScale = (graph->_zoomFactor * graph->_graphWidth + / static_cast(right - left)); + double eventHeight = graph->_graphHeight * (graphData->scale / 100.0); + GraphDataBase::TimeList::iterator lower + = lower_bound(graphData->times.begin(), graphData->times.end(), left); + GraphDataBase::TimeList::iterator upper + = upper_bound(graphData->times.begin(), graphData->times.end(), right); + // easier to transform x,y into graph coordinates + double xgraph, ygraph; + graph->window2GraphCoords(x, y, xgraph, ygraph); + double yrect = eventHeight - 1.5 * graph->_lineWidth; + for (GraphDataBase::TimeList::iterator ditr = lower, de = upper; + ditr != de; + ++ditr) + { + double xrect = (*ditr - left) * horizScale - 1.5 * graph->_lineWidth; + if (xrect <= xgraph && xgraph < xrect + 3.0 * graph->_lineWidth + && yrect <= ygraph && ygraph < yrect + 3.0 * graph->_lineWidth) + return static_cast(distance(lower, ditr)); + } + return -1; + } } diff --git a/grapher/GraphStyle.hxx b/grapher/GraphStyle.hxx index 9625f451..ce75d698 100644 --- a/grapher/GraphStyle.hxx +++ b/grapher/GraphStyle.hxx @@ -48,6 +48,10 @@ namespace systemtap public: void draw(std::tr1::shared_ptr graphData, Graph* graph, Cairo::RefPtr cr); + virtual ssize_t dataIndexAtPoint(double x, double y, + std::tr1::shared_ptr + graphData, + std::tr1::shared_ptr graph); static GraphStyleEvent instance; }; } -- cgit From 5cd2f827aa03091c7d1832c9734827d8caff732d Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 3 Dec 2009 15:35:34 -0500 Subject: PR11020: Check switch_file global flag inside inner loop for busy scripts * runtime/staprun/relay.c (reader_thread): Check switch_file thread flags inside inner read-write loop. And clear the flags after switching file. --- runtime/staprun/relay.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/staprun/relay.c b/runtime/staprun/relay.c index 59d7ac9a..39a2f393 100644 --- a/runtime/staprun/relay.c +++ b/runtime/staprun/relay.c @@ -166,9 +166,9 @@ static void *reader_thread(void *data) if (stop_threads) break; if (switch_file[cpu]) { - switch_file[cpu] = 0; if (switch_outfile(cpu, &fnum) < 0) goto error_out; + switch_file[cpu] = 0; wsize = 0; } } else { @@ -179,9 +179,11 @@ static void *reader_thread(void *data) while ((rc = read(relay_fd[cpu], buf, sizeof(buf))) > 0) { /* Switching file */ - if (fsize_max && wsize + rc > fsize_max) { + if ((fsize_max && wsize + rc > fsize_max) || + switch_file[cpu]) { if (switch_outfile(cpu, &fnum) < 0) goto error_out; + switch_file[cpu] = 0; wsize = 0; } if (write(out_fd[cpu], buf, rc) != rc) { -- cgit From 457a91c061a1658648fc155504795bf6f4c44740 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 3 Dec 2009 23:45:51 +0100 Subject: Error check in hover text code for empty graphs * grapher/GraphStyle.cxx(GraphStyleEvent::dataIndexAtPoint, GraphStyleBar::dataIndexAtPoint): check for empty graph data --- grapher/GraphStyle.cxx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx index cf3855e3..fdc8c4d6 100644 --- a/grapher/GraphStyle.cxx +++ b/grapher/GraphStyle.cxx @@ -50,7 +50,7 @@ namespace systemtap { shared_ptr > realData = dynamic_pointer_cast >(graphData); - if (!realData) + if (!realData || graphData->times.empty()) return -1; int64_t left, right; double top, bottom; @@ -58,6 +58,8 @@ namespace systemtap double t = graph->getTimeAtPoint(x); TimeListPair range = equal_range(graphData->times.begin(), graphData->times.end(), t); + if (range.first == graphData->times.end()) + return -1; size_t dataIndex = distance(graphData->times.begin(), range.first); double val = realData->data[dataIndex]; double ycoord = val * graph->_graphHeight / graphData->scale; @@ -149,7 +151,7 @@ namespace systemtap { shared_ptr > stringData = dynamic_pointer_cast >(graphData); - if (!stringData) + if (!stringData || graphData->times.empty()) return -1; int64_t left, right; double top, bottom; -- cgit From 5ddc5963ce06ecea574e90ca503a3ee598522d8f Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 13:08:01 +0100 Subject: support multiline data output from scripts run under the grapher This is accompanied by support for multiline output in hover text. * grapher/StapParser.cxx (ioCallback): Read data 'til the end of line character, not just '\n'. Be careful to use I/O functions that don't treat '\n' specially. * grapher/StapParser.hxx: ditto * grapher/CairoWidget.cxx (CairoTextBox::draw): Perform line breaks for hover text. * testsuite/systemtap.examples/general/grapher.stp: Do multiline output of keyboard events. Also, fix longstanding breaking in the pty probe. --- grapher/CairoWidget.cxx | 36 ++++++++++++++++++++---- grapher/GraphWidget.cxx | 2 +- grapher/StapParser.cxx | 27 ++++++++++++------ grapher/StapParser.hxx | 3 +- testsuite/systemtap.examples/general/grapher.stp | 18 ++++++++---- 5 files changed, 66 insertions(+), 20 deletions(-) diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx index f627dfaa..db0e464e 100644 --- a/grapher/CairoWidget.cxx +++ b/grapher/CairoWidget.cxx @@ -1,9 +1,15 @@ #include "CairoWidget.hxx" #include +#include + +#include namespace systemtap { + using namespace std; + using namespace boost; + void CairoPlayButton::draw(Cairo::RefPtr cr) { if (!_visible) @@ -44,10 +50,22 @@ namespace systemtap { if (!_visible) return; + vector lines; + split(lines, contents, is_any_of("\n")); + vector extents; + double width = 0.0, height = 0.0; + for (vector::iterator itr = lines.begin(), end = lines.end(); + itr != end; + ++itr) + { + Cairo::TextExtents extent; + cr->get_text_extents(*itr, extent); + extents.push_back(extent); + width = max(width, extent.width); + height += extent.height; + } + cr->save(); - Cairo::TextExtents extents; - cr->get_text_extents(contents, extents); - double width = extents.width, height = extents.height; cr->move_to(_x0 - 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 + height + 2); @@ -56,8 +74,16 @@ namespace systemtap cr->set_source_rgba(1.0, 1.0, 1.0, .8); cr->fill(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); - cr->move_to(_x0, _y0 + height); - cr->show_text(contents); + vector::iterator titr = extents.begin(); + double texty = _y0; + for (vector::iterator itr = lines.begin(), end = lines.end(); + itr != end; + ++itr,++titr) + { + cr->move_to(_x0, texty + titr->height); + cr->show_text(*itr); + texty += titr->height; + } cr->restore(); } } diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 9067988a..e37485b8 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -275,7 +275,7 @@ namespace systemtap { if (!_hoverText) _hoverText = shared_ptr(new CairoTextBox()); - _hoverText->setOrigin(_mouseX + 5, _mouseY - 5); + _hoverText->setOrigin(_mouseX + 10, _mouseY - 5); Graph::DatasetList& dataSets = g->getDatasets(); for (Graph::DatasetList::reverse_iterator ritr = dataSets.rbegin(), end = dataSets.rend(); diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 6218e229..2a246475 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -76,14 +77,14 @@ vector commaSplit(const boost::sub_range& range) _win->hide(); return true; } - buf[bytes_read] = '\0'; - _buffer += buf; + _buffer.append(buf, bytes_read); string::size_type ret = string::npos; - while ((ret = _buffer.find('\n')) != string::npos) + while ((ret = _buffer.find(_lineEndChar)) != string::npos) { Glib::ustring dataString(_buffer, 0, ret); - // %DataSet and %CSV declare a data set; all other statements begin with - // the name of a data set. + // %DataSet and %CSV declare a data set; all other + // statements begin with the name of a data set. + // Except %LineEnd :) sub_range found; if (dataString[0] == '%') { @@ -142,6 +143,15 @@ vector commaSplit(const boost::sub_range& range) setIter->second)); } } + else if ((found = find_first(dataString, "%LineEnd:"))) + { + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + int charAsInt = 0; + // parse hex and octal numbers too + stream >> std::setbase(0) >> charAsInt; + _lineEndChar = static_cast(charAsInt); + } else { cerr << "Unknown declaration " << dataString << endl; @@ -199,9 +209,10 @@ vector commaSplit(const boost::sub_range& range) else { int64_t time; - string data; - stream >> time >> data; - parseData(itr->second, time, data); + stringbuf data; + stream >> time; + stream.get(data, _lineEndChar); + parseData(itr->second, time, data.str()); } } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index a77ad1bc..4f1cbd5a 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -14,10 +14,11 @@ class StapParser GraphWidget* _widget; int _errFd; int _inFd; + unsigned char _lineEndChar; public: StapParser(Gtk::Window* win, GraphWidget* widget) : _win(win), _widget(widget), _errFd(-1), - _inFd(-1) + _inFd(-1), _lineEndChar('\n') { } void parseData(std::tr1::shared_ptr gdata, diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp index e8655b37..c1c60437 100755 --- a/testsuite/systemtap.examples/general/grapher.stp +++ b/testsuite/systemtap.examples/general/grapher.stp @@ -8,7 +8,7 @@ printf ("%%DataSet:pty 50 0000ff discreet\n"); printf ("cpu %%Title:CPU utilization\n"); printf ("cpu %%XAxisTitle:Time\n"); printf ("cpu %%YAxisTitle:Percent\n"); - +printf ("%%LineEnd:0\n"); } # CPU utilization @@ -26,17 +26,25 @@ function qsq_util_reset(q) { probe timer.ms(100) { # collect utilization percentages frequently foreach (q in qnames) - printf("cpu %d %d\n", gettimeofday_ms(), qsq_util_reset(q)) + printf("cpu %d %d%c", gettimeofday_ms(), qsq_util_reset(q), 0) } probe kernel.function("kbd_event") { if ($event_type == 1 && $value) - printf("kbd %d %d\n", gettimeofday_ms(), $event_code) + printf("kbd %d %d\n0x%x%c", gettimeofday_ms(), $event_code, $event_code, 0) } probe kernel.function("pty_write") { - if (count > 0) - printf("pty %d %.5s\n", gettimeofday_ms(), buf) + if ($count > 0) { + printf("pty %d ", gettimeofday_ms()) + str = kernel_string($buf) + for (i = 0; i < $count; ++i) { + # yes it's gross + c = substr(str, i, 1) + printf("%s\n", text_str(c)) + } + printf("%c", 0) + } } -- cgit From 52cf0905d93c33f7d6f768478572ea08df4c8af0 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 14:11:25 +0100 Subject: tweak multiline hover text to have proper interline spacing * grapher/CairoWidget.cxx (CairoTextBox::draw): Use font information to caculate legible spacing. Also change the font to something more readable. * testsuite/systemtap.examples/general/grapher.stp: Put carriage returns in the right spots. --- grapher/CairoWidget.cxx | 20 +++++++++++++------- testsuite/systemtap.examples/general/grapher.stp | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx index db0e464e..eefe3d28 100644 --- a/grapher/CairoWidget.cxx +++ b/grapher/CairoWidget.cxx @@ -50,6 +50,15 @@ namespace systemtap { if (!_visible) return; + cr->save(); + cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL, + Cairo::FONT_WEIGHT_BOLD); + cr->set_font_size(10.0); + Cairo::FontExtents fontExtent; + cr->get_font_extents(fontExtent); + // Some naughty fonts have a height less than ascent + descent + double fontHeight = max(fontExtent.ascent + fontExtent.descent + 1.0, + fontExtent.height); vector lines; split(lines, contents, is_any_of("\n")); vector extents; @@ -62,10 +71,8 @@ namespace systemtap cr->get_text_extents(*itr, extent); extents.push_back(extent); width = max(width, extent.width); - height += extent.height; + height += fontHeight; } - - cr->save(); cr->move_to(_x0 - 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 - 2); cr->line_to(_x0 + width + 2, _y0 + height + 2); @@ -74,15 +81,14 @@ namespace systemtap cr->set_source_rgba(1.0, 1.0, 1.0, .8); cr->fill(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); - vector::iterator titr = extents.begin(); double texty = _y0; for (vector::iterator itr = lines.begin(), end = lines.end(); itr != end; - ++itr,++titr) + ++itr) { - cr->move_to(_x0, texty + titr->height); + cr->move_to(_x0, texty + fontExtent.ascent); cr->show_text(*itr); - texty += titr->height; + texty += fontHeight; } cr->restore(); } diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp index c1c60437..baeeff5c 100755 --- a/testsuite/systemtap.examples/general/grapher.stp +++ b/testsuite/systemtap.examples/general/grapher.stp @@ -39,9 +39,11 @@ probe kernel.function("pty_write") { printf("pty %d ", gettimeofday_ms()) str = kernel_string($buf) for (i = 0; i < $count; ++i) { + if (i > 1) + printf("\n") # yes it's gross c = substr(str, i, 1) - printf("%s\n", text_str(c)) + printf("%s", text_str(c)) } printf("%c", 0) } -- cgit From 2ebfefae53de7d6c001554a159dbcc8edfac9ec7 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 17:12:06 +0100 Subject: hover text on the additional graphs * grapher/Graph.cxx (window2GraphCoords): Take the entire graph's position into account too. * grapher/GraphWidget.cxx (GraphWidget): Hook up the data dialog's OK button. (onDataDialogOpen): If a data set doesn't have a title, use it's name (key) instead. --- grapher/Graph.cxx | 2 +- grapher/GraphWidget.cxx | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx index 57f1dc9a..b3429ef7 100644 --- a/grapher/Graph.cxx +++ b/grapher/Graph.cxx @@ -210,6 +210,6 @@ namespace systemtap double& xgraph, double& ygraph) { xgraph = x -_xOffset; - ygraph = -y + _yOffset + _graphHeight; + ygraph = -(y - _graphY) + _yOffset + _graphHeight; } } diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index e37485b8..3d38627f 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -50,6 +50,11 @@ namespace systemtap _refXmlDataDialog->get_widget("dialog1", _dataDialog); Gtk::Button* button = 0; _refXmlDataDialog->get_widget("cancelbutton1", button); + button->signal_clicked() + .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel), + false); + // XXX + _refXmlDataDialog->get_widget("okbutton1", button); button->signal_clicked() .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel), false); @@ -263,7 +268,10 @@ namespace systemtap { Gtk::TreeModel::iterator litr = _listStore->append(); Gtk::TreeModel::Row row = *litr; - row[_dataColumns._dataName] = (*itr)->title; + if (!(*itr)->title.empty()) + row[_dataColumns._dataName] = (*itr)->title; + else + row[_dataColumns._dataName] = (*itr)->name; row[_dataColumns._graphData] = *itr; } } -- cgit From 8d6779975df8f3bef98ad2b2ae4ce310a543f781 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 17:31:55 +0100 Subject: restore event square color * grapher/GraphStyle.cxx (GraphStyleEvent::draw): set event color in inner loop. --- grapher/GraphStyle.cxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx index fdc8c4d6..b9429e2a 100644 --- a/grapher/GraphStyle.cxx +++ b/grapher/GraphStyle.cxx @@ -137,6 +137,8 @@ namespace systemtap // size_t dataIndex = ditr - graphData->times.begin(); double eventHeight = graph->_graphHeight * (graphData->scale / 100.0); cr->save(); + cr->set_source_rgba(graphData->color[0], graphData->color[1], + graphData->color[2], 1.0); cr->rectangle((*ditr - left) * horizScale - 1.5 * graph->_lineWidth, eventHeight - 1.5 * graph->_lineWidth, 3.0 * graph->_lineWidth, 3.0 * graph->_lineWidth); -- cgit From db41ebdabef8a7964ed92054ee7346cfded7179c Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 4 Dec 2009 19:30:08 +0100 Subject: Add new graph output to the last graph --- grapher/GraphWidget.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 3d38627f..739d9450 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -84,7 +84,7 @@ namespace systemtap void GraphWidget::addGraphData(shared_ptr data) { - _graphs[0]->addGraphData(data); + _graphs.back()->addGraphData(data); _graphData.push_back(data); } -- cgit From 6da1ad4654842c7a2489e18b9acc94f2f68a6b24 Mon Sep 17 00:00:00 2001 From: Wenji Huang Date: Mon, 7 Dec 2009 16:47:32 +0800 Subject: Fix regression introduced by commit 379c585 --- tapset/tcpmib.stp | 11 +---------- testsuite/buildok/tcpmib-all-probes.stp | 7 +++++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tapset/tcpmib.stp b/tapset/tcpmib.stp index 497fb7dd..aba7837b 100644 --- a/tapset/tcpmib.stp +++ b/tapset/tcpmib.stp @@ -99,16 +99,6 @@ function tcpmib_remote_port:long(sk:long) CATCH_DEREF_FAULT(); %} -function tcpmib_filter_key:long (sk:long, op:long) { - // ensure all these functions will build - if ( tcpmib_get_state(sk) ) return 0 - if ( tcpmib_local_addr(sk) ) return 0 - if ( tcpmib_remote_addr(sk) ) return 0 - if ( tcpmib_local_port(sk) ) return 0 - if ( tcpmib_remote_port(sk) ) return 0 - return op -} - /** * probe tcpmib.ActiveOpens - Count an active opening of a socket. * @sk: Pointer to the struct sock being acted on. @@ -124,6 +114,7 @@ tcpmib.ActiveOpens=kernel.function("tcp_connect").return sk = $sk; op = 1; if ( $return ) next; + // definition in tcpipstat.stp key = tcpmib_filter_key(sk,op); if ( key ) ActiveOpens[key] += op; } diff --git a/testsuite/buildok/tcpmib-all-probes.stp b/testsuite/buildok/tcpmib-all-probes.stp index 8d1105e1..5b44a99a 100755 --- a/testsuite/buildok/tcpmib-all-probes.stp +++ b/testsuite/buildok/tcpmib-all-probes.stp @@ -4,6 +4,13 @@ probe tcpmib.* {} +// This function is just for test, the real one is +// in tcpipstat.stp +function tcpmib_filter_key:long (sk:long, op:long) { + if (!sk) return 0 + return op +} + probe begin{ print(tcpmib_get_state(0) + tcpmib_local_addr(0) + -- cgit From e88061ec1fb047b65c247424dbadb10a85ff69ae Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 7 Dec 2009 12:23:27 +0100 Subject: Add a missing cairo context restore() It's not clear if this was causing any ill effects, but it is certainly bad form. * grapher/GraphWidget.cxx (on_expose_event): add missing cr->restore(). --- grapher/GraphWidget.cxx | 1 + 1 file changed, 1 insertion(+) diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 739d9450..cfec0adf 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -126,6 +126,7 @@ namespace systemtap } if (_hoverText && _hoverText->isVisible()) _hoverText->draw(cr); + cr->restore(); return true; } -- cgit From 5891de489db0e172162279247fb633a719fa3756 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 7 Dec 2009 12:43:56 +0100 Subject: option to display graph times relative to the start time This avoids having humongous numbers displayed on the graphs' x axis. Also, the dialog for adding a data set to a graph was cleaned up. * grapher/graph-dialog.glade: Add check box for display of relative time and a label for the data set list. Force the list of data sets to be larger. * grapher/Graph.hxx (_timeBase): new member * grapher/Graph.cxx (draw): Subtract _timeBase from displayed time value. * grapher/GraphWidget.hxx (DataModelColumns): Add a column for a data set's title, which is optional at the moment. * grapher/GraphWidget.hxx (_globalTimeBase, _timeBaseInitialized, _relativeTimesButton, _displayRelativeTimes): new members * grapher/GraphWidget.hxx (GraphWidget): Hook up check button for displaying relative time. (on_expose_event): Determine base time if needed; set base time in graphs. (onDataDialogOpen): Insert graph data set's name (key) and title into the list of data sets. --- grapher/Graph.cxx | 4 ++-- grapher/Graph.hxx | 1 + grapher/GraphWidget.cxx | 46 ++++++++++++++++++++++++++++++++++++++++++---- grapher/GraphWidget.hxx | 7 +++++++ grapher/graph-dialog.glade | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 6 deletions(-) diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx index b3429ef7..baa1182f 100644 --- a/grapher/Graph.cxx +++ b/grapher/Graph.cxx @@ -14,7 +14,7 @@ namespace systemtap _graphWidth(580), _graphHeight(180), _lineWidth(2), _autoScaling(true), _autoScrolling(true), _zoomFactor(1.0), _xOffset(20.0), _yOffset(0.0), - _playButton(new CairoPlayButton), + _playButton(new CairoPlayButton), _timeBase(0), _left(0), _right(1), _top(5.0), _bottom(0.0) { setOrigin(x, y); @@ -150,7 +150,7 @@ namespace systemtap cr->move_to(x, _yOffset); cr->line_to(x, _graphHeight); std::ostringstream stream; - stream << tickVal; + stream << (tickVal - _timeBase); Cairo::TextExtents extents; cr->get_text_extents(stream.str(), extents); // Room for this label? diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx index 044a66d3..93e23deb 100644 --- a/grapher/Graph.hxx +++ b/grapher/Graph.hxx @@ -39,6 +39,7 @@ namespace systemtap double _xOffset; double _yOffset; std::tr1::shared_ptr _playButton; + int64_t _timeBase; DatasetList& getDatasets() { return _datasets; } int64_t getTimeAtPoint(double x); void window2GraphCoords(double x, double y, double& xgraph, double& ygraph); diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index cfec0adf..9d5e12f8 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -4,6 +4,9 @@ #include #include +#define __STDC_LIMIT_MACROS +#include + #include #include #include @@ -22,7 +25,7 @@ namespace systemtap GraphWidget::GraphWidget() : _trackingDrag(false), _width(600), _height(200), _mouseX(0.0), - _mouseY(0.0) + _mouseY(0.0), _globalTimeBase(0), _timeBaseInitialized(false) { add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::SCROLL_MASK); @@ -70,6 +73,14 @@ namespace systemtap _listStore = Gtk::ListStore::create(_dataColumns); _dataTreeView->set_model(_listStore); _dataTreeView->append_column("Data", _dataColumns._dataName); + _dataTreeView->append_column("Title", _dataColumns._dataTitle); + _refXmlDataDialog->get_widget("checkbutton1", _relativeTimesButton); + _relativeTimesButton->signal_clicked() + .connect(sigc::mem_fun(*this, + &GraphWidget::onRelativeTimesButtonClicked)); + // Set button's initial value from that in .glade file + _displayRelativeTimes = _relativeTimesButton->get_active(); + } catch (const Gnome::Glade::XmlError& ex ) { @@ -100,6 +111,7 @@ namespace systemtap shared_ptr graph(new Graph(x, y)); _height = y + graph->_height; graph->setOrigin(x, y); + graph->_timeBase = _globalTimeBase; _graphs.push_back(graph); queue_resize(); } @@ -115,8 +127,29 @@ namespace systemtap cr->save(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->paint(); + if (!_timeBaseInitialized && !_graphData.empty()) + { + int64_t earliest = INT64_MAX; + for (GraphDataList::iterator gd = _graphData.begin(), + end = _graphData.end(); + gd != end; + ++gd) + { + if (!(*gd)->times.empty() && (*gd)->times[0] < earliest) + earliest = (*gd)->times[0]; + } + if (earliest != INT64_MAX) + { + _globalTimeBase = earliest; + _timeBaseInitialized = true; + } + } for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g) { + if (_displayRelativeTimes && _timeBaseInitialized) + (*g)->_timeBase = _globalTimeBase; + else + (*g)->_timeBase = 0.0; double x, y; (*g)->getOrigin(x, y); cr->save(); @@ -269,10 +302,9 @@ namespace systemtap { Gtk::TreeModel::iterator litr = _listStore->append(); Gtk::TreeModel::Row row = *litr; + row[_dataColumns._dataName] = (*itr)->name; if (!(*itr)->title.empty()) - row[_dataColumns._dataName] = (*itr)->title; - else - row[_dataColumns._dataName] = (*itr)->name; + row[_dataColumns._dataTitle] = (*itr)->title; row[_dataColumns._graphData] = *itr; } } @@ -326,4 +358,10 @@ namespace systemtap _hover_timeout_connection = Glib::signal_timeout() .connect(sigc::mem_fun(*this, &GraphWidget::onHoverTimeout), 1000); } + + void GraphWidget::onRelativeTimesButtonClicked() + { + _displayRelativeTimes = _relativeTimesButton->get_active(); + queue_draw(); + } } diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index 61d50e70..ea10720c 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -19,9 +19,11 @@ namespace systemtap DataModelColumns() { add(_dataName); + add(_dataTitle); add(_graphData); } Gtk::TreeModelColumn _dataName; + Gtk::TreeModelColumn _dataTitle; Gtk::TreeModelColumn > _graphData; }; @@ -72,8 +74,13 @@ namespace systemtap std::tr1::shared_ptr _hoverText; double _mouseX; double _mouseY; + int64_t _globalTimeBase; + bool _timeBaseInitialized; std::tr1::shared_ptr getGraphUnderPoint(double x, double y); void establishHoverTimeout(); + Gtk::CheckButton* _relativeTimesButton; + bool _displayRelativeTimes; + void onRelativeTimesButtonClicked(); }; } #endif // SYSTEMTAP_GRAPHWIDGET_H diff --git a/grapher/graph-dialog.glade b/grapher/graph-dialog.glade index cca2e0e3..85c10128 100644 --- a/grapher/graph-dialog.glade +++ b/grapher/graph-dialog.glade @@ -66,6 +66,31 @@ + + + True + Data sets + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + True @@ -83,6 +108,8 @@ + 200 + 100 True True False @@ -159,6 +186,25 @@ True + + + + True + True + Display relative times + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + -- cgit From b930d6ec364e35bb04a0860b1a5f2fbdee6effe3 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 7 Dec 2009 16:50:44 +0100 Subject: Change data set list display to use a check box for inclusion in a graph Incidently, this supports removing a data set from a graph. Also, remove the Add, Remove, and Cancel buttons from the data set dialog. * grapher/GraphWidget.hxx (DataModelColumns::_dataEnabled): new member _listConnection: new member * grapher/GraphWidget.cxx (GraphWidget): Delete connections for removed buttons. Connect to dialog show and hide signals instead of map. Add "Enabled" column to dialog list. (onDataAdd, onDataRemove): delete (onDataDialogOpen): Initialize list store with all data sets and hook up row_changed signal (onDataDialogClose, onRowChanged): new functions * grapher/graph-dialog.glade: Remove obsolete buttons (Add, Remove, Cancel). --- grapher/GraphWidget.cxx | 68 ++++++++++++++++++++++++-------------------- grapher/GraphWidget.hxx | 8 ++++-- grapher/graph-dialog.glade | 71 ++-------------------------------------------- 3 files changed, 47 insertions(+), 100 deletions(-) diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 9d5e12f8..db325d83 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -52,26 +52,19 @@ namespace systemtap _refXmlDataDialog = Gnome::Glade::Xml::create(PKGDATADIR "/graph-dialog.glade"); _refXmlDataDialog->get_widget("dialog1", _dataDialog); Gtk::Button* button = 0; - _refXmlDataDialog->get_widget("cancelbutton1", button); + _refXmlDataDialog->get_widget("closebutton1", button); button->signal_clicked() .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel), false); - // XXX - _refXmlDataDialog->get_widget("okbutton1", button); - button->signal_clicked() - .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel), - false); - _refXmlDataDialog->get_widget("button1", button); - button->signal_clicked() - .connect(sigc::mem_fun(*this, &GraphWidget::onDataAdd), false); - _refXmlDataDialog->get_widget("button2", button); - button->signal_clicked() - .connect(sigc::mem_fun(*this, &GraphWidget::onDataRemove), false); _refXmlDataDialog->get_widget("treeview1", _dataTreeView); - _dataDialog->signal_map() + _dataDialog->signal_show() .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogOpen)); + _dataDialog->signal_hide() + .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogClose)); _listStore = Gtk::ListStore::create(_dataColumns); _dataTreeView->set_model(_listStore); + _dataTreeView->append_column_editable("Enabled", + _dataColumns._dataEnabled); _dataTreeView->append_column("Data", _dataColumns._dataName); _dataTreeView->append_column("Title", _dataColumns._dataTitle); _refXmlDataDialog->get_widget("checkbutton1", _relativeTimesButton); @@ -275,23 +268,6 @@ namespace systemtap _dataDialog->hide(); } - void GraphWidget::onDataAdd() - { - Glib::RefPtr treeSelection = - _dataTreeView->get_selection(); - Gtk::TreeModel::iterator iter = treeSelection->get_selected(); - if (iter) - { - Gtk::TreeModel::Row row = *iter; - shared_ptr data = row[_dataColumns._graphData]; - _activeGraph->addGraphData(data); - } - } - - void GraphWidget::onDataRemove() - { - } - void GraphWidget::onDataDialogOpen() { _listStore->clear(); @@ -306,7 +282,20 @@ namespace systemtap if (!(*itr)->title.empty()) row[_dataColumns._dataTitle] = (*itr)->title; row[_dataColumns._graphData] = *itr; + Graph::DatasetList& gsets = _activeGraph->getDatasets(); + Graph::DatasetList::iterator setItr + = find(gsets.begin(), gsets.end(), *itr); + row[_dataColumns._dataEnabled] = (setItr != gsets.end()); } + _listConnection =_listStore->signal_row_changed() + .connect(sigc::mem_fun(*this, &GraphWidget::onRowChanged)); + + } + + void GraphWidget::onDataDialogClose() + { + if (_listConnection.connected()) + _listConnection.disconnect(); } bool GraphWidget::onHoverTimeout() @@ -364,4 +353,23 @@ namespace systemtap _displayRelativeTimes = _relativeTimesButton->get_active(); queue_draw(); } + + void GraphWidget::onRowChanged(const Gtk::TreeModel::Path&, + const Gtk::TreeModel::iterator& litr) + { + Gtk::TreeModel::Row row = *litr; + bool val = row[_dataColumns._dataEnabled]; + shared_ptr data = row[_dataColumns._graphData]; + Graph::DatasetList& graphData = _activeGraph->getDatasets(); + if (val + && find(graphData.begin(), graphData.end(), data) == graphData.end()) + { + _activeGraph->addGraphData(data); + } + else if (!val) + { + graphData.erase(remove(graphData.begin(), graphData.end(), data), + graphData.end()); + } + } } diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index ea10720c..146a08c3 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -18,10 +18,12 @@ namespace systemtap public: DataModelColumns() { + add(_dataEnabled); add(_dataName); add(_dataTitle); add(_graphData); } + Gtk::TreeModelColumn _dataEnabled; Gtk::TreeModelColumn _dataName; Gtk::TreeModelColumn _dataTitle; Gtk::TreeModelColumn > _graphData; @@ -64,9 +66,8 @@ namespace systemtap Gtk::Dialog* _dataDialog; Gtk::TreeView* _dataTreeView; void onDataDialogCancel(); - void onDataAdd(); - void onDataRemove(); void onDataDialogOpen(); + void onDataDialogClose(); bool onHoverTimeout(); DataModelColumns _dataColumns; Glib::RefPtr _listStore; @@ -81,6 +82,9 @@ namespace systemtap Gtk::CheckButton* _relativeTimesButton; bool _displayRelativeTimes; void onRelativeTimesButtonClicked(); + void onRowChanged(const Gtk::TreeModel::Path&, + const Gtk::TreeModel::iterator&); + sigc::connection _listConnection; }; } #endif // SYSTEMTAP_GRAPHWIDGET_H diff --git a/grapher/graph-dialog.glade b/grapher/graph-dialog.glade index 85c10128..8076d2b0 100644 --- a/grapher/graph-dialog.glade +++ b/grapher/graph-dialog.glade @@ -31,29 +31,15 @@ GTK_BUTTONBOX_END - + True True True - gtk-cancel + gtk-close True GTK_RELIEF_NORMAL True - -6 - - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 + -7 @@ -128,57 +114,6 @@ True - - - - True - False - 0 - - - - True - True - gtk-add - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - True - True - gtk-remove - True - GTK_RELIEF_NORMAL - True - - - - 0 - False - False - - - - - - - - - 0 - False - False - - 0 -- cgit From 9175e50559751538f4da02e6e17c61a8f5191a31 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 7 Dec 2009 18:51:55 +0100 Subject: make the list items in the data set list unselectable The checkbox selects the list, so it is just sloppy to allow the item to be selected. * grapher/GraphWidget.hxx (no_select_fun): New function; just returns false. * grapher/GraphWidget.cxx (GraphWidget): Connect list store selection to function that prevents selection. --- grapher/GraphWidget.cxx | 8 +++++++- grapher/GraphWidget.hxx | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index db325d83..c8d8cc45 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -66,7 +66,13 @@ namespace systemtap _dataTreeView->append_column_editable("Enabled", _dataColumns._dataEnabled); _dataTreeView->append_column("Data", _dataColumns._dataName); - _dataTreeView->append_column("Title", _dataColumns._dataTitle); + _dataTreeView->append_column("Title", _dataColumns._dataTitle); + // Disable selection in list + Glib::RefPtr listSelection + = _dataTreeView->get_selection(); + listSelection + ->set_select_function(sigc::mem_fun(*this, + &GraphWidget::no_select_fun)); _refXmlDataDialog->get_widget("checkbutton1", _relativeTimesButton); _relativeTimesButton->signal_clicked() .connect(sigc::mem_fun(*this, diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index 146a08c3..a2260aef 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -85,6 +85,12 @@ namespace systemtap void onRowChanged(const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&); sigc::connection _listConnection; + bool no_select_fun(const Glib::RefPtr& model, + const Gtk::TreeModel::Path& path, + bool) + { + return false; + } }; } #endif // SYSTEMTAP_GRAPHWIDGET_H -- cgit From f669d095ba7fe5a623b31abc05b4f6664059803b Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Mon, 7 Dec 2009 19:19:45 +0100 Subject: add copyright and license to grapher files --- grapher/CairoWidget.cxx | 8 ++++++++ grapher/CairoWidget.hxx | 8 ++++++++ grapher/Graph.cxx | 8 ++++++++ grapher/Graph.hxx | 8 ++++++++ grapher/GraphData.hxx | 8 ++++++++ grapher/GraphStyle.cxx | 8 ++++++++ grapher/GraphStyle.hxx | 8 ++++++++ grapher/GraphWidget.cxx | 8 ++++++++ grapher/GraphWidget.hxx | 8 ++++++++ grapher/StapParser.cxx | 8 ++++++++ grapher/StapParser.hxx | 8 ++++++++ grapher/grapher.cxx | 8 ++++++++ 12 files changed, 96 insertions(+) diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx index eefe3d28..26c2d029 100644 --- a/grapher/CairoWidget.cxx +++ b/grapher/CairoWidget.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "CairoWidget.hxx" #include diff --git a/grapher/CairoWidget.hxx b/grapher/CairoWidget.hxx index 8cfb816a..bcabafb2 100644 --- a/grapher/CairoWidget.hxx +++ b/grapher/CairoWidget.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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 SYSTEMTAP_CAIROWIDGET_H #define SYSTEMTAP_CAIROWIDGET_H 1 diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx index baa1182f..2d203ead 100644 --- a/grapher/Graph.cxx +++ b/grapher/Graph.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "Graph.hxx" #include diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx index 93e23deb..4dcb5169 100644 --- a/grapher/Graph.hxx +++ b/grapher/Graph.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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 SYSTEMTAP_GRAPH_HXX #define SYSTEMTAP_GRAPH_HXX 1 diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx index 04f415f3..fbb2bb8f 100644 --- a/grapher/GraphData.hxx +++ b/grapher/GraphData.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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 SYSTEMTAP_GRAPHDATA_HXX #define SYSTEMTAP_GRAPHDATA_HXX 1 diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx index b9429e2a..69ff4089 100644 --- a/grapher/GraphStyle.cxx +++ b/grapher/GraphStyle.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "GraphStyle.hxx" #include "GraphData.hxx" diff --git a/grapher/GraphStyle.hxx b/grapher/GraphStyle.hxx index ce75d698..bea4922a 100644 --- a/grapher/GraphStyle.hxx +++ b/grapher/GraphStyle.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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 SYSTEMTAP_GRAPHSTYLE_HXX #define SYSTEMTAP_GRAPHSTYLE_HXX 1 #include diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index c8d8cc45..8335fda2 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include #include #include diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index a2260aef..0e9f2a29 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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 SYSTEMTAP_GRAPHWIDGET_H #define SYSTEMTAP_GRAPHWIDGET_H diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 2a246475..edb7f5f2 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "StapParser.hxx" #include diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index 4f1cbd5a..476b0071 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "GraphData.hxx" #include "GraphWidget.hxx" diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 969bc762..1e5e30b8 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -1,3 +1,11 @@ +// systemtap grapher +// 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. + #include "GraphWidget.hxx" #include "StapParser.hxx" -- cgit From 9983df163a0b1743de5777f940b9d6a827142476 Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 7 Dec 2009 15:12:46 -0600 Subject: Small compile server shutdown fix. * testsuite/lib/systemtap.exp (shutdown_server): Only remove the temporary stap script if it exists. --- testsuite/lib/systemtap.exp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/testsuite/lib/systemtap.exp b/testsuite/lib/systemtap.exp index f16facc2..13e6d1a2 100644 --- a/testsuite/lib/systemtap.exp +++ b/testsuite/lib/systemtap.exp @@ -175,7 +175,9 @@ proc shutdown_server {} { } # Remove the temporary stap script - exec /bin/rm -fr $net_path + if [file exists $net_path] { + exec /bin/rm -fr $net_path + } } proc get_system_info {} { -- cgit From b2ea60606801aa9bf243f22318ac4bd8a25094fe Mon Sep 17 00:00:00 2001 From: David Smith Date: Mon, 7 Dec 2009 15:17:58 -0600 Subject: PR 10641 fixed by checking module name in unprivileged mode. * main.cxx (checkOptions): If in unprivileged mode, make sure module name starts with 'stap_'. * testsuite/parseko/cmdline05.stp: New testcase. * testsuite/parseok/cmdline03.stp: New testcase. --- main.cxx | 5 +++++ testsuite/parseko/cmdline05.stp | 6 ++++++ testsuite/parseok/cmdline03.stp | 6 ++++++ 3 files changed, 17 insertions(+) create mode 100755 testsuite/parseko/cmdline05.stp create mode 100755 testsuite/parseok/cmdline03.stp diff --git a/main.cxx b/main.cxx index 71c70df8..69d7fa77 100644 --- a/main.cxx +++ b/main.cxx @@ -429,6 +429,11 @@ checkOptions (systemtap_session &s) cerr << "You can't specify -g and --unprivileged together." << endl; optionsConflict = true; } + if (s.module_name.compare(0, 5, "stap_") != 0) + { + cerr << "In unprivileged mode, the module name must start with 'stap_'." << endl; + optionsConflict = true; + } } if (!s.kernel_symtab_path.empty()) diff --git a/testsuite/parseko/cmdline05.stp b/testsuite/parseko/cmdline05.stp new file mode 100755 index 00000000..f8c437ea --- /dev/null +++ b/testsuite/parseko/cmdline05.stp @@ -0,0 +1,6 @@ +#! /bin/sh + +# Make sure unprivileged ('--unprivileged') option isn't accepted when +# a module name not starting with 'stap_' is used. + +stap --unprivileged -m 'nfs' -p1 -e 'probe begin { exit() }' diff --git a/testsuite/parseok/cmdline03.stp b/testsuite/parseok/cmdline03.stp new file mode 100755 index 00000000..d0ba5bbf --- /dev/null +++ b/testsuite/parseok/cmdline03.stp @@ -0,0 +1,6 @@ +#! /bin/sh + +# Make sure unprivileged ('--unprivileged') option is accepted when a +# module name starting with 'stap_' is used. + +stap --unprivileged -m 'stap_foo' -p1 -e 'probe begin { exit() }' -- cgit From 72a9e5a2d3788f5465eb5e1610f2402744054f2e Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 8 Dec 2009 11:06:04 +0100 Subject: tiny refactoring of signal and pipe code --- grapher/grapher.cxx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 1e5e30b8..567b0405 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -227,19 +227,14 @@ int StapLauncher::launch() &ChildDeathReader::ioCallback), signalPipe[0], Glib::IO_IN); } + struct sigaction action; + action.sa_sigaction = handleChild; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP; + sigaction(SIGCLD, &action, 0); } - struct sigaction action; - action.sa_sigaction = handleChild; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_SIGINFO | SA_NOCLDSTOP; - sigaction(SIGCLD, &action, 0); int pipefd[4]; - if (pipe(&pipefd[0]) < 0) - { - std::perror("pipe"); - exit(1); - } - if (pipe(&pipefd[2]) < 0) + if (pipe(&pipefd[0]) < 0 || pipe(&pipefd[2]) < 0) { std::perror("pipe"); exit(1); -- cgit From 2d971c6b8835c7e38ce78dd554827f5f96bc7c04 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 8 Dec 2009 03:23:20 +0100 Subject: Add dtrace -I support. dtrace -I is used to pass through include paths to cpp when run. Thanks to David Malcolm for python coding and testing. * dtrace.in: Add -I support. * testsuite/systemtap.base/dtrace.exp: Add testcases for -C -I and -G -I. --- dtrace.in | 15 +++++--- testsuite/systemtap.base/dtrace.exp | 72 ++++++++++++++++++++++++++++++------- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/dtrace.in b/dtrace.in index 74d70e77..10bd19e3 100755 --- a/dtrace.in +++ b/dtrace.in @@ -120,13 +120,15 @@ class provider: def usage (): - print "Usage " + sys.argv[0] + " [--help] [-h | -G] -s File.d [-o File]" + print "Usage " + sys.argv[0] + " [--help] [-h | -G] [-C [-I]] -s File.d [-o ]" def help (): usage() print "Where -h builds a systemtap header file from the .d file" + print " -C when used with -h, also run cpp preprocessor" print " -o specifies an explicit output file name," - print " The default for -G is file.o and -h is file.h" + print " the default for -G is file.o and -h is file.h" + print " -I when running cpp pass through this -I include Path" print " -s specifies the name of the .d input file" print " -G builds a stub file.o from file.d," print " which is required by some packages that use dtrace." @@ -159,6 +161,8 @@ keep_temps = False use_cpp = False h_ext = '.h' filename = "" +s_filename = "" +includes = [] while (i < len (sys.argv)): if (sys.argv[i] == "-o"): i += 1 @@ -170,6 +174,8 @@ while (i < len (sys.argv)): use_cpp = True elif (sys.argv[i] == "-h"): build_header = True + elif (sys.argv[i].startswith("-I")): + includes.append(sys.argv[i]) elif (sys.argv[i] == "-G"): build_source = True elif (sys.argv[i] == "-k"): @@ -185,9 +191,10 @@ if (build_header == False and build_source == False): if (s_filename != "" and use_cpp): (d,fn) = mkstemp(suffix=".d") - retcode = call(["cpp", s_filename, fn]) + args = ['cpp'] + includes + [s_filename, fn] + retcode = call(args) if (retcode != 0): - print "\"cpp s_filename\" failed" + print "\"cpp includes s_filename\" failed" usage() sys.exit(1) s_filename = fn diff --git a/testsuite/systemtap.base/dtrace.exp b/testsuite/systemtap.base/dtrace.exp index f4cac5aa..f68af4f5 100644 --- a/testsuite/systemtap.base/dtrace.exp +++ b/testsuite/systemtap.base/dtrace.exp @@ -8,7 +8,7 @@ if {[installtest_p]} { set dtrace ../dtrace } -exec mkdir /tmp/dtrace +exec mkdir -p /tmp/dtrace set dpath "/tmp/dtrace/test.d" set fp [open $dpath "w"] @@ -23,11 +23,34 @@ provider tstsyscall " close $fp +exec mkdir -p /tmp/dtrace_inc +set ipath "/tmp/dtrace_inc/dtest.h" +set $fp [open $ipath "w"] +puts $fp " +#define INT16 short +#define INT32 int +" +close $fp + +set idpath "/tmp/dtrace/itest.d" +set $fp [open $idpath "w"] +puts $fp " +#include + +provider tstsyscall +{ + probe test(INT16 arg1, INT32 arg2, INT32 arg3, INT32 arg4, struct astruct arg5) +} +" +close $fp + +set incpath "/tmp/dtrace_inc" + # ----------------------------------------------------------------- # test command line option and file handling verbose -log "$dtrace -G -s $dpath -o XXX.o" -exec $dtrace -G -s $dpath -o XXX.o +catch {exec $dtrace -G -s $dpath -o XXX.o} if {[file exists XXX.o]} then { pass "dtrace -G -o XXX.o" } else { @@ -36,7 +59,7 @@ if {[file exists XXX.o]} then { exec rm -f XXX.o verbose -log "$dtrace -G -s $dpath -o XXX" -exec $dtrace -G -s $dpath -o XXX +catch {exec $dtrace -G -s $dpath -o XXX} if {[file exists XXX.o]} then { pass "dtrace -G -o XXX" } else { @@ -45,7 +68,7 @@ if {[file exists XXX.o]} then { exec rm -f XXX.o verbose -log "$dtrace -h -s $dpath -o XXX.h" -exec $dtrace -h -s $dpath -o XXX.h +catch {exec $dtrace -h -s $dpath -o XXX.h} if {[file exists XXX.h]} then { pass "dtrace -h -o XXX.h" } else { @@ -54,7 +77,7 @@ if {[file exists XXX.h]} then { exec rm -f XXX.h verbose -log "$dtrace -h -s $dpath -o XXX" -exec $dtrace -h -s $dpath -o XXX +catch {exec $dtrace -h -s $dpath -o XXX} if {[file exists XXX]} then { pass "dtrace -h -o XXX" } else { @@ -63,7 +86,7 @@ if {[file exists XXX]} then { exec rm -f XXX verbose -log "$dtrace -G -s $dpath -o /tmp/XXX.o" -exec $dtrace -G -s $dpath -o /tmp/XXX.o +catch {exec $dtrace -G -s $dpath -o /tmp/XXX.o} if {[file exists /tmp/XXX.o]} then { pass "dtrace -G -o /tmp/XXX.o" } else { @@ -72,7 +95,7 @@ if {[file exists /tmp/XXX.o]} then { exec rm -f /tmp/XXX.o verbose -log "$dtrace -G -s $dpath -o /tmp/XXX" -exec $dtrace -G -s $dpath -o /tmp/XXX +catch {exec $dtrace -G -s $dpath -o /tmp/XXX} if {[file exists /tmp/XXX.o]} then { pass "dtrace -G -o /tmp/XXX.o" } else { @@ -81,7 +104,7 @@ if {[file exists /tmp/XXX.o]} then { exec rm -f /tmp/XXX.o verbose -log "$dtrace -h -s $dpath -o /tmp/XXX.h" -exec $dtrace -h -s $dpath -o /tmp/XXX.h +catch {exec $dtrace -h -s $dpath -o /tmp/XXX.h} if {[file exists /tmp/XXX.h]} then { pass "dtrace -h -o /tmp/XXX.h" } else { @@ -90,7 +113,7 @@ if {[file exists /tmp/XXX.h]} then { exec rm -f /tmp/XXX.h verbose -log "$dtrace -h -s $dpath -o /tmp/XXX" -exec $dtrace -h -s $dpath -o /tmp/XXX +catch {exec $dtrace -h -s $dpath -o /tmp/XXX} if {[file exists /tmp/XXX]} then { pass "dtrace -h -o /tmp/XXX" } else { @@ -99,7 +122,7 @@ if {[file exists /tmp/XXX]} then { exec rm -f /tmp/XXX verbose -log "$dtrace -G -s $dpath" -exec $dtrace -G -s $dpath +catch {exec $dtrace -G -s $dpath} if {[file exists test.o]} then { pass "dtrace -G" } else { @@ -108,7 +131,7 @@ if {[file exists test.o]} then { exec rm -f test.o verbose -log "$dtrace -h -s $dpath" -exec $dtrace -h -s $dpath +catch {exec $dtrace -h -s $dpath} if {[file exists test.h]} then { pass "dtrace -h" } else { @@ -118,7 +141,7 @@ exec rm -f test.o set ok 0 verbose -log "$dtrace -C -h -s $dpath -o XXX.h" -exec $dtrace -C -h -s $dpath -o XXX.h +catch {exec $dtrace -C -h -s $dpath -o XXX.h} spawn cat XXX.h expect { "short arg1, int arg2, int arg3, int arg4" {incr ok} @@ -130,5 +153,28 @@ if { $ok != 0} { } exec rm -f XXX.h -exec /bin/rm -r /tmp/dtrace +set ok 0 +verbose -log "$dtrace -C -I$incpath -h -s $idpath -o XXX.h" +catch {exec $dtrace -C -I$incpath -h -s $idpath -o XXX.h} +spawn cat XXX.h +expect { + "short arg1, int arg2, int arg3, int arg4" {incr ok} +} +if { $ok != 0} { + pass "dtrace -C -Iincpath -h -o XXX.h" +} else { + fail "dtrace -C -Iincpath -h -o XXX.h" +} +exec rm -f XXX.h + +verbose -log "$dtrace -I$incpath -G -s $idpath" +catch {exec $dtrace -G -s $dpath} +if {[file exists test.o]} then { + pass "dtrace -Iincpath -G" +} else { + fail "dtrace -Iincpath -G" +} +exec rm -f test.o + +exec /bin/rm -r /tmp/dtrace /tmp/dtrace_inc # ----------------------------------------------------------------- -- cgit From 851418deb65964ef73f55e2aab0f3733c0e0e2e8 Mon Sep 17 00:00:00 2001 From: David Smith Date: Tue, 8 Dec 2009 10:40:27 -0600 Subject: Revert "PR 10641 fixed by checking module name in unprivileged mode." This reverts commit b2ea60606801aa9bf243f22318ac4bd8a25094fe. * main.cxx (checkOptions): Remove unprivileged mode module name check. * testsuite/parseko/cmdline05.stp: Delete unneeded testcase. * testsuite/parseok/cmdline03.stp: Ditto. --- main.cxx | 5 ----- testsuite/parseko/cmdline05.stp | 6 ------ testsuite/parseok/cmdline03.stp | 6 ------ 3 files changed, 17 deletions(-) delete mode 100755 testsuite/parseko/cmdline05.stp delete mode 100755 testsuite/parseok/cmdline03.stp diff --git a/main.cxx b/main.cxx index 69d7fa77..71c70df8 100644 --- a/main.cxx +++ b/main.cxx @@ -429,11 +429,6 @@ checkOptions (systemtap_session &s) cerr << "You can't specify -g and --unprivileged together." << endl; optionsConflict = true; } - if (s.module_name.compare(0, 5, "stap_") != 0) - { - cerr << "In unprivileged mode, the module name must start with 'stap_'." << endl; - optionsConflict = true; - } } if (!s.kernel_symtab_path.empty()) diff --git a/testsuite/parseko/cmdline05.stp b/testsuite/parseko/cmdline05.stp deleted file mode 100755 index f8c437ea..00000000 --- a/testsuite/parseko/cmdline05.stp +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/sh - -# Make sure unprivileged ('--unprivileged') option isn't accepted when -# a module name not starting with 'stap_' is used. - -stap --unprivileged -m 'nfs' -p1 -e 'probe begin { exit() }' diff --git a/testsuite/parseok/cmdline03.stp b/testsuite/parseok/cmdline03.stp deleted file mode 100755 index d0ba5bbf..00000000 --- a/testsuite/parseok/cmdline03.stp +++ /dev/null @@ -1,6 +0,0 @@ -#! /bin/sh - -# Make sure unprivileged ('--unprivileged') option is accepted when a -# module name starting with 'stap_' is used. - -stap --unprivileged -m 'stap_foo' -p1 -e 'probe begin { exit() }' -- cgit From 63b4fd1474ec5859fac4c9b710c8f466bcd3b0f7 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Tue, 8 Dec 2009 11:57:00 -0500 Subject: Add .library("lib").mark("mark") and use it for .mark semaphores. tapset-utrace.cxx (TOK_LIBRARY): New. (utrace_derived_probe::utrace_derived_probe): Add library and has_library. (utrace_builder::build): Handle library. (utrace_derived_probe_group::emit_probe_decl): Add sdt_sem_offset to emitted stap_utrace_probes. Add stap_task_finder_target mmap_callback for handling shared library. Handle sdt_sem_offset in emitted_stp_utrace_probe_cb. Add stap_utrace_mmap_found. (register_tapset_utrace): Handle .library tapset-utrace.cxx (TOK_LIBRARY): New. (base_query::base_query): Add path and has_library. (dwarf_derived_probe::dwarf_derived_probe) Likewise. (dwarf_derived_probe::register_patterns): Handle .library (sdt_query::convert_location): Likewise. (dwarf_builder::build): Likewise. (uprobe_derived_probe_group::emit_module_decls): Emit sdt_sem_address. Add sdt_sem_offset to emitted stap_uprobe_spec. Add offset and vm_flags to signature of stap_uprobe_change_plus, and handle sdt_sem_offset. Allow writeable segments in emitted stap_uprobe_mmap_found. sdt_misc.exp: Test .library util.cxx (find_executable): Add env_path to sig and use it in getenv. util.h (find_executable): Likewise. Make "PATH" the default. dtrace.in (provider): Turn on semaphores. sdt.h: Likewise. --- dtrace.in | 4 +- includes/sys/sdt.h | 2 +- tapset-utrace.cxx | 102 ++++++++++++++++--- tapsets.cxx | 179 +++++++++++++++++++++------------- testsuite/systemtap.base/sdt_misc.exp | 101 +++++++++++-------- util.cxx | 4 +- util.h | 3 +- 7 files changed, 271 insertions(+), 124 deletions(-) diff --git a/dtrace.in b/dtrace.in index 10bd19e3..3be05038 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 \n\n") in_comment = False typedefs = "" @@ -107,7 +107,7 @@ class provider: i += 1 self.h.write ('/* %s (%s) */\n' % (this_probe_canon,args_string)) # XXX Enable this when .so semaphores work properly - self.h.write ('#define %s_ENABLED() 1 /*%s_semaphore*/\n' % (this_probe_canon,this_probe)) + self.h.write ('#define %s_ENABLED() %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/includes/sys/sdt.h b/includes/sys/sdt.h index 3847c497..d85d8e2e 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -40,7 +40,7 @@ #define STAP_PROBE_DATA(probe, guard, arg) \ STAP_PROBE_DATA_(#probe,guard,arg) -#if defined STAP_HAS_SEMAPHORES && defined EXPERIMENTAL_UTRACE_SDT +#if defined STAP_HAS_SEMAPHORES && ! defined EXPERIMENTAL_KPROBE_SDT #define STAP_SEMAPHORE(probe) \ if (__builtin_expect ( probe ## _semaphore , 0)) #else diff --git a/tapset-utrace.cxx b/tapset-utrace.cxx index 795d88b7..bd668a2b 100644 --- a/tapset-utrace.cxx +++ b/tapset-utrace.cxx @@ -29,6 +29,7 @@ static const string TOK_END("end"); static const string TOK_THREAD("thread"); static const string TOK_SYSCALL("syscall"); static const string TOK_RETURN("return"); +static const string TOK_LIBRARY("library"); // ------------------------------------------------------------------------ @@ -52,13 +53,15 @@ struct utrace_derived_probe: public derived_probe { bool has_path; string path; + bool has_library; + string library; int64_t pid; enum utrace_derived_probe_flags flags; bool target_symbol_seen; utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, - enum utrace_derived_probe_flags f); + bool hp, string &pn, bool hl, string &ln, + int64_t pd, enum utrace_derived_probe_flags f); void join_group (systemtap_session& s); void emit_unprivileged_assertion (translator_output*); @@ -115,10 +118,10 @@ struct utrace_var_expanding_visitor: public var_expanding_visitor utrace_derived_probe::utrace_derived_probe (systemtap_session &s, probe* p, probe_point* l, - bool hp, string &pn, int64_t pd, - enum utrace_derived_probe_flags f): + bool hp, string &pn, bool hl, string &ln, + int64_t pd, enum utrace_derived_probe_flags f): derived_probe (p, new probe_point (*l) /* .components soon rewritten */ ), - has_path(hp), path(pn), pid(pd), flags(f), + has_path(hp), path(pn), has_library(hl), library(ln), pid(pd), flags(f), target_symbol_seen(false) { if (s.kernel_config["CONFIG_UTRACE"] != string("y")) @@ -599,9 +602,11 @@ struct utrace_builder: public derived_probe_builder vector & finished_results) { string path; + string lib; int64_t pid; bool has_path = get_param (parameters, TOK_PROCESS, path); + bool has_lib = get_param (parameters, TOK_LIBRARY, lib); bool has_pid = get_param (parameters, TOK_PROCESS, pid); enum utrace_derived_probe_flags flags = UDPF_NONE; @@ -647,9 +652,11 @@ struct utrace_builder: public derived_probe_builder // XXX: could we use /proc/$pid/exe in unwindsym_modules and elsewhere? } + if (has_lib) + lib = find_executable (lib, "LD_LIBRARY_PATH"); finished_results.push_back(new utrace_derived_probe(sess, base, location, - has_path, path, pid, + has_path, path, has_lib, lib, pid, flags)); } @@ -750,11 +757,25 @@ utrace_derived_probe_group::emit_probe_decl (systemtap_session& s, s.op->line() << " .engine_attached=0,"; if (p->sdt_semaphore_addr != 0) - s.op->line() << " .sdt_sem_address=(unsigned long)0x" + s.op->line() << " .sdt_sem_offset=(unsigned long)0x" << hex << p->sdt_semaphore_addr << dec << "ULL,"; - + s.op->line() << " .sdt_sem_address=0,"; s.op->line() << " .tsk=0,"; s.op->line() << " },"; + + if (p->has_library && p->sdt_semaphore_addr != 0) + { + s.op->newline() << "{"; + s.op->line() << " .tgt={"; + s.op->line() << " .procname=\"" << p->path << "\","; + s.op->line() << " .mmap_callback=&stap_utrace_mmap_found,"; + s.op->line() << " },"; + s.op->line() << " .pathname=\"" << p->library << "\","; + s.op->line() << " .sdt_sem_offset=(unsigned long)0x" + << hex << p->sdt_semaphore_addr << dec << "ULL,"; + s.op->line() << " .sdt_sem_address=0,"; + s.op->line() << " },"; + } } @@ -789,7 +810,11 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "struct utrace_engine_ops ops;"; s.op->newline() << "unsigned long events;"; s.op->newline() << "struct task_struct *tsk;"; + s.op->newline() << "unsigned long sdt_sem_offset;"; + // FIXME: if this probe is attached to more than 1 task, having 1 + // address here won't work s.op->newline() << "unsigned long sdt_sem_address;"; + s.op->newline(0) << "const char *pathname;"; s.op->newline(-1) << "};"; @@ -913,15 +938,23 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->indent(-1); s.op->newline(-1) << "}"; + s.op->newline() << "if (p->sdt_sem_offset && p->sdt_sem_address == 0) {"; + s.op->indent(1); + // If the probe is in the executable itself, the offset *is* the address. + s.op->newline() << "p->sdt_sem_address = p->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + + // Before writing to the semaphore, we need to check for VM_WRITE access. s.op->newline() << "if (p->sdt_sem_address != 0) {"; s.op->newline(1) << "size_t sdt_semaphore;"; // XXX p could get registered to more than one task! s.op->newline() << "p->tsk = tsk;"; - s.op->newline() << "__access_process_vm (tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore += 1;"; + + s.op->newline() << "if (__access_process_vm (tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0) == sizeof (sdt_semaphore)) {"; + s.op->newline(1) << "sdt_semaphore ++;"; s.op->newline() << "__access_process_vm (tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; s.op->newline(-1) << "}"; - + s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; // Since this engine could be attached to multiple threads, don't @@ -985,6 +1018,44 @@ utrace_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "return rc;"; s.op->newline(-1) << "}"; + // The task_finder_mmap_callback + s.op->newline() << "static int stap_utrace_mmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) {"; + s.op->newline(1) << "struct stap_utrace_probe *p = container_of(tgt, struct stap_utrace_probe, tgt);"; + s.op->newline() << "int rc = 0;"; + // the shared library we're interested in + s.op->newline() << "if (path == NULL || strcmp (path, p->pathname)) return 0;"; + s.op->newline() << "if (p->sdt_sem_address == 0) {"; + s.op->indent(1); + // If the probe is in the executable itself, the offset *is* the + // address. + s.op->newline() << "if (vm_flags & VM_EXECUTABLE) {"; + s.op->indent(1); + s.op->newline() << "p->sdt_sem_address = addr + p->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + // If the probe is in a .so, we have to calculate the address. + s.op->newline() << "else {"; + s.op->indent(1); + s.op->newline() << "p->sdt_sem_address = (addr - offset) + p->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + + s.op->newline() << "if (p->sdt_sem_address) {"; + s.op->newline(1) << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if (__access_process_vm (tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0) == sizeof (sdt_semaphore)) {"; + + s.op->newline(1) << "if (vm_flags & VM_WRITE) {"; + s.op->indent(1); + s.op->newline() << "sdt_semaphore ++;"; + s.op->newline() << "#ifdef DEBUG_UTRACE"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+semaphore %#x @ %#lx\\n\", sdt_semaphore, p->sdt_sem_address);"; + s.op->newline() << "#endif"; + s.op->newline() << "__access_process_vm (tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; + s.op->newline() << "return 0;"; + s.op->newline(-1) << "}"; + s.op->newline() << "static struct stap_utrace_probe stap_utrace_probes[] = {"; s.op->indent(1); @@ -1055,14 +1126,15 @@ utrace_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "if (p->engine_attached) {"; s.op->newline(1) << "stap_utrace_detach_ops(&p->ops);"; + // Before writing to the semaphore, we need to check for VM_WRITE access. s.op->newline() << "if (p->sdt_sem_address) {"; s.op->newline(1) << "size_t sdt_semaphore;"; // XXX p could get registered to more than one task! - s.op->newline() << "__access_process_vm (p->tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore -= 1;"; + s.op->newline() << "if (__access_process_vm (p->tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0) == sizeof (sdt_semaphore)) {"; + s.op->newline(1) << "sdt_semaphore --;"; s.op->newline() << "__access_process_vm (p->tsk, p->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; s.op->newline(-1) << "}"; - + s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; @@ -1094,6 +1166,8 @@ register_tapset_utrace(systemtap_session& s) ->bind(builder); roots[i]->bind(TOK_SYSCALL)->bind(TOK_RETURN) ->bind(builder); + roots[i]->bind_str(TOK_LIBRARY)->bind(TOK_SYSCALL) + ->bind(builder); } } diff --git a/tapsets.cxx b/tapsets.cxx index 51f1ccc9..bad72091 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -260,6 +260,7 @@ static const string TOK_PROCESS("process"); static const string TOK_MARK("mark"); static const string TOK_TRACE("trace"); static const string TOK_LABEL("label"); +static const string TOK_LIBRARY("library"); static int query_cu (Dwarf_Die * cudie, void * arg); static void query_addr(Dwarf_Addr addr, dwarf_query *q); @@ -349,8 +350,10 @@ struct dwarf_derived_probe: public derived_probe string module; string section; Dwarf_Addr addr; + string path; bool has_return; bool has_maxactive; + bool has_library; long maxactive_val; bool access_vars; @@ -460,7 +463,9 @@ struct base_query bool has_kernel; bool has_module; bool has_process; + bool has_library; string module_val; // has_kernel => module_val = "kernel" + string path; // executable path if module is a .so virtual void handle_query_module() = 0; }; @@ -478,8 +483,15 @@ base_query::base_query(dwflpp & dw, literal_map_t const & params): has_process = false; else { + string library_name; has_process = get_string_param(params, TOK_PROCESS, module_val); - if (has_process) + has_library = get_string_param (params, TOK_LIBRARY, library_name); + if (has_library) + { + path = find_executable (module_val); + module_val = find_executable (library_name, "LD_LIBRARY_PATH"); + } + else if (has_process) module_val = find_executable (module_val); } @@ -2840,11 +2852,13 @@ dwarf_derived_probe::dwarf_derived_probe(const string& funcname, Dwarf_Die* scope_die /* may be null */) : derived_probe (q.base_probe, new probe_point(*q.base_loc) /* .components soon rewritten */ ), module (module), section (section), addr (addr), + path (q.path), has_return (q.has_return), has_maxactive (q.has_maxactive), + has_library (q.has_library), maxactive_val (q.maxactive_val), access_vars(false), - saved_longs(0), saved_strings(0), + saved_longs(0), saved_strings(0), entry_handler(0) { if (q.has_process) @@ -3140,6 +3154,8 @@ dwarf_derived_probe::register_patterns(systemtap_session& s) register_function_and_statement_variants(root->bind_str(TOK_PROCESS), dw); root->bind_str(TOK_PROCESS)->bind_str(TOK_FUNCTION)->bind_str(TOK_LABEL) ->bind(dw); + root->bind_str(TOK_PROCESS)->bind_str(TOK_LIBRARY)->bind_str(TOK_MARK) + ->bind(dw); root->bind_str(TOK_PROCESS)->bind_str(TOK_MARK) ->bind(dw); root->bind_str(TOK_PROCESS)->bind_num(TOK_MARK) @@ -3983,46 +3999,52 @@ sdt_query::convert_probe (probe *base) void sdt_query::convert_location (probe *base, probe_point *location) { - switch (probe_type) - { - case uprobe_type: - if (sess.verbose > 3) - clog << "probe_type == uprobe_type, use statement addr: 0x" - << hex << probe_arg << dec << endl; - // process("executable").statement(probe_arg) - location->components[1]->functor = TOK_STATEMENT; - location->components[1]->arg = new literal_number(probe_arg); - break; + for (unsigned i = 0; i < location->components.size(); ++i) + if (location->components[i]->functor == TOK_MARK) + switch (probe_type) + { + case uprobe_type: + if (sess.verbose > 3) + clog << "probe_type == uprobe_type, use statement addr: 0x" + << hex << probe_arg << dec << endl; + // process("executable").statement(probe_arg) + location->components[i]->functor = TOK_STATEMENT; + location->components[i]->arg = new literal_number(probe_arg); + break; - case kprobe_type: - if (sess.verbose > 3) - clog << "probe_type == kprobe_type" << endl; - // kernel.function("*getegid*") - location->components[0]->functor = TOK_KERNEL; - location->components[0]->arg = NULL; - location->components[1]->functor = TOK_FUNCTION; - location->components[1]->arg = new literal_string("*getegid*"); - break; + case kprobe_type: + if (sess.verbose > 3) + clog << "probe_type == kprobe_type" << endl; + // kernel.function("*getegid*") + location->components[i]->functor = TOK_FUNCTION; + location->components[i]->arg = new literal_string("*getegid*"); + break; - case utrace_type: - if (sess.verbose > 3) - clog << "probe_type == utrace_type" << endl; - // process("executable").syscall - location->components[1]->functor = "syscall"; - location->components[1]->arg = NULL; - break; + case utrace_type: + if (sess.verbose > 3) + clog << "probe_type == utrace_type" << endl; + // process("executable").syscall + location->components[i]->functor = "syscall"; + location->components[i]->arg = NULL; + break; - default: - if (sess.verbose > 3) - clog << "probe_type == use_uprobe_no_dwarf, use label name: " - << "_stapprobe1_" << mark_name << endl; - // process("executable").function("*").label("_stapprobe1_MARK_NAME") - location->components[1]->functor = TOK_FUNCTION; - location->components[1]->arg = new literal_string("*"); - location->components.push_back(new probe_point::component(TOK_LABEL)); - location->components[2]->arg = new literal_string("_stapprobe1_" + mark_name); - break; - } + default: + if (sess.verbose > 3) + clog << "probe_type == use_uprobe_no_dwarf, use label name: " + << "_stapprobe1_" << mark_name << endl; + // process("executable").function("*").label("_stapprobe1_MARK_NAME") + location->components[1]->functor = TOK_FUNCTION; + location->components[1]->arg = new literal_string("*"); + location->components.push_back(new probe_point::component(TOK_LABEL)); + location->components[2]->arg = new literal_string("_stapprobe1_" + mark_name); + break; + } + else if (location->components[i]->functor == TOK_PROCESS + && probe_type == kprobe_type) + { + location->components[i]->functor = TOK_KERNEL; + location->components[i]->arg = NULL; + } base->locations.clear(); base->locations.push_back(location); @@ -4053,7 +4075,11 @@ dwarf_builder::build(systemtap_session & sess, } else if (get_param (parameters, TOK_PROCESS, module_name)) { - module_name = find_executable (module_name); // canonicalize it + string library_name; + if (get_param (parameters, TOK_LIBRARY, library_name)) + module_name = find_executable (library_name, "LD_LIBRARY_PATH"); + else + module_name = find_executable (module_name); // canonicalize it if (sess.kernel_config["CONFIG_UTRACE"] != string("y")) throw semantic_error ("process probes not available without kernel CONFIG_UTRACE"); @@ -4557,7 +4583,6 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // too big to embed in the initialized .data stap_uprobe_spec array. s.op->newline() << "static struct stap_uprobe {"; s.op->newline(1) << "union { struct uprobe up; struct uretprobe urp; };"; - s.op->newline() << "unsigned long sdt_sem_address;"; // relocated to this process s.op->newline() << "int spec_index;"; // index into stap_uprobe_specs; <0 == free && unregistered s.op->newline(-1) << "} stap_uprobes [MAXUPROBES];"; // XXX: consider a slab cache or somesuch s.op->newline() << "DEFINE_MUTEX(stap_uprobes_lock);"; // protects against concurrent registration/unregistration @@ -4600,6 +4625,8 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) } if (p->section != ".absolute") // ET_DYN { + if (p->has_library && p->sdt_semaphore_addr != 0) + s.op->line() << " .procname=\"" << p->path << "\", "; s.op->line() << " .mmap_callback=&stap_uprobe_mmap_found, "; s.op->line() << " .munmap_callback=&stap_uprobe_munmap_found, "; } @@ -4615,13 +4642,17 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->assert_0_indent(); + s.op->newline() << "unsigned long sdt_sem_address [] = {"; + for (unsigned i =0; iline() << "0,"; + s.op->line() << "0};"; 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 long sdt_sem_offset;"; s.op->newline(-1) << "} stap_uprobe_specs [] = {"; // NB: read-only structure s.op->indent(1); for (unsigned i =0; iline() << " .ph=&" << p->name << ","; if (p->sdt_semaphore_addr != 0) - s.op->line() << " .sdt_sem_address=(unsigned long)0x" + s.op->line() << " .sdt_sem_offset=(unsigned long)0x" << hex << p->sdt_semaphore_addr << dec << "ULL,"; if (p->has_return) @@ -4706,7 +4737,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // unregistration. s.op->newline(); - s.op->newline() << "static int stap_uprobe_change_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf) {"; + s.op->newline() << "static int stap_uprobe_change_plus (struct task_struct *tsk, unsigned long relocation, unsigned long length, const struct stap_uprobe_tf *stf, unsigned long offset, unsigned long vm_flags) {"; s.op->newline(1) << "int tfi = (stf - stap_uprobe_finders);"; s.op->newline() << "int spec_index;"; @@ -4757,6 +4788,20 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // was full (registration; MAXUPROBES) or that no matching entry was // found (unregistration; should not happen). + s.op->newline() << "if (sups->sdt_sem_offset && sdt_sem_address[spec_index] == 0) {"; + s.op->indent(1); + // If the probe is in the executable itself, the offset *is* the address. + s.op->newline() << "if (vm_flags & VM_EXECUTABLE) {"; + s.op->indent(1); + s.op->newline() << "sdt_sem_address[spec_index] = relocation + sups->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + // If the probe is in a .so, we have to calculate the address. + s.op->newline() << "else {"; + s.op->indent(1); + s.op->newline() << "sdt_sem_address[spec_index] = (relocation - offset) + sups->sdt_sem_offset;"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; // sdt_sem_offset + s.op->newline() << "if (slotted_p) {"; s.op->newline(1) << "struct stap_uprobe *sup = & stap_uprobes[i];"; s.op->newline() << "if (sups->return_p) {"; @@ -4770,23 +4815,23 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "sup->up.handler = &enter_uprobe_probe;"; s.op->newline() << "rc = register_uprobe (& sup->up);"; - // PR10655: also handle ENABLED semaphore manipulations here - s.op->newline() << "if (!rc && sups->sdt_sem_address) {"; - s.op->newline(1) << "unsigned short sdt_semaphore;"; // NB: fixed size - s.op->newline() << "sup->sdt_sem_address = relocation + sups->sdt_sem_address;"; - s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore ++;"; - s.op->newline() << "#ifdef DEBUG_UPROBES"; - s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+semaphore %#x @ %#lx\\n\", sdt_semaphore, sup->sdt_sem_address);"; - s.op->newline() << "#endif"; - - s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline() << "if (sdt_sem_address[spec_index]) {"; + s.op->newline(1) << "unsigned short sdt_semaphore = 0;"; // NB: fixed size + s.op->newline() << "if ( __access_process_vm (tsk, sdt_sem_address[spec_index], &sdt_semaphore, sizeof (sdt_semaphore), 0)) {"; + // We have an executable or a writeable segment of a .so + s.op->newline(1) << "if (vm_flags == 0 || vm_flags & VM_WRITE) {"; + s.op->newline(1) << "sdt_semaphore ++;"; + s.op->newline() << "__access_process_vm (tsk, sdt_sem_address[spec_index], &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; + s.op->newline(-1) << "}"; // sdt_sem_address // XXX: error handling in __access_process_vm! // XXX: need to analyze possibility of race condition + s.op->newline(-1) << "}"; s.op->newline(-1) << "}"; - s.op->newline() << "if (rc) {"; // failed to register + + s.op->newline() << "if (rc && !(vm_flags & VM_WRITE)) {"; // failed to register s.op->newline(1) << "_stp_warn (\"u*probe failed %s[%d] '%s' addr %p rc %d\\n\", tsk->comm, tsk->tgid, sups->pp, (void*)(relocation + sups->address), rc);"; // NB: we need to release this slot, so we need to borrow the mutex temporarily. s.op->newline() << "mutex_lock (& stap_uprobes_lock);"; @@ -4919,7 +4964,7 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) // ET_EXEC events are modeled as if shlib events, but with 0 relocation bases s.op->newline() << "if (register_p)"; - s.op->newline(1) << "return stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf);"; + s.op->newline(1) << "return stap_uprobe_change_plus (tsk, 0, TASK_SIZE, stf, 0, 0);"; s.op->newline(-1) << "else"; s.op->newline(1) << "return stap_uprobe_change_minus (tsk, 0, TASK_SIZE, stf);"; s.op->indent(-1); @@ -4932,18 +4977,19 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s) s.op->newline() << "static int stap_uprobe_mmap_found (struct stap_task_finder_target *tgt, struct task_struct *tsk, char *path, unsigned long addr, unsigned long length, unsigned long offset, unsigned long vm_flags) {"; s.op->newline(1) << "const struct stap_uprobe_tf *stf = container_of(tgt, struct stap_uprobe_tf, finder);"; // 1 - shared libraries' executable segments load from offset 0 - ld.so convention - s.op->newline() << "if (offset != 0) return 0;"; + // offset != 0 is now allowed so stap_uprobe_change_plus can set a semaphore, + // i.e. a static extern, in a shared object // 2 - the shared library we're interested in s.op->newline() << "if (path == NULL || strcmp (path, stf->pathname)) return 0;"; - // 3 - mapping should be executable - s.op->newline() << "if (!(vm_flags & VM_EXEC)) return 0;"; + // 3 - mapping should be executable or writeable (for semaphore in .so) + s.op->newline() << "if (!((vm_flags & VM_EXEC) || (vm_flags & VM_WRITE))) return 0;"; s.op->newline() << "#ifdef DEBUG_TASK_FINDER_VMA"; s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"+mmap pid %d path %s addr %p length %u offset %p stf %p %p path %s\\n\", " << "tsk->tgid, path, (void *) addr, (unsigned)length, (void*) offset, tgt, stf, stf->pathname);"; s.op->newline() << "#endif"; - s.op->newline() << "return stap_uprobe_change_plus (tsk, addr, length, stf);"; + s.op->newline() << "return stap_uprobe_change_plus (tsk, addr, length, stf, offset, vm_flags);"; s.op->newline(-1) << "}"; s.op->assert_0_indent(); @@ -5021,7 +5067,7 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "if (sup->spec_index < 0) continue;"; // free slot // PR10655: decrement that ENABLED semaphore - s.op->newline() << "if (sups->sdt_sem_address != 0) {"; + s.op->newline() << "if (sdt_sem_address[sup->spec_index]) {"; s.op->newline(1) << "unsigned short sdt_semaphore;"; // NB: fixed size s.op->newline() << "pid_t pid = (sups->return_p ? sup->urp.u.pid : sup->up.pid);"; s.op->newline() << "struct task_struct *tsk;"; @@ -5041,12 +5087,13 @@ uprobe_derived_probe_group::emit_module_exit (systemtap_session& s) s.op->newline() << "#endif /* 2.6.31 */"; s.op->newline() << "if (tsk) {"; // just in case the thing exited while we weren't watching - s.op->newline(1) << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 0);"; - s.op->newline() << "sdt_semaphore --;"; + s.op->newline(1) << "if (__access_process_vm (tsk, sdt_sem_address[sup->spec_index], &sdt_semaphore, sizeof (sdt_semaphore), 0)) {"; + s.op->newline(1) << "sdt_semaphore --;"; s.op->newline() << "#ifdef DEBUG_UPROBES"; - s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-semaphore %#x @ %#lx\\n\", sdt_semaphore, sup->sdt_sem_address);"; + s.op->newline() << "_stp_dbug (__FUNCTION__,__LINE__, \"-semaphore %#x @ %#lx\\n\", sdt_semaphore, sdt_sem_address[sup->spec_index]);"; s.op->newline() << "#endif"; - s.op->newline() << "(void) __access_process_vm (tsk, sup->sdt_sem_address, &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline() << "(void) __access_process_vm (tsk, sdt_sem_address[sup->spec_index], &sdt_semaphore, sizeof (sdt_semaphore), 1);"; + s.op->newline(-1) << "}"; // access_process_vm // XXX: error handling in __access_process_vm! // XXX: need to analyze possibility of race condition s.op->newline(-1) << "}"; diff --git a/testsuite/systemtap.base/sdt_misc.exp b/testsuite/systemtap.base/sdt_misc.exp index 4e6f953f..062181a5 100644 --- a/testsuite/systemtap.base/sdt_misc.exp +++ b/testsuite/systemtap.base/sdt_misc.exp @@ -3,20 +3,17 @@ set test "sdt_misc" # Test miscellaneous features of .mark probes # Compile a C program to use as the user-space probing target -set sup_srcpath "[pwd]/static_user_markers.c" -set sup_exepath "[pwd]/static_user_markers.x" -set sup_sopath "[pwd]/libsdt.so" -set supcplus_exepath "[pwd]/static_user_markers_cplus.x" +set sup_srcpath "[pwd]/sdt_misc.c" +set supcplus_exepath "[pwd]/sdt_misc_cplus.x" set fp [open $sup_srcpath "w"] puts $fp " #include -#define USE_STAP_PROBE 1 -#include \"static_user_markers_.h\" +#include \"sdt_misc_.h\" void bar (int i) { - STATIC_USER_MARKERS_TEST_PROBE_2(i); + SDT_MISC_TEST_PROBE_2(i); if (i == 0) i = 1000; STAP_PROBE1(static_uprobes,test_probe_2,i); @@ -28,7 +25,7 @@ baz (int i, char* s) STAP_PROBE1(static_uprobes,test_probe_0,i); if (i == 0) i = 1000; - STATIC_USER_MARKERS_TEST_PROBE_3(i,s); + SDT_MISC_TEST_PROBE_3(i,s); } void @@ -42,7 +39,7 @@ buz (int parm) struct astruct bstruct = {parm, parm + 1}; if (parm == 0) parm = 1000; - DTRACE_PROBE1(static_user_markers,test_probe_4,&bstruct); + DTRACE_PROBE1(sdt_misc,test_probe_4,&bstruct); } #ifndef NO_MAIN @@ -57,34 +54,50 @@ main () " close $fp -set sup_stppath "[pwd]/static_user_markers.stp" +set sup_stppath "[pwd]/sdt_misc.stp" set fp [open $sup_stppath "w"] puts $fp " -probe process(\"static_user_markers.x\").mark(\"test_probe_0\") +%( \$# > 1 %? +probe process(@1).library(@2).mark(\"test_probe_0\") +%: +probe process(@1).mark(\"test_probe_0\") +%) { printf(\"In %s probe %#x\\n\", \$\$name, \$arg1) } -probe process(\"static_user_markers.x\").mark(\"test_probe_2\") +%( \$# > 1 %? +probe process(@1).library(@2).mark(\"test_probe_2\") +%: +probe process(@1).mark(\"test_probe_2\") +%) { printf(\"In %s probe %#x\\n\", \$\$name, \$arg1) } -probe process(\"static_user_markers.x\").mark(\"test_probe_3\") +%( \$# > 1 %? +probe process(@1).library(@2).mark(\"test_probe_3\") +%: +probe process(@1).mark(\"test_probe_3\") +%) { printf(\"In %s probe %#x %#x\\n\", \$\$name, \$arg1, \$arg2) } -probe process(\"static_user_markers.x\").mark(\"test_probe_4\") +%( \$# > 1 %? +probe process(@1).library(@2).mark(\"test_probe_4\") +%: +probe process(@1).mark(\"test_probe_4\") +%) { printf(\"In %s dtrace probe %#x %#x\\n\", \$\$name, \$arg1->a, \$arg1->b) } " close $fp -set sup_dpath "[pwd]/static_user_markers_.d" -set sup_hpath "[pwd]/static_user_markers_.h" -set sup_opath "[pwd]/static_user_markers_.o" +set sup_dpath "[pwd]/sdt_misc_.d" +set sup_hpath "[pwd]/sdt_misc_.h" +set sup_opath "[pwd]/sdt_misc_.o" set fp [open $sup_dpath "w"] puts $fp " -provider static_user_markers { +provider sdt_misc { probe test_probe_0 (); probe test_probe_2 (int i); probe test_probe_3 (int i, char* x); @@ -130,7 +143,7 @@ set pbtype_mssgs {{uprobe} {utrace} {kprobe}} for {set i 0} {$i < [llength $pbtype_flags]} {incr i} { set pbtype_flag [lindex $pbtype_flags $i] set pbtype_mssg [lindex $pbtype_mssgs $i] -set testprog "sdt.c.exe.$i" +set sup_exepath "[pwd]/sdt_misc-$pbtype_mssg.x" set sup_flags "additional_flags=-I$srcdir/../includes/sys" set sup_flags "$sup_flags additional_flags=-I$sdtdir" @@ -163,7 +176,7 @@ if {![utrace_p]} { set ok 0 verbose -log "spawn stap -c $sup_exepath $sup_stppath" -spawn stap -c $sup_exepath $sup_stppath +spawn stap -c $sup_exepath $sup_stppath $sup_exepath expect { -timeout 180 -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } @@ -198,17 +211,17 @@ set ok 0 set fail "types" verbose -log "spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x" spawn stap -c ./sdt_types.x $srcdir/$subdir/sdt_types.stp ./sdt_types.x + expect { -timeout 180 -re {FAIL: [a-z_]+var} { regexp " .*$" $expect_out(0,string) s; incr ok; set fail "$fail $s"; exp_continue } - timeout { fail "$test (timeout) } + timeout { fail "$test (timeout)" } eof { } } wait -set pbtype_mssgs {{uprobe} {utrace} {kprobe}} if { $ok != 0} { if { $pbtype_mssg == "uprobe" } { fail "$test $fail $pbtype_mssg" @@ -222,7 +235,7 @@ if { $ok != 0} { # Test probe in shared object -set sup_srcmainpath "[pwd]/static_user_markers_.c" +set sup_srcmainpath "[pwd]/sdt_misc_.c" set fp [open $sup_srcmainpath "w"] puts $fp " int @@ -238,9 +251,11 @@ close $fp set sup_flags "$sup_flags additional_flags=-shared" set sup_flags "$sup_flags additional_flags=-fPIC" set sup_flags "$sup_flags additional_flags=-DNO_MAIN" +set sup_sopath "[pwd]/libsdt-$pbtype_mssg.so" +set sup_exepath "[pwd]/sdt_misc-$pbtype_mssg-shared.x" set res0 [target_compile $sup_srcpath $sup_sopath executable $sup_flags ] set sup0_flags "additional_flags=-g additional_flags=-Wl,-rpath,[pwd]" -set sup0_flags "$sup0_flags additional_flags=-L[pwd] additional_flags=-lsdt" +set sup0_flags "$sup0_flags additional_flags=-L[pwd] additional_flags=-lsdt-$pbtype_mssg" set res [target_compile $sup_srcmainpath $sup_exepath executable $sup0_flags ] if { $res0 != "" || $res != "" } { verbose "target_compile failed: $res0 $res" 2 @@ -254,21 +269,28 @@ if { $res0 != "" || $res != "" } { } set ok 0 -# verbose -log "stap -c $sup_exepath -e probe process(\"$sup_sopath\").mark(\"test_probe_2\") {printf(\"In %s probe %#x\\n\", \$\$name, \$arg1)}" -# spawn stap -c $sup_exepath -e "probe process(\"$sup_sopath\").mark(\"test_probe_2\") {printf(\"In %s probe %#x\\n\", \$\$name, \$arg1)}" -# expect { -# -timeout 180 -# -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } -# timeout { fail "$test (timeout)" } -# eof { } -# } -# wait - -if {$ok == 2} { +verbose -log "spawn stap -c $sup_exepath $sup_stppath $sup_exepath $sup_sopath" +if { $pbtype_mssg != "kprobe" } { + spawn stap -c $sup_exepath $sup_stppath $sup_exepath $sup_sopath +} else { + spawn stap -c $sup_exepath $sup_stppath $sup_sopath +} +expect { + -timeout 180 + -re {In test_probe_2 probe 0x2} { incr ok; exp_continue } + -re {In test_probe_0 probe 0x3} { incr ok; exp_continue } + -re {In test_probe_3 probe 0x3 0x[0-9a-f][0-9a-f]} { incr ok; exp_continue } + -re {In test_probe_4 dtrace probe 0x4 0x5} { incr ok; exp_continue } + timeout { fail "$test (timeout)" } + eof { } +} + +wait + +if {$ok == 5} { pass "$test shared $pbtype_mssg" } else { -# fail "$test shared ($ok) $pbtype_mssg" - xfail "$test shared ($ok) $pbtype_mssg" + fail "$test ($ok) shared $pbtype_mssg" } # Test .mark probe wildcard matching @@ -288,9 +310,12 @@ if { $ok == 45 } { fail "$test wildcard ($ok) $pbtype_mssg" } +if { $verbose == 0 } { + catch {exec rm -f libsdt-$pbtype_mssg.so sdt_misc-$pbtype_mssg.x sdt_misc-$pbtype_mssg-shared.x } +} # for {set i 0} } if { $verbose == 0 } { -catch {exec rm -f $sup_srcpath $sup_exepath $sup_sopath $supcplus_exepath $sup_dpath $sup_hpath $sup_opath $sup_stppath $sdt_types.x $sup_srcmainpath} + catch {exec rm -f sdt_misc_.c sdt_misc.c sdt_misc_.d sdt_misc_.h sdt_misc_.o sdt_misc.stp sdt_types.x} } diff --git a/util.cxx b/util.cxx index bffeb04e..736e5a30 100644 --- a/util.cxx +++ b/util.cxx @@ -244,7 +244,7 @@ tokenize(const string& str, vector& tokens, // same policy as execvp(). A program name not containing a slash // will be searched along the $PATH. -string find_executable(const string& name) +string find_executable(const string& name, const string& env_path) { string retpath; @@ -259,7 +259,7 @@ string find_executable(const string& name) } else // Nope, search $PATH. { - char *path = getenv("PATH"); + char *path = getenv(env_path.c_str()); if (path) { // Split PATH up. diff --git a/util.h b/util.h index bb6c71bc..8fc64cbd 100644 --- a/util.h +++ b/util.h @@ -15,7 +15,8 @@ int remove_file_or_dir(const char *dir); bool in_group_id (gid_t target_gid); void tokenize(const std::string& str, std::vector& tokens, const std::string& delimiters); -std::string find_executable(const std::string& name); +std::string find_executable(const std::string& name, + const std::string& env_path = "PATH"); const std::string cmdstr_quoted(const std::string& cmd); std::string git_revision(const std::string& path); int stap_system(int verbose, const std::string& command); -- cgit From cfd482078cd4805076cc6fd7e4e8642b97a03b25 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 8 Dec 2009 12:44:03 +0100 Subject: refactor list of data sets out of GraphWidget into a global data structure. Also, add a sigc signal for broadcasting data set changes. * grapher/GraphData.hxx (GraphDataList) new typedef (getGraphData, graphDataSignal): new functions * grapher/Graph.hxx (DatasetList): remove typedef in favor of systemtap::GraphDataList * grapher/GraphWidget.cxx (GraphWidget, onGraphDataChanged): Use graphDataSignal to notice new data sets that need to be added. Use the global data set list instead of one embedded in GraphWidget. * grapher/StapParser.hxx: delete the _widget member; use signals to broadcast that there are new data sets instead of calling into the widget. --- grapher/Graph.cxx | 9 ++++++--- grapher/Graph.hxx | 5 ++--- grapher/GraphData.hxx | 14 +++++++++++++ grapher/GraphWidget.cxx | 52 ++++++++++++++++++++++++++++++++++++------------- grapher/GraphWidget.hxx | 4 +--- grapher/StapParser.cxx | 6 ++++-- grapher/StapParser.hxx | 7 ++----- grapher/grapher.cxx | 4 ++-- 8 files changed, 69 insertions(+), 32 deletions(-) diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx index 2d203ead..ea1bd091 100644 --- a/grapher/Graph.cxx +++ b/grapher/Graph.cxx @@ -16,6 +16,9 @@ namespace systemtap { using namespace std; using namespace std::tr1; + + GraphDataList GraphDataBase::graphData; + sigc::signal GraphDataBase::graphDataChanged; Graph::Graph(double x, double y) : _width(600), _height(200), _graphX(0), _graphY(0), @@ -40,7 +43,7 @@ namespace systemtap int linesPossible = (int)(_graphWidth / (_lineWidth + 2.0)); // Find latest time. int64_t latestTime = 0; - for (DatasetList::iterator ditr = _datasets.begin(), + for (GraphDataList::iterator ditr = _datasets.begin(), de = _datasets.end(); ditr != de; ++ditr) @@ -54,7 +57,7 @@ namespace systemtap } int64_t minDiff = 0; int64_t maxTotal = 0; - for (DatasetList::iterator ditr = _datasets.begin(), + for (GraphDataList::iterator ditr = _datasets.begin(), de = _datasets.end(); ditr != de; ++ditr) @@ -92,7 +95,7 @@ namespace systemtap cr->translate(_xOffset, _yOffset); cr->set_line_width(_lineWidth); - for (DatasetList::iterator itr = _datasets.begin(), e = _datasets.end(); + for (GraphDataList::iterator itr = _datasets.begin(), e = _datasets.end(); itr != e; ++itr) { diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx index 4dcb5169..c928fec2 100644 --- a/grapher/Graph.hxx +++ b/grapher/Graph.hxx @@ -19,7 +19,6 @@ namespace systemtap class Graph : public CairoWidget { public: - typedef std::vector > DatasetList; friend class GraphWidget; Graph(double x = 0.0, double y = 0.0); virtual void draw(Cairo::RefPtr cr); @@ -48,11 +47,11 @@ namespace systemtap double _yOffset; std::tr1::shared_ptr _playButton; int64_t _timeBase; - DatasetList& getDatasets() { return _datasets; } + GraphDataList& getDatasets() { return _datasets; } int64_t getTimeAtPoint(double x); void window2GraphCoords(double x, double y, double& xgraph, double& ygraph); protected: - DatasetList _datasets; + GraphDataList _datasets; int64_t _left; int64_t _right; double _top; diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx index fbb2bb8f..fb1ca9f5 100644 --- a/grapher/GraphData.hxx +++ b/grapher/GraphData.hxx @@ -19,10 +19,14 @@ #include +#include + #include "GraphStyle.hxx" namespace systemtap { + struct GraphDataBase; + typedef std::vector > GraphDataList; struct GraphDataBase { virtual ~GraphDataBase() {} @@ -43,6 +47,9 @@ namespace systemtap std::string xAxisText; std::string yAxisText; TimeList times; + static GraphDataList graphData; + // signal stuff for telling everyone about changes to the data set list + static sigc::signal graphDataChanged; }; template @@ -69,5 +76,12 @@ namespace systemtap Element; std::vector elements; }; + + inline GraphDataList& getGraphData() { return GraphDataBase::graphData; } + + inline sigc::signal& graphDataSignal() + { + return GraphDataBase::graphDataChanged; + } } #endif diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx index 8335fda2..bdf60ed2 100644 --- a/grapher/GraphWidget.cxx +++ b/grapher/GraphWidget.cxx @@ -87,7 +87,8 @@ namespace systemtap &GraphWidget::onRelativeTimesButtonClicked)); // Set button's initial value from that in .glade file _displayRelativeTimes = _relativeTimesButton->get_active(); - + graphDataSignal() + .connect(sigc::mem_fun(*this, &GraphWidget::onGraphDataChanged)); } catch (const Gnome::Glade::XmlError& ex ) { @@ -100,10 +101,32 @@ namespace systemtap { } - void GraphWidget::addGraphData(shared_ptr data) + void GraphWidget::onGraphDataChanged() { - _graphs.back()->addGraphData(data); - _graphData.push_back(data); + // add any new graph data to the last graph + GraphDataList newData; + GraphDataList& allData = getGraphData(); + for (GraphDataList::iterator gditr = allData.begin(), gdend = allData.end(); + gditr != gdend; + ++gditr) + { + bool found = false; + for (GraphList::iterator gitr = _graphs.begin(), gend = _graphs.end(); + gitr != gend; + ++gitr) + { + GraphDataList& gdata = (*gitr)->getDatasets(); + if (find(gdata.begin(), gdata.end(), *gditr) != gdata.end()) + { + found = true; + break; + } + } + if (!found) + newData.push_back(*gditr); + } + copy(newData.begin(), newData.end(), + back_inserter(_graphs.back()->getDatasets())); } void GraphWidget::addGraph() @@ -134,11 +157,12 @@ namespace systemtap cr->save(); cr->set_source_rgba(0.0, 0.0, 0.0, 1.0); cr->paint(); - if (!_timeBaseInitialized && !_graphData.empty()) + if (!_timeBaseInitialized && !getGraphData().empty()) { + GraphDataList& graphData = getGraphData(); int64_t earliest = INT64_MAX; - for (GraphDataList::iterator gd = _graphData.begin(), - end = _graphData.end(); + for (GraphDataList::iterator gd = graphData.begin(), + end = graphData.end(); gd != end; ++gd) { @@ -285,8 +309,8 @@ namespace systemtap void GraphWidget::onDataDialogOpen() { _listStore->clear(); - for (GraphDataList::iterator itr = _graphData.begin(), - end = _graphData.end(); + for (GraphDataList::iterator itr = getGraphData().begin(), + end = getGraphData().end(); itr != end; ++itr) { @@ -296,8 +320,8 @@ namespace systemtap if (!(*itr)->title.empty()) row[_dataColumns._dataTitle] = (*itr)->title; row[_dataColumns._graphData] = *itr; - Graph::DatasetList& gsets = _activeGraph->getDatasets(); - Graph::DatasetList::iterator setItr + GraphDataList& gsets = _activeGraph->getDatasets(); + GraphDataList::iterator setItr = find(gsets.begin(), gsets.end(), *itr); row[_dataColumns._dataEnabled] = (setItr != gsets.end()); } @@ -320,8 +344,8 @@ namespace systemtap if (!_hoverText) _hoverText = shared_ptr(new CairoTextBox()); _hoverText->setOrigin(_mouseX + 10, _mouseY - 5); - Graph::DatasetList& dataSets = g->getDatasets(); - for (Graph::DatasetList::reverse_iterator ritr = dataSets.rbegin(), + GraphDataList& dataSets = g->getDatasets(); + for (GraphDataList::reverse_iterator ritr = dataSets.rbegin(), end = dataSets.rend(); ritr != end; ++ritr) @@ -374,7 +398,7 @@ namespace systemtap Gtk::TreeModel::Row row = *litr; bool val = row[_dataColumns._dataEnabled]; shared_ptr data = row[_dataColumns._graphData]; - Graph::DatasetList& graphData = _activeGraph->getDatasets(); + GraphDataList& graphData = _activeGraph->getDatasets(); if (val && find(graphData.begin(), graphData.end(), data) == graphData.end()) { diff --git a/grapher/GraphWidget.hxx b/grapher/GraphWidget.hxx index 0e9f2a29..89b86db9 100644 --- a/grapher/GraphWidget.hxx +++ b/grapher/GraphWidget.hxx @@ -42,14 +42,11 @@ namespace systemtap public: GraphWidget(); virtual ~GraphWidget(); - void addGraphData(std::tr1::shared_ptr data); void addGraph(); protected: typedef std::vector > GraphList; GraphList _graphs; - typedef std::vector > GraphDataList; - GraphDataList _graphData; // For click and drag std::tr1::shared_ptr _activeGraph; // Dragging all graphs simultaneously, or perhaps seperately @@ -99,6 +96,7 @@ namespace systemtap { return false; } + void onGraphDataChanged(); }; } #endif // SYSTEMTAP_GRAPHWIDGET_H diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index edb7f5f2..653c00de 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -118,7 +118,8 @@ vector commaSplit(const boost::sub_range& range) dataSet->color[2] = (hexColor & 0xff) / 255.0; dataSet->scale = scale; _dataSets.insert(std::make_pair(setName, dataSet)); - _widget->addGraphData(dataSet); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); } else if (style == "discreet") { @@ -131,7 +132,8 @@ vector commaSplit(const boost::sub_range& range) dataSet->color[2] = (hexColor & 0xff) / 255.0; dataSet->scale = scale; _dataSets.insert(std::make_pair(setName, dataSet)); - _widget->addGraphData(dataSet); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); } } else if ((found = find_first(dataString, "%CSV:"))) diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index 476b0071..eba8a7af 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -7,7 +7,6 @@ // later version. #include "GraphData.hxx" -#include "GraphWidget.hxx" #include namespace systemtap @@ -19,14 +18,12 @@ class StapParser DataMap _dataSets; CSVData _csv; Gtk::Window* _win; - GraphWidget* _widget; int _errFd; int _inFd; unsigned char _lineEndChar; public: - StapParser(Gtk::Window* win, - GraphWidget* widget) : _win(win), _widget(widget), _errFd(-1), - _inFd(-1), _lineEndChar('\n') + StapParser(Gtk::Window* win) + : _win(win), _errFd(-1), _inFd(-1), _lineEndChar('\n') { } void parseData(std::tr1::shared_ptr gdata, diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 567b0405..4769877f 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -161,7 +161,7 @@ public: void cleanUp(); tr1::shared_ptr makeStapParser() { - tr1::shared_ptr result(new StapParser(_win, _widget)); + tr1::shared_ptr result(new StapParser(_win)); _parsers.push_back(ParserInstance(-1, result)); return result; } @@ -274,7 +274,7 @@ int StapLauncher::launch() } _exit(1); } - tr1::shared_ptr sp(new StapParser(_win, _widget)); + tr1::shared_ptr sp(new StapParser(_win)); _parsers.push_back(ParserInstance(childPid, sp)); sp->setErrFd(pipefd[2]); sp->setInFd(pipefd[0]); -- cgit From 8cabc8bcdcd22e8726734f1a18f23ed7d9c19e9f Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 8 Dec 2009 23:17:47 +0100 Subject: grapher: start of a dialog for displaying active stap processes The names of active scripts are displayed in a list; mock buttons suggest being able to stop and restart them. * grapher/processwindow.glade: new file * grapher/Makefile.am: add processwindow.glade to installed files * grapher/StapParser.hxx (StapProcess): new class (StapParser): factor out members that are now in StapProcess (ioCallback): Use the new childDied signal instead of aborting the whole grapher when a child dies. * grapher/grapher.cxx (ProcModelColumns, ProcWindow): classes for displaying stap process window. (GrapherWindow::on_menu_proc_window): new function --- grapher/Makefile.am | 2 +- grapher/Makefile.in | 5 +- grapher/StapParser.cxx | 12 +- grapher/StapParser.hxx | 77 ++++++--- grapher/grapher.cxx | 156 ++++++++++++++---- grapher/processwindow.glade | 372 +++++++++++++++++++++++++++++++++++++++++++ grapher/processwindow.gladep | 8 + 7 files changed, 573 insertions(+), 59 deletions(-) create mode 100644 grapher/processwindow.glade create mode 100644 grapher/processwindow.gladep diff --git a/grapher/Makefile.am b/grapher/Makefile.am index 5bca286a..1087f44d 100644 --- a/grapher/Makefile.am +++ b/grapher/Makefile.am @@ -9,5 +9,5 @@ stapgraph_CPPFLAGS = -DPKGDATADIR='"${pkgdatadir}"' stapgraph_CXXFLAGS = $(libglade_CFLAGS) -Wall -Werror stapgraph_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx GraphStyle.cxx stapgraph_LDADD = $(libglade_LIBS) -dist_pkgdata_DATA = graph-dialog.glade stap-start.glade +dist_pkgdata_DATA = graph-dialog.glade stap-start.glade processwindow.glade endif diff --git a/grapher/Makefile.in b/grapher/Makefile.in index f06402bc..c608e516 100644 --- a/grapher/Makefile.in +++ b/grapher/Makefile.in @@ -112,7 +112,8 @@ am__base_list = \ man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) -am__dist_pkgdata_DATA_DIST = graph-dialog.glade stap-start.glade +am__dist_pkgdata_DATA_DIST = graph-dialog.glade stap-start.glade \ + processwindow.glade DATA = $(dist_pkgdata_DATA) ETAGS = etags CTAGS = ctags @@ -246,7 +247,7 @@ top_srcdir = @top_srcdir@ @BUILD_GRAPHER_TRUE@stapgraph_CXXFLAGS = $(libglade_CFLAGS) -Wall -Werror @BUILD_GRAPHER_TRUE@stapgraph_SOURCES = grapher.cxx StapParser.cxx Graph.cxx GraphWidget.cxx CairoWidget.cxx GraphStyle.cxx @BUILD_GRAPHER_TRUE@stapgraph_LDADD = $(libglade_LIBS) -@BUILD_GRAPHER_TRUE@dist_pkgdata_DATA = graph-dialog.glade stap-start.glade +@BUILD_GRAPHER_TRUE@dist_pkgdata_DATA = graph-dialog.glade stap-start.glade processwindow.glade all: all-am .SUFFIXES: diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 653c00de..b82cc024 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -25,6 +25,12 @@ namespace systemtap using namespace std; using namespace std::tr1; + sigc::signal& childDiedSignal() + { + static sigc::signal deathSignal; + return deathSignal; + } + vector commaSplit(const boost::sub_range& range) { using namespace boost; @@ -72,7 +78,7 @@ vector commaSplit(const boost::sub_range& range) using namespace boost; if (ioCondition & Glib::IO_HUP) { - _win->hide(); + childDiedSignal().emit(getPid()); return true; } if ((ioCondition & Glib::IO_IN) == 0) @@ -82,7 +88,7 @@ vector commaSplit(const boost::sub_range& range) bytes_read = read(_inFd, buf, sizeof(buf) - 1); if (bytes_read <= 0) { - _win->hide(); + childDiedSignal().emit(getPid()); return true; } _buffer.append(buf, bytes_read); @@ -242,7 +248,7 @@ vector commaSplit(const boost::sub_range& range) bytes_read = read(_errFd, buf, sizeof(buf) - 1); if (bytes_read <= 0) { - _win->hide(); + cerr << "StapParser: error reading from stderr!\n"; return true; } if (write(STDOUT_FILENO, buf, bytes_read) < 0) diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index eba8a7af..cfb807a8 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -9,30 +9,61 @@ #include "GraphData.hxx" #include +#include + +#include + namespace systemtap { -class StapParser -{ - std::string _buffer; - typedef std::map > DataMap; - DataMap _dataSets; - CSVData _csv; - Gtk::Window* _win; - int _errFd; - int _inFd; - unsigned char _lineEndChar; -public: - StapParser(Gtk::Window* win) - : _win(win), _errFd(-1), _inFd(-1), _lineEndChar('\n') + // arguments and script for a stap process + struct StapProcess { - } - void parseData(std::tr1::shared_ptr gdata, - int64_t 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; } -}; + StapProcess(pid_t pid_ = -1) : pid(pid_) {} + std::string stapArgs; + std::string script; + std::string scriptArgs; + // arguments passed from a single array, like from the command line. + char **argv; + // -1 if the grapher is reading from stdin + pid_t pid; + }; + + class StapParser + { + std::string _buffer; + typedef std::map > DataMap; + DataMap _dataSets; + CSVData _csv; + int _errFd; + int _inFd; + unsigned char _lineEndChar; + std::tr1::shared_ptr _process; + public: + StapParser() + : _errFd(-1), _inFd(-1), _lineEndChar('\n') + { + } + void parseData(std::tr1::shared_ptr gdata, + int64_t time, const std::string& dataString); + bool ioCallback(Glib::IOCondition ioCondition); + bool errIoCallback(Glib::IOCondition ioCondition); + int getErrFd() const { return _errFd; } + void setErrFd(int fd) { _errFd = fd; } + int getInFd() const { return _inFd; } + void setInFd(int fd) { _inFd = fd; } + pid_t getPid() const + { + if (_process) + return _process->pid; + else + return -1; + } + std::tr1::shared_ptr getProcess() { return _process; } + void setProcess(std::tr1::shared_ptr process) + { + _process = process; + } + }; + + sigc::signal& childDiedSignal(); } diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 4769877f..2a9a617b 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -39,6 +39,7 @@ #include using namespace std; +using namespace tr1; using namespace systemtap; @@ -159,22 +160,33 @@ public: } int launch(); void cleanUp(); - tr1::shared_ptr makeStapParser() + shared_ptr makeStapParser() { - tr1::shared_ptr result(new StapParser(_win)); - _parsers.push_back(ParserInstance(-1, result)); + shared_ptr result(new StapParser); + _parsers.push_back(result); return result; } +private: + struct pidPred + { + pidPred(pid_t pid_) : pid(pid_) {} + bool operator()(const shared_ptr& parser) const + { + return parser->getPid() == pid; + } + pid_t pid; + }; +public: pid_t reap() { + using namespace boost; 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); + = find_if(_parsers.begin(), _parsers.end(), pidPred(pid)); if (itr != _parsers.end()) - itr->childPid = -1; + (*itr)->setProcess(tr1::shared_ptr()); return pid; } void killAll() @@ -183,10 +195,12 @@ public: itr != end; ++itr) { - if (itr->childPid >= 0) - kill(itr->childPid, SIGTERM); + if ((*itr)->getPid() >= 0) + kill((*itr)->getPid(), SIGTERM); } } + typedef vector > ParserList; + ParserList _parsers; protected: char** _argv; string _stapArgs; @@ -196,18 +210,6 @@ protected: ChildDeathReader::Callback* _deathCallback; Gtk::Window* _win; GraphWidget* _widget; - struct ParserInstance - { - ParserInstance() : childPid(-1) {} - ParserInstance(int childPid_, tr1::shared_ptr stapParser_) - : childPid(childPid_), stapParser(stapParser_) - { - } - pid_t childPid; - tr1::shared_ptr stapParser; - }; - typedef vector ParserList; - ParserList _parsers; }; int StapLauncher::launch() @@ -274,8 +276,18 @@ int StapLauncher::launch() } _exit(1); } - tr1::shared_ptr sp(new StapParser(_win)); - _parsers.push_back(ParserInstance(childPid, sp)); + tr1::shared_ptr sp(new StapParser); + shared_ptr proc(new StapProcess(childPid)); + if (_argv) + proc->argv = _argv; + else + { + proc->stapArgs = _stapArgs; + proc->script = _script; + proc->scriptArgs = _scriptArgs; + } + sp->setProcess(proc); + _parsers.push_back(sp); sp->setErrFd(pipefd[2]); sp->setInFd(pipefd[0]); Glib::signal_io().connect(sigc::mem_fun(sp.get(), @@ -305,21 +317,22 @@ void StapLauncher::cleanUp() itr != end; ++itr) { - if (itr->childPid > 0) - kill(itr->childPid, SIGTERM); + pid_t childPid = (*itr)->getPid(); + if (childPid > 0) + kill(childPid, SIGTERM); int status; pid_t killedPid = -1; if ((killedPid = wait(&status)) == -1) { std::perror("wait"); } - else if (killedPid != itr->childPid) + else if (killedPid != childPid) { std::cerr << "wait: killed Pid " << killedPid << " != child Pid " - << itr->childPid << "\n"; + << childPid << "\n"; } else if (_deathCallback) - _deathCallback->childDied(itr->childPid); + _deathCallback->childDied(childPid); } } @@ -338,6 +351,58 @@ private: Gtk::Entry* _scriptArgEntry; }; +class ProcModelColumns : public Gtk::TreeModelColumnRecord +{ +public: + ProcModelColumns() + { + add(_scriptName); + add(_proc); + } + Gtk::TreeModelColumn _scriptName; + Gtk::TreeModelColumn > _proc; +}; + +class ProcWindow +{ +public: + ProcWindow(); + ProcModelColumns _modelColumns; + Glib::RefPtr _xml; + Gtk::Window* _window; + Gtk::TreeView* _dataTreeView; + Glib::RefPtr _listStore; + void onClose(); +}; + +ProcWindow::ProcWindow() +{ + try + { + _xml = Gnome::Glade::Xml::create(PKGDATADIR "/processwindow.glade"); + _xml->get_widget("window1", _window); + _xml->get_widget("treeview1", _dataTreeView); + + } + catch (const Gnome::Glade::XmlError& ex ) + { + std::cerr << ex.what() << std::endl; + throw; + } + _listStore = Gtk::ListStore::create(_modelColumns); + _dataTreeView->set_model(_listStore); + _dataTreeView->append_column("Script", _modelColumns._scriptName); + Gtk::Button* button = 0; + _xml->get_widget("button5", button); + button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onClose), + false); +} + +void ProcWindow::onClose() +{ + _window->hide(); +} + class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback { public: @@ -355,25 +420,28 @@ public: protected: virtual void on_menu_file_quit(); virtual void on_menu_script_start(); + virtual void on_menu_proc_window(); void addGraph(); // menu support Glib::RefPtr m_refUIManager; Glib::RefPtr m_refActionGroup; GraphicalStapLauncher* _graphicalLauncher; - + shared_ptr _procWindow; }; + GrapherWindow::GrapherWindow() + : _procWindow(new ProcWindow) { 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"), + 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"), @@ -381,6 +449,12 @@ GrapherWindow::GrapherWindow() m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT), sigc::mem_fun(*this, &GrapherWindow::on_menu_file_quit)); + // Window menu + m_refActionGroup->add(Gtk::Action::create("WindowMenu", "Window")); + m_refActionGroup->add(Gtk::Action::create("ProcessWindow", + "Stap processes..."), + sigc::mem_fun(*this, + &GrapherWindow::on_menu_proc_window)); m_refUIManager = Gtk::UIManager::create(); m_refUIManager->insert_action_group(m_refActionGroup); @@ -394,6 +468,9 @@ GrapherWindow::GrapherWindow() " " " " " " + " " + " " + " " " " ""; try @@ -425,6 +502,25 @@ void GrapherWindow::on_menu_script_start() _graphicalLauncher->runDialog(); } + +void GrapherWindow::on_menu_proc_window() +{ + _procWindow->_listStore->clear(); + for (StapLauncher::ParserList::iterator spitr + = _graphicalLauncher->_parsers.begin(), + end = _graphicalLauncher->_parsers.end(); + spitr != end; + ++spitr) + { + shared_ptr sp = (*spitr)->getProcess(); + Gtk::TreeModel::iterator litr = _procWindow->_listStore->append(); + Gtk::TreeModel::Row row = *litr; + if (sp) + row[_procWindow->_modelColumns._scriptName] = sp->script; + } + _procWindow->_window->show(); +} + void GrapherWindow::childDied(int pid) { hide(); diff --git a/grapher/processwindow.glade b/grapher/processwindow.glade new file mode 100644 index 00000000..ad1bdd14 --- /dev/null +++ b/grapher/processwindow.glade @@ -0,0 +1,372 @@ + + + + + + + stap processes + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + False + + + + True + False + 0 + + + + True + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_BOTH + True + True + + + + True + True + True + False + + + + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-cancel + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Kill + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + False + False + + + + + + True + True + True + False + + + + True + True + GTK_RELIEF_NORMAL + True + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-refresh + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Restart + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + False + False + + + + + 0 + False + False + + + + + + True + False + 0 + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 300 + True + True + True + False + False + True + False + False + False + + + + + 0 + True + True + + + + + + 26 + True + GTK_SHADOW_OUT + GTK_POS_LEFT + GTK_POS_TOP + + + + True + False + 0 + + + + 17 + True + label1 + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 20 + True + True + True + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + GTK_BUTTONBOX_END + 0 + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + + + + + 0 + True + True + + + + + + + diff --git a/grapher/processwindow.gladep b/grapher/processwindow.gladep new file mode 100644 index 00000000..183077ba --- /dev/null +++ b/grapher/processwindow.gladep @@ -0,0 +1,8 @@ + + + + + + + FALSE + -- cgit From 3a31e709a19d469c217cc1b65f9f1d6b2ee51ffb Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Wed, 9 Dec 2009 10:57:36 -0500 Subject: Handle .probes section big endian 32 bit case. sdt.h (STAP_PROBE_ADDR): Add 32 bit big endian case. (STAP_PROBE_DATA_): Use .balign tapsets.cxx (sdt_query::get_next_probe): Stop if there is no probe name. --- includes/sys/sdt.h | 18 ++++++++++-------- tapsets.cxx | 10 +++++++++- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/includes/sys/sdt.h b/includes/sys/sdt.h index d85d8e2e..7c23d55a 100644 --- a/includes/sys/sdt.h +++ b/includes/sys/sdt.h @@ -12,9 +12,11 @@ #ifdef __LP64__ -#define STAP_PROBE_ADDR "\t.quad " +#define STAP_PROBE_ADDR(arg) "\t.quad " arg +#elif defined (__BIG_ENDIAN__) +#define STAP_PROBE_ADDR(arg) "\t.long 0\n\t.long " arg #else -#define STAP_PROBE_ADDR "\t.long " +#define STAP_PROBE_ADDR(arg) "\t.long " arg #endif /* Allocated section needs to be writable when creating pic shared objects @@ -26,14 +28,14 @@ /* An allocated section .probes that holds the probe names and addrs. */ #define STAP_PROBE_DATA_(probe,guard,arg) \ __asm__ volatile (".section .probes," ALLOCSEC "\n" \ - "\t.align 8\n" \ + "\t.balign 8\n" \ "1:\n\t.asciz " #probe "\n" \ - "\t.align 4\n" \ + "\t.balign 4\n" \ "\t.int " #guard "\n" \ - "\t.align 8\n" \ - STAP_PROBE_ADDR "1b\n" \ - "\t.align 8\n" \ - STAP_PROBE_ADDR #arg "\n" \ + "\t.balign 8\n" \ + STAP_PROBE_ADDR("1b\n") \ + "\t.balign 8\n" \ + STAP_PROBE_ADDR(#arg "\n") \ "\t.int 0\n" \ "\t.previous\n") diff --git a/tapsets.cxx b/tapsets.cxx index bad72091..555a6587 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -3829,7 +3829,13 @@ sdt_query::init_probe_scn() bool sdt_query::get_next_probe() { - // Extract probe info from the .probes section + // Extract probe info from the .probes section, e.g. + // 74657374 5f70726f 62655f32 00000000 test_probe_2.... + // 50524233 00000000 980c2000 00000000 PRB3...... ..... + // 01000000 00000000 00000000 00000000 ................ + // test_probe_2 is probe_name, probe_type is 50524233, + // *probe_name (pbe->name) is 980c2000, probe_arg (pbe->arg) is 1 + // probe_scn_offset is position currently being scanned in .probes while (probe_scn_offset < pdata->d_size) { @@ -3855,6 +3861,8 @@ sdt_query::get_next_probe() probe_scn_offset += sizeof(__uint32_t); probe_scn_offset += probe_scn_offset % sizeof(__uint64_t); pbe = (struct probe_entry*) ((char*)pdata->d_buf + probe_scn_offset); + if (pbe->name == 0) + return false; probe_name = (char*)((char*)pdata->d_buf + pbe->name - (char*)probe_scn_addr); probe_arg = pbe->arg; if (sess.verbose > 4) -- cgit From 965b658f73ff2a6d11198edc1b84a06a900c1fd7 Mon Sep 17 00:00:00 2001 From: David Smith Date: Wed, 9 Dec 2009 10:38:15 -0600 Subject: PR 10848 partial fix by using systemtap memory functions everywhere. * runtime/addr-map.c (add_bad_addr_entry): Uses systemtap memory allocation/deallocation wrappers. * runtime/itrace.c (create_itrace_info): Ditto. (remove_usr_itrace_info): Ditto. --- runtime/addr-map.c | 11 +++++------ runtime/itrace.c | 9 +++++++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/runtime/addr-map.c b/runtime/addr-map.c index 35de7a64..abb723f3 100644 --- a/runtime/addr-map.c +++ b/runtime/addr-map.c @@ -163,12 +163,11 @@ add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, spin_unlock(&addr_map_lock); if (new_map) { - kfree(new_map); + _stp_kfree(new_map); new_map = 0; } - new_map = kmalloc(sizeof(*new_map) - + sizeof(*new_entry) * (old_size + 1), - GFP_KERNEL); + new_map = _stp_kmalloc(sizeof(*new_map) + + sizeof(*new_entry) * (old_size + 1)); if (!new_map) return -ENOMEM; new_map->size = old_size + 1; @@ -191,7 +190,7 @@ add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, if (existing_max) *existing_max = max_entry; spin_unlock(&addr_map_lock); - kfree(new_map); + _stp_kfree(new_map); return 1; } existing = upper_bound(min_addr, old_map); @@ -210,7 +209,7 @@ add_bad_addr_entry(unsigned long min_addr, unsigned long max_addr, blackmap = new_map; spin_unlock(&addr_map_lock); if (old_map) - kfree(old_map); + _stp_kfree(old_map); return 0; } diff --git a/runtime/itrace.c b/runtime/itrace.c index f2ed86f2..5b2437a4 100644 --- a/runtime/itrace.c +++ b/runtime/itrace.c @@ -219,7 +219,12 @@ static struct itrace_info *create_itrace_info( if (debug) printk(KERN_INFO "create_itrace_info: tid=%d\n", tsk->pid); /* initialize ui */ - ui = kzalloc(sizeof(struct itrace_info), GFP_USER); + ui = _stp_kzalloc(sizeof(struct itrace_info)); + if (ui == NULL) { + printk(KERN_ERR "%s:%d: Unable to allocate memory\n", + __FUNCTION__, __LINE__); + return NULL; + } ui->tsk = tsk; ui->tid = tsk->pid; ui->step_flag = step_flag; @@ -329,7 +334,7 @@ void static remove_usr_itrace_info(struct itrace_info *ui) spin_lock(&itrace_lock); list_del(&ui->link); spin_unlock(&itrace_lock); - kfree(ui); + _stp_kfree(ui); } void static cleanup_usr_itrace(void) -- cgit From 3e1613e1f7ab589089e8ed5a504330bb9cb128db Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Wed, 9 Dec 2009 22:09:39 +0100 Subject: show the status of stap processes in the process window Also, the "kill" button now works. * grapher/StapParser.hxx (_ioConnection, _errIoConnection): new members for sigc connections. (initIo): New function (parsers, parserListChangedSignal): new variables * grapher/StapParser.cxx (ioCallback): disconnect signals when child dies (initIo): new function * grapher/grapher.cxx (StapLauncher): eliminate death callback in favor of childDied signal. Use global parsers list (ProcWindow::_listSelection): new member (ProcWindow::show, hide, onParserListChanged, onSelectionChanged, onKill): new functions (ProcWindow::ProcWindow): Set up cell renderer for status icon * grapher/processwindow.glade: labels for display script and stap arguments --- grapher/StapParser.cxx | 338 ++++++++++++++++++++++++-------------------- grapher/StapParser.hxx | 8 ++ grapher/grapher.cxx | 167 +++++++++++++++------- grapher/processwindow.glade | 132 ++++++++++++++--- 4 files changed, 418 insertions(+), 227 deletions(-) diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index b82cc024..a9a5109a 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -30,7 +30,15 @@ namespace systemtap static sigc::signal deathSignal; return deathSignal; } - + + ParserList parsers; + + sigc::signal& parserListChangedSignal() + { + static sigc::signal listChangedSignal; + return listChangedSignal; + } + vector commaSplit(const boost::sub_range& range) { using namespace boost; @@ -72,171 +80,173 @@ vector commaSplit(const boost::sub_range& range) } bool StapParser::ioCallback(Glib::IOCondition ioCondition) - { - using namespace std; - using std::tr1::shared_ptr; - using namespace boost; - if (ioCondition & Glib::IO_HUP) - { - childDiedSignal().emit(getPid()); - return true; - } - if ((ioCondition & Glib::IO_IN) == 0) + { + using namespace std; + using std::tr1::shared_ptr; + using namespace boost; + if (ioCondition & Glib::IO_HUP) + { + childDiedSignal().emit(getPid()); + _ioConnection.disconnect(); + _errIoConnection.disconnect(); + return true; + } + if ((ioCondition & Glib::IO_IN) == 0) + return true; + char buf[256]; + ssize_t bytes_read = 0; + bytes_read = read(_inFd, buf, sizeof(buf) - 1); + if (bytes_read <= 0) + { + childDiedSignal().emit(getPid()); return true; - char buf[256]; - ssize_t bytes_read = 0; - bytes_read = read(_inFd, buf, sizeof(buf) - 1); - if (bytes_read <= 0) - { - childDiedSignal().emit(getPid()); - return true; - } - _buffer.append(buf, bytes_read); - string::size_type ret = string::npos; - while ((ret = _buffer.find(_lineEndChar)) != string::npos) - { - Glib::ustring dataString(_buffer, 0, ret); - // %DataSet and %CSV declare a data set; all other - // statements begin with the name of a data set. - // Except %LineEnd :) - sub_range found; - if (dataString[0] == '%') - { - if ((found = find_first(dataString, "%DataSet:"))) - { - string setName; - int hexColor; - double scale; - string style; - istringstream stream(Glib::ustring(found.end(), - dataString.end())); - stream >> setName >> scale >> std::hex >> hexColor - >> style; - if (style == "bar" || style == "dot") - { - std::tr1::shared_ptr > - dataSet(new GraphData); - dataSet->name = setName; - if (style == "dot") - dataSet->style = &GraphStyleDot::instance; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - dataSet->scale = scale; - _dataSets.insert(std::make_pair(setName, dataSet)); - getGraphData().push_back(dataSet); - graphDataSignal().emit(); - } - else if (style == "discreet") - { - std::tr1::shared_ptr > - dataSet(new GraphData); - dataSet->name = setName; - dataSet->style = &GraphStyleEvent::instance; - dataSet->color[0] = (hexColor >> 16) / 255.0; - dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; - dataSet->color[2] = (hexColor & 0xff) / 255.0; - dataSet->scale = scale; - _dataSets.insert(std::make_pair(setName, dataSet)); - getGraphData().push_back(dataSet); - graphDataSignal().emit(); - } - } - else if ((found = find_first(dataString, "%CSV:"))) - { - vector tokens - = commaSplit(sub_range(found.end(), - dataString.end())); - for (vector::iterator tokIter = tokens.begin(), - e = tokens.end(); - tokIter != e; - ++tokIter) - { - DataMap::iterator setIter = _dataSets.find(*tokIter); - if (setIter != _dataSets.end()) - _csv.elements - .push_back(CSVData::Element(*tokIter, - setIter->second)); - } - } - else if ((found = find_first(dataString, "%LineEnd:"))) - { - istringstream stream(Glib::ustring(found.end(), - dataString.end())); - int charAsInt = 0; - // parse hex and octal numbers too - stream >> std::setbase(0) >> charAsInt; - _lineEndChar = static_cast(charAsInt); - } - else - { - cerr << "Unknown declaration " << dataString << endl; - } - } - else - { - std::istringstream stream(dataString); - string setName; - stream >> setName; - DataMap::iterator itr = _dataSets.find(setName); - if (itr != _dataSets.end()) - { - shared_ptr gdata = itr->second; - string decl; - // Hack: scan from the beginning of dataString again - if (findTaggedValue(dataString, "%Title:", decl)) - { - gdata->title = decl; - } - else if (findTaggedValue(dataString, "%XAxisTitle:", decl)) - { - gdata->xAxisText = decl; - } - else if (findTaggedValue(dataString, "%YAxisTitle:", decl)) - { - gdata->yAxisText = decl; - } - else if ((found = find_first(dataString, "%YMax:"))) - { - double ymax; - std::istringstream - stream(Glib::ustring(found.end(), dataString.end())); - stream >> ymax; - gdata->scale = ymax; - } - else + } + _buffer.append(buf, bytes_read); + string::size_type ret = string::npos; + while ((ret = _buffer.find(_lineEndChar)) != string::npos) + { + Glib::ustring dataString(_buffer, 0, ret); + // %DataSet and %CSV declare a data set; all other + // statements begin with the name of a data set. + // Except %LineEnd :) + sub_range found; + if (dataString[0] == '%') + { + if ((found = find_first(dataString, "%DataSet:"))) + { + string setName; + int hexColor; + double scale; + string style; + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + stream >> setName >> scale >> std::hex >> hexColor + >> style; + if (style == "bar" || style == "dot") + { + std::tr1::shared_ptr > + dataSet(new GraphData); + dataSet->name = setName; + if (style == "dot") + dataSet->style = &GraphStyleDot::instance; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); + } + else if (style == "discreet") { - if (!_csv.elements.empty()) + std::tr1::shared_ptr > + dataSet(new GraphData); + dataSet->name = setName; + dataSet->style = &GraphStyleEvent::instance; + dataSet->color[0] = (hexColor >> 16) / 255.0; + dataSet->color[1] = ((hexColor >> 8) & 0xff) / 255.0; + dataSet->color[2] = (hexColor & 0xff) / 255.0; + dataSet->scale = scale; + _dataSets.insert(std::make_pair(setName, dataSet)); + getGraphData().push_back(dataSet); + graphDataSignal().emit(); + } + } + else if ((found = find_first(dataString, "%CSV:"))) + { + vector tokens + = commaSplit(sub_range(found.end(), + dataString.end())); + for (vector::iterator tokIter = tokens.begin(), + e = tokens.end(); + tokIter != e; + ++tokIter) + { + DataMap::iterator setIter = _dataSets.find(*tokIter); + if (setIter != _dataSets.end()) + _csv.elements + .push_back(CSVData::Element(*tokIter, + setIter->second)); + } + } + else if ((found = find_first(dataString, "%LineEnd:"))) + { + istringstream stream(Glib::ustring(found.end(), + dataString.end())); + int charAsInt = 0; + // parse hex and octal numbers too + stream >> std::setbase(0) >> charAsInt; + _lineEndChar = static_cast(charAsInt); + } + else + { + cerr << "Unknown declaration " << dataString << endl; + } + } + else + { + std::istringstream stream(dataString); + string setName; + stream >> setName; + DataMap::iterator itr = _dataSets.find(setName); + if (itr != _dataSets.end()) + { + shared_ptr gdata = itr->second; + string decl; + // Hack: scan from the beginning of dataString again + if (findTaggedValue(dataString, "%Title:", decl)) + { + gdata->title = decl; + } + else if (findTaggedValue(dataString, "%XAxisTitle:", decl)) + { + gdata->xAxisText = decl; + } + else if (findTaggedValue(dataString, "%YAxisTitle:", decl)) + { + gdata->yAxisText = decl; + } + else if ((found = find_first(dataString, "%YMax:"))) + { + double ymax; + std::istringstream + stream(Glib::ustring(found.end(), dataString.end())); + stream >> ymax; + gdata->scale = ymax; + } + else + { + if (!_csv.elements.empty()) { - vector tokens = commaSplit(dataString); - int i = 0; - int64_t time; - vector::iterator tokIter = tokens.begin(); - std::istringstream timeStream(*tokIter++); - timeStream >> time; - for (vector::iterator e = tokens.end(); - tokIter != e; - ++tokIter, ++i) + vector tokens = commaSplit(dataString); + int i = 0; + int64_t time; + vector::iterator tokIter = tokens.begin(); + std::istringstream timeStream(*tokIter++); + timeStream >> time; + for (vector::iterator e = tokens.end(); + tokIter != e; + ++tokIter, ++i) { - parseData(_csv.elements[i].second, time, - *tokIter); + parseData(_csv.elements[i].second, time, + *tokIter); } } - else + else { - int64_t time; - stringbuf data; - stream >> time; - stream.get(data, _lineEndChar); - parseData(itr->second, time, data.str()); + int64_t time; + stringbuf data; + stream >> time; + stream.get(data, _lineEndChar); + parseData(itr->second, time, data.str()); } } - } - } - _buffer.erase(0, ret + 1); - } - return true; - } + } + } + _buffer.erase(0, ret + 1); + } + return true; + } bool StapParser::errIoCallback(Glib::IOCondition ioCondition) { @@ -255,4 +265,18 @@ vector commaSplit(const boost::sub_range& range) ; return true; } + + void StapParser::initIo(int inFd, int errFd) + { + _inFd = inFd; + _errFd = errFd; + _ioConnection = Glib::signal_io() + .connect(sigc::mem_fun(*this, &StapParser::errIoCallback), + _errFd, + Glib::IO_IN); + _errIoConnection = Glib::signal_io() + .connect(sigc::mem_fun(*this, &StapParser::ioCallback), + _inFd, + Glib::IO_IN | Glib::IO_HUP); + } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index cfb807a8..4dd711e6 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -38,6 +38,8 @@ namespace systemtap int _inFd; unsigned char _lineEndChar; std::tr1::shared_ptr _process; + sigc::connection _ioConnection; + sigc::connection _errIoConnection; public: StapParser() : _errFd(-1), _inFd(-1), _lineEndChar('\n') @@ -63,7 +65,13 @@ namespace systemtap { _process = process; } + void initIo(int inFd, int errFd); }; sigc::signal& childDiedSignal(); + + typedef std::vector > ParserList; + extern ParserList parsers; + + sigc::signal& parserListChangedSignal(); } diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 2a9a617b..00670fe0 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -106,14 +106,14 @@ private: class StapLauncher : public ChildDeathReader { public: - StapLauncher() : _argv(0), _childPid(-1), _deathCallback(0) {} + StapLauncher() : _argv(0), _childPid(-1) {} StapLauncher(char** argv) - : _argv(argv), _childPid(-1), _deathCallback(0) + : _argv(argv), _childPid(-1) { } StapLauncher(const string& stapArgs, const string& script, const string& scriptArgs) - : _childPid(-1), _deathCallback(0), _win(0), _widget(0) + : _childPid(-1), _win(0), _widget(0) { setArgs(stapArgs, script, scriptArgs); } @@ -149,10 +149,7 @@ public: _script.clear(); _scriptArgs.clear(); } - void setDeathCallback(ChildDeathReader::Callback* callback) - { - _deathCallback = callback; - } + void setWinParams(Gtk::Window* win, GraphWidget* widget) { _win = win; @@ -163,7 +160,8 @@ public: shared_ptr makeStapParser() { shared_ptr result(new StapParser); - _parsers.push_back(result); + parsers.push_back(result); + parserListChangedSignal().emit(); return result; } private: @@ -184,14 +182,22 @@ public: if (pid < 0) return pid; ParserList::iterator itr - = find_if(_parsers.begin(), _parsers.end(), pidPred(pid)); - if (itr != _parsers.end()) - (*itr)->setProcess(tr1::shared_ptr()); + = find_if(parsers.begin(), parsers.end(), pidPred(pid)); + if (itr != parsers.end()) + { + tr1::shared_ptr sp = (*itr)->getProcess(); + if (sp) + { + sp->pid = -1; + parserListChangedSignal().emit(); + } + } + childDiedSignal().emit(pid); return pid; } void killAll() { - for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end(); + for (ParserList::iterator itr = parsers.begin(), end = parsers.end(); itr != end; ++itr) { @@ -199,15 +205,12 @@ public: kill((*itr)->getPid(), SIGTERM); } } - typedef vector > ParserList; - ParserList _parsers; protected: char** _argv; string _stapArgs; string _script; string _scriptArgs; int _childPid; - ChildDeathReader::Callback* _deathCallback; Gtk::Window* _win; GraphWidget* _widget; }; @@ -287,17 +290,9 @@ int StapLauncher::launch() proc->scriptArgs = _scriptArgs; } sp->setProcess(proc); - _parsers.push_back(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), - pipefd[0], - Glib::IO_IN | Glib::IO_HUP); + parsers.push_back(sp); + parserListChangedSignal().emit(); + sp->initIo(pipefd[0], pipefd[2]); return childPid; } @@ -313,7 +308,7 @@ void StapLauncher::cleanUp() char buf; while (read(signalPipe[0], &buf, 1) > 0) reap(); - for (ParserList::iterator itr = _parsers.begin(), end = _parsers.end(); + for (ParserList::iterator itr = parsers.begin(), end = parsers.end(); itr != end; ++itr) { @@ -331,8 +326,10 @@ void StapLauncher::cleanUp() std::cerr << "wait: killed Pid " << killedPid << " != child Pid " << childPid << "\n"; } - else if (_deathCallback) - _deathCallback->childDied(childPid); + else + { + childDiedSignal().emit(childPid); + } } } @@ -356,13 +353,16 @@ class ProcModelColumns : public Gtk::TreeModelColumnRecord public: ProcModelColumns() { + add(_iconName); add(_scriptName); add(_proc); } + Gtk::TreeModelColumn _iconName; Gtk::TreeModelColumn _scriptName; Gtk::TreeModelColumn > _proc; }; +// This should probably be a Gtk window, with the appropriate glade magic class ProcWindow { public: @@ -372,10 +372,20 @@ public: Gtk::Window* _window; Gtk::TreeView* _dataTreeView; Glib::RefPtr _listStore; + Glib::RefPtr _listSelection; void onClose(); + void show(); + void hide(); + void onParserListChanged(); + void onSelectionChanged(); + void onKill(); +private: + bool _open; + void refresh(); }; ProcWindow::ProcWindow() + : _open(false) { try { @@ -390,12 +400,27 @@ ProcWindow::ProcWindow() throw; } _listStore = Gtk::ListStore::create(_modelColumns); - _dataTreeView->set_model(_listStore); + _dataTreeView->set_model(_listStore); + // Display a nice icon for the state of the process + Gtk::CellRendererPixbuf* cell = Gtk::manage(new Gtk::CellRendererPixbuf); + _dataTreeView->append_column("State", *cell); + Gtk::TreeViewColumn* column = _dataTreeView->get_column(0); + if (column) + column->add_attribute(cell->property_icon_name(), _modelColumns._iconName); _dataTreeView->append_column("Script", _modelColumns._scriptName); Gtk::Button* button = 0; _xml->get_widget("button5", button); button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onClose), false); + _xml->get_widget("button1", button); + button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onKill), + false); + parserListChangedSignal() + .connect(sigc::mem_fun(*this, &ProcWindow::onParserListChanged)); + _listSelection = _dataTreeView->get_selection(); + _listSelection->signal_changed() + .connect(sigc::mem_fun(*this, &ProcWindow::onSelectionChanged)); + } void ProcWindow::onClose() @@ -403,6 +428,63 @@ void ProcWindow::onClose() _window->hide(); } +void ProcWindow::show() +{ + _open = true; + refresh(); + _window->show(); + +} + +void ProcWindow::hide() +{ + _open = false; + _window->hide(); +} + +void ProcWindow::refresh() +{ + _listStore->clear(); + for (ParserList::iterator spitr = parsers.begin(), end = parsers.end(); + spitr != end; + ++spitr) + { + shared_ptr sp = (*spitr)->getProcess(); + if (sp) + { + Gtk::TreeModel::iterator litr = _listStore->append(); + Gtk::TreeModel::Row row = *litr; + row[_modelColumns._iconName] = sp->pid >= 0 ? "gtk-yes" : "gtk-no"; + row[_modelColumns._scriptName] = sp->script; + row[_modelColumns._proc] = sp; + } + } +} + +void ProcWindow::onParserListChanged() +{ + if (_open) + { + refresh(); + _window->queue_draw(); + } +} + +void ProcWindow::onSelectionChanged() +{ +} + +void ProcWindow::onKill() +{ + Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + if (!itr) + return; + Gtk::TreeModel::Row row = *itr; + shared_ptr proc = row[_modelColumns._proc]; + if (proc->pid >= 0) + kill(proc->pid, SIGTERM); +} + class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback { public: @@ -411,7 +493,6 @@ public: Gtk::VBox m_Box; Gtk::ScrolledWindow scrolled; GraphWidget w; - void childDied(int pid); void setGraphicalLauncher(GraphicalStapLauncher* launcher) { _graphicalLauncher = launcher; @@ -505,30 +586,9 @@ void GrapherWindow::on_menu_script_start() void GrapherWindow::on_menu_proc_window() { - _procWindow->_listStore->clear(); - for (StapLauncher::ParserList::iterator spitr - = _graphicalLauncher->_parsers.begin(), - end = _graphicalLauncher->_parsers.end(); - spitr != end; - ++spitr) - { - shared_ptr sp = (*spitr)->getProcess(); - Gtk::TreeModel::iterator litr = _procWindow->_listStore->append(); - Gtk::TreeModel::Row row = *litr; - if (sp) - row[_procWindow->_modelColumns._scriptName] = sp->script; - } - _procWindow->_window->show(); + _procWindow->show(); } -void GrapherWindow::childDied(int pid) -{ - hide(); -} - - - - int main(int argc, char** argv) { Gtk::Main app(argc, argv); @@ -553,7 +613,6 @@ int main(int argc, char** argv) else if (argc > 1) { launcher.setArgv(argv + 1); - launcher.setDeathCallback(&win); launcher.launch(); } Gtk::Main::run(win); diff --git a/grapher/processwindow.glade b/grapher/processwindow.glade index ad1bdd14..3886cb34 100644 --- a/grapher/processwindow.glade +++ b/grapher/processwindow.glade @@ -263,23 +263,60 @@ 0 - - 17 + True - label1 - False - False - GTK_JUSTIFY_LEFT - False - False - 0 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 + False + 0 + + + + True + stap arguments: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + 0 @@ -288,6 +325,69 @@ + + + True + False + 0 + + + + True + script arguments: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + True + True + + + True -- cgit From 268c22b1917243cf1c02f8e1ca39ee83c7297ccc Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 4 Dec 2009 07:37:56 +0300 Subject: Fix regression in statistic operations In commit 98c783852039061db8c1611742660aaded0eab77 ("Use proper types for do_div") I imprudently changed some variables to an unsigned type while in some places the code actually relies on a sign. So, let's be a bit smarter now and use temporary variables. Reported-by: Wenji Huang Signed-off-by: Anton Vorontsov --- runtime/stat-common.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/runtime/stat-common.c b/runtime/stat-common.c index f9703049..fabe8404 100644 --- a/runtime/stat-common.c +++ b/runtime/stat-common.c @@ -34,9 +34,10 @@ static int _stp_stat_calc_buckets(int stop, int start, int interval) return buckets; } -static int needed_space(uint64_t v) +static int needed_space(int64_t v) { int space = 0; + uint64_t tmp; if (v == 0) return 1; @@ -45,9 +46,10 @@ static int needed_space(uint64_t v) space++; v = -v; } - while (v) { + tmp = v; + while (tmp) { /* v /= 10; */ - do_div (v, 10); + do_div(tmp, 10); space++; } return space; @@ -134,7 +136,8 @@ static void _stp_stat_print_histogram_buf(char *buf, size_t size, Hist st, stat { int scale, i, j, val_space, cnt_space; int low_bucket = -1, high_bucket = 0, over = 0, under = 0; - uint64_t val, v, valmax = 0; + int64_t val, valmax = 0; + uint64_t v; int eliding = 0; char *cur_buf = buf, *fake = buf; char **bufptr = (buf == NULL ? &fake : &cur_buf); @@ -282,7 +285,7 @@ static void _stp_stat_print_histogram(Hist st, stat *sd) _stp_print_flush(); } -static void __stp_stat_add (Hist st, stat *sd, uint64_t val) +static void __stp_stat_add(Hist st, stat *sd, int64_t val) { int n; if (sd->count == 0) { @@ -310,7 +313,10 @@ static void __stp_stat_add (Hist st, stat *sd, uint64_t val) if (val < 0) val = 0; else { - do_div (val, st->interval); + uint64_t tmp = val; + + do_div(tmp, st->interval); + val = tmp; val++; } -- cgit From b25c01a187d636f1bd3c8c414e7dbe3e84c1b266 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 9 Dec 2009 17:30:52 -0800 Subject: Begin to parameterize loc2c for proper DWARF target address size. * loc2c.c (stack_slot_type): New function. (translate): Use it in place of STACK_TYPE and UTYPE macros. (emit_loc_address, emit_loc_value, c_emit_location): Likewise. --- loc2c.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/loc2c.c b/loc2c.c index 008d5a42..d3ec55fa 100644 --- a/loc2c.c +++ b/loc2c.c @@ -76,6 +76,15 @@ struct location }; }; +/* Select the C type to use in the emitted code to represent slots in the + DWARF expression stack. For really proper semantics this should be the + target address size. */ +static const char * +stack_slot_type (struct location *context __attribute__ ((unused)), bool sign) +{ + return sign ? STACK_TYPE : UTYPE; +} + static struct location * alloc_location (struct obstack *pool, struct location *origin) { @@ -491,7 +500,8 @@ translate (struct obstack *pool, int indent, Dwarf_Addr addrbias, POP (b); POP (a); push ("(%s) " STACKFMT " >> (%s)" STACKFMT, - UTYPE, a, UTYPE, b); + stack_slot_type (loc, true), a, + stack_slot_type (loc, true), b); break; } @@ -2187,7 +2197,8 @@ emit_loc_address (FILE *out, struct location *loc, unsigned int indent, else { emit ("%*s{\n", indent * 2, ""); - emit ("%*s%s " STACKFMT, (indent + 1) * 2, "", STACK_TYPE, 0); + emit ("%*s%s " STACKFMT, (indent + 1) * 2, "", + stack_slot_type (loc, false), 0); unsigned i; for (i = 1; i < loc->address.stack_depth; ++i) emit (", " STACKFMT, i); @@ -2207,7 +2218,7 @@ emit_loc_value (FILE *out, struct location *loc, unsigned int indent, bool *used_deref, unsigned int *max_stack) { if (declare) - emit ("%*s%s %s;\n", indent * 2, "", STACK_TYPE, target); + emit ("%*s%s %s;\n", indent * 2, "", stack_slot_type (loc, false), target); emit_header (out, loc, indent++); @@ -2260,7 +2271,7 @@ c_emit_location (FILE *out, struct location *loc, int indent, { if (l->byte_size == 0 || l->byte_size == (Dwarf_Word) -1) emit ("%*s%s %s;\n", (indent + 1) * 2, "", - STACK_TYPE, l->address.declare); + stack_slot_type (l, false), l->address.declare); else emit ("%*suint%" PRIu64 "_t %s;\n", (indent + 1) * 2, "", l->byte_size * 8, l->address.declare); -- cgit From f8e5918969fb63a6148c906025e4ec1f010ca6c6 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 10 Dec 2009 13:13:30 +0100 Subject: grapher: change SIGCHLD handling and exit cleanup The signal handler now calls waitpid() and writes the pid and status to its pipe. * grapher.cxx (ChildInfo): new class (handleChild): wait for zombies and write their status down the pipe. (ChildDeathReader::ioCallback): Read dead child's pid from signal handler pipe and emit signal. (ChildDeathReader::reap): delete (ChildDeathReader::Callback): delete (StapLauncher::StapLauncher): Connect to childDied signal. (StapLauncher setWinParams, reap, cleanUp): delete (onChildDied): new function that updates the parsers list when a child dies. (GrapherWindow): Remove ChildDeathReader::Callback base class (GrapherWindow::onParserListChanged): New function; exits if program is quitting and no parsers are left. (on_menu_file_quit): Kill all children; don't hide (and exit) unless there are no parsers. (main): Don't do any cleanup after Gtk loop exits. --- grapher/grapher.cxx | 210 ++++++++++++++++++++++++---------------------------- 1 file changed, 95 insertions(+), 115 deletions(-) diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 00670fe0..8e7a4dba 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -46,59 +46,78 @@ using namespace systemtap; // magic for noticing that the child stap process has died. int signalPipe[2] = {-1, -1}; +struct ChildInfo + { + pid_t pid; + int waitInfo; +}; + 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); - } + { + void handleChild(int signum, siginfo_t* info, void* context) + { + struct ChildInfo childInfo; + ssize_t err; + + // Loop doing waitpid because the SIGCHLD signal isn't queued; + // multiple signals might get lost. If we get an error because + // there are no zombie children (return value <= 0 because of + // WNOHANG or no children exist at all), assume that an earlier + // invocation of handleChild already cleaned them up. + while ((childInfo.pid = waitpid(-1, &childInfo.waitInfo, WNOHANG))) + { + if (childInfo.pid < 0 && errno != ECHILD) + { + char errbuf[256]; + strerror_r(errno, errbuf, sizeof(errbuf)); + err = write(STDERR_FILENO, errbuf, strlen(errbuf)); + err = write(STDERR_FILENO, "\n", 1); + return; + } + else if (childInfo.pid > 0) + { + err = write(signalPipe[1], &childInfo, sizeof(childInfo)); + } + else + return; + } + } } // Waits for a gtk I/O signal, indicating that a child has died, then // performs an action class ChildDeathReader + { + public: + ChildDeathReader() : sigfd(-1) {} + ChildDeathReader(int sigfd_) : sigfd(sigfd_) {} + int getSigfd() { return sigfd; } + void setSigfd(int sigfd_) { sigfd = sigfd_; } + + bool ioCallback(Glib::IOCondition ioCondition) + { + if ((ioCondition & Glib::IO_IN) == 0) + return true; + ChildInfo info; + if (read(sigfd, &info, sizeof(info)) < static_cast(sizeof(info))) + cerr << "couldn't read ChildInfo from signal handler\n"; + else + childDiedSignal().emit(info.pid); + return true; + } +private: + int sigfd; +}; + +struct PidPred { -public: - struct Callback - { - virtual ~Callback() {} - virtual void childDied(int pid) {} - }; - ChildDeathReader() : sigfd(-1) {} - ChildDeathReader(int sigfd_) : sigfd(sigfd_) {} - int getSigfd() { return sigfd; } - void setSigfd(int sigfd_) { sigfd = sigfd_; } - virtual pid_t reap() + PidPred(pid_t pid_) : pid(pid_) {} + bool operator()(const shared_ptr& parser) const { - pid_t pid; - int status; - if ((pid = waitpid(-1, &status, WNOHANG)) == -1) - { - std::perror("waitpid"); - return -1; - } - else - { - return pid; - } + return parser->getPid() == pid; } - bool ioCallback(Glib::IOCondition ioCondition) - { - if ((ioCondition & Glib::IO_IN) == 0) - return true; - char buf; - - if (read(sigfd, &buf, 1) <= 0) - return true; - reap(); - return true; - } -private: - int sigfd; + pid_t pid; }; // Depending on how args are passed, either launch stap directly or @@ -106,14 +125,18 @@ private: class StapLauncher : public ChildDeathReader { public: - StapLauncher() : _argv(0), _childPid(-1) {} + StapLauncher() : _argv(0), _childPid(-1) + { + childDiedSignal().connect(sigc::mem_fun(*this, &StapLauncher::onChildDied)); + } StapLauncher(char** argv) : _argv(argv), _childPid(-1) { + childDiedSignal().connect(sigc::mem_fun(*this, &StapLauncher::onChildDied)); } StapLauncher(const string& stapArgs, const string& script, const string& scriptArgs) - : _childPid(-1), _win(0), _widget(0) + : _childPid(-1) { setArgs(stapArgs, script, scriptArgs); } @@ -150,13 +173,7 @@ public: _scriptArgs.clear(); } - void setWinParams(Gtk::Window* win, GraphWidget* widget) - { - _win = win; - _widget = widget; - } int launch(); - void cleanUp(); shared_ptr makeStapParser() { shared_ptr result(new StapParser); @@ -164,25 +181,11 @@ public: parserListChangedSignal().emit(); return result; } -private: - struct pidPred - { - pidPred(pid_t pid_) : pid(pid_) {} - bool operator()(const shared_ptr& parser) const - { - return parser->getPid() == pid; - } - pid_t pid; - }; public: - pid_t reap() + void onChildDied(pid_t pid) { - using namespace boost; - pid_t pid = ChildDeathReader::reap(); - if (pid < 0) - return pid; ParserList::iterator itr - = find_if(parsers.begin(), parsers.end(), pidPred(pid)); + = find_if(parsers.begin(), parsers.end(), PidPred(pid)); if (itr != parsers.end()) { tr1::shared_ptr sp = (*itr)->getProcess(); @@ -192,12 +195,12 @@ public: parserListChangedSignal().emit(); } } - childDiedSignal().emit(pid); - return pid; } void killAll() { - for (ParserList::iterator itr = parsers.begin(), end = parsers.end(); + ParserList parsersCopy(parsers.begin(), parsers.end()); + for (ParserList::iterator itr = parsersCopy.begin(), + end = parsersCopy.end(); itr != end; ++itr) { @@ -211,8 +214,6 @@ protected: string _script; string _scriptArgs; int _childPid; - Gtk::Window* _win; - GraphWidget* _widget; }; int StapLauncher::launch() @@ -296,43 +297,6 @@ int StapLauncher::launch() return childPid; } -void StapLauncher::cleanUp() -{ - 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) - { - pid_t childPid = (*itr)->getPid(); - if (childPid > 0) - kill(childPid, SIGTERM); - int status; - pid_t killedPid = -1; - if ((killedPid = wait(&status)) == -1) - { - std::perror("wait"); - } - else if (killedPid != childPid) - { - std::cerr << "wait: killed Pid " << killedPid << " != child Pid " - << childPid << "\n"; - } - else - { - childDiedSignal().emit(childPid); - } - } -} - class GraphicalStapLauncher : public StapLauncher { public: @@ -485,7 +449,7 @@ void ProcWindow::onKill() kill(proc->pid, SIGTERM); } -class GrapherWindow : public Gtk::Window, public ChildDeathReader::Callback +class GrapherWindow : public Gtk::Window { public: GrapherWindow(); @@ -503,21 +467,24 @@ protected: virtual void on_menu_script_start(); virtual void on_menu_proc_window(); void addGraph(); + void onParserListChanged(); // menu support Glib::RefPtr m_refUIManager; Glib::RefPtr m_refActionGroup; GraphicalStapLauncher* _graphicalLauncher; shared_ptr _procWindow; + bool _quitting; }; GrapherWindow::GrapherWindow() - : _procWindow(new ProcWindow) + : _procWindow(new ProcWindow), _quitting(false) { set_title("systemtap grapher"); add(m_Box); - + parserListChangedSignal() + .connect(sigc::mem_fun(*this, &GrapherWindow::onParserListChanged)); //Create actions for menus and toolbars: m_refActionGroup = Gtk::ActionGroup::create(); //File menu: @@ -575,7 +542,13 @@ GrapherWindow::GrapherWindow() void GrapherWindow::on_menu_file_quit() { - hide(); + using namespace boost; + _quitting = true; + if (find_if(parsers.begin(), parsers.end(), !bind(PidPred(-1), _1)) + != parsers.end()) + _graphicalLauncher->killAll(); + else + hide(); } void GrapherWindow::on_menu_script_start() @@ -589,6 +562,15 @@ void GrapherWindow::on_menu_proc_window() _procWindow->show(); } +void GrapherWindow::onParserListChanged() +{ + using namespace boost; + if (_quitting + && (find_if(parsers.begin(), parsers.end(), !bind(PidPred(-1), _1)) + == parsers.end())) + hide(); +} + int main(int argc, char** argv) { Gtk::Main app(argc, argv); @@ -597,7 +579,6 @@ int main(int argc, char** argv) win.set_title("Grapher"); win.set_default_size(600, 250); - launcher.setWinParams(&win, &win.w); win.setGraphicalLauncher(&launcher); @@ -616,7 +597,6 @@ int main(int argc, char** argv) launcher.launch(); } Gtk::Main::run(win); - launcher.cleanUp(); return 0; } -- cgit From b35632fd3d2547414c80023c5c60c847e3dc92ea Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 10 Dec 2009 15:11:08 +0100 Subject: grapher: more implementation stap process window The process arguments are displayed, and the "kill" button is insensitive when a process is dead or nothing is selected. * grapher/grapher.cxx (ProcWindow _killButton, _restartButton, _stapArgsLabel, _scriptArgsLabel): new members (ProcWindow::ProcWindow): hook 'em up (ProcWindow::onSelectionChanged): Enable / disable kill button and display process arguments. * grapher/processwindow.glade: Replace bizzare handle window with a horizontal pane. Tweak various widget sizes. --- grapher/grapher.cxx | 38 +++++- grapher/processwindow.glade | 290 +++++++++++++++++++++----------------------- 2 files changed, 173 insertions(+), 155 deletions(-) diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 8e7a4dba..e3d5289a 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -335,6 +335,10 @@ public: Glib::RefPtr _xml; Gtk::Window* _window; Gtk::TreeView* _dataTreeView; + Gtk::Button* _killButton; + Gtk::Button* _restartButton; + Gtk::Label* _stapArgsLabel; + Gtk::Label* _scriptArgsLabel; Glib::RefPtr _listStore; Glib::RefPtr _listSelection; void onClose(); @@ -376,15 +380,19 @@ ProcWindow::ProcWindow() _xml->get_widget("button5", button); button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onClose), false); - _xml->get_widget("button1", button); - button->signal_clicked().connect(sigc::mem_fun(*this, &ProcWindow::onKill), - false); + _xml->get_widget("button1", _killButton); + _killButton->signal_clicked() + .connect(sigc::mem_fun(*this, &ProcWindow::onKill), false); + _killButton->set_sensitive(false); + _xml->get_widget("button2", _restartButton); + _restartButton->set_sensitive(false); parserListChangedSignal() .connect(sigc::mem_fun(*this, &ProcWindow::onParserListChanged)); _listSelection = _dataTreeView->get_selection(); _listSelection->signal_changed() .connect(sigc::mem_fun(*this, &ProcWindow::onSelectionChanged)); - + _xml->get_widget("label7", _stapArgsLabel); + _xml->get_widget("label8", _scriptArgsLabel); } void ProcWindow::onClose() @@ -436,6 +444,28 @@ void ProcWindow::onParserListChanged() void ProcWindow::onSelectionChanged() { + Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + shared_ptr proc; + if (itr) + { + Gtk::TreeModel::Row row = *itr; + proc = row[_modelColumns._proc]; + } + if (proc) + { + if (proc->pid >= 0) + _killButton->set_sensitive(true); + else + _killButton->set_sensitive(false); + _stapArgsLabel->set_text(proc->stapArgs); + _scriptArgsLabel->set_text(proc->scriptArgs); + } + else + { + _killButton->set_sensitive(false); + _stapArgsLabel->set_text(""); + _scriptArgsLabel->set_text(""); + } } void ProcWindow::onKill() diff --git a/grapher/processwindow.glade b/grapher/processwindow.glade index 3886cb34..a598fba6 100644 --- a/grapher/processwindow.glade +++ b/grapher/processwindow.glade @@ -212,10 +212,9 @@ - + True - False - 0 + True @@ -228,7 +227,7 @@ - 300 + 250 True True True @@ -242,81 +241,41 @@ - 0 - True - True + True + False - - 26 + + 124 True - GTK_SHADOW_OUT - GTK_POS_LEFT - GTK_POS_TOP + False + 0 - + True False 0 - + True - False - 0 - - - - True - stap arguments: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - - - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - + stap arguments: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 0 @@ -326,111 +285,140 @@ - + True - False - 0 + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + False + False + + - - - True - script arguments: - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - + + + True + False + 0 - - - True - - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - PANGO_ELLIPSIZE_NONE - -1 - False - 0 - - - 0 - False - False - - + + + True + script arguments: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 0 - True - True + False + False - + True - True - GTK_POLICY_ALWAYS - GTK_POLICY_ALWAYS - GTK_SHADOW_IN - GTK_CORNER_TOP_LEFT - - - - 20 - True - True - True - False - True - GTK_JUSTIFY_LEFT - GTK_WRAP_NONE - True - 0 - 0 - 0 - 0 - 0 - 0 - - - + + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 0 - True - True + False + False + + 0 + True + True + + + + + + True + True + GTK_POLICY_ALWAYS + GTK_POLICY_ALWAYS + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + 20 + True + True + True + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_NONE + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + 0 + True + True + - 0 - True - True + True + True -- cgit From 1b9fad80af5504ef03c2a88504dbc47bea003721 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Thu, 10 Dec 2009 21:34:27 +0100 Subject: grapher: integrate graph events from stdin with the stap process framework. This was the original way to do graphing and had bitrotted some. * grapher/StapParser.cxx (initIO): new catchHUP argument (ioCallback): Only disconnect signals, etc. on IN_HUP if catchHUP is true. (errIoCallback): Write error messages to stderr, not stdout. * grapher/grapher.cxx (StapLauncher::launch): Don't catchHUP on our stap process children. (ProcWindow::refresh): Display something reasonable for the stap "process" that is feeding stdin. (main): Use StapParser::initIO to initialize parser reading from stdin. --- grapher/StapParser.cxx | 31 ++++++++++++++++++++----------- grapher/StapParser.hxx | 5 +++-- grapher/grapher.cxx | 17 +++++++++-------- 3 files changed, 32 insertions(+), 21 deletions(-) diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index a9a5109a..2513680b 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -86,9 +86,12 @@ vector commaSplit(const boost::sub_range& range) using namespace boost; if (ioCondition & Glib::IO_HUP) { - childDiedSignal().emit(getPid()); - _ioConnection.disconnect(); - _errIoConnection.disconnect(); + if (_catchHUP) + { + childDiedSignal().emit(getPid()); + _ioConnection.disconnect(); + _errIoConnection.disconnect(); + } return true; } if ((ioCondition & Glib::IO_IN) == 0) @@ -261,22 +264,28 @@ vector commaSplit(const boost::sub_range& range) cerr << "StapParser: error reading from stderr!\n"; return true; } - if (write(STDOUT_FILENO, buf, bytes_read) < 0) + if (write(STDERR_FILENO, buf, bytes_read) < 0) ; return true; } - void StapParser::initIo(int inFd, int errFd) + void StapParser::initIo(int inFd, int errFd, bool catchHUP) { _inFd = inFd; _errFd = errFd; + _catchHUP = catchHUP; + Glib::IOCondition inCond = Glib::IO_IN; + if (catchHUP) + inCond |= Glib::IO_HUP; + if (_errFd >= 0) + { + _errIoConnection = Glib::signal_io() + .connect(sigc::mem_fun(*this, &StapParser::errIoCallback), + _errFd, Glib::IO_IN); + } _ioConnection = Glib::signal_io() - .connect(sigc::mem_fun(*this, &StapParser::errIoCallback), - _errFd, - Glib::IO_IN); - _errIoConnection = Glib::signal_io() .connect(sigc::mem_fun(*this, &StapParser::ioCallback), - _inFd, - Glib::IO_IN | Glib::IO_HUP); + _inFd, inCond); + } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index 4dd711e6..24e84fc9 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -37,12 +37,13 @@ namespace systemtap int _errFd; int _inFd; unsigned char _lineEndChar; + bool _catchHUP; std::tr1::shared_ptr _process; sigc::connection _ioConnection; sigc::connection _errIoConnection; public: StapParser() - : _errFd(-1), _inFd(-1), _lineEndChar('\n') + : _errFd(-1), _inFd(-1), _lineEndChar('\n'), _catchHUP(false) { } void parseData(std::tr1::shared_ptr gdata, @@ -65,7 +66,7 @@ namespace systemtap { _process = process; } - void initIo(int inFd, int errFd); + void initIo(int inFd, int errFd, bool catchHUP); }; sigc::signal& childDiedSignal(); diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index e3d5289a..6dead221 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -293,7 +293,7 @@ int StapLauncher::launch() sp->setProcess(proc); parsers.push_back(sp); parserListChangedSignal().emit(); - sp->initIo(pipefd[0], pipefd[2]); + sp->initIo(pipefd[0], pipefd[2], false); return childPid; } @@ -422,14 +422,19 @@ void ProcWindow::refresh() ++spitr) { shared_ptr sp = (*spitr)->getProcess(); + Gtk::TreeModel::iterator litr = _listStore->append(); + Gtk::TreeModel::Row row = *litr; if (sp) { - Gtk::TreeModel::iterator litr = _listStore->append(); - Gtk::TreeModel::Row row = *litr; row[_modelColumns._iconName] = sp->pid >= 0 ? "gtk-yes" : "gtk-no"; row[_modelColumns._scriptName] = sp->script; row[_modelColumns._proc] = sp; } + else + { + row[_modelColumns._iconName] = "gtk-yes"; + row[_modelColumns._scriptName] = "standard input"; + } } } @@ -615,11 +620,7 @@ int main(int argc, char** argv) if (argc == 2 && !std::strcmp(argv[1], "-")) { tr1::shared_ptr 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); + sp->initIo(STDIN_FILENO, -1, true); } else if (argc > 1) { -- cgit From 7f707e2cb5d4e3a6a097ae9d5fdb9883ee7a81e0 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 10 Dec 2009 17:01:10 -0500 Subject: runtime: print stp_alloc statistics in startup printk * runtime/alloc.c: Define DEBUG_MEM. * runtime/print.c (_stp_print_kernel_info): Reformat/rescale mem values. --- runtime/alloc.c | 2 +- runtime/print.c | 31 ++++++++++++------------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/runtime/alloc.c b/runtime/alloc.c index 403d20ee..6c2bd66d 100644 --- a/runtime/alloc.c +++ b/runtime/alloc.c @@ -16,7 +16,7 @@ static int _stp_allocated_net_memory = 0; #define STP_ALLOC_FLAGS (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN) -//#define DEBUG_MEM +#define DEBUG_MEM /* * If DEBUG_MEM is defined (stap -DDEBUG_MEM ...) then full memory * tracking is used. Each allocation is recorded and matched with diff --git a/runtime/print.c b/runtime/print.c index 335403fb..09ebd05e 100644 --- a/runtime/print.c +++ b/runtime/print.c @@ -217,14 +217,8 @@ static void _stp_print_char (const char c) static void _stp_print_kernel_info(char *vstr, int ctx, int num_probes) { printk(KERN_DEBUG - "%s: systemtap: %s, base: %p, memory: %lu+%lu+%u+%u" -#ifdef DEBUG_MEM - "+%u" -#endif - " data+text+ctx+net" -#ifdef DEBUG_MEM - "+alloc" -#endif + "%s: systemtap: %s, base: %p" + ", memory: %ludata/%lutext/%uctx/%unet/%ualloc kb" ", probes: %d" #ifndef STP_PRIVILEGED ", unpriv-uid: %d" @@ -234,19 +228,18 @@ static void _stp_print_kernel_info(char *vstr, int ctx, int num_probes) vstr, #ifndef STAPCONF_GRSECURITY THIS_MODULE->module_core, - (unsigned long) (THIS_MODULE->core_size - THIS_MODULE->core_text_size), - (unsigned long) THIS_MODULE->core_text_size, + (unsigned long) (THIS_MODULE->core_size - THIS_MODULE->core_text_size)/1024, + (unsigned long) (THIS_MODULE->core_text_size)/1024, #else - THIS_MODULE->module_core_rx, - (unsigned long) (THIS_MODULE->core_size_rw - THIS_MODULE->core_size_rx), - (unsigned long) THIS_MODULE->core_size_rx, -#endif - ctx, - _stp_allocated_net_memory, -#ifdef DEBUG_MEM - _stp_allocated_memory - _stp_allocated_net_memory, + THIS_MODULE->module_core_rx, + (unsigned long) (THIS_MODULE->core_size_rw - THIS_MODULE->core_size_rx)/1024, + (unsigned long) (THIS_MODULE->core_size_rx)/1024, #endif - num_probes + ctx/1024, + _stp_allocated_net_memory/1024, + (_stp_allocated_memory - _stp_allocated_net_memory - ctx)/1024, + /* (un-double-counting net/ctx because they're also stp_alloc'd) */ + num_probes #ifndef STP_PRIVILEGED , _stp_uid #endif -- cgit From e83324285bb277300f5c91ee1c2a39bf04df502d Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Thu, 10 Dec 2009 17:52:56 -0500 Subject: runtime: undefine DEBUG_MEM, retain alloc counting DEBUG_MEM can & does evoke locking timeouts. * runtime/alloc.c (*): Track __stp_allocated_memory regardless of DEBUG_MEM. --- runtime/alloc.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/runtime/alloc.c b/runtime/alloc.c index 6c2bd66d..7b072900 100644 --- a/runtime/alloc.c +++ b/runtime/alloc.c @@ -16,7 +16,7 @@ static int _stp_allocated_net_memory = 0; #define STP_ALLOC_FLAGS (GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN) -#define DEBUG_MEM +/* #define DEBUG_MEM */ /* * If DEBUG_MEM is defined (stap -DDEBUG_MEM ...) then full memory * tracking is used. Each allocation is recorded and matched with @@ -32,10 +32,10 @@ static int _stp_allocated_net_memory = 0; * would be nice, but DEBUG_MEM is only for testing. */ -#ifdef DEBUG_MEM +static int _stp_allocated_memory = 0; +#ifdef DEBUG_MEM static DEFINE_SPINLOCK(_stp_mem_lock); -static int _stp_allocated_memory = 0; #define MEM_MAGIC 0xc11cf77f #define MEM_FENCE_SIZE 32 @@ -176,11 +176,11 @@ static void _stp_mem_debug_free(void *addr, enum _stp_memtype type) static void *_stp_kmalloc(size_t size) { + _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); - _stp_allocated_memory += size; } return ret; #else @@ -191,12 +191,12 @@ static void *_stp_kmalloc(size_t size) static void *_stp_kzalloc(size_t size) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) { + _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); memset (ret, 0, size); - _stp_allocated_memory += size; } #else void *ret = kmalloc(size, STP_ALLOC_FLAGS); @@ -207,11 +207,11 @@ static void *_stp_kzalloc(size_t size) } #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */ { + _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kzalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); - _stp_allocated_memory += size; } return ret; #else @@ -222,11 +222,11 @@ static void *_stp_kzalloc(size_t size) static void *_stp_vmalloc(unsigned long size) { + _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = __vmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS, PAGE_KERNEL); if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_VMALLOC); - _stp_allocated_memory += size; } return ret; #else @@ -248,6 +248,8 @@ static void *_stp_alloc_percpu(size_t size) if (size > _STP_MAX_PERCPU_SIZE) return NULL; + _stp_allocated_memory += size * num_online_cpus(); + #ifdef STAPCONF_ALLOC_PERCPU_ALIGN ret = __alloc_percpu(size, 8); #else @@ -261,7 +263,6 @@ static void *_stp_alloc_percpu(size_t size) return NULL; } _stp_mem_debug_percpu(m, ret, size); - _stp_allocated_memory += size * num_online_cpus(); } #endif return ret; @@ -272,11 +273,11 @@ static void *_stp_alloc_percpu(size_t size) #else static void *_stp_kmalloc_node(size_t size, int node) { + _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kmalloc_node(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS, node); if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); - _stp_allocated_memory += size; } return ret; #else -- cgit From e47f92ea31a605802c59541ca325ffd567c45ca4 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Fri, 11 Dec 2009 14:03:47 +0100 Subject: grapher: implement restarting a stap process * grapher/StapParser.cxx (StapParser::disconnect): new function * grapher/StapParser.hxx (StapProcess::StapProcess): initialize argv to 0 * grapher/grapher.cxx (StapLauncher::setArgs): Set argv to 0 (StapLauncher launch, launchUsingParser): Refactor launch(), extracting function a that (re)launches a stap process using an existing parser. (StapLauncher::onChildDied): call disconnect() on dead parser. (GrapherWindow::_graphicalLauncher, setGraphicalLauncher): delete member, replacing with... (graphicalLauncher): new variable (ProcModelColumns): Store parser object in the list model instead of just a StapProcess object. (ProcWindow::onRestart): new function (ProcWindow::refresh): Preserve the list selection when the process list is refreshed. (ProcWindow::onSelectionChanged): Manage the restart button's state. --- grapher/StapParser.cxx | 18 ++++++ grapher/StapParser.hxx | 3 +- grapher/grapher.cxx | 155 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 128 insertions(+), 48 deletions(-) diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx index 2513680b..2595e8cc 100644 --- a/grapher/StapParser.cxx +++ b/grapher/StapParser.cxx @@ -288,4 +288,22 @@ vector commaSplit(const boost::sub_range& range) _inFd, inCond); } + + void StapParser::disconnect() + { + if (_ioConnection.connected()) + _ioConnection.disconnect(); + if (_errIoConnection.connected()) + _errIoConnection.disconnect(); + if (_inFd >= 0) + { + close(_inFd); + _inFd = -1; + } + if (_errFd >= 0) + { + close(_errFd); + _errFd = -1; + } + } } diff --git a/grapher/StapParser.hxx b/grapher/StapParser.hxx index 24e84fc9..169533b6 100644 --- a/grapher/StapParser.hxx +++ b/grapher/StapParser.hxx @@ -18,7 +18,7 @@ namespace systemtap // arguments and script for a stap process struct StapProcess { - StapProcess(pid_t pid_ = -1) : pid(pid_) {} + StapProcess(pid_t pid_ = -1) : argv(0), pid(pid_) {} std::string stapArgs; std::string script; std::string scriptArgs; @@ -67,6 +67,7 @@ namespace systemtap _process = process; } void initIo(int inFd, int errFd, bool catchHUP); + void disconnect(); }; sigc::signal& childDiedSignal(); diff --git a/grapher/grapher.cxx b/grapher/grapher.cxx index 6dead221..0111184a 100644 --- a/grapher/grapher.cxx +++ b/grapher/grapher.cxx @@ -153,6 +153,7 @@ public: void setArgs(const string& stapArgs, const string& script, const string& scriptArgs) { + _argv = 0; _stapArgs = stapArgs; _script = script; _scriptArgs = scriptArgs; @@ -174,6 +175,7 @@ public: } int launch(); + int launchUsingParser(shared_ptr parser); shared_ptr makeStapParser() { shared_ptr result(new StapParser); @@ -188,6 +190,7 @@ public: = find_if(parsers.begin(), parsers.end(), PidPred(pid)); if (itr != parsers.end()) { + (*itr)->disconnect(); tr1::shared_ptr sp = (*itr)->getProcess(); if (sp) { @@ -218,7 +221,36 @@ protected: int StapLauncher::launch() { - int childPid = -1; + tr1::shared_ptr sp(new StapParser); + shared_ptr proc(new StapProcess(-1)); + if (_argv) + proc->argv = _argv; + else + { + proc->stapArgs = _stapArgs; + proc->script = _script; + proc->scriptArgs = _scriptArgs; + } + sp->setProcess(proc); + pid_t childPid = launchUsingParser(sp); + if (childPid >= 0) + { + parsers.push_back(sp); + parserListChangedSignal().emit(); + } + return childPid; +} + +int StapLauncher::launchUsingParser(shared_ptr sp) +{ + shared_ptr proc = sp->getProcess(); + if (!proc) + { + cerr << "Can't launch parser with null process structure\n"; + return -1; + } + + proc->pid = -1; if (signalPipe[0] < 0) { if (pipe(&signalPipe[0]) < 0) @@ -245,11 +277,11 @@ int StapLauncher::launch() std::perror("pipe"); exit(1); } - if ((childPid = fork()) == -1) + if ((proc->pid = fork()) == -1) { exit(1); } - else if (childPid) + else if (proc->pid) { close(pipefd[1]); close(pipefd[3]); @@ -260,41 +292,28 @@ int StapLauncher::launch() dup2(pipefd[3], STDERR_FILENO); for_each(&pipefd[0], &pipefd[4], close); for_each(&signalPipe[0], &signalPipe[2], close); - if (_argv) + if (proc->argv) { char argv0[] = "stap"; - char** argvEnd = _argv; + char** argvEnd = proc->argv; for (; *argvEnd; ++argvEnd) ; - char** realArgv = new char*[argvEnd - _argv + 2]; + char** realArgv = new char*[argvEnd - proc->argv + 2]; realArgv[0] = argv0; std::copy(_argv, argvEnd + 1, &realArgv[1]); execvp("stap", realArgv); } else { - string argString = "stap" + _stapArgs + " " + _script + " " - + _scriptArgs; + string argString = "stap" + proc->stapArgs + " " + proc->script + " " + + proc->scriptArgs; execl("/bin/sh", "sh", "-c", argString.c_str(), static_cast(0)); } _exit(1); } - tr1::shared_ptr sp(new StapParser); - shared_ptr proc(new StapProcess(childPid)); - if (_argv) - proc->argv = _argv; - else - { - proc->stapArgs = _stapArgs; - proc->script = _script; - proc->scriptArgs = _scriptArgs; - } - sp->setProcess(proc); - parsers.push_back(sp); - parserListChangedSignal().emit(); sp->initIo(pipefd[0], pipefd[2], false); - return childPid; + return proc->pid; } class GraphicalStapLauncher : public StapLauncher @@ -312,6 +331,8 @@ private: Gtk::Entry* _scriptArgEntry; }; +GraphicalStapLauncher *graphicalLauncher = 0; + class ProcModelColumns : public Gtk::TreeModelColumnRecord { public: @@ -319,11 +340,11 @@ public: { add(_iconName); add(_scriptName); - add(_proc); + add(_parser); } Gtk::TreeModelColumn _iconName; Gtk::TreeModelColumn _scriptName; - Gtk::TreeModelColumn > _proc; + Gtk::TreeModelColumn > _parser; }; // This should probably be a Gtk window, with the appropriate glade magic @@ -347,6 +368,7 @@ public: void onParserListChanged(); void onSelectionChanged(); void onKill(); + void onRestart(); private: bool _open; void refresh(); @@ -385,6 +407,8 @@ ProcWindow::ProcWindow() .connect(sigc::mem_fun(*this, &ProcWindow::onKill), false); _killButton->set_sensitive(false); _xml->get_widget("button2", _restartButton); + _restartButton->signal_clicked() + .connect(sigc::mem_fun(*this, &ProcWindow::onRestart), false); _restartButton->set_sensitive(false); parserListChangedSignal() .connect(sigc::mem_fun(*this, &ProcWindow::onParserListChanged)); @@ -416,25 +440,53 @@ void ProcWindow::hide() void ProcWindow::refresh() { + // If a process is already selected, try to leave it selected after + // the list is reconstructed. + shared_ptr selectedParser; + { + Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + if (itr) + { + Gtk::TreeModel::Row row = *itr; + selectedParser = row[_modelColumns._parser]; + } + } _listStore->clear(); for (ParserList::iterator spitr = parsers.begin(), end = parsers.end(); spitr != end; ++spitr) { - shared_ptr sp = (*spitr)->getProcess(); + shared_ptr parser = *spitr; + shared_ptr sp = parser->getProcess(); Gtk::TreeModel::iterator litr = _listStore->append(); Gtk::TreeModel::Row row = *litr; if (sp) { row[_modelColumns._iconName] = sp->pid >= 0 ? "gtk-yes" : "gtk-no"; row[_modelColumns._scriptName] = sp->script; - row[_modelColumns._proc] = sp; } else { row[_modelColumns._iconName] = "gtk-yes"; row[_modelColumns._scriptName] = "standard input"; } + row[_modelColumns._parser] = parser; + } + if (selectedParser) + { + Gtk::TreeModel::Children children = _listStore->children(); + for (Gtk::TreeModel::Children::const_iterator itr = children.begin(), + end = children.end(); + itr != end; + ++itr) + { + Gtk::TreeModel::Row row = *itr; + if (row[_modelColumns._parser] == selectedParser) + { + _listSelection->select(row); + break; + } + } } } @@ -450,24 +502,26 @@ void ProcWindow::onParserListChanged() void ProcWindow::onSelectionChanged() { Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + shared_ptr parser; shared_ptr proc; if (itr) { Gtk::TreeModel::Row row = *itr; - proc = row[_modelColumns._proc]; + parser = row[_modelColumns._parser]; + proc = parser->getProcess(); } if (proc) { - if (proc->pid >= 0) - _killButton->set_sensitive(true); - else - _killButton->set_sensitive(false); + bool procRunning = proc->pid >= 0; + _killButton->set_sensitive(procRunning); + _restartButton->set_sensitive(!procRunning); _stapArgsLabel->set_text(proc->stapArgs); _scriptArgsLabel->set_text(proc->scriptArgs); } else { _killButton->set_sensitive(false); + _restartButton->set_sensitive(false); _stapArgsLabel->set_text(""); _scriptArgsLabel->set_text(""); } @@ -479,11 +533,26 @@ void ProcWindow::onKill() if (!itr) return; Gtk::TreeModel::Row row = *itr; - shared_ptr proc = row[_modelColumns._proc]; - if (proc->pid >= 0) + shared_ptr parser = row[_modelColumns._parser]; + shared_ptr proc = parser->getProcess(); + if (proc && proc->pid >= 0) kill(proc->pid, SIGTERM); } +void ProcWindow::onRestart() +{ + Gtk::TreeModel::iterator itr = _listSelection->get_selected(); + if (!itr) + return; + Gtk::TreeModel::Row row = *itr; + shared_ptr parser = row[_modelColumns._parser]; + shared_ptr proc = parser->getProcess(); + if (!proc) + return; + if (graphicalLauncher->launchUsingParser(parser) > 0) + parserListChangedSignal().emit(); +} + class GrapherWindow : public Gtk::Window { public: @@ -492,11 +561,6 @@ public: Gtk::VBox m_Box; Gtk::ScrolledWindow scrolled; GraphWidget w; - void setGraphicalLauncher(GraphicalStapLauncher* launcher) - { - _graphicalLauncher = launcher; - } - GraphicalStapLauncher* getGraphicalLauncher() { return _graphicalLauncher; } protected: virtual void on_menu_file_quit(); virtual void on_menu_script_start(); @@ -506,7 +570,6 @@ protected: // menu support Glib::RefPtr m_refUIManager; Glib::RefPtr m_refActionGroup; - GraphicalStapLauncher* _graphicalLauncher; shared_ptr _procWindow; bool _quitting; }; @@ -581,14 +644,14 @@ void GrapherWindow::on_menu_file_quit() _quitting = true; if (find_if(parsers.begin(), parsers.end(), !bind(PidPred(-1), _1)) != parsers.end()) - _graphicalLauncher->killAll(); + graphicalLauncher->killAll(); else hide(); } void GrapherWindow::on_menu_script_start() { - _graphicalLauncher->runDialog(); + graphicalLauncher->runDialog(); } @@ -609,23 +672,21 @@ void GrapherWindow::onParserListChanged() int main(int argc, char** argv) { Gtk::Main app(argc, argv); - GraphicalStapLauncher launcher; + graphicalLauncher = new GraphicalStapLauncher; GrapherWindow win; win.set_title("Grapher"); win.set_default_size(600, 250); - win.setGraphicalLauncher(&launcher); - if (argc == 2 && !std::strcmp(argv[1], "-")) { - tr1::shared_ptr sp = launcher.makeStapParser(); + tr1::shared_ptr sp = graphicalLauncher->makeStapParser(); sp->initIo(STDIN_FILENO, -1, true); } else if (argc > 1) { - launcher.setArgv(argv + 1); - launcher.launch(); + graphicalLauncher->setArgv(argv + 1); + graphicalLauncher->launch(); } Gtk::Main::run(win); return 0; -- cgit From a48b443b8f9c1cafaf2a78bd05584f4049093920 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Fri, 11 Dec 2009 12:18:31 -0500 Subject: runtime build: fix alloc.c buildability on old gcc 3.4 * runtime/alloc.c (_stp_kmalloc): Move var decl back to top. --- runtime/alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/alloc.c b/runtime/alloc.c index 7b072900..2e98b94e 100644 --- a/runtime/alloc.c +++ b/runtime/alloc.c @@ -191,7 +191,6 @@ static void *_stp_kmalloc(size_t size) static void *_stp_kzalloc(size_t size) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) { - _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kmalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); if (likely(ret)) { @@ -200,6 +199,7 @@ static void *_stp_kzalloc(size_t size) } #else void *ret = kmalloc(size, STP_ALLOC_FLAGS); + _stp_allocated_memory += size; if (likely(ret)) memset (ret, 0, size); #endif /* DEBUG_MEM */ @@ -207,9 +207,9 @@ static void *_stp_kzalloc(size_t size) } #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15) */ { - _stp_allocated_memory += size; #ifdef DEBUG_MEM void *ret = kzalloc(size + MEM_DEBUG_SIZE, STP_ALLOC_FLAGS); + _stp_allocated_memory += size; if (likely(ret)) { ret = _stp_mem_debug_setup(ret, size, MEM_KMALLOC); } -- cgit From 81bcf6d6dd9ce44667951bf6212b6b3c8febaf31 Mon Sep 17 00:00:00 2001 From: Stan Cox Date: Fri, 11 Dec 2009 16:59:55 -0500 Subject: Use env(SYSTEMTAP_TESTAPPS) for all systemtap.apps mysql.exp: Use env(SYSTEMTAP_TESTAPPS). (mysqlrelease): Update and check for download failure. postgres.exp: Use env(SYSTEMTAP_TESTAPPS). stap-tcl.stp: Use .library("library").mark("mark"). tcl.exp: Likewise. --- testsuite/systemtap.apps/mysql.exp | 13 ++++++++++--- testsuite/systemtap.apps/postgres.exp | 6 ++++-- testsuite/systemtap.apps/stap-tcl.stp | 2 +- testsuite/systemtap.apps/tcl.exp | 6 ++++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/testsuite/systemtap.apps/mysql.exp b/testsuite/systemtap.apps/mysql.exp index efeffbae..497949c0 100644 --- a/testsuite/systemtap.apps/mysql.exp +++ b/testsuite/systemtap.apps/mysql.exp @@ -4,14 +4,16 @@ set test "mysql" global env -if {! [info exists env(SYSTEMTAP_TEST_SDT)]} { - unsupported "mysql (\"SYSTEMTAP_TEST_SDT\" not in 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-mysql.stp ########## set msdata "[pwd]/stap-mysql" -set mysqlrelease "mysql-5.4.1-beta" +set mysqlrelease "mysql-5.4.3-beta" set mysqldir "[pwd]/mysql/install/" set testsuite "[pwd]" @@ -291,6 +293,11 @@ kill \$STAPPID if \[ ! -r $mysqlrelease.tar.gz \] ; then wget http://dev.mysql.com/get/Downloads/MySQL-5.4/$mysqlrelease.tar.gz/from/ftp://mirror.services.wisc.edu/mirrors/mysql/ fi +if \[ ! -r $mysqlrelease.tar.gz \] ; then + echo FAIL: wget $mysqlrelease.tar.gz + exit +fi + if \[ ! -d mysql/src \] ; then tar -x -z -f $mysqlrelease.tar.gz diff --git a/testsuite/systemtap.apps/postgres.exp b/testsuite/systemtap.apps/postgres.exp index 2d58a54f..b7f522a1 100644 --- a/testsuite/systemtap.apps/postgres.exp +++ b/testsuite/systemtap.apps/postgres.exp @@ -4,8 +4,10 @@ set test "postgres" global env -if {! [info exists env(SYSTEMTAP_TEST_SDT)]} { - unsupported "postgres (\"SYSTEMTAP_TEST_SDT\" not in env)" +if {! [info exists env(SYSTEMTAP_TESTAPPS)] || ( + ! [string match "tcl" $env(SYSTEMTAP_TESTAPPS)] && + ! [string match "all" $env(SYSTEMTAP_TESTAPPS)])} { + untested "$test sdt app" return } diff --git a/testsuite/systemtap.apps/stap-tcl.stp b/testsuite/systemtap.apps/stap-tcl.stp index d3293b09..db3e3690 100644 --- a/testsuite/systemtap.apps/stap-tcl.stp +++ b/testsuite/systemtap.apps/stap-tcl.stp @@ -1,6 +1,6 @@ global counts -probe process(@1).mark("*") { +probe process(@1).library(@2).mark("*") { counts[$$name]<<<1 # PR10878; check also $$parms length } diff --git a/testsuite/systemtap.apps/tcl.exp b/testsuite/systemtap.apps/tcl.exp index bfcf2239..c95fa5e0 100644 --- a/testsuite/systemtap.apps/tcl.exp +++ b/testsuite/systemtap.apps/tcl.exp @@ -29,7 +29,8 @@ if {$rc != 0} { } 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] +verbose -log "spawn stap -DMAXSKIPPED=8024 -t -p4 $srcdir/$subdir/stap-tcl.stp tcl/install/bin/tclsh${tclreleasemajor} tcl/install/lib/libtcl${tclreleasemajor}.so" +set rc [catch {exec stap -DMAXSKIPPED=8024 -t -p4 $srcdir/$subdir/stap-tcl.stp tcl/install/bin/tclsh${tclreleasemajor} tcl/install/lib/libtcl${tclreleasemajor}.so} out] clone_output $out if {$rc != 0} { fail $test @@ -47,7 +48,8 @@ if {![installtest_p]} { 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 +verbose -log "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/bin/tclsh${tclreleasemajor} tcl/install/lib/libtcl${tclreleasemajor}.so" +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/bin/tclsh${tclreleasemajor} tcl/install/lib/libtcl${tclreleasemajor}.so expect { -timeout 1000 -re {^OK [^\r\n]*[\r\n]} { incr ok; exp_continue } -- cgit From 958c58e8231563e9349e4d8ea56c04c25e1501c0 Mon Sep 17 00:00:00 2001 From: Eugeniy Meshcheryakov Date: Sat, 12 Dec 2009 00:56:36 +0100 Subject: Do not use condition_codes() on arm It does not exist in recent kernels. Use regs->ARM_cpsr instead, this should work with all versions of linux found in git repo (versions >=2.6.12-rc2). Difference between condition_codes() and regs->ARM_cpsr should not matter for systemtap. --- runtime/regs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/regs.c b/runtime/regs.c index e963affa..61f2f317 100644 --- a/runtime/regs.c +++ b/runtime/regs.c @@ -267,7 +267,7 @@ static const char *processor_modes[]= static void _stp_print_regs(struct pt_regs * regs) { - unsigned long flags = condition_codes(regs); + unsigned long flags = regs->ARM_cpsr; #ifdef CONFIG_SMP _stp_printf(" CPU: %d", smp_processor_id()); -- cgit