summaryrefslogtreecommitdiffstats
path: root/translate.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'translate.cxx')
-rw-r--r--translate.cxx393
1 files changed, 200 insertions, 193 deletions
diff --git a/translate.cxx b/translate.cxx
index b1037fef..433b82be 100644
--- a/translate.cxx
+++ b/translate.cxx
@@ -1,6 +1,6 @@
// translation pass
// Copyright (C) 2005-2008 Red Hat Inc.
-// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2005-2008 Intel Corporation.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
@@ -14,6 +14,7 @@
#include "session.h"
#include "tapsets.h"
#include "util.h"
+#include "dwarf_wrappers.h"
#include <cstdlib>
#include <iostream>
@@ -43,6 +44,7 @@ struct c_unparser: public unparser, public visitor
functiondecl* current_function;
unsigned tmpvar_counter;
unsigned label_counter;
+ unsigned action_counter;
bool probe_or_function_needs_deref_fault_handler;
varuse_collecting_visitor vcv_needs_global_locks;
@@ -110,7 +112,7 @@ struct c_unparser: public unparser, public visitor
void collect_map_index_types(vector<vardecl* > const & vars,
set< pair<vector<exp_type>, exp_type> > & types);
- void visit_statement (statement* s, unsigned actions, bool stmtize);
+ void record_actions (unsigned actions, bool update=false);
void visit_block (block* s);
void visit_embeddedcode (embeddedcode* s);
@@ -619,10 +621,10 @@ struct mapvar
else
throw semantic_error("adding a value of an unsupported map type");
- res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
+ res += "; if (unlikely(rc)) { c->last_error = \"Array overflow, check " +
stringify(maxsize > 0 ?
"size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
- + "\"; }";
+ + "\"; goto out; }}";
return res;
}
@@ -640,10 +642,10 @@ struct mapvar
else
throw semantic_error("setting a value of an unsupported map type");
- res += "; if (unlikely(rc)) c->last_error = \"Array overflow, check " +
+ res += "; if (unlikely(rc)) { c->last_error = \"Array overflow, check " +
stringify(maxsize > 0 ?
"size limit (" + stringify(maxsize) + ")" : "MAXMAPENTRIES")
- + "\"; }";
+ + "\"; goto out; }}";
return res;
}
@@ -870,9 +872,7 @@ c_unparser::emit_common_header ()
o->newline() << "const char *last_error;";
// NB: last_error is used as a health flag within a probe.
// While it's 0, execution continues
- // When it's "", current function or probe unwinds and returns early
// When it's "something", probe code unwinds, _stp_error's, sets error state
- // See c_unparser::visit_statement()
o->newline() << "const char *last_stmt;";
o->newline() << "struct pt_regs *regs;";
o->newline() << "unsigned long *unwaddr;";
@@ -1087,27 +1087,18 @@ c_unparser::emit_module_init ()
// one may install the incorrect debuginfo or -devel RPM, and try to
// run a probe compiled for a different version. Catch this early,
// just in case modversions didn't.
- o->newline() << "down_read (& uts_sem);";
o->newline() << "{";
- o->indent(1);
+ o->newline(1) << "const char* release = UTS_RELEASE;";
- // Args, linux 2.6.19+ did a switcheroo on system_utsname to utsname().
- o->newline() << "#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)";
- o->newline() << "const char* machine = utsname()->machine;";
- o->newline() << "const char* release = utsname()->release;";
- o->newline() << "#else";
- o->newline() << "const char* machine = system_utsname.machine;";
- o->newline() << "const char* release = system_utsname.release;";
- o->newline() << "#endif";
+ // NB: This UTS_RELEASE compile-time macro directly checks only that
+ // the compile-time kbuild tree matches the compile-time debuginfo/etc.
+ // It does not check the run time kernel value. However, this is
+ // probably OK since the kbuild modversions system aims to prevent
+ // mismatches between kbuild and runtime versions at module-loading time.
- o->newline() << "if (strcmp (machine, "
- << lex_cast_qstring (session->architecture) << ")) {";
- o->newline(1) << "_stp_error (\"module machine mismatch (%s vs %s)\", "
- << "machine, "
- << lex_cast_qstring (session->architecture)
- << ");";
- o->newline() << "rc = -EINVAL;";
- o->newline(-1) << "}";
+ // o->newline() << "const char* machine = UTS_MACHINE;";
+ // NB: We could compare UTS_MACHINE too, but on x86 it lies
+ // (UTS_MACHINE=i386, but uname -m is i686). Sheesh.
o->newline() << "if (strcmp (release, "
<< lex_cast_qstring (session->kernel_release) << ")) {";
@@ -1118,8 +1109,9 @@ c_unparser::emit_module_init ()
o->newline() << "rc = -EINVAL;";
o->newline(-1) << "}";
+ // XXX: perform buildid-based checking if able
+
o->newline(-1) << "}";
- o->newline() << "up_read (& uts_sem);";
o->newline() << "if (rc) goto out;";
o->newline() << "(void) probe_point;";
@@ -1315,9 +1307,8 @@ c_unparser::emit_module_exit ()
o->newline() << "struct stat_data *stats = _stp_stat_get (time_"
<< p->name
<< ", 0);";
- o->newline() << "const char *error;";
o->newline() << "if (stats->count) {";
- o->newline(1) << "int64_t avg = _stp_div64 (&error, stats->sum, stats->count);";
+ o->newline(1) << "int64_t avg = _stp_div64 (NULL, stats->sum, stats->count);";
o->newline() << "_stp_printf (\"probe %s (%s), hits: %lld, cycles: %lldmin/%lldavg/%lldmax\\n\",";
o->newline() << "probe_point, decl_location, (long long) stats->count, (long long) stats->min, (long long) avg, (long long) stats->max);";
o->newline(-1) << "}";
@@ -1352,6 +1343,7 @@ c_unparser::emit_function (functiondecl* v)
this->current_probe = 0;
this->current_function = v;
this->tmpvar_counter = 0;
+ this->action_counter = 0;
o->newline()
<< "struct function_" << c_varname (v->name) << "_locals * "
@@ -1400,26 +1392,21 @@ c_unparser::emit_function (functiondecl* v)
this->current_function = 0;
- o->newline(-1) << "out:";
- o->newline(1) << ";";
-
- // Function prologue: this is why we redirect the "return" above.
- // Decrement nesting level.
- o->newline() << "c->nesting --;";
- // Reset last_error to NULL if it was set to "" by script-level return()
- o->newline() << "if (c->last_error && ! c->last_error[0])";
- o->newline(1) << "c->last_error = 0;";
- o->indent(-1);
+ record_actions(0, true);
if (this->probe_or_function_needs_deref_fault_handler) {
// Emit this handler only if the body included a
// print/printf/etc. using a string or memory buffer!
- o->newline(1) << "return;";
o->newline() << "CATCH_DEREF_FAULT ();";
- o->newline() << "goto out;";
- o->indent(-1);
}
+ o->newline(-1) << "out:";
+ o->newline(1) << ";";
+
+ // Function prologue: this is why we redirect the "return" above.
+ // Decrement nesting level.
+ o->newline() << "c->nesting --;";
+
o->newline() << "#undef CONTEXT";
o->newline() << "#undef THIS";
o->newline(-1) << "}\n";
@@ -1436,6 +1423,7 @@ c_unparser::emit_probe (derived_probe* v)
this->current_function = 0;
this->current_probe = v;
this->tmpvar_counter = 0;
+ this->action_counter = 0;
// If we about to emit a probe that is exactly the same as another
// probe previously emitted, make the second probe just call the
@@ -1555,6 +1543,14 @@ c_unparser::emit_probe (derived_probe* v)
v->body->visit (this);
+ record_actions(0, true);
+
+ if (this->probe_or_function_needs_deref_fault_handler) {
+ // Emit this handler only if the body included a
+ // print/printf/etc. using a string or memory buffer!
+ o->newline() << "CATCH_DEREF_FAULT ();";
+ }
+
o->newline(-1) << "out:";
// NB: no need to uninitialize locals, except if arrays/stats can
// someday be local
@@ -1566,14 +1562,6 @@ c_unparser::emit_probe (derived_probe* v)
if (v->needs_global_locks ())
emit_unlocks (vut);
- if (this->probe_or_function_needs_deref_fault_handler) {
- // Emit this handler only if the body included a
- // print/printf/etc. using a string or memory buffer!
- o->newline() << "return;";
- o->newline() << "CATCH_DEREF_FAULT ();";
- o->newline() << "goto out;";
- }
-
o->newline(-1) << "}\n";
}
@@ -2049,18 +2037,22 @@ c_unparser_assignment::c_assignop(tmpvar & res,
o->newline() << lval << " = " << rval << ";";
res = rval;
}
- else
- {
- if (macop == "/=")
- o->newline() << lval << " = _stp_div64 (&c->last_error, "
- << lval << ", " << rval << ");";
- else if (macop == "%=")
- o->newline() << lval << " = _stp_mod64 (&c->last_error, "
- << lval << ", " << rval << ");";
+ else
+ {
+ if (macop == "/=" || macop == "%=")
+ {
+ o->newline() << "if (unlikely(!" << rval << ")) {";
+ o->newline(1) << "c->last_error = \"division by 0\";";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
+ o->newline() << lval << " = "
+ << ((macop == "/=") ? "_stp_div64" : "_stp_mod64")
+ << " (NULL, " << lval << ", " << rval << ");";
+ }
else
o->newline() << lval << " " << macop << " " << rval << ";";
res = lval;
- }
+ }
}
}
else
@@ -2210,39 +2202,24 @@ c_unparser::getiter(symbol *s)
}
-
-// An artificial common "header" for each statement. This is where
-// activity counts limits and error state early exits are enforced.
+// Queue up some actions to remove from actionremaining. Set update=true at
+// the end of basic blocks to actually update actionremaining and check it
+// against MAXACTION.
void
-c_unparser::visit_statement (statement *s, unsigned actions, bool stmtize)
+c_unparser::record_actions (unsigned actions, bool update)
{
- // For some constructs, it is important to avoid an error branch
- // right to the bottom of the probe/function. The foreach()
- // iteration construct is one example. Instead, if we are nested
- // within a loop, we branch merely to its "break" label. The next
- // statement will branch one level higher, and so on, until we can
- // go straight "out".
- string outlabel = "out";
- unsigned loops = loop_break_labels.size();
- if (loops > 0)
- outlabel = loop_break_labels[loops-1];
-
- if (s)
- {
- o->newline() << "if (unlikely (c->last_error)) goto " << outlabel << ";";
- assert (s->tok);
- if (stmtize)
- o->newline() << "c->last_stmt = " << lex_cast_qstring(*s->tok) << ";";
- }
+ action_counter += actions;
- if (actions > 0)
+ // Update if needed, or after queueing up a few actions, in case of very
+ // large code sequences.
+ if ((update && action_counter > 0) || action_counter >= 10/*<-arbitrary*/)
{
- o->newline() << "c->actionremaining -= " << actions << ";";
- // XXX: This check is inserted too frequently.
+ o->newline() << "c->actionremaining -= " << action_counter << ";";
o->newline() << "if (unlikely (c->actionremaining <= 0)) {";
o->newline(1) << "c->last_error = \"MAXACTION exceeded\";";
- o->newline() << "goto " << outlabel << ";";
+ o->newline() << "goto out;";
o->newline(-1) << "}";
+ action_counter = 0;
}
}
@@ -2253,13 +2230,6 @@ c_unparser::visit_block (block *s)
o->newline() << "{";
o->indent (1);
- // visit_statement (s, 0, false);
- //
- // NB: this is not necessary, since the last_error can be handled
- // just as easily by the first real body statement, and the
- // last_stmt won't be used since this nesting structure cannot
- // itself cause an error.
-
for (unsigned i=0; i<s->statements.size(); i++)
{
try
@@ -2279,12 +2249,6 @@ c_unparser::visit_block (block *s)
void
c_unparser::visit_embeddedcode (embeddedcode *s)
{
- // visit_statement (s, 1, true);
- //
- // NB: this is not necessary, since this can occur only at the top
- // level of a function (so no errors can be pending), and the
- // action-count is already incremented at the point of call.
-
o->newline() << "{";
o->newline(1) << s->code;
o->newline(-1) << "}";
@@ -2294,12 +2258,6 @@ c_unparser::visit_embeddedcode (embeddedcode *s)
void
c_unparser::visit_null_statement (null_statement *)
{
- // visit_statement (s, 0, false);
- //
- // NB: this is not necessary, since the last_error can be handled just as
- // easily by the next statement, and the last_stmt won't be used since this
- // statement cannot cause an error.
-
o->newline() << "/* null */;";
}
@@ -2307,17 +2265,17 @@ c_unparser::visit_null_statement (null_statement *)
void
c_unparser::visit_expr_statement (expr_statement *s)
{
- visit_statement (s, 1, false);
o->newline() << "(void) ";
s->value->visit (this);
o->line() << ";";
+ record_actions(1);
}
void
c_unparser::visit_if_statement (if_statement *s)
{
- visit_statement (s, 1, false);
+ record_actions(1, true);
o->newline() << "if (";
o->indent (1);
s->condition->visit (this);
@@ -2325,12 +2283,14 @@ c_unparser::visit_if_statement (if_statement *s)
o->line() << ") {";
o->indent (1);
s->thenblock->visit (this);
+ record_actions(0, true);
o->newline(-1) << "}";
if (s->elseblock)
{
o->newline() << "else {";
o->indent (1);
s->elseblock->visit (this);
+ record_actions(0, true);
o->newline(-1) << "}";
}
}
@@ -2380,8 +2340,6 @@ c_tmpcounter::visit_for_loop (for_loop *s)
void
c_unparser::visit_for_loop (for_loop *s)
{
- visit_statement (s, 1, false);
-
string ctr = stringify (label_counter++);
string toplabel = "top_" + ctr;
string contlabel = "continue_" + ctr;
@@ -2389,6 +2347,7 @@ c_unparser::visit_for_loop (for_loop *s)
// initialization
if (s->init) s->init->visit (this);
+ record_actions(1, true);
// condition
o->newline(-1) << toplabel << ":";
@@ -2397,7 +2356,7 @@ c_unparser::visit_for_loop (for_loop *s)
// Equivalently, it can stand for the evaluation of the condition
// expression.
o->indent(1);
- visit_statement (0, 1, false);
+ record_actions(1);
o->newline() << "if (! (";
if (s->cond->type != pe_long)
@@ -2409,6 +2368,7 @@ c_unparser::visit_for_loop (for_loop *s)
loop_break_labels.push_back (breaklabel);
loop_continue_labels.push_back (contlabel);
s->block->visit (this);
+ record_actions(0, true);
loop_break_labels.pop_back ();
loop_continue_labels.pop_back ();
@@ -2529,8 +2489,6 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
if (array)
{
- visit_statement (s, 1, false);
-
mapvar mv = getmap (array->referent, s->tok);
itervar iv = getiter (array);
vector<var> keys;
@@ -2555,9 +2513,10 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
// aggregate array if required
if (mv.is_parallel())
{
- o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << "))";
+ o->newline() << "if (unlikely(NULL == " << mv.calculate_aggregate() << ")) {";
o->newline(1) << "c->last_error = \"aggregation overflow in " << mv << "\";";
- o->indent(-1);
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
// sort array if desired
if (s->sort_direction)
@@ -2624,6 +2583,8 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
o->newline() << *limitv << " = 0LL;";
}
+ record_actions(1, true);
+
// condition
o->newline(-1) << toplabel << ":";
@@ -2631,7 +2592,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
// Equivalently, it can stand for the evaluation of the
// condition expression.
o->indent(1);
- visit_statement (0, 1, false);
+ record_actions(1);
o->newline() << "if (! (" << iv << ")) goto " << breaklabel << ";";
@@ -2659,6 +2620,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
c_assign (v, iv.get_key (v.type(), i), s->tok);
}
s->block->visit (this);
+ record_actions(0, true);
o->newline(-1) << "}";
loop_break_labels.pop_back ();
loop_continue_labels.pop_back ();
@@ -2703,6 +2665,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
}
// XXX: break / continue don't work here yet
+ record_actions(1, true);
o->newline() << "for (" << bucketvar << " = 0; "
<< bucketvar << " < " << v.buckets() << "; "
<< bucketvar << "++) { ";
@@ -2720,6 +2683,7 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
}
s->block->visit (this);
+ record_actions(1, true);
o->newline(-1) << "}";
}
}
@@ -2728,8 +2692,6 @@ c_unparser::visit_foreach_loop (foreach_loop *s)
void
c_unparser::visit_return_statement (return_statement* s)
{
- visit_statement (s, 1, false);
-
if (current_function == 0)
throw semantic_error ("cannot 'return' from probe", s->tok);
@@ -2738,21 +2700,19 @@ c_unparser::visit_return_statement (return_statement* s)
"vs", s->tok);
c_assign ("l->__retvalue", s->value, "return value");
- o->newline() << "c->last_error = \"\";";
- // NB: last_error needs to get reset to NULL in the caller
- // probe/function
+ record_actions(1, true);
+ o->newline() << "goto out;";
}
void
c_unparser::visit_next_statement (next_statement* s)
{
- visit_statement (s, 1, false);
-
if (current_probe == 0)
throw semantic_error ("cannot 'next' from function", s->tok);
- o->newline() << "c->last_error = \"\";";
+ record_actions(1, true);
+ o->newline() << "goto out;";
}
@@ -2879,19 +2839,19 @@ c_tmpcounter::visit_delete_statement (delete_statement* s)
void
c_unparser::visit_delete_statement (delete_statement* s)
{
- visit_statement (s, 1, false);
delete_statement_operand_visitor dv (this);
s->value->visit (&dv);
+ record_actions(1);
}
void
c_unparser::visit_break_statement (break_statement* s)
{
- visit_statement (s, 1, false);
if (loop_break_labels.size() == 0)
throw semantic_error ("cannot 'break' outside loop", s->tok);
+ record_actions(1, true);
string label = loop_break_labels[loop_break_labels.size()-1];
o->newline() << "goto " << label << ";";
}
@@ -2900,10 +2860,10 @@ c_unparser::visit_break_statement (break_statement* s)
void
c_unparser::visit_continue_statement (continue_statement* s)
{
- visit_statement (s, 1, false);
if (loop_continue_labels.size() == 0)
throw semantic_error ("cannot 'continue' outside loop", s->tok);
+ record_actions(1, true);
string label = loop_continue_labels[loop_continue_labels.size()-1];
o->newline() << "goto " << label << ";";
}
@@ -3001,8 +2961,6 @@ c_unparser::visit_binary_expression (binary_expression* e)
o->line() << "({";
o->indent(1);
- // NB: Need last_stmt set here because of possible last_error generation
- o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
if (e->left->tok->type == tok_number)
left.override(c_expression(e->left));
@@ -3022,8 +2980,13 @@ c_unparser::visit_binary_expression (binary_expression* e)
o->line() << ";";
}
+ o->newline() << "if (unlikely(!" << right << ")) {";
+ o->newline(1) << "c->last_error = \"division by 0\";";
+ o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
o->newline() << ((e->op == "/") ? "_stp_div64" : "_stp_mod64")
- << " (&c->last_error, " << left << ", " << right << ");";
+ << " (NULL, " << left << ", " << right << ");";
o->newline(-1) << "})";
}
@@ -3741,16 +3704,19 @@ c_unparser::visit_arrayindex (arrayindex* e)
// PR 2142+2610: empty aggregates
o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
- << " || " << agg.value() << "->count == 0)";
+ << " || " << agg.value() << "->count == 0) {";
o->newline(1) << "c->last_error = \"empty aggregate\";";
- o->newline(-1) << "else {";
+ o->newline() << "goto out;";
+ o->newline(-1) << "} else {";
o->newline(1) << "if (" << histogram_index_check(*v, idx[0]) << ")";
o->newline(1) << res << " = " << agg << "->histogram[" << idx[0] << "];";
- o->newline(-1) << "else";
+ o->newline(-1) << "else {";
o->newline(1) << "c->last_error = \"histogram index out of range\";";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
o->newline(-1) << "}";
- o->newline(-1) << res << ";";
+ o->newline() << res << ";";
delete v;
}
@@ -3954,6 +3920,7 @@ c_unparser::visit_functioncall (functioncall* e)
// call function
o->newline() << "function_" << c_varname (r->name) << " (c);";
+ o->newline() << "if (unlikely(c->last_error)) goto out;";
// return result from retvalue slot
if (r->type == pe_unknown)
@@ -4050,6 +4017,7 @@ c_unparser::visit_print_format (print_format* e)
<< " || " << agg.value() << "->count == 0) {";
o->newline(1) << "c->last_error = \"empty aggregate\";";
o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ o->newline() << "goto out;";
o->newline(-1) << "} else";
o->newline(1) << "_stp_stat_print_histogram (" << v->hist() << ", " << agg.value() << ");";
o->indent(-1);
@@ -4144,9 +4112,7 @@ c_unparser::visit_print_format (print_format* e)
components[0].type = print_format::conv_literal;
}
- // Make the [s]printf call, but not if there was an error evaluating the args
- o->newline() << "if (likely (! c->last_error)) {";
- o->indent(1);
+ // Make the [s]printf call...
// Generate code to check that any pointer arguments are actually accessible. */
int arg_ix = 0;
@@ -4187,7 +4153,6 @@ c_unparser::visit_print_format (print_format* e)
o->line() << tmp[0].value() << ");";
else
o->line() << '"' << format_string << "\");";
- o->newline(-1) << "}";
return;
}
if (use_print)
@@ -4197,7 +4162,6 @@ c_unparser::visit_print_format (print_format* e)
o->line() << tmp[0].value() << ");";
else
o->line() << '"' << format_string << "\");";
- o->newline(-1) << "}";
return;
}
@@ -4232,7 +4196,6 @@ c_unparser::visit_print_format (print_format* e)
}
o->line() << ");";
- o->newline(-1) << "}";
o->newline() << res.value() << ";";
}
}
@@ -4307,16 +4270,18 @@ c_unparser::visit_stat_op (stat_op* e)
else
{
o->newline() << "if (unlikely (" << agg.value() << " == NULL)"
- << " || " << agg.value() << "->count == 0)";
+ << " || " << agg.value() << "->count == 0) {";
o->newline(1) << "c->last_error = \"empty aggregate\";";
- o->indent(-1);
+ o->newline() << "c->last_stmt = " << lex_cast_qstring(*e->tok) << ";";
+ o->newline() << "goto out;";
+ o->newline(-1) << "}";
}
o->newline() << "else";
o->indent(1);
switch (e->ctype)
{
case sc_average:
- c_assign(res, ("_stp_div64(&c->last_error, " + agg.value() + "->sum, "
+ c_assign(res, ("_stp_div64(NULL, " + agg.value() + "->sum, "
+ agg.value() + "->count)"),
e->tok);
break;
@@ -4361,36 +4326,50 @@ c_unparser::visit_hist_op (hist_op*)
}
-static map< Dwarf_Addr, string> addrmap;
-
-#include <string.h>
-static int
-kernel_filter (const char *module, const char *file __attribute__((unused)))
+struct unwindsym_dump_context
{
- return !strcmp(module,"kernel");
-}
+ systemtap_session& session;
+ ostream& output;
+};
+
static int
-get_symbols (Dwfl_Module *m,
- void **userdata __attribute__ ((unused)),
- const char *name __attribute__ ((unused)),
- Dwarf_Addr base __attribute__ ((unused)),
- void *arg __attribute__ ((unused)))
+dump_unwindsyms (Dwfl_Module *m,
+ void **userdata __attribute__ ((unused)),
+ const char *name,
+ Dwarf_Addr base,
+ void *arg)
{
+ unwindsym_dump_context* c = (unwindsym_dump_context*) arg;
+ assert (c);
+
+ string modname = name;
+
+ // skip modules/files we're not actually interested in
+ if (c->session.unwindsym_modules.find(modname) == c->session.unwindsym_modules.end())
+ return DWARF_CB_OK;
+
+ if (c->session.verbose > 1)
+ clog << "dump_unwindsyms " << name << " base=0x" << hex << base << dec << endl;
+
+ // We want to extract several bits of information:
+ // - parts of the program-header that map the file's physical offsets to the text section
+ // - symbol table of the text section
+ // - the contents .debug_frame section
+ // In the future, we'll also care about data symbols.
+
int syments = dwfl_module_getsymtab(m);
assert(syments);
for (int i = 1; i < syments; ++i)
{
GElf_Sym sym;
const char *name = dwfl_module_getsym(m, i, &sym, NULL);
- if (name) {
- if (GELF_ST_TYPE (sym.st_info) == STT_FUNC ||
- strcmp(name, "_etext") == 0 ||
- strcmp(name, "_stext") == 0 ||
- strcmp(name, "modules_op") == 0)
- addrmap[sym.st_value] = name;
- }
+ if (name)
+ {
+ if (GELF_ST_TYPE (sym.st_info) == STT_FUNC)
+ ; // addrmap[sym.st_value] = name;
+ }
}
return DWARF_CB_OK;
}
@@ -4399,26 +4378,23 @@ get_symbols (Dwfl_Module *m,
void
emit_symbol_data (systemtap_session& s)
{
- ofstream kallsyms_out ((s.tmpdir + "/stap-symbols.h").c_str());
- s.op->newline() << "\n\n#include \"stap-symbols.h\"";
+ string symfile = "stap-symbols.h";
+ ofstream kallsyms_out ((s.tmpdir + "/" + symfile).c_str());
- if (s.verbose > 1)
- {
- std::set<std::string>::iterator it = s.unwindsym_modules.begin();
- clog << "unwindsym modules: ";
- while (it != s.unwindsym_modules.end())
- {
- clog << *(it++) << " ";
- }
- clog << endl;
- }
+ unwindsym_dump_context ctx = { s, kallsyms_out };
+
+ s.op->newline() << "\n\n#include \"" << symfile << "\"";
+ // XXX: copied from tapsets.cxx, sadly
static char debuginfo_path_arr[] = "-:.debug:/usr/lib/debug:build";
static char *debuginfo_env_arr = getenv("SYSTEMTAP_DEBUGINFO_PATH");
static char *debuginfo_path = (debuginfo_env_arr ?
- debuginfo_env_arr : debuginfo_path_arr);
-
+ debuginfo_env_arr : debuginfo_path_arr);
+ static const char *debug_path = (debuginfo_env_arr ?
+ debuginfo_env_arr : s.kernel_release.c_str());
+
+ // ---- step 1: process any kernel modules listed
static const Dwfl_Callbacks kernel_callbacks =
{
dwfl_linux_kernel_find_elf,
@@ -4431,27 +4407,55 @@ emit_symbol_data (systemtap_session& s)
if (!dwfl)
throw semantic_error ("cannot open dwfl");
dwfl_report_begin (dwfl);
-
- int rc = dwfl_linux_kernel_report_offline (dwfl,
- s.kernel_release.c_str(),
- kernel_filter);
+ int rc = dwfl_linux_kernel_report_offline (dwfl, debug_path, NULL /* XXX: filtering callback */);
dwfl_report_end (dwfl, NULL, NULL);
- if (rc < 0)
- throw semantic_error ("dwfl rc");
-
- dwfl_getmodules (dwfl, &get_symbols, NULL, 0);
+ dwfl_assert ("dwfl_linux_kernel_report_offline", rc);
+ ptrdiff_t off = 0;
+ do
+ {
+ if (pending_interrupts) return;
+ off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0);
+ }
+ while (off > 0);
+ dwfl_assert("dwfl_getmodules", off == 0);
dwfl_end(dwfl);
-
- int i = 0;
- map< Dwarf_Addr, string>::iterator pos;
- kallsyms_out << "struct _stp_symbol _stp_kernel_symbols [] = {";
- for (pos = addrmap.begin(); pos != addrmap.end(); pos++) {
- kallsyms_out << " { 0x" << hex << pos->first << ", " << "\"" << pos->second << "\" },\n";
- i++;
- }
-
- kallsyms_out << "};\n";
- kallsyms_out << "unsigned _stp_num_kernel_symbols = " << dec << i << ";\n";
+
+
+ // ---- step 2: process any user modules (files) listed
+ static const Dwfl_Callbacks user_callbacks =
+ {
+ NULL, /* dwfl_linux_kernel_find_elf, */
+ dwfl_standard_find_debuginfo,
+ dwfl_offline_section_address,
+ & debuginfo_path
+ };
+
+ for (std::set<std::string>::iterator it = s.unwindsym_modules.begin();
+ it != s.unwindsym_modules.end();
+ it++)
+ {
+ string modname = *it;
+ assert (modname.length() != 0);
+ if (modname[0] != '/') continue; // user-space files must be full paths
+
+ Dwfl *dwfl = dwfl_begin (&user_callbacks);
+ if (!dwfl)
+ throw semantic_error ("cannot create dwfl for " + modname);
+
+ dwfl_report_begin (dwfl);
+ Dwfl_Module* mod = dwfl_report_offline (dwfl, modname.c_str(), modname.c_str(), -1);
+ dwfl_report_end (dwfl, NULL, NULL);
+ dwfl_assert ("dwfl_report_offline", mod);
+ ptrdiff_t off = 0;
+ do
+ {
+ if (pending_interrupts) return;
+ off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0);
+ }
+ while (off > 0);
+ dwfl_assert("dwfl_getmodules", off == 0);
+ dwfl_end(dwfl);
+ }
}
@@ -4532,7 +4536,10 @@ translate_pass (systemtap_session& s)
s.op->newline() << "#include <linux/delay.h>";
s.op->newline() << "#include <linux/profile.h>";
s.op->newline() << "#include <linux/random.h>";
+ s.op->newline() << "#include <linux/utsrelease.h>";
s.op->newline() << "#include <linux/utsname.h>";
+ s.op->newline() << "#include <linux/version.h>";
+ s.op->newline() << "#include <linux/compile.h>";
s.op->newline() << "#include \"loc2c-runtime.h\" ";
// XXX: old 2.6 kernel hack