summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buildrun.cxx5
-rw-r--r--dwflpp.cxx16
-rw-r--r--grapher/CairoWidget.cxx162
-rw-r--r--grapher/CairoWidget.hxx84
-rw-r--r--grapher/Graph.cxx386
-rw-r--r--grapher/Graph.hxx82
-rw-r--r--grapher/GraphData.hxx104
-rw-r--r--grapher/GraphStyle.cxx328
-rw-r--r--grapher/GraphStyle.hxx84
-rw-r--r--grapher/GraphWidget.cxx710
-rw-r--r--grapher/GraphWidget.hxx150
-rw-r--r--grapher/StapParser.cxx526
-rw-r--r--grapher/StapParser.hxx112
-rw-r--r--loc2c.c7
-rw-r--r--runtime/autoconf-regset.c7
-rw-r--r--runtime/autoconf-utrace-regset.c8
-rw-r--r--runtime/loc2c-runtime.h371
-rw-r--r--runtime/stack-i386.c2
-rw-r--r--runtime/stack-x86_64.c2
-rw-r--r--runtime/stack.c4
-rw-r--r--runtime/sym.c167
-rw-r--r--runtime/sym.h7
-rw-r--r--runtime/task_finder_vma.c71
-rw-r--r--runtime/transport/symbols.c2
-rw-r--r--runtime/unwind.c31
-rw-r--r--runtime/uprobes/uprobes.c38
-rw-r--r--runtime/uprobes/uprobes.h8
-rw-r--r--stapprobes.3stap.in31
-rw-r--r--tapset/context-symbols.stp4
-rw-r--r--tapsets.cxx47
-rw-r--r--testsuite/buildok/vm.tracepoints.stp31
-rw-r--r--testsuite/systemtap.base/externalvar.exp2
-rwxr-xr-xtestsuite/systemtap.examples/general/grapher.stp23
-rw-r--r--testsuite/systemtap.examples/memory/vm.tracepoints.meta13
-rw-r--r--testsuite/systemtap.examples/memory/vm.tracepoints.stp18
35 files changed, 2075 insertions, 1568 deletions
diff --git a/buildrun.cxx b/buildrun.cxx
index 0f2f05b5..48f27a3a 100644
--- a/buildrun.cxx
+++ b/buildrun.cxx
@@ -123,6 +123,9 @@ compile_pass (systemtap_session& s)
// "autoconf" options go here
+ // RHBZ 543529: early rhel6 kernels' module-signing kbuild logic breaks out-of-tree modules
+ o << "CONFIG_MODULE_SIG := n" << endl;
+
string module_cflags = "EXTRA_CFLAGS";
o << module_cflags << " :=" << endl;
@@ -162,6 +165,8 @@ compile_pass (systemtap_session& s)
output_autoconf(s, o, "autoconf-x86-gs.c", "STAPCONF_X86_GS", NULL);
output_autoconf(s, o, "autoconf-grsecurity.c", "STAPCONF_GRSECURITY", NULL);
output_autoconf(s, o, "autoconf-trace-printk.c", "STAPCONF_TRACE_PRINTK", NULL);
+ output_autoconf(s, o, "autoconf-regset.c", "STAPCONF_REGSET", NULL);
+ output_autoconf(s, o, "autoconf-utrace-regset.c", "STAPCONF_UTRACE_REGSET", NULL);
#if 0
/* NB: For now, the performance hit of probe_kernel_read/write (vs. our
diff --git a/dwflpp.cxx b/dwflpp.cxx
index 0e8a352d..4fb0d54e 100644
--- a/dwflpp.cxx
+++ b/dwflpp.cxx
@@ -1282,6 +1282,16 @@ dwflpp::resolve_prologue_endings (func_info_map_t & funcs)
continue;
}
+ if (entrypc == 0)
+ {
+ if (sess.verbose > 2)
+ clog << "null entrypc dwarf line record for function '"
+ << it->name << "'\n";
+ // This is probably an inlined function. We'll skip this instance;
+ // it is messed up.
+ continue;
+ }
+
if (sess.verbose>2)
clog << "prologue searching function '" << it->name << "'"
<< " 0x" << hex << entrypc << "-0x" << highpc << dec
@@ -1513,7 +1523,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
// This gives us the module name, and section name within the
// module, for a kernel module (or other ET_REL module object).
obstack_printf (pool, "({ unsigned long addr = 0; ");
- obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", NULL); ",
modname, secname, reloc_address);
obstack_printf (pool, "addr; })");
}
@@ -1527,7 +1537,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
// kernel will never move after being loaded (unlike modules and
// user-space dynamic share libraries).
obstack_printf (pool, "({ static unsigned long addr = 0; ");
- obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "if (addr==0) addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", NULL); ",
modname, secname, address); // PR10000 NB: not reloc_address
obstack_printf (pool, "addr; })");
}
@@ -1535,7 +1545,7 @@ dwflpp::emit_address (struct obstack *pool, Dwarf_Addr address)
{
enable_task_finder (sess);
obstack_printf (pool, "({ unsigned long addr = 0; ");
- obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 "); ",
+ obstack_printf (pool, "addr = _stp_module_relocate (\"%s\",\"%s\",%#" PRIx64 ", current); ",
modname, ".dynamic", reloc_address);
obstack_printf (pool, "addr; })");
}
diff --git a/grapher/CairoWidget.cxx b/grapher/CairoWidget.cxx
index 26c2d029..81a6d3c7 100644
--- a/grapher/CairoWidget.cxx
+++ b/grapher/CairoWidget.cxx
@@ -15,89 +15,89 @@
namespace systemtap
{
- using namespace std;
- using namespace boost;
+using namespace std;
+using namespace boost;
- void CairoPlayButton::draw(Cairo::RefPtr<Cairo::Context> cr)
- {
- if (!_visible)
- return;
- cr->save();
- cr->set_line_width(1.0);
- // square with rounded corners
- cr->move_to(_x0, _y0 + _radius);
- cr->arc(_x0 + _radius, _y0 + _radius, _radius, M_PI, -M_PI_2);
- cr->line_to(_x0 + _size - _radius, _y0);
- cr->arc(_x0 + _size - _radius, _y0 + _radius, _radius, -M_PI_2, 0.0);
- cr->line_to(_x0 + _size, _y0 + _size - _radius);
- cr->arc(_x0 + _size - _radius, _y0 + _size - _radius, _radius, 0.0, M_PI_2);
- cr->line_to(_x0 + _radius, _y0 + _size);
- cr->arc(_x0 + _radius, _y0 + _size - _radius, _radius, M_PI_2, M_PI);
- cr->close_path();
- //cr->rectangle(_x0, _y0, 50.0, 50.0);
- cr->set_source_rgba(1.0, 1.0, 1.0, .8);
- cr->stroke();
- // play equalateral triangle
- cr->move_to(_x0 + .25 * _size, _y0 + (.5 - 1.0 / (sqrt(3.0) * 2.0)) * _size);
- cr->line_to(_x0 + .75 * _size, _y0 + .5 * _size);
- cr->line_to(_x0 + .25 * _size, _y0 + (.5 + 1.0 / (sqrt(3.0) * 2.0)) * _size);
- cr->close_path();
- cr->fill();
- cr->restore();
- }
+void CairoPlayButton::draw(Cairo::RefPtr<Cairo::Context> cr)
+{
+ if (!_visible)
+ return;
+ cr->save();
+ cr->set_line_width(1.0);
+ // square with rounded corners
+ cr->move_to(_x0, _y0 + _radius);
+ cr->arc(_x0 + _radius, _y0 + _radius, _radius, M_PI, -M_PI_2);
+ cr->line_to(_x0 + _size - _radius, _y0);
+ cr->arc(_x0 + _size - _radius, _y0 + _radius, _radius, -M_PI_2, 0.0);
+ cr->line_to(_x0 + _size, _y0 + _size - _radius);
+ cr->arc(_x0 + _size - _radius, _y0 + _size - _radius, _radius, 0.0, M_PI_2);
+ cr->line_to(_x0 + _radius, _y0 + _size);
+ cr->arc(_x0 + _radius, _y0 + _size - _radius, _radius, M_PI_2, M_PI);
+ cr->close_path();
+ //cr->rectangle(_x0, _y0, 50.0, 50.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+ cr->stroke();
+ // play equalateral triangle
+ cr->move_to(_x0 + .25 * _size, _y0 + (.5 - 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->line_to(_x0 + .75 * _size, _y0 + .5 * _size);
+ cr->line_to(_x0 + .25 * _size, _y0 + (.5 + 1.0 / (sqrt(3.0) * 2.0)) * _size);
+ cr->close_path();
+ cr->fill();
+ cr->restore();
+}
- bool CairoPlayButton::containsPoint(double x, double y)
- {
- if (x >= _x0 && (x < (_x0 + 50.0)) && (y >= _y0) && (y < (_y0 + 50)))
- return true;
- else
+bool CairoPlayButton::containsPoint(double x, double y)
+{
+ if (x >= _x0 && (x < (_x0 + 50.0)) && (y >= _y0) && (y < (_y0 + 50)))
+ return true;
+ else
return false;
- }
+}
- void CairoTextBox::draw(Cairo::RefPtr<Cairo::Context> cr)
- {
- 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<string> lines;
- split(lines, contents, is_any_of("\n"));
- vector<Cairo::TextExtents> extents;
- double width = 0.0, height = 0.0;
- for (vector<string>::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 += fontHeight;
- }
- cr->move_to(_x0 - 2, _y0 - 2);
- cr->line_to(_x0 + width + 2, _y0 - 2);
- cr->line_to(_x0 + width + 2, _y0 + height + 2);
- cr->line_to(_x0 - 2, _y0 + height + 2);
- cr->close_path();
- 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);
- double texty = _y0;
- for (vector<string>::iterator itr = lines.begin(), end = lines.end();
- itr != end;
- ++itr)
- {
- cr->move_to(_x0, texty + fontExtent.ascent);
- cr->show_text(*itr);
- texty += fontHeight;
- }
- cr->restore();
- }
+void CairoTextBox::draw(Cairo::RefPtr<Cairo::Context> cr)
+{
+ 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<string> lines;
+ split(lines, contents, is_any_of("\n"));
+ vector<Cairo::TextExtents> extents;
+ double width = 0.0, height = 0.0;
+ for (vector<string>::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 += fontHeight;
+ }
+ cr->move_to(_x0 - 2, _y0 - 2);
+ cr->line_to(_x0 + width + 2, _y0 - 2);
+ cr->line_to(_x0 + width + 2, _y0 + height + 2);
+ cr->line_to(_x0 - 2, _y0 + height + 2);
+ cr->close_path();
+ 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);
+ double texty = _y0;
+ for (vector<string>::iterator itr = lines.begin(), end = lines.end();
+ itr != end;
+ ++itr)
+ {
+ cr->move_to(_x0, texty + fontExtent.ascent);
+ cr->show_text(*itr);
+ texty += fontHeight;
+ }
+ cr->restore();
+}
}
diff --git a/grapher/CairoWidget.hxx b/grapher/CairoWidget.hxx
index bcabafb2..32d92cce 100644
--- a/grapher/CairoWidget.hxx
+++ b/grapher/CairoWidget.hxx
@@ -12,51 +12,51 @@
#include <cairomm/context.h>
namespace systemtap
{
- class CairoWidget
+class CairoWidget
+{
+public:
+ CairoWidget(bool visible = false)
+ : _visible(visible)
+ {}
+ bool isVisible() const { return _visible; }
+ void setVisible(bool visible) { _visible = visible; }
+ void getOrigin(double &x, double &y) const
{
- public:
- CairoWidget(bool visible = false)
- : _visible(visible)
- {}
- bool isVisible() const { return _visible; }
- void setVisible(bool visible) { _visible = visible; }
- void getOrigin(double &x, double &y) const
- {
- x = _x0;
- y = _y0;
- }
- void setOrigin(double x, double y)
- {
- _x0 = x;
- _y0 = y;
- }
- virtual void draw(Cairo::RefPtr<Cairo::Context> cr) = 0;
- virtual bool containsPoint(double x, double y) { return false; }
- protected:
- bool _visible;
- double _x0;
- double _y0;
- };
-
- class CairoPlayButton : public CairoWidget
+ x = _x0;
+ y = _y0;
+ }
+ void setOrigin(double x, double y)
{
- public:
- CairoPlayButton(bool visible = false)
- : CairoWidget(visible), _size(50.0), _radius(5)
- {
- }
- virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
- virtual bool containsPoint(double x, double y);
- protected:
- double _size;
- double _radius;
- };
+ _x0 = x;
+ _y0 = y;
+ }
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr) = 0;
+ virtual bool containsPoint(double x, double y) { return false; }
+protected:
+ bool _visible;
+ double _x0;
+ double _y0;
+};
- class CairoTextBox : public CairoWidget
+class CairoPlayButton : public CairoWidget
+{
+public:
+ CairoPlayButton(bool visible = false)
+ : CairoWidget(visible), _size(50.0), _radius(5)
{
- public:
- void draw(Cairo::RefPtr<Cairo::Context> cr);
- std::string contents;
- };
+ }
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
+ virtual bool containsPoint(double x, double y);
+protected:
+ double _size;
+ double _radius;
+};
+
+class CairoTextBox : public CairoWidget
+{
+public:
+ void draw(Cairo::RefPtr<Cairo::Context> cr);
+ std::string contents;
+};
}
#endif
diff --git a/grapher/Graph.cxx b/grapher/Graph.cxx
index ea1bd091..dc808fa4 100644
--- a/grapher/Graph.cxx
+++ b/grapher/Graph.cxx
@@ -14,213 +14,213 @@
namespace systemtap
{
- using namespace std;
- using namespace std::tr1;
+using namespace std;
+using namespace std::tr1;
- GraphDataList GraphDataBase::graphData;
- sigc::signal<void> GraphDataBase::graphDataChanged;
+GraphDataList GraphDataBase::graphData;
+sigc::signal<void> GraphDataBase::graphDataChanged;
- Graph::Graph(double x, double y)
- : _width(600), _height(200), _graphX(0), _graphY(0),
- _graphWidth(580), _graphHeight(180),
- _lineWidth(2), _autoScaling(true), _autoScrolling(true),
- _zoomFactor(1.0), _xOffset(20.0), _yOffset(0.0),
- _playButton(new CairoPlayButton), _timeBase(0),
- _left(0), _right(1), _top(5.0), _bottom(0.0)
- {
- setOrigin(x, y);
- _graphX = x;
- _graphY = y;
- }
+Graph::Graph(double x, double y)
+ : _width(600), _height(200), _graphX(0), _graphY(0),
+ _graphWidth(580), _graphHeight(180),
+ _lineWidth(2), _autoScaling(true), _autoScrolling(true),
+ _zoomFactor(1.0), _xOffset(20.0), _yOffset(0.0),
+ _playButton(new CairoPlayButton), _timeBase(0),
+ _left(0), _right(1), _top(5.0), _bottom(0.0)
+{
+ setOrigin(x, y);
+ _graphX = x;
+ _graphY = y;
+}
- void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
- {
+void Graph::draw(Cairo::RefPtr<Cairo::Context> cr)
+{
- if (_autoScaling)
- {
- // line separation
- int linesPossible = (int)(_graphWidth / (_lineWidth + 2.0));
- // Find latest time.
- int64_t latestTime = 0;
- for (GraphDataList::iterator ditr = _datasets.begin(),
- de = _datasets.end();
- ditr != de;
- ++ditr)
- {
- if (!(*ditr)->times.empty())
- {
- int64_t lastDataTime = (*ditr)->times.back();
- if (lastDataTime > latestTime)
- latestTime = lastDataTime;
- }
- }
- int64_t minDiff = 0;
- int64_t maxTotal = 0;
- for (GraphDataList::iterator ditr = _datasets.begin(),
- de = _datasets.end();
- ditr != de;
- ++ditr)
- {
- GraphDataBase::TimeList& gtimes = (*ditr)->times;
- if (gtimes.size() <= 1)
- continue;
- double totalDiff = 0.0;
- for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(),
- re = gtimes.rend();
- ritr + 1 != gtimes.rend();
- ritr++)
- {
- int64_t timeDiff = *ritr - *(ritr + 1);
- if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0))
- minDiff = timeDiff;
- if (minDiff != 0
- && ((totalDiff + timeDiff) / minDiff + 1) > linesPossible)
- break;
- totalDiff += timeDiff;
- }
- if (totalDiff > maxTotal)
- maxTotal = totalDiff;
- }
- // Now we have a global scale.
- _right = latestTime;
- if (maxTotal != 0)
- _left = latestTime - maxTotal;
- else
- _left = _right - 1;
- }
- cr->save();
- double horizScale
- = _zoomFactor * _graphWidth / static_cast<double>(_right - _left);
- cr->translate(_xOffset, _yOffset);
- cr->set_line_width(_lineWidth);
+ if (_autoScaling)
+ {
+ // line separation
+ int linesPossible = (int)(_graphWidth / (_lineWidth + 2.0));
+ // Find latest time.
+ int64_t latestTime = 0;
+ for (GraphDataList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ if (!(*ditr)->times.empty())
+ {
+ int64_t lastDataTime = (*ditr)->times.back();
+ if (lastDataTime > latestTime)
+ latestTime = lastDataTime;
+ }
+ }
+ int64_t minDiff = 0;
+ int64_t maxTotal = 0;
+ for (GraphDataList::iterator ditr = _datasets.begin(),
+ de = _datasets.end();
+ ditr != de;
+ ++ditr)
+ {
+ GraphDataBase::TimeList& gtimes = (*ditr)->times;
+ if (gtimes.size() <= 1)
+ continue;
+ double totalDiff = 0.0;
+ for (GraphDataBase::TimeList::reverse_iterator ritr = gtimes.rbegin(),
+ re = gtimes.rend();
+ ritr + 1 != gtimes.rend();
+ ritr++)
+ {
+ int64_t timeDiff = *ritr - *(ritr + 1);
+ if (timeDiff < minDiff || (timeDiff != 0 && minDiff == 0))
+ minDiff = timeDiff;
+ if (minDiff != 0
+ && ((totalDiff + timeDiff) / minDiff + 1) > linesPossible)
+ break;
+ totalDiff += timeDiff;
+ }
+ if (totalDiff > maxTotal)
+ maxTotal = totalDiff;
+ }
+ // Now we have a global scale.
+ _right = latestTime;
+ if (maxTotal != 0)
+ _left = latestTime - maxTotal;
+ else
+ _left = _right - 1;
+ }
+ cr->save();
+ double horizScale
+ = _zoomFactor * _graphWidth / static_cast<double>(_right - _left);
+ cr->translate(_xOffset, _yOffset);
+ cr->set_line_width(_lineWidth);
- for (GraphDataList::iterator itr = _datasets.begin(), e = _datasets.end();
- itr != e;
- ++itr)
- {
- shared_ptr<GraphDataBase> graphData = *itr;
- cr->save();
- cr->translate(0.0, _graphHeight);
- cr->scale(1.0, -1.0);
- graphData->style->draw(graphData, this, cr);
- cr->restore();
- cr->save();
- cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
- Cairo::FONT_WEIGHT_BOLD);
- cr->set_font_size(14.0);
- cr->set_source_rgba(1.0, 1.0, 1.0, .8);
+ for (GraphDataList::iterator itr = _datasets.begin(), e = _datasets.end();
+ itr != e;
+ ++itr)
+ {
+ shared_ptr<GraphDataBase> graphData = *itr;
+ cr->save();
+ cr->translate(0.0, _graphHeight);
+ cr->scale(1.0, -1.0);
+ graphData->style->draw(graphData, this, cr);
+ cr->restore();
+ cr->save();
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_BOLD);
+ cr->set_font_size(14.0);
+ cr->set_source_rgba(1.0, 1.0, 1.0, .8);
- if (!graphData->title.empty())
- {
- cr->move_to(20.0, 20.0);
- cr->show_text(graphData->title);
- }
- if (!graphData->xAxisText.empty())
- {
- cr->move_to(10.0, _graphHeight - 5);
- cr->show_text(graphData->xAxisText);
- }
- if (!graphData->yAxisText.empty())
- {
- cr->save();
- cr->translate(10.0, _height - 10.0);
- cr->rotate(-M_PI / 2.0);
- cr->move_to(10.0, 0.0);
- cr->show_text(graphData->yAxisText);
- cr->restore();
- }
- cr->restore();
+ if (!graphData->title.empty())
+ {
+ cr->move_to(20.0, 20.0);
+ cr->show_text(graphData->title);
+ }
+ if (!graphData->xAxisText.empty())
+ {
+ cr->move_to(10.0, _graphHeight - 5);
+ cr->show_text(graphData->xAxisText);
+ }
+ if (!graphData->yAxisText.empty())
+ {
+ cr->save();
+ cr->translate(10.0, _height - 10.0);
+ cr->rotate(-M_PI / 2.0);
+ cr->move_to(10.0, 0.0);
+ cr->show_text(graphData->yAxisText);
+ cr->restore();
+ }
+ cr->restore();
- }
- cr->restore();
- // Draw axes
- double diff = static_cast<double>(_right - _left);
- int64_t majorUnit
- = static_cast<int64_t>(pow(10.0, floor(log(diff) / log(10.0))));
- int64_t startTime = (_left / majorUnit) * majorUnit;
- cr->save();
- cr->set_source_rgba(1.0, 1.0, 1.0, .9);
- cr->set_line_cap(Cairo::LINE_CAP_BUTT);
- cr->set_line_width(_lineWidth);
- cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
- Cairo::FONT_WEIGHT_NORMAL);
- cr->set_font_size(10.0);
- cr->move_to(_xOffset, _yOffset);
- cr->line_to(_xOffset, _height);
- cr->move_to(_xOffset, _graphHeight);
- cr->line_to(_graphWidth, _graphHeight);
- cr->stroke();
- std::valarray<double> dash(1);
- dash[0] = _graphHeight / 10;
- cr->set_dash(dash, 0);
- double prevTextAdvance = 0;
- for (int64_t tickVal = startTime; tickVal <= _right; tickVal += majorUnit)
- {
- double x = (tickVal - _left) * horizScale + _xOffset;
- cr->move_to(x, _yOffset);
- cr->line_to(x, _graphHeight);
- std::ostringstream stream;
- stream << (tickVal - _timeBase);
- Cairo::TextExtents extents;
- cr->get_text_extents(stream.str(), extents);
- // Room for this label?
- if (x + extents.x_bearing > prevTextAdvance)
- {
- cr->move_to(x, _graphHeight + 5 + extents.height);
- cr->show_text(stream.str());
- prevTextAdvance = x + extents.x_advance;
- }
- }
- cr->stroke();
- cr->restore();
+ }
+ cr->restore();
+ // Draw axes
+ double diff = static_cast<double>(_right - _left);
+ int64_t majorUnit
+ = static_cast<int64_t>(pow(10.0, floor(log(diff) / log(10.0))));
+ int64_t startTime = (_left / majorUnit) * majorUnit;
+ cr->save();
+ cr->set_source_rgba(1.0, 1.0, 1.0, .9);
+ cr->set_line_cap(Cairo::LINE_CAP_BUTT);
+ cr->set_line_width(_lineWidth);
+ cr->select_font_face("Sans", Cairo::FONT_SLANT_NORMAL,
+ Cairo::FONT_WEIGHT_NORMAL);
+ cr->set_font_size(10.0);
+ cr->move_to(_xOffset, _yOffset);
+ cr->line_to(_xOffset, _height);
+ cr->move_to(_xOffset, _graphHeight);
+ cr->line_to(_graphWidth, _graphHeight);
+ cr->stroke();
+ std::valarray<double> dash(1);
+ dash[0] = _graphHeight / 10;
+ cr->set_dash(dash, 0);
+ double prevTextAdvance = 0;
+ for (int64_t tickVal = startTime; tickVal <= _right; tickVal += majorUnit)
+ {
+ double x = (tickVal - _left) * horizScale + _xOffset;
+ cr->move_to(x, _yOffset);
+ cr->line_to(x, _graphHeight);
+ std::ostringstream stream;
+ stream << (tickVal - _timeBase);
+ Cairo::TextExtents extents;
+ cr->get_text_extents(stream.str(), extents);
+ // Room for this label?
+ if (x + extents.x_bearing > prevTextAdvance)
+ {
+ cr->move_to(x, _graphHeight + 5 + extents.height);
+ cr->show_text(stream.str());
+ prevTextAdvance = x + extents.x_advance;
+ }
+ }
+ cr->stroke();
+ cr->restore();
- if (!_autoScrolling)
- {
- _playButton->setVisible(true);
- _playButton->setOrigin(_graphWidth / 2 - 25, .875 * _graphHeight - 50);
- _playButton->draw(cr);
- }
+ if (!_autoScrolling)
+ {
+ _playButton->setVisible(true);
+ _playButton->setOrigin(_graphWidth / 2 - 25, .875 * _graphHeight - 50);
+ _playButton->draw(cr);
+ }
- }
+}
- void Graph::addGraphData(shared_ptr<GraphDataBase> data)
- {
- _datasets.push_back(data);
- }
+void Graph::addGraphData(shared_ptr<GraphDataBase> data)
+{
+ _datasets.push_back(data);
+}
- void Graph::getExtents(int64_t& left, int64_t& right, double& top,
- double& bottom) const
- {
- left = _left;
- right = _right;
- top = _top;
- bottom = _bottom;
- }
+void Graph::getExtents(int64_t& left, int64_t& right, double& top,
+ double& bottom) const
+{
+ left = _left;
+ right = _right;
+ top = _top;
+ bottom = _bottom;
+}
- void Graph::setExtents(int64_t left, int64_t right, double top, double bottom)
- {
- _left = left;
- _right = right;
- _top = top;
- _bottom = bottom;
- }
+void Graph::setExtents(int64_t left, int64_t right, double top, double bottom)
+{
+ _left = left;
+ _right = right;
+ _top = top;
+ _bottom = bottom;
+}
- bool Graph::containsPoint(double x, double y)
- {
- return x >= _x0 && x < _x0 + _width && y >= _y0 && y < _y0 + _height;
- }
+bool Graph::containsPoint(double x, double y)
+{
+ return x >= _x0 && x < _x0 + _width && y >= _y0 && y < _y0 + _height;
+}
- int64_t Graph::getTimeAtPoint(double x)
- {
- return (_left
- + (_right - _left) * ((x - _xOffset)/(_zoomFactor * _graphWidth)));
- }
+int64_t Graph::getTimeAtPoint(double x)
+{
+ return (_left
+ + (_right - _left) * ((x - _xOffset)/(_zoomFactor * _graphWidth)));
+}
- void Graph::window2GraphCoords(double x, double y,
- double& xgraph, double& ygraph)
- {
- xgraph = x -_xOffset;
- ygraph = -(y - _graphY) + _yOffset + _graphHeight;
- }
+void Graph::window2GraphCoords(double x, double y,
+ double& xgraph, double& ygraph)
+{
+ xgraph = x -_xOffset;
+ ygraph = -(y - _graphY) + _yOffset + _graphHeight;
+}
}
diff --git a/grapher/Graph.hxx b/grapher/Graph.hxx
index c928fec2..efabd22d 100644
--- a/grapher/Graph.hxx
+++ b/grapher/Graph.hxx
@@ -16,46 +16,46 @@
namespace systemtap
{
- class Graph : public CairoWidget
- {
- public:
- friend class GraphWidget;
- Graph(double x = 0.0, double y = 0.0);
- virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
- virtual bool containsPoint(double x, double y);
- double getLineWidth() { return _lineWidth; }
- void setLineWidth(double lineWidth) { _lineWidth = lineWidth; }
- bool getAutoScaling() const { return _autoScaling; }
- void setAutoScaling(bool val) { _autoScaling = val; }
- void addGraphData(std::tr1::shared_ptr<GraphDataBase> data);
- void getExtents(int64_t& left, int64_t& right, double& top, double& bottom)
- const;
- void setExtents(int64_t left, int64_t right, double top, double bottom);
- // extents of the whole graph area
- double _width;
- double _height;
- // Position, extents of the graph
- double _graphX;
- double _graphY;
- double _graphWidth;
- double _graphHeight;
- double _lineWidth;
- bool _autoScaling;
- bool _autoScrolling;
- double _zoomFactor;
- double _xOffset;
- double _yOffset;
- std::tr1::shared_ptr<CairoPlayButton> _playButton;
- int64_t _timeBase;
- GraphDataList& getDatasets() { return _datasets; }
- int64_t getTimeAtPoint(double x);
- void window2GraphCoords(double x, double y, double& xgraph, double& ygraph);
- protected:
- GraphDataList _datasets;
- int64_t _left;
- int64_t _right;
- double _top;
- double _bottom;
- };
+class Graph : public CairoWidget
+{
+public:
+ friend class GraphWidget;
+ Graph(double x = 0.0, double y = 0.0);
+ virtual void draw(Cairo::RefPtr<Cairo::Context> cr);
+ virtual bool containsPoint(double x, double y);
+ double getLineWidth() { return _lineWidth; }
+ void setLineWidth(double lineWidth) { _lineWidth = lineWidth; }
+ bool getAutoScaling() const { return _autoScaling; }
+ void setAutoScaling(bool val) { _autoScaling = val; }
+ void addGraphData(std::tr1::shared_ptr<GraphDataBase> data);
+ void getExtents(int64_t& left, int64_t& right, double& top, double& bottom)
+ const;
+ void setExtents(int64_t left, int64_t right, double top, double bottom);
+ // extents of the whole graph area
+ double _width;
+ double _height;
+ // Position, extents of the graph
+ double _graphX;
+ double _graphY;
+ double _graphWidth;
+ double _graphHeight;
+ double _lineWidth;
+ bool _autoScaling;
+ bool _autoScrolling;
+ double _zoomFactor;
+ double _xOffset;
+ double _yOffset;
+ std::tr1::shared_ptr<CairoPlayButton> _playButton;
+ int64_t _timeBase;
+ GraphDataList& getDatasets() { return _datasets; }
+ int64_t getTimeAtPoint(double x);
+ void window2GraphCoords(double x, double y, double& xgraph, double& ygraph);
+protected:
+ GraphDataList _datasets;
+ int64_t _left;
+ int64_t _right;
+ double _top;
+ double _bottom;
+};
}
#endif
diff --git a/grapher/GraphData.hxx b/grapher/GraphData.hxx
index fb1ca9f5..863b1d07 100644
--- a/grapher/GraphData.hxx
+++ b/grapher/GraphData.hxx
@@ -25,63 +25,63 @@
namespace systemtap
{
- struct GraphDataBase;
- typedef std::vector<std::tr1::shared_ptr<GraphDataBase> > GraphDataList;
- struct GraphDataBase
- {
- virtual ~GraphDataBase() {}
+struct GraphDataBase;
+typedef std::vector<std::tr1::shared_ptr<GraphDataBase> > GraphDataList;
+struct GraphDataBase
+{
+ virtual ~GraphDataBase() {}
- typedef boost::circular_buffer<int64_t> TimeList;
- GraphDataBase(TimeList::capacity_type cap = 50000)
- : scale(1.0), style(&GraphStyleBar::instance), times(cap)
- {
- color[0] = 0.0; color[1] = 1.0; color[2] = 0.0;
- }
- virtual std::string elementAsString(size_t element) = 0;
- // size of grid square at "normal" viewing
- std::string name;
- double scale;
- double color[3];
- GraphStyle* style;
- std::string title;
- 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<void> graphDataChanged;
- };
+ typedef boost::circular_buffer<int64_t> TimeList;
+ GraphDataBase(TimeList::capacity_type cap = 50000)
+ : scale(1.0), style(&GraphStyleBar::instance), times(cap)
+ {
+ color[0] = 0.0; color[1] = 1.0; color[2] = 0.0;
+ }
+ virtual std::string elementAsString(size_t element) = 0;
+ // size of grid square at "normal" viewing
+ std::string name;
+ double scale;
+ double color[3];
+ GraphStyle* style;
+ std::string title;
+ 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<void> graphDataChanged;
+};
- template<typename T>
- class GraphData : public GraphDataBase
+template<typename T>
+class GraphData : public GraphDataBase
+{
+public:
+ typedef T data_type;
+ typedef boost::circular_buffer<data_type> DataList;
+ GraphData(typename DataList::capacity_type cap = 50000)
+ : GraphDataBase(cap), data(cap)
{
- public:
- typedef T data_type;
- typedef boost::circular_buffer<data_type> DataList;
- GraphData(typename DataList::capacity_type cap = 50000)
- : GraphDataBase(cap), data(cap)
- {
- }
- std::string elementAsString(size_t element)
- {
- std::ostringstream stream;
- stream << data[element];
- return stream.str();
- }
- DataList data;
- };
- struct CSVData
+ }
+ std::string elementAsString(size_t element)
{
- typedef std::pair<std::string, std::tr1::shared_ptr<GraphDataBase> >
- Element;
- std::vector<Element> elements;
- };
+ std::ostringstream stream;
+ stream << data[element];
+ return stream.str();
+ }
+ DataList data;
+};
+struct CSVData
+{
+ typedef std::pair<std::string, std::tr1::shared_ptr<GraphDataBase> >
+ Element;
+ std::vector<Element> elements;
+};
- inline GraphDataList& getGraphData() { return GraphDataBase::graphData; }
+inline GraphDataList& getGraphData() { return GraphDataBase::graphData; }
- inline sigc::signal<void>& graphDataSignal()
- {
- return GraphDataBase::graphDataChanged;
- }
+inline sigc::signal<void>& graphDataSignal()
+{
+ return GraphDataBase::graphDataChanged;
+}
}
#endif
diff --git a/grapher/GraphStyle.cxx b/grapher/GraphStyle.cxx
index 69ff4089..6bf4e109 100644
--- a/grapher/GraphStyle.cxx
+++ b/grapher/GraphStyle.cxx
@@ -13,179 +13,179 @@
namespace systemtap
{
- using namespace std;
- using namespace tr1;
+using namespace std;
+using namespace tr1;
- typedef pair<GraphDataBase::TimeList::iterator,
- GraphDataBase::TimeList::iterator> TimeListPair;
+typedef pair<GraphDataBase::TimeList::iterator,
+ GraphDataBase::TimeList::iterator> TimeListPair;
- GraphStyleBar GraphStyleBar::instance;
+GraphStyleBar GraphStyleBar::instance;
- void GraphStyleBar::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
- {
- shared_ptr<GraphData<double> > realData
- = dynamic_pointer_cast<GraphData<double> >(graphData);
- if (!realData)
- return;
- int64_t left, right;
- double top, bottom;
- graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
- 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);
- for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
- ditr != de;
- ++ditr)
- {
- size_t dataIndex = ditr - graphData->times.begin();
- cr->set_source_rgba(graphData->color[0], graphData->color[1],
- graphData->color[2], 1.0);
- cr->move_to((*ditr - left) * horizScale, 0);
- cr->line_to((*ditr - left) * horizScale,
- realData->data[dataIndex] * graph->_graphHeight
- / graphData->scale);
- cr->stroke();
- }
- }
+void GraphStyleBar::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
+{
+ shared_ptr<GraphData<double> > realData
+ = dynamic_pointer_cast<GraphData<double> >(graphData);
+ if (!realData)
+ return;
+ int64_t left, right;
+ double top, bottom;
+ graph->getExtents(left, right, top, bottom);
+ double horizScale = (graph->_zoomFactor * graph->_graphWidth
+ / static_cast<double>(right - left));
+ 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);
+ for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
+ ditr != de;
+ ++ditr)
+ {
+ size_t dataIndex = ditr - graphData->times.begin();
+ cr->set_source_rgba(graphData->color[0], graphData->color[1],
+ graphData->color[2], 1.0);
+ cr->move_to((*ditr - left) * horizScale, 0);
+ cr->line_to((*ditr - left) * horizScale,
+ realData->data[dataIndex] * graph->_graphHeight
+ / graphData->scale);
+ cr->stroke();
+ }
+}
- ssize_t GraphStyleBar::dataIndexAtPoint(double x, double y,
- shared_ptr<GraphDataBase> graphData,
- shared_ptr<Graph> graph)
- {
- shared_ptr<GraphData<double> > realData
- = dynamic_pointer_cast<GraphData<double> >(graphData);
- if (!realData || graphData->times.empty())
- return -1;
- int64_t left, right;
- double top, bottom;
- graph->getExtents(left, right, top, bottom);
- 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;
- if (y >= graph->_yOffset + graph->_graphHeight - ycoord)
- return static_cast<ssize_t>(dataIndex);
- else
- return -1;
- }
+ssize_t GraphStyleBar::dataIndexAtPoint(double x, double y,
+ shared_ptr<GraphDataBase> graphData,
+ shared_ptr<Graph> graph)
+{
+ shared_ptr<GraphData<double> > realData
+ = dynamic_pointer_cast<GraphData<double> >(graphData);
+ if (!realData || graphData->times.empty())
+ return -1;
+ int64_t left, right;
+ double top, bottom;
+ graph->getExtents(left, right, top, bottom);
+ 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;
+ if (y >= graph->_yOffset + graph->_graphHeight - ycoord)
+ return static_cast<ssize_t>(dataIndex);
+ else
+ return -1;
+}
- GraphStyleDot GraphStyleDot::instance;
+GraphStyleDot GraphStyleDot::instance;
- void GraphStyleDot::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
- {
- shared_ptr<GraphData<double> > realData
- = dynamic_pointer_cast<GraphData<double> >(graphData);
- if (!realData)
- return;
- int64_t left, right;
- double top, bottom;
- graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
- 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);
- cr->set_source_rgba(graphData->color[0], graphData->color[1],
- graphData->color[2], 1.0);
+void GraphStyleDot::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
+{
+ shared_ptr<GraphData<double> > realData
+ = dynamic_pointer_cast<GraphData<double> >(graphData);
+ if (!realData)
+ return;
+ int64_t left, right;
+ double top, bottom;
+ graph->getExtents(left, right, top, bottom);
+ double horizScale = (graph->_zoomFactor * graph->_graphWidth
+ / static_cast<double>(right - left));
+ 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);
+ cr->set_source_rgba(graphData->color[0], graphData->color[1],
+ graphData->color[2], 1.0);
- for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
- ditr != de;
- ++ditr)
- {
- size_t dataIndex = ditr - graphData->times.begin();
- cr->arc((*ditr - left) * horizScale,
- (realData->data[dataIndex]
- * graph->_graphHeight / graphData->scale),
- graph->_lineWidth / 2.0, 0.0, M_PI * 2.0);
- cr->fill();
- }
- }
+ for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
+ ditr != de;
+ ++ditr)
+ {
+ size_t dataIndex = ditr - graphData->times.begin();
+ cr->arc((*ditr - left) * horizScale,
+ (realData->data[dataIndex]
+ * graph->_graphHeight / graphData->scale),
+ graph->_lineWidth / 2.0, 0.0, M_PI * 2.0);
+ cr->fill();
+ }
+}
- GraphStyleEvent GraphStyleEvent::instance;
+GraphStyleEvent GraphStyleEvent::instance;
- void GraphStyleEvent::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
- {
- shared_ptr<GraphData<string> > stringData
- = dynamic_pointer_cast<GraphData<string> >(graphData);
- if (!stringData)
- return;
- int64_t left, right;
- double top, bottom;
- graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(right - left));
- double eventHeight = graph->_graphHeight * (graphData->scale / 100.0);
- cr->save();
- cr->set_line_width(3 * graph->_lineWidth);
- cr->set_source_rgba(graphData->color[0], graphData->color[1],
- graphData->color[2], .33);
- cr->move_to(0, eventHeight);
- cr->line_to(graph->_graphWidth, eventHeight);
- cr->stroke();
- cr->restore();
- 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);
- for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
- ditr != de;
- ++ditr)
- {
- // 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);
- cr->fill();
- cr->restore();
- }
- }
+void GraphStyleEvent::draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr)
+{
+ shared_ptr<GraphData<string> > stringData
+ = dynamic_pointer_cast<GraphData<string> >(graphData);
+ if (!stringData)
+ return;
+ int64_t left, right;
+ double top, bottom;
+ graph->getExtents(left, right, top, bottom);
+ double horizScale = (graph->_zoomFactor * graph->_graphWidth
+ / static_cast<double>(right - left));
+ double eventHeight = graph->_graphHeight * (graphData->scale / 100.0);
+ cr->save();
+ cr->set_line_width(3 * graph->_lineWidth);
+ cr->set_source_rgba(graphData->color[0], graphData->color[1],
+ graphData->color[2], .33);
+ cr->move_to(0, eventHeight);
+ cr->line_to(graph->_graphWidth, eventHeight);
+ cr->stroke();
+ cr->restore();
+ 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);
+ for (GraphDataBase::TimeList::iterator ditr = lower, de = upper;
+ ditr != de;
+ ++ditr)
+ {
+ // 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);
+ cr->fill();
+ cr->restore();
+ }
+}
- ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y,
- shared_ptr<GraphDataBase> graphData,
- shared_ptr<Graph> graph)
- {
- shared_ptr<GraphData<string> > stringData
- = dynamic_pointer_cast<GraphData<string> >(graphData);
- if (!stringData || graphData->times.empty())
- return -1;
- int64_t left, right;
- double top, bottom;
- graph->getExtents(left, right, top, bottom);
- double horizScale = (graph->_zoomFactor * graph->_graphWidth
- / static_cast<double>(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<ssize_t>(distance(lower, ditr));
- }
+ssize_t GraphStyleEvent::dataIndexAtPoint(double x, double y,
+ shared_ptr<GraphDataBase> graphData,
+ shared_ptr<Graph> graph)
+{
+ shared_ptr<GraphData<string> > stringData
+ = dynamic_pointer_cast<GraphData<string> >(graphData);
+ if (!stringData || graphData->times.empty())
return -1;
- }
+ int64_t left, right;
+ double top, bottom;
+ graph->getExtents(left, right, top, bottom);
+ double horizScale = (graph->_zoomFactor * graph->_graphWidth
+ / static_cast<double>(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<ssize_t>(distance(lower, ditr));
+ }
+ return -1;
+}
}
diff --git a/grapher/GraphStyle.hxx b/grapher/GraphStyle.hxx
index bea4922a..4924ed2e 100644
--- a/grapher/GraphStyle.hxx
+++ b/grapher/GraphStyle.hxx
@@ -14,53 +14,53 @@
namespace systemtap
{
- class GraphDataBase;
- class Graph;
+class GraphDataBase;
+class Graph;
- class GraphStyle
+class GraphStyle
+{
+public:
+ virtual void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr) = 0;
+ virtual ssize_t dataIndexAtPoint(double x, double y,
+ std::tr1::shared_ptr<GraphDataBase>
+ graphData,
+ std::tr1::shared_ptr<Graph> graph)
{
- public:
- virtual void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr) = 0;
- virtual ssize_t dataIndexAtPoint(double x, double y,
- std::tr1::shared_ptr<GraphDataBase>
- graphData,
- std::tr1::shared_ptr<Graph> graph)
- {
- return -1;
- }
- };
+ return -1;
+ }
+};
- class GraphStyleBar : public GraphStyle
- {
- public:
- void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
+class GraphStyleBar : public GraphStyle
+{
+public:
+ void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
- static GraphStyleBar instance;
- ssize_t dataIndexAtPoint(double x, double y,
- std::tr1::shared_ptr<GraphDataBase> graphData,
- std::tr1::shared_ptr<Graph> graph);
- };
+ static GraphStyleBar instance;
+ ssize_t dataIndexAtPoint(double x, double y,
+ std::tr1::shared_ptr<GraphDataBase> graphData,
+ std::tr1::shared_ptr<Graph> graph);
+};
- class GraphStyleDot : public GraphStyle
- {
- public:
- void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
- static GraphStyleDot instance;
- };
+class GraphStyleDot : public GraphStyle
+{
+public:
+ void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
+ static GraphStyleDot instance;
+};
- class GraphStyleEvent : public GraphStyle
- {
- public:
- void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
- Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
- virtual ssize_t dataIndexAtPoint(double x, double y,
- std::tr1::shared_ptr<GraphDataBase>
- graphData,
- std::tr1::shared_ptr<Graph> graph);
- static GraphStyleEvent instance;
- };
+class GraphStyleEvent : public GraphStyle
+{
+public:
+ void draw(std::tr1::shared_ptr<GraphDataBase> graphData,
+ Graph* graph, Cairo::RefPtr<Cairo::Context> cr);
+ virtual ssize_t dataIndexAtPoint(double x, double y,
+ std::tr1::shared_ptr<GraphDataBase>
+ graphData,
+ std::tr1::shared_ptr<Graph> graph);
+ static GraphStyleEvent instance;
+};
}
#endif
diff --git a/grapher/GraphWidget.cxx b/grapher/GraphWidget.cxx
index bdf60ed2..db7493fb 100644
--- a/grapher/GraphWidget.cxx
+++ b/grapher/GraphWidget.cxx
@@ -26,388 +26,388 @@
namespace systemtap
{
- using namespace std;
- using namespace std::tr1;
+using namespace std;
+using namespace std::tr1;
- GraphWidget::GraphWidget()
- : _trackingDrag(false), _width(600), _height(200), _mouseX(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);
- Glib::signal_timeout()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_timeout), 1000);
- signal_expose_event()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_expose_event), false);
- signal_button_press_event()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_button_press_event),
- false);
- signal_button_release_event()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_button_release_event),
- false);
- signal_motion_notify_event()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_motion_notify_event),
- false);
- signal_scroll_event()
- .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false);
- // Temporary testing of multiple graphs
- shared_ptr<Graph> graph(new Graph);
- _graphs.push_back(graph);
- try
- {
- _refXmlDataDialog = Gnome::Glade::Xml::create(PKGDATADIR "/graph-dialog.glade");
- _refXmlDataDialog->get_widget("dialog1", _dataDialog);
- Gtk::Button* button = 0;
- _refXmlDataDialog->get_widget("closebutton1", button);
- button->signal_clicked()
- .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel),
- false);
- _refXmlDataDialog->get_widget("treeview1", _dataTreeView);
- _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);
- // Disable selection in list
- Glib::RefPtr<Gtk::TreeSelection> 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,
- &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 )
- {
- std::cerr << ex.what() << std::endl;
- throw;
- }
- }
+GraphWidget::GraphWidget()
+ : _trackingDrag(false), _width(600), _height(200), _mouseX(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);
+ Glib::signal_timeout()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_timeout), 1000);
+ signal_expose_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_expose_event), false);
+ signal_button_press_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_press_event),
+ false);
+ signal_button_release_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_button_release_event),
+ false);
+ signal_motion_notify_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_motion_notify_event),
+ false);
+ signal_scroll_event()
+ .connect(sigc::mem_fun(*this, &GraphWidget::on_scroll_event), false);
+ // Temporary testing of multiple graphs
+ shared_ptr<Graph> graph(new Graph);
+ _graphs.push_back(graph);
+ try
+ {
+ _refXmlDataDialog = Gnome::Glade::Xml::create(PKGDATADIR "/graph-dialog.glade");
+ _refXmlDataDialog->get_widget("dialog1", _dataDialog);
+ Gtk::Button* button = 0;
+ _refXmlDataDialog->get_widget("closebutton1", button);
+ button->signal_clicked()
+ .connect(sigc::mem_fun(*this, &GraphWidget::onDataDialogCancel),
+ false);
+ _refXmlDataDialog->get_widget("treeview1", _dataTreeView);
+ _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);
+ // Disable selection in list
+ Glib::RefPtr<Gtk::TreeSelection> 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,
+ &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 )
+ {
+ std::cerr << ex.what() << std::endl;
+ throw;
+ }
+}
- GraphWidget::~GraphWidget()
- {
- }
+GraphWidget::~GraphWidget()
+{
+}
- void GraphWidget::onGraphDataChanged()
- {
- // 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::onGraphDataChanged()
+{
+ // 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()
- {
- double x = 0.0;
- double y = 0.0;
- if (!_graphs.empty())
- {
- _graphs.back()->getOrigin(x, y);
- y += _graphs.back()->_height + 10;
- }
- shared_ptr<Graph> graph(new Graph(x, y));
- _height = y + graph->_height;
- graph->setOrigin(x, y);
- graph->_timeBase = _globalTimeBase;
- _graphs.push_back(graph);
- queue_resize();
- }
+void GraphWidget::addGraph()
+{
+ double x = 0.0;
+ double y = 0.0;
+ if (!_graphs.empty())
+ {
+ _graphs.back()->getOrigin(x, y);
+ y += _graphs.back()->_height + 10;
+ }
+ shared_ptr<Graph> graph(new Graph(x, y));
+ _height = y + graph->_height;
+ graph->setOrigin(x, y);
+ graph->_timeBase = _globalTimeBase;
+ _graphs.push_back(graph);
+ queue_resize();
+}
- bool GraphWidget::on_expose_event(GdkEventExpose* event)
- {
- // This is where we draw on the window
- Glib::RefPtr<Gdk::Window> window = get_window();
- if(!window)
- return true;
-
- Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
- cr->save();
- cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
- cr->paint();
- if (!_timeBaseInitialized && !getGraphData().empty())
- {
- GraphDataList& graphData = getGraphData();
- 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();
- cr->translate(x, y);
- (*g)->draw(cr);
- cr->restore();
- }
- if (_hoverText && _hoverText->isVisible())
- _hoverText->draw(cr);
- cr->restore();
+bool GraphWidget::on_expose_event(GdkEventExpose* event)
+{
+ // This is where we draw on the window
+ Glib::RefPtr<Gdk::Window> window = get_window();
+ if(!window)
return true;
- }
- bool GraphWidget::on_button_press_event(GdkEventButton* event)
- {
- shared_ptr<Graph> g = getGraphUnderPoint(event->x, event->y);
- if (g)
- {
- _activeGraph = g;
- if (event->button == 3)
- {
- _dataDialog->show();
- return true;
- }
- }
- if (!_activeGraph)
- return true;
- double activeX, activeY;
- _activeGraph->getOrigin(activeX, activeY);
- if (!_activeGraph->_autoScrolling
- && _activeGraph->_playButton->containsPoint(event->x - activeX,
- event->y - activeY))
- {
- _activeGraph->_autoScaling = true;
- _activeGraph->_autoScrolling = true;
- queue_draw();
- }
- else
- {
- _trackingDrag = true;
- _activeGraph->_autoScaling = false;
- _activeGraph->_autoScrolling = false;
- _dragOriginX = event->x;
- _dragOriginY = event->y;
- _dragOrigLeft = _activeGraph->_left;
- _dragOrigRight = _activeGraph->_right;
- establishHoverTimeout();
- }
- return true;
- }
+ Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
+ cr->save();
+ cr->set_source_rgba(0.0, 0.0, 0.0, 1.0);
+ cr->paint();
+ if (!_timeBaseInitialized && !getGraphData().empty())
+ {
+ GraphDataList& graphData = getGraphData();
+ 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();
+ cr->translate(x, y);
+ (*g)->draw(cr);
+ cr->restore();
+ }
+ if (_hoverText && _hoverText->isVisible())
+ _hoverText->draw(cr);
+ cr->restore();
+ return true;
+}
- bool GraphWidget::on_button_release_event(GdkEventButton* event)
- {
- // Was data dialog launched?
- if (event->button != 3)
- {
- _activeGraph.reset();
- _trackingDrag = false;
- }
+bool GraphWidget::on_button_press_event(GdkEventButton* event)
+{
+ shared_ptr<Graph> g = getGraphUnderPoint(event->x, event->y);
+ if (g)
+ {
+ _activeGraph = g;
+ if (event->button == 3)
+ {
+ _dataDialog->show();
+ return true;
+ }
+ }
+ if (!_activeGraph)
return true;
- }
-
- bool GraphWidget::on_motion_notify_event(GdkEventMotion* event)
- {
- Glib::RefPtr<Gdk::Window> win = get_window();
- if(!win)
- return true;
- _mouseX = event->x;
- _mouseY = event->y;
- if (_trackingDrag && _activeGraph)
- {
- Gtk::Allocation allocation = get_allocation();
- const int width = allocation.get_width();
- double motion = (_mouseX - _dragOriginX) / (double) width;
- double increment = motion * (_dragOrigLeft - _dragOrigRight);
- _activeGraph->_left = _dragOrigLeft + increment;
- _activeGraph->_right = _dragOrigRight + increment;
- queue_draw();
- }
- if (_hoverText && _hoverText->isVisible())
- {
- _hoverText->setVisible(false);
- queue_draw();
- }
- establishHoverTimeout();
+ double activeX, activeY;
+ _activeGraph->getOrigin(activeX, activeY);
+ if (!_activeGraph->_autoScrolling
+ && _activeGraph->_playButton->containsPoint(event->x - activeX,
+ event->y - activeY))
+ {
+ _activeGraph->_autoScaling = true;
+ _activeGraph->_autoScrolling = true;
+ queue_draw();
+ }
+ else
+ {
+ _trackingDrag = true;
+ _activeGraph->_autoScaling = false;
+ _activeGraph->_autoScrolling = false;
+ _dragOriginX = event->x;
+ _dragOriginY = event->y;
+ _dragOrigLeft = _activeGraph->_left;
+ _dragOrigRight = _activeGraph->_right;
+ establishHoverTimeout();
+ }
+ return true;
+}
+bool GraphWidget::on_button_release_event(GdkEventButton* event)
+{
+ // Was data dialog launched?
+ if (event->button != 3)
+ {
+ _activeGraph.reset();
+ _trackingDrag = false;
+ }
+ return true;
+}
+
+bool GraphWidget::on_motion_notify_event(GdkEventMotion* event)
+{
+ Glib::RefPtr<Gdk::Window> win = get_window();
+ if(!win)
return true;
- }
+ _mouseX = event->x;
+ _mouseY = event->y;
+ if (_trackingDrag && _activeGraph)
+ {
+ Gtk::Allocation allocation = get_allocation();
+ const int width = allocation.get_width();
+ double motion = (_mouseX - _dragOriginX) / (double) width;
+ double increment = motion * (_dragOrigLeft - _dragOrigRight);
+ _activeGraph->_left = _dragOrigLeft + increment;
+ _activeGraph->_right = _dragOrigRight + increment;
+ queue_draw();
+ }
+ if (_hoverText && _hoverText->isVisible())
+ {
+ _hoverText->setVisible(false);
+ queue_draw();
+ }
+ establishHoverTimeout();
- bool GraphWidget::on_scroll_event(GdkEventScroll* event)
- {
- for (GraphList::iterator gitr = _graphs.begin();
- gitr != _graphs.end();
- ++gitr)
- {
- if ((*gitr)->containsPoint(event->x, event->y))
- {
- if (event->direction == GDK_SCROLL_UP)
- (*gitr)->_zoomFactor += .1;
- else if (event->direction == GDK_SCROLL_DOWN)
- (*gitr)->_zoomFactor -= .1;
- queue_draw();
- break;
- }
- }
- return true;
- }
+ return true;
+}
- bool GraphWidget::on_timeout()
- {
- queue_draw();
- return true;
- }
+bool GraphWidget::on_scroll_event(GdkEventScroll* event)
+{
+ for (GraphList::iterator gitr = _graphs.begin();
+ gitr != _graphs.end();
+ ++gitr)
+ {
+ if ((*gitr)->containsPoint(event->x, event->y))
+ {
+ if (event->direction == GDK_SCROLL_UP)
+ (*gitr)->_zoomFactor += .1;
+ else if (event->direction == GDK_SCROLL_DOWN)
+ (*gitr)->_zoomFactor -= .1;
+ queue_draw();
+ break;
+ }
+ }
+ return true;
+}
- void GraphWidget::on_size_request(Gtk::Requisition* req)
- {
- req->width = _width;
- req->height = _height;
- }
+bool GraphWidget::on_timeout()
+{
+ queue_draw();
+ return true;
+}
- void GraphWidget::onDataDialogCancel()
- {
- _dataDialog->hide();
- }
+void GraphWidget::on_size_request(Gtk::Requisition* req)
+{
+ req->width = _width;
+ req->height = _height;
+}
+
+void GraphWidget::onDataDialogCancel()
+{
+ _dataDialog->hide();
+}
- void GraphWidget::onDataDialogOpen()
- {
- _listStore->clear();
- for (GraphDataList::iterator itr = getGraphData().begin(),
- end = getGraphData().end();
- itr != end;
- ++itr)
- {
- Gtk::TreeModel::iterator litr = _listStore->append();
- Gtk::TreeModel::Row row = *litr;
- row[_dataColumns._dataName] = (*itr)->name;
- if (!(*itr)->title.empty())
- row[_dataColumns._dataTitle] = (*itr)->title;
- row[_dataColumns._graphData] = *itr;
- GraphDataList& gsets = _activeGraph->getDatasets();
- GraphDataList::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::onDataDialogOpen()
+{
+ _listStore->clear();
+ for (GraphDataList::iterator itr = getGraphData().begin(),
+ end = getGraphData().end();
+ itr != end;
+ ++itr)
+ {
+ Gtk::TreeModel::iterator litr = _listStore->append();
+ Gtk::TreeModel::Row row = *litr;
+ row[_dataColumns._dataName] = (*itr)->name;
+ if (!(*itr)->title.empty())
+ row[_dataColumns._dataTitle] = (*itr)->title;
+ row[_dataColumns._graphData] = *itr;
+ GraphDataList& gsets = _activeGraph->getDatasets();
+ GraphDataList::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();
- }
+void GraphWidget::onDataDialogClose()
+{
+ if (_listConnection.connected())
+ _listConnection.disconnect();
+}
- bool GraphWidget::onHoverTimeout()
- {
- shared_ptr<Graph> g = getGraphUnderPoint(_mouseX, _mouseY);
- if (g && !g->_autoScrolling)
- {
- if (!_hoverText)
- _hoverText = shared_ptr<CairoTextBox>(new CairoTextBox());
- _hoverText->setOrigin(_mouseX + 10, _mouseY - 5);
- GraphDataList& dataSets = g->getDatasets();
- for (GraphDataList::reverse_iterator ritr = dataSets.rbegin(),
- end = dataSets.rend();
- ritr != end;
- ++ritr)
+bool GraphWidget::onHoverTimeout()
+{
+ shared_ptr<Graph> g = getGraphUnderPoint(_mouseX, _mouseY);
+ if (g && !g->_autoScrolling)
+ {
+ if (!_hoverText)
+ _hoverText = shared_ptr<CairoTextBox>(new CairoTextBox());
+ _hoverText->setOrigin(_mouseX + 10, _mouseY - 5);
+ GraphDataList& dataSets = g->getDatasets();
+ for (GraphDataList::reverse_iterator ritr = dataSets.rbegin(),
+ end = dataSets.rend();
+ ritr != end;
+ ++ritr)
{
- ssize_t index
- = (*ritr)->style->dataIndexAtPoint(_mouseX, _mouseY, *ritr, g);
- if (index >= 0)
+ ssize_t index
+ = (*ritr)->style->dataIndexAtPoint(_mouseX, _mouseY, *ritr, g);
+ if (index >= 0)
{
- _hoverText->contents = (*ritr)->name
- + ": " + (*ritr)->elementAsString(index);
- _hoverText->setVisible(true);
- queue_draw();
- break;
+ _hoverText->contents = (*ritr)->name
+ + ": " + (*ritr)->elementAsString(index);
+ _hoverText->setVisible(true);
+ queue_draw();
+ break;
}
}
- }
- return false;
- }
+ }
+ return false;
+}
- shared_ptr<Graph> GraphWidget::getGraphUnderPoint(double x, double y)
- {
- for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g)
- {
- if (x >= (*g)->_graphX
- && x < (*g)->_graphX + (*g)->_graphWidth
- && y >= (*g)->_graphY
- && y < (*g)->_graphY + (*g)->_graphHeight)
- return *g;
- }
- return shared_ptr<Graph>();
- }
+shared_ptr<Graph> GraphWidget::getGraphUnderPoint(double x, double y)
+{
+ for (GraphList::iterator g = _graphs.begin(); g != _graphs.end(); ++g)
+ {
+ if (x >= (*g)->_graphX
+ && x < (*g)->_graphX + (*g)->_graphWidth
+ && y >= (*g)->_graphY
+ && y < (*g)->_graphY + (*g)->_graphHeight)
+ return *g;
+ }
+ return shared_ptr<Graph>();
+}
- void GraphWidget::establishHoverTimeout()
- {
- if (_hover_timeout_connection.connected())
- _hover_timeout_connection.disconnect();
- _hover_timeout_connection = Glib::signal_timeout()
- .connect(sigc::mem_fun(*this, &GraphWidget::onHoverTimeout), 1000);
- }
+void GraphWidget::establishHoverTimeout()
+{
+ if (_hover_timeout_connection.connected())
+ _hover_timeout_connection.disconnect();
+ _hover_timeout_connection = Glib::signal_timeout()
+ .connect(sigc::mem_fun(*this, &GraphWidget::onHoverTimeout), 1000);
+}
- void GraphWidget::onRelativeTimesButtonClicked()
- {
- _displayRelativeTimes = _relativeTimesButton->get_active();
- queue_draw();
- }
+void GraphWidget::onRelativeTimesButtonClicked()
+{
+ _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<GraphDataBase> data = row[_dataColumns._graphData];
- GraphDataList& 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());
- }
- }
+void GraphWidget::onRowChanged(const Gtk::TreeModel::Path&,
+ const Gtk::TreeModel::iterator& litr)
+{
+ Gtk::TreeModel::Row row = *litr;
+ bool val = row[_dataColumns._dataEnabled];
+ shared_ptr<GraphDataBase> data = row[_dataColumns._graphData];
+ GraphDataList& 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 89b86db9..f90da361 100644
--- a/grapher/GraphWidget.hxx
+++ b/grapher/GraphWidget.hxx
@@ -19,84 +19,84 @@
namespace systemtap
{
- class CairoPlayButton;
+class CairoPlayButton;
- class DataModelColumns : public Gtk::TreeModelColumnRecord
+class DataModelColumns : public Gtk::TreeModelColumnRecord
+{
+public:
+ DataModelColumns()
{
- public:
- DataModelColumns()
- {
- add(_dataEnabled);
- add(_dataName);
- add(_dataTitle);
- add(_graphData);
- }
- Gtk::TreeModelColumn<bool> _dataEnabled;
- Gtk::TreeModelColumn<Glib::ustring> _dataName;
- Gtk::TreeModelColumn<Glib::ustring> _dataTitle;
- Gtk::TreeModelColumn<std::tr1::shared_ptr<GraphDataBase> > _graphData;
- };
+ add(_dataEnabled);
+ add(_dataName);
+ add(_dataTitle);
+ add(_graphData);
+ }
+ Gtk::TreeModelColumn<bool> _dataEnabled;
+ Gtk::TreeModelColumn<Glib::ustring> _dataName;
+ Gtk::TreeModelColumn<Glib::ustring> _dataTitle;
+ Gtk::TreeModelColumn<std::tr1::shared_ptr<GraphDataBase> > _graphData;
+};
- class GraphWidget : public Gtk::DrawingArea
- {
- public:
- GraphWidget();
- virtual ~GraphWidget();
- void addGraph();
+class GraphWidget : public Gtk::DrawingArea
+{
+public:
+ GraphWidget();
+ virtual ~GraphWidget();
+ void addGraph();
- protected:
- typedef std::vector<std::tr1::shared_ptr<Graph> > GraphList;
- GraphList _graphs;
- // For click and drag
- std::tr1::shared_ptr<Graph> _activeGraph;
- // Dragging all graphs simultaneously, or perhaps seperately
- typedef std::vector<std::pair<double, double> > DragList;
- DragList dragCoords;
- //Override default signal handler:
- virtual bool on_expose_event(GdkEventExpose* event);
- virtual bool on_motion_notify_event(GdkEventMotion* event);
- virtual bool on_button_press_event(GdkEventButton* event);
- virtual bool on_button_release_event(GdkEventButton* event);
- virtual bool on_scroll_event(GdkEventScroll* event);
- bool on_timeout();
- virtual void on_size_request(Gtk::Requisition* req);
- bool _trackingDrag;
- double _dragOriginX;
- double _dragOriginY;
- double _dragOrigLeft;
- double _dragOrigRight;
- double _width;
- double _height;
- Glib::RefPtr<Gnome::Glade::Xml> _refXmlDataDialog;
- Gtk::Dialog* _dataDialog;
- Gtk::TreeView* _dataTreeView;
- void onDataDialogCancel();
- void onDataDialogOpen();
- void onDataDialogClose();
- bool onHoverTimeout();
- DataModelColumns _dataColumns;
- Glib::RefPtr<Gtk::ListStore> _listStore;
- sigc::connection _hover_timeout_connection;
- std::tr1::shared_ptr<CairoTextBox> _hoverText;
- double _mouseX;
- double _mouseY;
- int64_t _globalTimeBase;
- bool _timeBaseInitialized;
- std::tr1::shared_ptr<Graph> getGraphUnderPoint(double x, double y);
- void establishHoverTimeout();
- Gtk::CheckButton* _relativeTimesButton;
- bool _displayRelativeTimes;
- void onRelativeTimesButtonClicked();
- void onRowChanged(const Gtk::TreeModel::Path&,
- const Gtk::TreeModel::iterator&);
- sigc::connection _listConnection;
- bool no_select_fun(const Glib::RefPtr<Gtk::TreeModel>& model,
- const Gtk::TreeModel::Path& path,
- bool)
- {
- return false;
- }
- void onGraphDataChanged();
- };
+protected:
+ typedef std::vector<std::tr1::shared_ptr<Graph> > GraphList;
+ GraphList _graphs;
+ // For click and drag
+ std::tr1::shared_ptr<Graph> _activeGraph;
+ // Dragging all graphs simultaneously, or perhaps seperately
+ typedef std::vector<std::pair<double, double> > DragList;
+ DragList dragCoords;
+ //Override default signal handler:
+ virtual bool on_expose_event(GdkEventExpose* event);
+ virtual bool on_motion_notify_event(GdkEventMotion* event);
+ virtual bool on_button_press_event(GdkEventButton* event);
+ virtual bool on_button_release_event(GdkEventButton* event);
+ virtual bool on_scroll_event(GdkEventScroll* event);
+ bool on_timeout();
+ virtual void on_size_request(Gtk::Requisition* req);
+ bool _trackingDrag;
+ double _dragOriginX;
+ double _dragOriginY;
+ double _dragOrigLeft;
+ double _dragOrigRight;
+ double _width;
+ double _height;
+ Glib::RefPtr<Gnome::Glade::Xml> _refXmlDataDialog;
+ Gtk::Dialog* _dataDialog;
+ Gtk::TreeView* _dataTreeView;
+ void onDataDialogCancel();
+ void onDataDialogOpen();
+ void onDataDialogClose();
+ bool onHoverTimeout();
+ DataModelColumns _dataColumns;
+ Glib::RefPtr<Gtk::ListStore> _listStore;
+ sigc::connection _hover_timeout_connection;
+ std::tr1::shared_ptr<CairoTextBox> _hoverText;
+ double _mouseX;
+ double _mouseY;
+ int64_t _globalTimeBase;
+ bool _timeBaseInitialized;
+ std::tr1::shared_ptr<Graph> getGraphUnderPoint(double x, double y);
+ void establishHoverTimeout();
+ Gtk::CheckButton* _relativeTimesButton;
+ bool _displayRelativeTimes;
+ void onRelativeTimesButtonClicked();
+ void onRowChanged(const Gtk::TreeModel::Path&,
+ const Gtk::TreeModel::iterator&);
+ sigc::connection _listConnection;
+ bool no_select_fun(const Glib::RefPtr<Gtk::TreeModel>& model,
+ const Gtk::TreeModel::Path& path,
+ bool)
+ {
+ return false;
+ }
+ void onGraphDataChanged();
+};
}
#endif // SYSTEMTAP_GRAPHWIDGET_H
diff --git a/grapher/StapParser.cxx b/grapher/StapParser.cxx
index 2595e8cc..803b5fb3 100644
--- a/grapher/StapParser.cxx
+++ b/grapher/StapParser.cxx
@@ -22,22 +22,22 @@
namespace systemtap
{
- using namespace std;
- using namespace std::tr1;
+using namespace std;
+using namespace std::tr1;
- sigc::signal<void, pid_t>& childDiedSignal()
- {
- static sigc::signal<void, pid_t> deathSignal;
- return deathSignal;
- }
+sigc::signal<void, pid_t>& childDiedSignal()
+{
+ static sigc::signal<void, pid_t> deathSignal;
+ return deathSignal;
+}
- ParserList parsers;
+ParserList parsers;
- sigc::signal<void>& parserListChangedSignal()
- {
- static sigc::signal<void> listChangedSignal;
- return listChangedSignal;
- }
+sigc::signal<void>& parserListChangedSignal()
+{
+ static sigc::signal<void> listChangedSignal;
+ return listChangedSignal;
+}
vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
{
@@ -47,263 +47,263 @@ vector<string> commaSplit(const boost::sub_range<Glib::ustring>& range)
return result;
}
- void StapParser::parseData(shared_ptr<GraphDataBase> gdata,
- int64_t time, const string& dataString)
- {
- std::istringstream stream(dataString);
- shared_ptr<GraphData<double> > dblptr;
- shared_ptr<GraphData<string> > strptr;
- dblptr = dynamic_pointer_cast<GraphData<double> >(gdata);
- if (dblptr)
- {
- double data;
- stream >> data;
- dblptr->times.push_back(time);
- dblptr->data.push_back(data);
- }
- else if ((strptr = dynamic_pointer_cast<GraphData<string> >(gdata))
- != 0)
- {
- strptr->times.push_back(time);
- strptr->data.push_back(dataString);
- }
- }
+void StapParser::parseData(shared_ptr<GraphDataBase> gdata,
+ int64_t time, const string& dataString)
+{
+ std::istringstream stream(dataString);
+ shared_ptr<GraphData<double> > dblptr;
+ shared_ptr<GraphData<string> > strptr;
+ dblptr = dynamic_pointer_cast<GraphData<double> >(gdata);
+ if (dblptr)
+ {
+ double data;
+ stream >> data;
+ dblptr->times.push_back(time);
+ dblptr->data.push_back(data);
+ }
+ else if ((strptr = dynamic_pointer_cast<GraphData<string> >(gdata))
+ != 0)
+ {
+ strptr->times.push_back(time);
+ strptr->data.push_back(dataString);
+ }
+}
- bool findTaggedValue(const string& src, const char* tag, string& result)
- {
- using namespace boost;
- sub_range<const string> found = find_first(src, tag);
- if (found.empty())
- return false;
- result.insert(result.end(),found.end(), src.end());
- return true;
- }
+bool findTaggedValue(const string& src, const char* tag, string& result)
+{
+ using namespace boost;
+ sub_range<const string> found = find_first(src, tag);
+ if (found.empty())
+ return false;
+ result.insert(result.end(),found.end(), src.end());
+ return true;
+}
- bool StapParser::ioCallback(Glib::IOCondition ioCondition)
- {
- using namespace std;
- using std::tr1::shared_ptr;
- using namespace boost;
- if (ioCondition & Glib::IO_HUP)
- {
- if (_catchHUP)
- {
- childDiedSignal().emit(getPid());
- _ioConnection.disconnect();
- _errIoConnection.disconnect();
- }
- return true;
- }
- if ((ioCondition & Glib::IO_IN) == 0)
+bool StapParser::ioCallback(Glib::IOCondition ioCondition)
+{
+ using namespace std;
+ using std::tr1::shared_ptr;
+ using namespace boost;
+ if (ioCondition & Glib::IO_HUP)
+ {
+ if (_catchHUP)
+ {
+ childDiedSignal().emit(getPid());
+ _ioConnection.disconnect();
+ _errIoConnection.disconnect();
+ }
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<Glib::ustring> 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<GraphData<double> >
- dataSet(new GraphData<double>);
- 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<GraphData<string> >
- dataSet(new GraphData<string>);
- 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<string> tokens
- = commaSplit(sub_range<Glib::ustring>(found.end(),
- dataString.end()));
- for (vector<string>::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<char>(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<GraphDataBase> 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<string> tokens = commaSplit(dataString);
- int i = 0;
- int64_t time;
- vector<string>::iterator tokIter = tokens.begin();
- std::istringstream timeStream(*tokIter++);
- timeStream >> time;
- for (vector<string>::iterator e = tokens.end();
- tokIter != e;
- ++tokIter, ++i)
- {
- parseData(_csv.elements[i].second, time,
- *tokIter);
- }
- }
- else
- {
- int64_t time;
- stringbuf data;
- stream >> time;
- stream.get(data, _lineEndChar);
- parseData(itr->second, time, data.str());
- }
- }
- }
- }
- _buffer.erase(0, ret + 1);
- }
+ }
+ if ((ioCondition & Glib::IO_IN) == 0)
return true;
- }
-
- bool StapParser::errIoCallback(Glib::IOCondition ioCondition)
- {
- using namespace std;
- if ((ioCondition & Glib::IO_IN) == 0)
+ 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(_errFd, buf, sizeof(buf) - 1);
- if (bytes_read <= 0)
- {
- cerr << "StapParser: error reading from stderr!\n";
- return true;
- }
- if (write(STDERR_FILENO, buf, bytes_read) < 0)
- ;
+ }
+ _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<Glib::ustring> 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<GraphData<double> >
+ dataSet(new GraphData<double>);
+ 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<GraphData<string> >
+ dataSet(new GraphData<string>);
+ 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<string> tokens
+ = commaSplit(sub_range<Glib::ustring>(found.end(),
+ dataString.end()));
+ for (vector<string>::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<char>(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<GraphDataBase> 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<string> tokens = commaSplit(dataString);
+ int i = 0;
+ int64_t time;
+ vector<string>::iterator tokIter = tokens.begin();
+ std::istringstream timeStream(*tokIter++);
+ timeStream >> time;
+ for (vector<string>::iterator e = tokens.end();
+ tokIter != e;
+ ++tokIter, ++i)
+ {
+ parseData(_csv.elements[i].second, time,
+ *tokIter);
+ }
+ }
+ else
+ {
+ int64_t time;
+ stringbuf data;
+ stream >> time;
+ stream.get(data, _lineEndChar);
+ parseData(itr->second, time, data.str());
+ }
+ }
+ }
+ }
+ _buffer.erase(0, ret + 1);
+ }
+ return true;
+}
+
+bool StapParser::errIoCallback(Glib::IOCondition ioCondition)
+{
+ using namespace std;
+ if ((ioCondition & Glib::IO_IN) == 0)
return true;
- }
+ char buf[256];
+ ssize_t bytes_read = 0;
+ bytes_read = read(_errFd, buf, sizeof(buf) - 1);
+ if (bytes_read <= 0)
+ {
+ cerr << "StapParser: error reading from stderr!\n";
+ return true;
+ }
+ if (write(STDERR_FILENO, buf, bytes_read) < 0)
+ ;
+ return true;
+}
- 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::ioCallback),
- _inFd, inCond);
+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::ioCallback),
+ _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;
- }
- }
+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 169533b6..b410ab18 100644
--- a/grapher/StapParser.hxx
+++ b/grapher/StapParser.hxx
@@ -15,65 +15,65 @@
namespace systemtap
{
- // arguments and script for a stap process
- struct StapProcess
- {
- StapProcess(pid_t pid_ = -1) : argv(0), 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;
- };
+// arguments and script for a stap process
+struct StapProcess
+{
+ StapProcess(pid_t pid_ = -1) : argv(0), 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
+class StapParser
+{
+ std::string _buffer;
+ typedef std::map<std::string, std::tr1::shared_ptr<GraphDataBase> > DataMap;
+ DataMap _dataSets;
+ CSVData _csv;
+ int _errFd;
+ int _inFd;
+ unsigned char _lineEndChar;
+ bool _catchHUP;
+ std::tr1::shared_ptr<StapProcess> _process;
+ sigc::connection _ioConnection;
+ sigc::connection _errIoConnection;
+public:
+ StapParser()
+ : _errFd(-1), _inFd(-1), _lineEndChar('\n'), _catchHUP(false)
+ {
+ }
+ void parseData(std::tr1::shared_ptr<GraphDataBase> 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<StapProcess> getProcess() { return _process; }
+ void setProcess(std::tr1::shared_ptr<StapProcess> process)
{
- std::string _buffer;
- typedef std::map<std::string, std::tr1::shared_ptr<GraphDataBase> > DataMap;
- DataMap _dataSets;
- CSVData _csv;
- int _errFd;
- int _inFd;
- unsigned char _lineEndChar;
- bool _catchHUP;
- std::tr1::shared_ptr<StapProcess> _process;
- sigc::connection _ioConnection;
- sigc::connection _errIoConnection;
- public:
- StapParser()
- : _errFd(-1), _inFd(-1), _lineEndChar('\n'), _catchHUP(false)
- {
- }
- void parseData(std::tr1::shared_ptr<GraphDataBase> 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<StapProcess> getProcess() { return _process; }
- void setProcess(std::tr1::shared_ptr<StapProcess> process)
- {
- _process = process;
- }
- void initIo(int inFd, int errFd, bool catchHUP);
- void disconnect();
- };
+ _process = process;
+ }
+ void initIo(int inFd, int errFd, bool catchHUP);
+ void disconnect();
+};
- sigc::signal<void, pid_t>& childDiedSignal();
+sigc::signal<void, pid_t>& childDiedSignal();
- typedef std::vector<std::tr1::shared_ptr<StapParser> > ParserList;
- extern ParserList parsers;
+typedef std::vector<std::tr1::shared_ptr<StapParser> > ParserList;
+extern ParserList parsers;
- sigc::signal<void>& parserListChangedSignal();
+sigc::signal<void>& parserListChangedSignal();
}
diff --git a/loc2c.c b/loc2c.c
index d3ec55fa..a7473784 100644
--- a/loc2c.c
+++ b/loc2c.c
@@ -30,6 +30,13 @@
#define N_(x) x
+/* NB: PR10601 may make one suspect that intptr_t and uintptr_t aren't
+ right, for example on a 64-bit kernel targeting a 32-bit userspace
+ process. At least these types are always at least as wide as
+ userspace (since 64-bit userspace doesn't run on a 32-bit kernel).
+ So as long as deref() and {fetch,store}_register() widen/narrow
+ their underlying values to these, there should be no problem. */
+
#define STACK_TYPE "intptr_t" /* Must be the signed type. */
#define UTYPE "uintptr_t" /* Must be the unsigned type. */
#define SFORMAT "%" PRId64 "L"
diff --git a/runtime/autoconf-regset.c b/runtime/autoconf-regset.c
new file mode 100644
index 00000000..9d994b03
--- /dev/null
+++ b/runtime/autoconf-regset.c
@@ -0,0 +1,7 @@
+#include <linux/regset.h>
+
+int foobar(int n) {
+ const struct user_regset_view *rsv = task_user_regset_view(current);
+ const struct user_regset *rs = & rsv->regsets[0];
+ return rsv->n + n + (rs->get)(current, rs, 0, 0, NULL, NULL);
+}
diff --git a/runtime/autoconf-utrace-regset.c b/runtime/autoconf-utrace-regset.c
new file mode 100644
index 00000000..1728f239
--- /dev/null
+++ b/runtime/autoconf-utrace-regset.c
@@ -0,0 +1,8 @@
+#include <linux/tracehook.h>
+
+/* old rhel5 utrace regset */
+int foobar(int n) {
+ const struct utrace_regset_view *rsv = utrace_native_view(current);
+ const struct utrace_regset *rs = & rsv->regsets[0];
+ return rsv->n + n + (rs->get)(current, rs, 0, 0, NULL, NULL);
+}
diff --git a/runtime/loc2c-runtime.h b/runtime/loc2c-runtime.h
index e9e5a071..c75639ee 100644
--- a/runtime/loc2c-runtime.h
+++ b/runtime/loc2c-runtime.h
@@ -1,5 +1,5 @@
/* target operations
- * Copyright (C) 2005 Red Hat Inc.
+ * Copyright (C) 2005-2009 Red Hat Inc.
* Copyright (C) 2005, 2006, 2007 Intel Corporation.
* Copyright (C) 2007 Quentin Barnes.
*
@@ -44,10 +44,10 @@
can be pasted into an identifier name. These definitions turn it into a
per-register macro, defined below for machines with individually-named
registers. */
-#define fetch_register(regno) \
- ((intptr_t) dwarf_register_##regno (c->regs))
-#define store_register(regno, value) \
- (dwarf_register_##regno (c->regs) = (value))
+#define k_fetch_register(regno) \
+ ((intptr_t) k_dwarf_register_##regno (c->regs))
+#define k_store_register(regno, value) \
+ (k_dwarf_register_##regno (c->regs) = (value))
/* The deref and store_deref macros are called to safely access addresses
@@ -82,35 +82,266 @@
})
#endif
+/* PR 10601: user-space (user_regset) register access. */
+#if defined(STAPCONF_REGSET)
+#include <linux/regset.h>
+#endif
+
+#if defined(STAPCONF_UTRACE_REGSET)
+#include <linux/tracehook.h>
+/* adapt new names to old decls */
+#define user_regset_view utrace_regset_view
+#define user_regset utrace_regset
+#define task_user_regset_view utrace_native_view
+#endif
+
+#if defined(STAPCONF_REGSET) || defined(STAPCONF_UTRACE_REGSET)
+
+struct usr_regset_lut {
+ char *name;
+ unsigned rsn;
+ unsigned pos;
+};
+
+
+/* DWARF register number -to- user_regset bank/offset mapping table.
+ The register numbers come from the processor-specific ELF documents.
+ The user-regset bank/offset values come from kernel $ARCH/include/asm/user*.h
+ or $ARCH/kernel/ptrace.c. */
+static const struct usr_regset_lut url_i386[] = {
+ { "ax", NT_PRSTATUS, 6*4 },
+ { "cx", NT_PRSTATUS, 1*4 },
+ { "dx", NT_PRSTATUS, 2*4 },
+ { "bx", NT_PRSTATUS, 0*4 },
+ { "sp", NT_PRSTATUS, 15*4 },
+ { "bp", NT_PRSTATUS, 5*4 },
+ { "si", NT_PRSTATUS, 3*4 },
+ { "di", NT_PRSTATUS, 4*4 },
+ { "ip", NT_PRSTATUS, 12*4 },
+};
+
+static const struct usr_regset_lut url_x86_64[] = {
+ { "rax", NT_PRSTATUS, 10*8 },
+ { "rdx", NT_PRSTATUS, 12*8 },
+ { "rcx", NT_PRSTATUS, 11*8 },
+ { "rbx", NT_PRSTATUS, 5*8 },
+ { "rsi", NT_PRSTATUS, 13*8 },
+ { "rdi", NT_PRSTATUS, 14*8 },
+ { "rbp", NT_PRSTATUS, 4*8 },
+ { "rsp", NT_PRSTATUS, 19*8 },
+ { "r8", NT_PRSTATUS, 9*8 },
+ { "r9", NT_PRSTATUS, 8*8 },
+ { "r10", NT_PRSTATUS, 7*8 },
+ { "r11", NT_PRSTATUS, 6*8 },
+ { "r12", NT_PRSTATUS, 3*8 },
+ { "r13", NT_PRSTATUS, 2*8 },
+ { "r14", NT_PRSTATUS, 1*8 },
+ { "r15", NT_PRSTATUS, 0*8 },
+ { "rip", NT_PRSTATUS, 16*8 },
+ /* XXX: SSE registers %xmm0-%xmm7 */
+ /* XXX: SSE2 registers %xmm8-%xmm15 */
+ /* XXX: FP registers %st0-%st7 */
+ /* XXX: MMX registers %mm0-%mm7 */
+};
+/* XXX: insert other architectures here. */
+
+
+static u32 ursl_fetch32 (const struct usr_regset_lut* lut, unsigned lutsize, int e_machine, unsigned regno)
+{
+ u32 value = ~0;
+ const struct user_regset_view *rsv = task_user_regset_view(current);
+ unsigned rsi;
+ int rc;
+ unsigned rsn;
+ unsigned pos;
+ unsigned count;
+
+ WARN_ON (!rsv);
+ if (!rsv) goto out;
+ WARN_ON (regno >= lutsize);
+ if (regno >= lutsize) goto out;
+ if (rsv->e_machine != e_machine) goto out;
+
+ rsn = lut[regno].rsn;
+ pos = lut[regno].pos;
+ count = sizeof(value);
+
+ for (rsi=0; rsi<rsv->n; rsi++)
+ if (rsv->regsets[rsi].core_note_type == rsn)
+ {
+ const struct user_regset *rs = & rsv->regsets[rsi];
+ rc = (rs->get)(current, rs, pos, count, & value, NULL);
+ WARN_ON (rc);
+ /* success */
+ goto out;
+ }
+ WARN_ON (1); /* did not find appropriate regset! */
+
+ out:
+ return value;
+}
+
+
+static void ursl_store32 (const struct usr_regset_lut* lut,unsigned lutsize, int e_machine, unsigned regno, u32 value)
+{
+ const struct user_regset_view *rsv = task_user_regset_view(current);
+ unsigned rsi;
+ int rc;
+ unsigned rsn;
+ unsigned pos;
+ unsigned count;
+
+ WARN_ON (!rsv);
+ if (!rsv) goto out;
+ WARN_ON (regno >= lutsize);
+ if (regno >= lutsize) goto out;
+ if (rsv->e_machine != e_machine) goto out;
+
+ rsn = lut[regno].rsn;
+ pos = lut[regno].pos;
+ count = sizeof(value);
+
+ for (rsi=0; rsi<rsv->n; rsi++)
+ if (rsv->regsets[rsi].core_note_type == rsn)
+ {
+ const struct user_regset *rs = & rsv->regsets[rsi];
+ rc = (rs->set)(current, rs, pos, count, & value, NULL);
+ WARN_ON (rc);
+ /* success */
+ goto out;
+ }
+ WARN_ON (1); /* did not find appropriate regset! */
+
+ out:
+ return;
+}
+
+
+static u64 ursl_fetch64 (const struct usr_regset_lut* lut, unsigned lutsize, int e_machine, unsigned regno)
+{
+ u64 value = ~0;
+ const struct user_regset_view *rsv = task_user_regset_view(current);
+ unsigned rsi;
+ int rc;
+ unsigned rsn;
+ unsigned pos;
+ unsigned count;
+
+ if (!rsv) goto out;
+ if (regno >= lutsize) goto out;
+ if (rsv->e_machine != e_machine) goto out;
+
+ rsn = lut[regno].rsn;
+ pos = lut[regno].pos;
+ count = sizeof(value);
+
+ for (rsi=0; rsi<rsv->n; rsi++)
+ if (rsv->regsets[rsi].core_note_type == rsn)
+ {
+ const struct user_regset *rs = & rsv->regsets[rsi];
+ rc = (rs->get)(current, rs, pos, count, & value, NULL);
+ if (rc)
+ goto out;
+ /* success */
+ return value;
+ }
+ out:
+ printk (KERN_WARNING "process %d mach %d regno %d not available for fetch.\n", current->tgid, e_machine, regno);
+ return value;
+}
+
+
+static void ursl_store64 (const struct usr_regset_lut* lut,unsigned lutsize, int e_machine, unsigned regno, u64 value)
+{
+ const struct user_regset_view *rsv = task_user_regset_view(current);
+ unsigned rsi;
+ int rc;
+ unsigned rsn;
+ unsigned pos;
+ unsigned count;
+
+ WARN_ON (!rsv);
+ if (!rsv) goto out;
+ WARN_ON (regno >= lutsize);
+ if (regno >= lutsize) goto out;
+ if (rsv->e_machine != e_machine) goto out;
+
+ rsn = lut[regno].rsn;
+ pos = lut[regno].pos;
+ count = sizeof(value);
+
+ for (rsi=0; rsi<rsv->n; rsi++)
+ if (rsv->regsets[rsi].core_note_type == rsn)
+ {
+ const struct user_regset *rs = & rsv->regsets[rsi];
+ rc = (rs->set)(current, rs, pos, count, & value, NULL);
+ if (rc)
+ goto out;
+ /* success */
+ return;
+ }
+
+ out:
+ printk (KERN_WARNING "process %d mach %d regno %d not available for store.\n", current->tgid, e_machine, regno);
+ return;
+}
+
+
+#if defined (__i386__)
+
+#define u_fetch_register(regno) ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno)
+#define u_store_register(regno,value) ursl_store32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value)
+
+#elif defined (__x86_64__)
+
+#define u_fetch_register(regno) (_stp_probing_32bit_app(c->regs) ? ursl_fetch32(url_i386, ARRAY_SIZE(url_i386), EM_386, regno) : ursl_fetch64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno))
+#define u_store_register(regno,value) (_stp_probing_32bit_app(c->regs) ? ursl_store2(url_i386, ARRAY_SIZE(url_i386), EM_386, regno, value) : ursl_store64(url_x86_64, ARRAY_SIZE(url_x86_64), EM_X86_64, regno, value))
+
+#else
+
+/* Some other architecture; downgrade to kernel register access. */
+#define u_fetch_register(regno) k_fetch_register(regno)
+#define u_store_register(regno,value) k_store_register(regno,value)
+
+#endif
+
+
+#else /* ! STAPCONF_REGSET */
+/* Downgrade to kernel register access. */
+#define u_fetch_register(regno) k_fetch_register(regno)
+#define u_store_register(regno,value) k_store_register(regno,value)
+#endif
+
+
#if defined (STAPCONF_X86_UNIREGS) && defined (__i386__)
-#define dwarf_register_0(regs) regs->ax
-#define dwarf_register_1(regs) regs->cx
-#define dwarf_register_2(regs) regs->dx
-#define dwarf_register_3(regs) regs->bx
-#define dwarf_register_4(regs) ((long) &regs->sp)
-#define dwarf_register_5(regs) regs->bp
-#define dwarf_register_6(regs) regs->si
-#define dwarf_register_7(regs) regs->di
+#define k_dwarf_register_0(regs) regs->ax
+#define k_dwarf_register_1(regs) regs->cx
+#define k_dwarf_register_2(regs) regs->dx
+#define k_dwarf_register_3(regs) regs->bx
+#define k_dwarf_register_4(regs) ((long) &regs->sp)
+#define k_dwarf_register_5(regs) regs->bp
+#define k_dwarf_register_6(regs) regs->si
+#define k_dwarf_register_7(regs) regs->di
#elif defined (STAPCONF_X86_UNIREGS) && defined (__x86_64__)
-#define dwarf_register_0(regs) regs->ax
-#define dwarf_register_1(regs) regs->dx
-#define dwarf_register_2(regs) regs->cx
-#define dwarf_register_3(regs) regs->bx
-#define dwarf_register_4(regs) regs->si
-#define dwarf_register_5(regs) regs->di
-#define dwarf_register_6(regs) regs->bp
-#define dwarf_register_7(regs) regs->sp
-#define dwarf_register_8(regs) regs->r8
-#define dwarf_register_9(regs) regs->r9
-#define dwarf_register_10(regs) regs->r10
-#define dwarf_register_11(regs) regs->r11
-#define dwarf_register_12(regs) regs->r12
-#define dwarf_register_13(regs) regs->r13
-#define dwarf_register_14(regs) regs->r14
-#define dwarf_register_15(regs) regs->r15
+#define k_dwarf_register_0(regs) regs->ax
+#define k_dwarf_register_1(regs) regs->dx
+#define k_dwarf_register_2(regs) regs->cx
+#define k_dwarf_register_3(regs) regs->bx
+#define k_dwarf_register_4(regs) regs->si
+#define k_dwarf_register_5(regs) regs->di
+#define k_dwarf_register_6(regs) regs->bp
+#define k_dwarf_register_7(regs) regs->sp
+#define k_dwarf_register_8(regs) regs->r8
+#define k_dwarf_register_9(regs) regs->r9
+#define k_dwarf_register_10(regs) regs->r10
+#define k_dwarf_register_11(regs) regs->r11
+#define k_dwarf_register_12(regs) regs->r12
+#define k_dwarf_register_13(regs) regs->r13
+#define k_dwarf_register_14(regs) regs->r14
+#define k_dwarf_register_15(regs) regs->r15
#elif defined __i386__
@@ -120,60 +351,60 @@
For a kernel mode trap, the interrupted state's esp is actually an
address inside where the `struct pt_regs' on the kernel trap stack points. */
-#define dwarf_register_0(regs) regs->eax
-#define dwarf_register_1(regs) regs->ecx
-#define dwarf_register_2(regs) regs->edx
-#define dwarf_register_3(regs) regs->ebx
-#define dwarf_register_4(regs) (user_mode(regs) ? regs->esp : (long)&regs->esp)
-#define dwarf_register_5(regs) regs->ebp
-#define dwarf_register_6(regs) regs->esi
-#define dwarf_register_7(regs) regs->edi
+#define k_dwarf_register_0(regs) regs->eax
+#define k_dwarf_register_1(regs) regs->ecx
+#define k_dwarf_register_2(regs) regs->edx
+#define k_dwarf_register_3(regs) regs->ebx
+#define k_dwarf_register_4(regs) (user_mode(regs) ? regs->esp : (long)&regs->esp)
+#define k_dwarf_register_5(regs) regs->ebp
+#define k_dwarf_register_6(regs) regs->esi
+#define k_dwarf_register_7(regs) regs->edi
#elif defined __ia64__
-#undef fetch_register
-#undef store_register
+#undef k_fetch_register
+#undef k_store_register
-#define fetch_register(regno) ia64_fetch_register(regno, c->regs, &c->unwaddr)
-#define store_register(regno,value) ia64_store_register(regno, c->regs, value)
+#define k_fetch_register(regno) ia64_fetch_register(regno, c->regs, &c->unwaddr)
+#define k_store_register(regno,value) ia64_store_register(regno, c->regs, value)
#elif defined __x86_64__
-#define dwarf_register_0(regs) regs->rax
-#define dwarf_register_1(regs) regs->rdx
-#define dwarf_register_2(regs) regs->rcx
-#define dwarf_register_3(regs) regs->rbx
-#define dwarf_register_4(regs) regs->rsi
-#define dwarf_register_5(regs) regs->rdi
-#define dwarf_register_6(regs) regs->rbp
-#define dwarf_register_7(regs) regs->rsp
-#define dwarf_register_8(regs) regs->r8
-#define dwarf_register_9(regs) regs->r9
-#define dwarf_register_10(regs) regs->r10
-#define dwarf_register_11(regs) regs->r11
-#define dwarf_register_12(regs) regs->r12
-#define dwarf_register_13(regs) regs->r13
-#define dwarf_register_14(regs) regs->r14
-#define dwarf_register_15(regs) regs->r15
+#define k_dwarf_register_0(regs) regs->rax
+#define k_dwarf_register_1(regs) regs->rdx
+#define k_dwarf_register_2(regs) regs->rcx
+#define k_dwarf_register_3(regs) regs->rbx
+#define k_dwarf_register_4(regs) regs->rsi
+#define k_dwarf_register_5(regs) regs->rdi
+#define k_dwarf_register_6(regs) regs->rbp
+#define k_dwarf_register_7(regs) regs->rsp
+#define k_dwarf_register_8(regs) regs->r8
+#define k_dwarf_register_9(regs) regs->r9
+#define k_dwarf_register_10(regs) regs->r10
+#define k_dwarf_register_11(regs) regs->r11
+#define k_dwarf_register_12(regs) regs->r12
+#define k_dwarf_register_13(regs) regs->r13
+#define k_dwarf_register_14(regs) regs->r14
+#define k_dwarf_register_15(regs) regs->r15
#elif defined __powerpc__
-#undef fetch_register
-#undef store_register
-#define fetch_register(regno) ((intptr_t) c->regs->gpr[regno])
-#define store_register(regno,value) (c->regs->gpr[regno] = (value))
+#undef k_fetch_register
+#undef k_store_register
+#define k_fetch_register(regno) ((intptr_t) c->regs->gpr[regno])
+#define k_store_register(regno,value) (c->regs->gpr[regno] = (value))
#elif defined (__arm__)
-#undef fetch_register
-#undef store_register
-#define fetch_register(regno) ((long) c->regs->uregs[regno])
-#define store_register(regno,value) (c->regs->uregs[regno] = (value))
+#undef k_fetch_register
+#undef k_store_register
+#define k_fetch_register(regno) ((long) c->regs->uregs[regno])
+#define k_store_register(regno,value) (c->regs->uregs[regno] = (value))
#elif defined (__s390__) || defined (__s390x__)
-#undef fetch_register
-#undef store_register
-#define fetch_register(regno) ((intptr_t) c->regs->gprs[regno])
-#define store_register(regno,value) (c->regs->gprs[regno] = (value))
+#undef k_fetch_register
+#undef k_store_register
+#define k_fetch_register(regno) ((intptr_t) c->regs->gprs[regno])
+#define k_store_register(regno,value) (c->regs->gprs[regno] = (value))
#endif
@@ -228,6 +459,7 @@
} \
})
+
extern void __deref_bad(void);
extern void __store_deref_bad(void);
@@ -746,6 +978,7 @@ extern void __store_deref_bad(void);
#endif /* STAPCONF_PROBE_KERNEL */
+
#define deref_string(dst, addr, maxbytes) \
({ \
uintptr_t _addr; \
diff --git a/runtime/stack-i386.c b/runtime/stack-i386.c
index 66d892d3..d10aeb2f 100644
--- a/runtime/stack-i386.c
+++ b/runtime/stack-i386.c
@@ -63,7 +63,7 @@ static void __stp_stack_print (struct pt_regs *regs, int verbose, int levels,
while (levels && (tsk || !arch_unw_user_mode(&info))) {
int ret = unwind(&info, tsk);
-#if defined(UPROBES_API_VERSION) && UPROBES_API_VERSION > 1
+#ifdef CONFIG_UTRACE
unsigned long maybe_pc = 0;
if (ri) {
maybe_pc = uprobe_get_pc(ri, UNW_PC(&info),
diff --git a/runtime/stack-x86_64.c b/runtime/stack-x86_64.c
index d6c63412..030e5ef1 100644
--- a/runtime/stack-x86_64.c
+++ b/runtime/stack-x86_64.c
@@ -38,7 +38,7 @@ static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels,
while (levels && (tsk || !arch_unw_user_mode(&info))) {
int ret = unwind(&info, tsk);
-#if defined(UPROBES_API_VERSION) && UPROBES_API_VERSION > 1
+#ifdef CONFIG_UTRACE
unsigned long maybe_pc = 0;
if (ri) {
maybe_pc = uprobe_get_pc(ri, UNW_PC(&info),
diff --git a/runtime/stack.c b/runtime/stack.c
index 4dd1dca3..50dde6e1 100644
--- a/runtime/stack.c
+++ b/runtime/stack.c
@@ -133,13 +133,15 @@ static void _stp_stack_print(struct pt_regs *regs, int verbose, struct kretprobe
}
_stp_symbol_print((unsigned long)_stp_ret_addr_r(pi));
} else if (ri) {
+#ifdef CONFIG_UTRACE /* as a proxy for presence of uprobes */
if (verbose == SYM_VERBOSE_FULL) {
_stp_print("Returning from: ");
- _stp_usymbol_print(ri->rp->u.vaddr, tsk);
+ _stp_usymbol_print(ri->rp->u.vaddr, tsk); /* otherwise this dereference fails */
_stp_print("\nReturning to : ");
_stp_usymbol_print(ri->ret_addr, tsk);
} else
_stp_func_print(ri->ret_addr, verbose, 0, tsk);
+#endif
} else {
_stp_print_char(' ');
if (tsk)
diff --git a/runtime/sym.c b/runtime/sym.c
index cd0c8a71..06691dc9 100644
--- a/runtime/sym.c
+++ b/runtime/sym.c
@@ -19,6 +19,22 @@
/* Callback that needs to be registered (in
session.unwindsyms_modules) for every user task path for which we
might need symbols or unwind info. */
+static int _stp_tf_exec_cb(struct stap_task_finder_target *tgt,
+ struct task_struct *tsk,
+ int register_p,
+ int process_p)
+{
+#ifdef DEBUG_TASK_FINDER_VMA
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "tsk %d:%d , register_p: %d, process_p: %d\n",
+ tsk->pid, tsk->tgid, register_p, process_p);
+#endif
+ if (process_p && ! register_p)
+ stap_drop_vma_maps(tsk);
+
+ return 0;
+}
+
static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt,
struct task_struct *tsk,
char *path,
@@ -42,40 +58,22 @@ static int _stp_tf_mmap_cb(struct stap_task_finder_target *tgt,
if (strcmp(path, _stp_modules[i]->path) == 0)
{
#ifdef DEBUG_TASK_FINDER_VMA
- _stp_dbug(__FUNCTION__, __LINE__,
- "vm_cb: matched path %s to module\n",
- path);
+ _stp_dbug(__FUNCTION__, __LINE__,
+ "vm_cb: matched path %s to module (for sec: %s)\n",
+ path, _stp_modules[i]->sections[0].name);
#endif
- module = _stp_modules[i];
- // cheat...
- // We are abusing the "first" section address
- // here to indicate where the module (actually
- // first segment) is loaded (which is why we
- // are ignoring the offset). It would be good
- // to redesign the stp_module/stp_section
- // data structures to better align with the
- // actual memory mappings we are interested
- // in (especially the "section" naming is
- // slightly confusing since what we really
- // seem to mean are elf segments (which can
- // contain multiple elf sections). PR11015.
- if (strcmp(".dynamic",
- module->sections[0].name) == 0)
- {
- if (module->sections[0].addr == 0)
- module->sections[0].addr = addr;
- else if (module->sections[0].addr != addr)
- _stp_error ("Reloaded module '%s'"
- " at 0x%lx, was 0x%lx\n",
- path, addr,
- module->sections[0].addr);
- }
- break;
+ module = _stp_modules[i];
+ /* XXX We really only need to register .dynamic
+ sections, but .absolute exes are also necessary
+ atm. */
+ return stap_add_vma_map_info(tsk->group_leader,
+ addr,
+ addr + length,
+ offset,
+ module);
}
}
}
- stap_add_vma_map_info(tsk->group_leader, addr, addr + length, offset,
- module);
return 0;
}
@@ -84,15 +82,25 @@ static int _stp_tf_munmap_cb(struct stap_task_finder_target *tgt,
unsigned long addr,
unsigned long length)
{
+ /* Unconditionally remove vm map info, ignore if not present. */
stap_remove_vma_map_info(tsk->group_leader, addr, addr + length, 0);
return 0;
}
-/* XXX: this needs to be address-space-specific. */
-static unsigned long _stp_module_relocate(const char *module, const char *section, unsigned long offset)
+/* Returns absolute address of offset into module/section for given task.
+ If tsk == NULL module/section is assumed to be absolute/static already
+ (e.g. kernel, kernel-modules and static executables). Returns zero when
+ module and section couldn't be found (aren't in memory yet). */
+static unsigned long _stp_module_relocate(const char *module,
+ const char *section,
+ unsigned long offset,
+ struct task_struct *tsk)
{
+ /* XXX This doesn't look thread safe XXX */
static struct _stp_module *last = NULL;
static struct _stp_section *last_sec;
+ static struct task_struct *last_tsk;
+ static unsigned long last_offset;
unsigned i, j;
/* if module is -1, we invalidate last. _stp_del_module calls this when modules are deleted. */
@@ -110,8 +118,10 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
/* Most likely our relocation is in the same section of the same module as the last. */
if (last) {
- if (!strcmp(module, last->name) && !strcmp(section, last_sec->name)) {
- offset += last_sec->addr;
+ if (!strcmp(module, last->name)
+ && !strcmp(section, last_sec->name)
+ && tsk == last_tsk) {
+ offset += last_offset;
dbug_sym(1, "cached address=%lx\n", offset);
return offset;
}
@@ -124,11 +134,33 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
for (j = 0; j < last->num_sections; j++) {
last_sec = &last->sections[j];
if (!strcmp(section, last_sec->name)) {
-
- if (last_sec->addr == 0) /* module/section not in memory */
- continue;
-
- offset += last_sec->addr;
+ /* mod and sec name match. tsk should match dynamic/static. */
+ if (last_sec->static_addr != 0) {
+ last_offset = last_sec->static_addr;
+ } else {
+ if (!tsk) { /* static section, not in memory yet? */
+ if (strcmp(".dynamic", section) == 0)
+ _stp_error("internal error, _stp_module_relocate '%s' "
+ "section '%s', should not be tsk dynamic\n",
+ module, section);
+ last = NULL;
+ return 0;
+ } else { /* dynamic section, look up through tsk vma. */
+ if (strcmp(".dynamic", last_sec->name) != 0) {
+ _stp_error("internal error, _stp_module_relocate '%s' "
+ "section '%s', should not be tsk dynamic\n",
+ module, section);
+ return 0;
+ }
+ if (stap_find_vma_map_info_user(tsk->group_leader, last,
+ &last_offset, NULL,
+ NULL) != 0) {
+ last = NULL;
+ return 0;
+ }
+ }
+ }
+ offset += last_offset;
dbug_sym(1, "address=%lx\n", offset);
return offset;
}
@@ -140,11 +172,12 @@ static unsigned long _stp_module_relocate(const char *module, const char *sectio
}
/* Return module owner and, if sec != NULL, fills in closest section
- of the address if found, return NULL otherwise.
- XXX: needs to be address-space-specific. */
+ of the address if found, return NULL otherwise. Fills in rel_addr
+ (addr relative to closest section) when given. */
static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
struct task_struct *task,
- struct _stp_section **sec)
+ struct _stp_section **sec,
+ unsigned long *rel_addr)
{
void *user = NULL;
unsigned midx = 0;
@@ -160,11 +193,21 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
{
struct _stp_module *m = (struct _stp_module *)user;
if (sec)
- *sec = &m->sections[0]; // XXX check actual section and relocate
+ *sec = &m->sections[0]; // dynamic user modules have one section.
+ if (rel_addr)
+ {
+ /* XXX .absolute sections really shouldn't be here... */
+ if (strcmp(".dynamic", m->sections[0].name) == 0)
+ *rel_addr = addr - vm_start;
+ else
+ *rel_addr = addr;
+ }
dbug_sym(1, "found section %s in module %s at 0x%lx\n",
m->sections[0].name, m->name, vm_start);
return m;
}
+ /* XXX should really not fallthrough, but sometimes current is passed
+ when it shouldn't - see probefunc() for example. */
}
for (midx = 0; midx < _stp_num_modules; midx++)
@@ -174,12 +217,14 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
{
unsigned long sec_addr;
unsigned long sec_size;
- sec_addr = _stp_modules[midx]->sections[secidx].addr;
+ sec_addr = _stp_modules[midx]->sections[secidx].static_addr;
sec_size = _stp_modules[midx]->sections[secidx].size;
if (addr >= sec_addr && addr < sec_addr + sec_size)
{
if (sec)
*sec = & _stp_modules[midx]->sections[secidx];
+ if (rel_addr)
+ *rel_addr = addr - sec_addr;
return _stp_modules[midx];
}
}
@@ -188,7 +233,6 @@ static struct _stp_module *_stp_mod_sec_lookup(unsigned long addr,
}
-/* XXX: needs to be address-space-specific. */
static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbolsize,
unsigned long *offset,
const char **modname,
@@ -200,13 +244,14 @@ static const char *_stp_kallsyms_lookup(unsigned long addr, unsigned long *symbo
struct _stp_section *sec = NULL;
struct _stp_symbol *s = NULL;
unsigned end, begin = 0;
+ unsigned long rel_addr = 0;
- m = _stp_mod_sec_lookup(addr, task, &sec);
+ m = _stp_mod_sec_lookup(addr, task, &sec, &rel_addr);
if (unlikely (m == NULL || sec == NULL))
return NULL;
/* NB: relativize the address to the section. */
- addr -= sec->addr;
+ addr = rel_addr;
end = sec->num_symbols;
/* binary search for symbols within the module */
@@ -268,9 +313,9 @@ static int _stp_module_check(void)
/* notes end address */
if (!strcmp(m->name, "kernel")) {
notes_addr = _stp_module_relocate("kernel",
- "_stext", m->build_id_offset);
+ "_stext", m->build_id_offset, NULL);
base_addr = _stp_module_relocate("kernel",
- "_stext", 0);
+ "_stext", 0, NULL);
} else {
notes_addr = m->notes_sect + m->build_id_offset;
base_addr = m->notes_sect;
@@ -446,14 +491,20 @@ static void _stp_sym_init(void)
static struct stap_task_finder_target vmcb = {
// NB: no .pid, no .procname filters here.
// This means that we get a system-wide mmap monitoring
- // widget while the script is running. (The system-wideness may
- // be restricted by stap -c or -x.) But this seems to
- // be necessary if we want to to stack tracebacks through arbitrary
- // shared libraries. XXX: There may be an optimization opportunity
- // for executables (for which the main task-finder callback should be
- // sufficient).
+ // widget while the script is running. (The
+ // system-wideness may be restricted by stap -c or
+ // -x.) But this seems to be necessary if we want to
+ // to stack tracebacks through arbitrary shared libraries.
+ //
+ // XXX: There may be an optimization opportunity
+ // for executables (for which the main task-finder
+ // callback should be sufficient).
+ .pid = 0,
+ .procname = NULL,
+ .callback = &_stp_tf_exec_cb,
.mmap_callback = &_stp_tf_mmap_cb,
.munmap_callback = &_stp_tf_munmap_cb,
+ .mprotect_callback = NULL
};
if (! initialized) {
int rc;
@@ -462,8 +513,10 @@ static void _stp_sym_init(void)
#ifdef DEBUG_TASK_FINDER_VMA
_stp_dbug(__FUNCTION__, __LINE__, "registered vmcb");
#endif
- (void) rc; // XXX
- initialized = 1;
+ if (rc != 0)
+ _stp_error("Couldn't register task finder target: %d\n", rc);
+ else
+ initialized = 1;
}
#endif
}
diff --git a/runtime/sym.h b/runtime/sym.h
index 9f2bdfd0..ce6ab736 100644
--- a/runtime/sym.h
+++ b/runtime/sym.h
@@ -17,7 +17,7 @@ struct _stp_symbol {
struct _stp_section {
const char *name;
- unsigned long addr; /* XXX: belongs in per-address-space tables */
+ unsigned long static_addr; /* XXX non-null if everywhere the same. */
unsigned long size; /* length of the address space module covers. */
struct _stp_symbol *symbols; /* ordered by address */
unsigned num_symbols;
@@ -70,7 +70,10 @@ static unsigned long _stp_kretprobe_trampoline;
_stp_sym_init () should track vma maps. */
static char _stp_need_vma_tracker;
-static unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset);
+static unsigned long _stp_module_relocate (const char *module,
+ const char *section,
+ unsigned long offset,
+ struct task_struct *tsk);
static struct _stp_module *_stp_get_unwind_info (unsigned long addr);
#endif /* _STP_SYM_H_ */
diff --git a/runtime/task_finder_vma.c b/runtime/task_finder_vma.c
index ed9c6f4f..9a32323f 100644
--- a/runtime/task_finder_vma.c
+++ b/runtime/task_finder_vma.c
@@ -270,6 +270,7 @@ stap_add_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
// Remove the vma entry from the vma hash table.
+// Returns -ESRCH if the entry isn't present.
static int
stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
unsigned long vm_end, unsigned long vm_pgoff)
@@ -277,6 +278,7 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
struct hlist_head *head;
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
+ int rc = -ESRCH;
// Take a write lock since we are most likely going to delete
// after reading.
@@ -286,13 +288,15 @@ stap_remove_vma_map_info(struct task_struct *tsk, unsigned long vm_start,
if (entry != NULL) {
hlist_del(&entry->hlist);
__stp_tf_vma_put_free_entry(entry);
+ rc = 0;
}
write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
- return 0;
+ return rc;
}
-// Finds vma info if the vma is present in the vma map hash table.
-// Returns ESRCH if not present. The __stp_tf_vma_lock must *not* be
+// Finds vma info if the vma is present in the vma map hash table for
+// a given task and address (between vm_start and vm_end).
+// Returns -ESRCH if not present. The __stp_tf_vma_lock must *not* be
// locked before calling this function.
static int
stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
@@ -303,7 +307,7 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
struct hlist_node *node;
struct __stp_tf_vma_entry *entry;
struct __stp_tf_vma_entry *found_entry = NULL;
- int rc = ESRCH;
+ int rc = -ESRCH;
unsigned long flags;
read_lock_irqsave(&__stp_tf_vma_lock, flags);
@@ -330,3 +334,62 @@ stap_find_vma_map_info(struct task_struct *tsk, unsigned long vm_addr,
read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
return rc;
}
+
+// Finds vma info if the vma is present in the vma map hash table for
+// a given task with the given user handle.
+// Returns -ESRCH if not present. The __stp_tf_vma_lock must *not* be
+// locked before calling this function.
+static int
+stap_find_vma_map_info_user(struct task_struct *tsk, void *user,
+ unsigned long *vm_start, unsigned long *vm_end,
+ unsigned long *vm_pgoff)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct __stp_tf_vma_entry *entry;
+ struct __stp_tf_vma_entry *found_entry = NULL;
+ int rc = -ESRCH;
+
+ unsigned long flags;
+ read_lock_irqsave(&__stp_tf_vma_lock, flags);
+ head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
+ hlist_for_each_entry(entry, node, head, hlist) {
+ if (tsk->pid == entry->pid
+ && user == entry->user) {
+ found_entry = entry;
+ break;
+ }
+ }
+ if (found_entry != NULL) {
+ if (vm_start != NULL)
+ *vm_start = found_entry->vm_start;
+ if (vm_end != NULL)
+ *vm_end = found_entry->vm_end;
+ if (vm_pgoff != NULL)
+ *vm_pgoff = found_entry->vm_pgoff;
+ rc = 0;
+ }
+ read_unlock_irqrestore(&__stp_tf_vma_lock, flags);
+ return rc;
+}
+
+static int
+stap_drop_vma_maps(struct task_struct *tsk)
+{
+ struct hlist_head *head;
+ struct hlist_node *node;
+ struct hlist_node *n;
+ struct __stp_tf_vma_entry *entry;
+
+ unsigned long flags;
+ write_lock_irqsave(&__stp_tf_vma_lock, flags);
+ head = &__stp_tf_vma_map[__stp_tf_vma_map_hash(tsk)];
+ hlist_for_each_entry_safe(entry, node, n, head, hlist) {
+ if (tsk->pid == entry->pid) {
+ hlist_del(&entry->hlist);
+ __stp_tf_vma_put_free_entry(entry);
+ }
+ }
+ write_unlock_irqrestore(&__stp_tf_vma_lock, flags);
+ return 0;
+}
diff --git a/runtime/transport/symbols.c b/runtime/transport/symbols.c
index a214d1f2..e2f9fd65 100644
--- a/runtime/transport/symbols.c
+++ b/runtime/transport/symbols.c
@@ -61,7 +61,7 @@ static void _stp_do_relocation(const char __user *buf, size_t count)
continue;
else
{
- _stp_modules[mi]->sections[si].addr = msg.address;
+ _stp_modules[mi]->sections[si].static_addr = msg.address;
break;
}
} /* loop over sections */
diff --git a/runtime/unwind.c b/runtime/unwind.c
index 7607770e..c8e3580d 100644
--- a/runtime/unwind.c
+++ b/runtime/unwind.c
@@ -496,7 +496,7 @@ static char *_stp_eh_enc_name(signed type)
// and the elfutils base relocation done during loading of the .dwarf_frame
// in translate.cxx.
static unsigned long
-adjustStartLoc (unsigned long startLoc,
+adjustStartLoc (unsigned long startLoc, struct task_struct *tsk,
struct _stp_module *m,
struct _stp_section *s,
unsigned ptrType, int is_ehframe)
@@ -521,10 +521,14 @@ adjustStartLoc (unsigned long startLoc,
return startLoc;
}
- if (strcmp (s->name, ".dynamic") == 0)
- return startLoc + s->addr;
+ if (strcmp (s->name, ".dynamic") == 0) {
+ unsigned long vm_addr;
+ if (stap_find_vma_map_info_user(tsk->group_leader, m,
+ &vm_addr, NULL, NULL) == 0)
+ return startLoc + vm_addr;
+ }
- startLoc = _stp_module_relocate (m->name, s->name, startLoc);
+ startLoc = _stp_module_relocate (m->name, s->name, startLoc, tsk);
startLoc -= m->dwarf_module_base;
return startLoc;
}
@@ -532,7 +536,7 @@ adjustStartLoc (unsigned long startLoc,
/* If we previously created an unwind header, then use it now to binary search */
/* for the FDE corresponding to pc. XXX FIXME not currently supported. */
-static u32 *_stp_search_unwind_hdr(unsigned long pc,
+static u32 *_stp_search_unwind_hdr(unsigned long pc, struct task_struct *tsk,
struct _stp_module *m,
struct _stp_section *s)
{
@@ -581,7 +585,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
do {
const u8 *cur = ptr + (num / 2) * (2 * tableSize);
startLoc = read_pointer(&cur, cur + tableSize, hdr[3]);
- startLoc = adjustStartLoc(startLoc, m, s, hdr[3], 1);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, hdr[3], 1);
if (pc < startLoc)
num /= 2;
else {
@@ -590,7 +594,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
}
} while (startLoc && num > 1);
- if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), m, s, hdr[3], 1)) != 0 && pc >= startLoc)
+ if (num == 1 && (startLoc = adjustStartLoc(read_pointer(&ptr, ptr + tableSize, hdr[3]), tsk, m, s, hdr[3], 1)) != 0 && pc >= startLoc)
fde = (void *)read_pointer(&ptr, ptr + tableSize, hdr[3]);
dbug_unwind(1, "returning fde=%lx startLoc=%lx", (unsigned long) fde, startLoc);
@@ -601,6 +605,7 @@ static u32 *_stp_search_unwind_hdr(unsigned long pc,
* number in case of an error. A positive return means unwinding is finished;
* don't try to fallback to dumping addresses on the stack. */
static int unwind_frame(struct unwind_frame_info *frame,
+ struct task_struct *tsk,
struct _stp_module *m, struct _stp_section *s,
void *table, uint32_t table_len, int is_ehframe)
{
@@ -619,7 +624,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
goto err;
}
- fde = _stp_search_unwind_hdr(pc, m, s);
+ fde = _stp_search_unwind_hdr(pc, tsk, m, s);
dbug_unwind(1, "%s: fde=%lx\n", m->name, (unsigned long) fde);
/* found the fde, now set startLoc and endLoc */
@@ -629,7 +634,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
ptr = (const u8 *)(fde + 2);
ptrType = fde_pointer_type(cie, table, table_len);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!(ptrType & DW_EH_PE_indirect))
@@ -660,7 +665,7 @@ static int unwind_frame(struct unwind_frame_info *frame,
ptr = (const u8 *)(fde + 2);
startLoc = read_pointer(&ptr, (const u8 *)(fde + 1) + *fde, ptrType);
- startLoc = adjustStartLoc(startLoc, m, s, ptrType, is_ehframe);
+ startLoc = adjustStartLoc(startLoc, tsk, m, s, ptrType, is_ehframe);
dbug_unwind(2, "startLoc=%lx, ptrType=%s\n", startLoc, _stp_eh_enc_name(ptrType));
if (!startLoc)
continue;
@@ -902,18 +907,18 @@ static int unwind(struct unwind_frame_info *frame, struct task_struct *tsk)
if (UNW_PC(frame) == 0)
return -EINVAL;
- m = _stp_mod_sec_lookup (pc, tsk, &s);
+ m = _stp_mod_sec_lookup (pc, tsk, &s, NULL);
if (unlikely(m == NULL)) {
dbug_unwind(1, "No module found for pc=%lx", pc);
return -EINVAL;
}
dbug_unwind(1, "trying debug_frame\n");
- res = unwind_frame (frame, m, s, m->debug_frame,
+ res = unwind_frame (frame, tsk, m, s, m->debug_frame,
m->debug_frame_len, 0);
if (res != 0) {
dbug_unwind(1, "debug_frame failed: %d, trying eh_frame\n", res);
- res = unwind_frame (frame, m, s, m->eh_frame,
+ res = unwind_frame (frame, tsk, m, s, m->eh_frame,
m->eh_frame_len, 1);
}
diff --git a/runtime/uprobes/uprobes.c b/runtime/uprobes/uprobes.c
index 60c84509..cdb98707 100644
--- a/runtime/uprobes/uprobes.c
+++ b/runtime/uprobes/uprobes.c
@@ -2596,6 +2596,44 @@ static void uretprobe_set_trampoline(struct uprobe_process *uproc,
}
}
+unsigned long uprobe_get_pc(struct uretprobe_instance *ri, unsigned long pc,
+ unsigned long sp)
+{
+ struct uretprobe *rp;
+ struct uprobe_kimg *uk;
+ struct uprobe_process *uproc;
+ unsigned long trampoline_addr;
+ struct hlist_node *r;
+ struct uretprobe_instance *ret_inst;
+
+ if (!ri)
+ return 0;
+ rp = ri->rp;
+ uk = (struct uprobe_kimg *)rp->u.kdata;
+ if (!uk)
+ return 0;
+ uproc = uk->ppt->uproc;
+ if (IS_ERR(uproc->uretprobe_trampoline_addr))
+ return pc;
+ trampoline_addr = (unsigned long)uproc->uretprobe_trampoline_addr;
+ if (pc != trampoline_addr)
+ return pc;
+ r = &ri->hlist;
+ hlist_for_each_entry_from(ret_inst, r, hlist) {
+ if (ret_inst->ret_addr == trampoline_addr)
+ continue;
+ /* First handler with a stack pointer lower than the
+ address (or equal) must be the one. */
+ if (ret_inst->sp == sp || compare_stack_ptrs(ret_inst->sp, sp))
+ return ret_inst->ret_addr;
+ }
+ printk(KERN_ERR "Original return address for trampoline not found at "
+ "0x%lx pid/tgid=%d/%d\n", sp, current->pid, current->tgid);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(uprobe_get_pc);
+
#else /* ! CONFIG_URETPROBES */
static void uretprobe_handle_entry(struct uprobe *u, struct pt_regs *regs,
diff --git a/runtime/uprobes/uprobes.h b/runtime/uprobes/uprobes.h
index d542420d..e888f9e8 100644
--- a/runtime/uprobes/uprobes.h
+++ b/runtime/uprobes/uprobes.h
@@ -95,6 +95,14 @@ extern void unregister_uretprobe(struct uretprobe *rp);
/* For PRs 9940, 6852... */
extern void unmap_uprobe(struct uprobe *u);
extern void unmap_uretprobe(struct uretprobe *rp);
+/*
+ * Given a program counter, translate it back to the original address
+ * if it is the address of the trampoline. sp is the stack pointer for
+ * the frame that corresponds to the address.
+ */
+extern unsigned long uprobe_get_pc(struct uretprobe_instance *ri,
+ unsigned long pc,
+ unsigned long sp);
#ifdef UPROBES_IMPLEMENTATION
diff --git a/stapprobes.3stap.in b/stapprobes.3stap.in
index 2cb206c5..8b39545e 100644
--- a/stapprobes.3stap.in
+++ b/stapprobes.3stap.in
@@ -660,37 +660,6 @@ and a string of name=value pairs for all parameters of the tracepoint
is available in
.BR $$vars " or " $$parms .
-.SS PERFORMANCE MONITORING HARDWARE
-
-The perfmon family of probe points is used to access the performance
-monitoring hardware available in modern processors. This family of
-probes points needs the perfmon2 support in the kernel to access the
-performance monitoring hardware.
-.PP
-Performance monitor hardware points begin with a
-.BR perfmon ". "
-The next part of the names the event being counted
-.BR counter("event") .
-The event names are processor implementation specific with the
-exception of the generic
-.BR cycles " and " instructions
-events, which are available on all processors. This sets up a counter
-on the processor to count the number of events occurring on the
-processor. For more details on the performance monitoring events
-available on a specific processor use the command perfmon2 command:
-
-.SAMPLE
-pfmon \-l
-.ESAMPLE
-.TP
-$counter
-is a handle used in the body of the probe for operations
-involving the counter associated with the probe.
-.TP
-read_counter
-is a function that is passed the handle for the perfmon probe and returns
-the current count for the event.
-
.SH EXAMPLES
.PP
Here are some example probe points, defining the associated events.
diff --git a/tapset/context-symbols.stp b/tapset/context-symbols.stp
index 6cd4dcbb..38900196 100644
--- a/tapset/context-symbols.stp
+++ b/tapset/context-symbols.stp
@@ -91,7 +91,7 @@ function probemod:string () %{ /* pure */
*dst = 0;
} else if (CONTEXT->regs) {
struct _stp_module *m;
- m = _stp_mod_sec_lookup (REG_IP(CONTEXT->regs), current, NULL);
+ m = _stp_mod_sec_lookup (REG_IP(CONTEXT->regs), current, NULL, NULL);
if (m && m->name)
strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
else
@@ -111,7 +111,7 @@ function probemod:string () %{ /* pure */
*/
function modname:string (addr: long) %{ /* pure */
struct _stp_module *m;
- m = _stp_mod_sec_lookup (THIS->addr, current, NULL);
+ m = _stp_mod_sec_lookup (THIS->addr, current, NULL, NULL);
if (m && m->name)
strlcpy (THIS->__retvalue, m->name, MAXSTRINGLEN);
else
diff --git a/tapsets.cxx b/tapsets.cxx
index 007aea6d..e14cc496 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -2400,9 +2400,13 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
try
{
+ // PR10601: adapt to kernel-vs-userspace loc2c-runtime
+ ec->code += "\n#define fetch_register " + string(q.has_process?"u":"k") + "_fetch_register\n";
+ ec->code += "#define store_register " + string(q.has_process?"u":"k") + "_store_register\n";
+
if (q.has_return && (e->base_name == "$return"))
{
- ec->code = q.dw.literal_stmt_for_return (scope_die,
+ ec->code += q.dw.literal_stmt_for_return (scope_die,
addr,
e,
lvalue,
@@ -2410,7 +2414,7 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
}
else
{
- ec->code = q.dw.literal_stmt_for_local (getscopes(e),
+ ec->code += q.dw.literal_stmt_for_local (getscopes(e),
addr,
e->base_name.substr(1),
e,
@@ -2422,6 +2426,10 @@ dwarf_var_expanding_visitor::visit_target_symbol (target_symbol *e)
ec->code += "/* pure */";
ec->code += "/* unprivileged */";
+
+ // PR10601
+ ec->code += "\n#undef fetch_register\n";
+ ec->code += "\n#undef store_register\n";
}
catch (const semantic_error& er)
{
@@ -2687,6 +2695,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
// split the module string by ':' for alternatives
vector<string> modules;
tokenize(e->module, modules, ":");
+ bool userspace_p=false; // PR10601
for (unsigned i = 0; code.empty() && i < modules.size(); ++i)
{
string& module = modules[i];
@@ -2697,7 +2706,8 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
dwflpp* dw;
try
{
- if (! is_user_module (module))
+ userspace_p=is_user_module (module);
+ if (! userspace_p)
{
// kernel or kernel module target
dw = db.get_kern_dw(s, module);
@@ -2739,9 +2749,14 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
embeddedcode *ec = new embeddedcode;
ec->tok = e->tok;
- ec->code = code;
fdecl->body = ec;
+ // PR10601: adapt to kernel-vs-userspace loc2c-runtime
+ ec->code += "\n#define fetch_register " + string(userspace_p?"u":"k") + "_fetch_register\n";
+ ec->code += "#define store_register " + string(userspace_p?"u":"k") + "_store_register\n";
+
+ ec->code += code;
+
// Give the fdecl an argument for the pointer we're trying to cast
vardecl *v1 = new vardecl;
v1->type = pe_long;
@@ -2781,6 +2796,10 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e)
ec->code += "/* unprivileged */";
+ // PR10601
+ ec->code += "\n#undef fetch_register\n";
+ ec->code += "\n#undef store_register\n";
+
s.functions[fdecl->name] = fdecl;
// Synthesize a functioncall.
@@ -3410,7 +3429,7 @@ dwarf_derived_probe_group::emit_module_init (systemtap_session& s)
s.op->newline() << "for (i=0; i<" << probes_by_module.size() << "; i++) {";
s.op->newline(1) << "struct stap_dwarf_probe *sdp = & stap_dwarf_probes[i];";
s.op->newline() << "struct stap_dwarf_kprobe *kp = & stap_dwarf_kprobes[i];";
- s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address);";
+ s.op->newline() << "unsigned long relocated_addr = _stp_module_relocate (sdp->module, sdp->section, sdp->address, NULL);";
s.op->newline() << "if (relocated_addr == 0) continue;"; // quietly; assume module is absent
s.op->newline() << "probe_point = sdp->pp;"; // for error messages
s.op->newline() << "if (sdp->return_p) {";
@@ -4672,6 +4691,10 @@ uprobe_derived_probe_group::emit_module_decls (systemtap_session& s)
for (unsigned i =0; i<probes.size(); i++)
s.op->line() << "0,";
s.op->line() << "0};";
+ s.op->newline() << "unsigned long sdt_sem_tid [] = {";
+ for (unsigned i =0; i<probes.size(); i++)
+ s.op->line() << "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;";
@@ -4815,17 +4838,19 @@ 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->newline() << "if (sups->sdt_sem_offset && (sdt_sem_tid[spec_index] != tsk->tgid || 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() << "sdt_sem_tid[spec_index] = tsk->tgid;";
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() << "sdt_sem_tid[spec_index] = tsk->tgid;";
s.op->newline(-1) << "}";
s.op->newline(-1) << "}"; // sdt_sem_offset
@@ -5758,9 +5783,13 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
fdecl->name = fname;
fdecl->body = ec;
+ // PR10601: adapt to kernel-vs-userspace loc2c-runtime
+ ec->code += "\n#define fetch_register k_fetch_register\n";
+ ec->code += "#define store_register k_store_register\n";
+
try
{
- ec->code = dw.literal_stmt_for_pointer (&arg->type_die, e,
+ ec->code += dw.literal_stmt_for_pointer (&arg->type_die, e,
lvalue, fdecl->type);
}
catch (const semantic_error& er)
@@ -5818,6 +5847,10 @@ tracepoint_var_expanding_visitor::visit_target_symbol_arg (target_symbol* e)
ec->code += "/* unprivileged */";
+ // PR10601
+ ec->code += "\n#undef fetch_register\n";
+ ec->code += "\n#undef store_register\n";
+
dw.sess.functions[fdecl->name] = fdecl;
// Synthesize a functioncall.
diff --git a/testsuite/buildok/vm.tracepoints.stp b/testsuite/buildok/vm.tracepoints.stp
new file mode 100644
index 00000000..488ca0fc
--- /dev/null
+++ b/testsuite/buildok/vm.tracepoints.stp
@@ -0,0 +1,31 @@
+#! stap -up4
+
+probe vm.kfree {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p \n", execname(), call_site, caller_function, ptr)
+}
+
+probe vm.kmalloc {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_alloc {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmalloc_node {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_alloc_node {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p %-15d %-15d %-15d %-15s \n", execname(), call_site, caller_function, ptr, bytes_req, bytes_alloc, gfp_flags, gfp_flag_name)
+}
+
+probe vm.kmem_cache_free {
+ println(name)
+ printf("%-15s %-15p %-15s %-15p \n", execname(), call_site, caller_function, ptr)
+}
diff --git a/testsuite/systemtap.base/externalvar.exp b/testsuite/systemtap.base/externalvar.exp
index 668dec55..f6553f45 100644
--- a/testsuite/systemtap.base/externalvar.exp
+++ b/testsuite/systemtap.base/externalvar.exp
@@ -67,4 +67,4 @@ if { $n != $m } {
} else {
pass $test
}
-# exec rm -f $testexe $testso
+catch {exec rm -f $testexe $testso}
diff --git a/testsuite/systemtap.examples/general/grapher.stp b/testsuite/systemtap.examples/general/grapher.stp
index baeeff5c..46f5063c 100755
--- a/testsuite/systemtap.examples/general/grapher.stp
+++ b/testsuite/systemtap.examples/general/grapher.stp
@@ -35,17 +35,18 @@ probe kernel.function("kbd_event") {
}
probe kernel.function("pty_write") {
- if ($count > 0) {
- 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", text_str(c))
- }
- printf("%c", 0)
+ count = %(kernel_v>="2.6.31" %? $c %: $count %)
+ if (count > 0) {
+ 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", text_str(c))
+ }
+ printf("%c", 0)
}
}
diff --git a/testsuite/systemtap.examples/memory/vm.tracepoints.meta b/testsuite/systemtap.examples/memory/vm.tracepoints.meta
new file mode 100644
index 00000000..9fdb73f6
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/vm.tracepoints.meta
@@ -0,0 +1,13 @@
+title: Collect slab allocation statistics
+name: vm.tracepoints.stp
+version: 1.0
+author: Rajasekhar
+keywords: memory slab allocator
+subsystem: memory
+status: production
+exit: user-controlled
+output: sorted-list
+scope: system-wide
+description: The script will probe all memory slab/slub allocations and collects information about the size of the object (bytes requested) and user-space process in execution. When run over a period of time, it helps to correlate kernel-space memory consumption owing to user-space processes.
+test_check: stap -p4 vm.tracepoints.stp
+test_installcheck: stap vm.tracepoints.stp -c "sleep 10"
diff --git a/testsuite/systemtap.examples/memory/vm.tracepoints.stp b/testsuite/systemtap.examples/memory/vm.tracepoints.stp
new file mode 100644
index 00000000..07cee6f5
--- /dev/null
+++ b/testsuite/systemtap.examples/memory/vm.tracepoints.stp
@@ -0,0 +1,18 @@
+global slabs
+
+probe vm.kmem_cache_alloc {
+ slabs [execname(), bytes_req]<<<1
+}
+
+probe timer.ms(10000)
+{
+ dummy = "";
+ foreach ([name, bytes] in slabs) {
+ if (dummy != name)
+ printf("\nProcess:%s\n", name);
+ printf("Slab_size:%d\tCount:%d\n", bytes, @count(slabs[name, bytes]));
+ dummy = name;
+ }
+ delete slabs
+ printf("\n-------------------------------------------------------\n\n")
+}