diff options
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 @@ -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(); } @@ -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) ®s->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) ®s->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)®s->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)®s->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") +} |