diff options
Diffstat (limited to 'translate.cxx')
-rw-r--r-- | translate.cxx | 393 |
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 |