diff options
author | fche <fche> | 2005-08-24 17:01:52 +0000 |
---|---|---|
committer | fche <fche> | 2005-08-24 17:01:52 +0000 |
commit | bb788f9f3b8c22489a5dc5659a935e272b0e9b64 (patch) | |
tree | 969af38f4e6f3f9283f0dbf75967268df6d8c4fc /tapsets.cxx | |
parent | d072ec9d384f4f6072317e530b42a834f0982921 (diff) | |
download | systemtap-steved-bb788f9f3b8c22489a5dc5659a935e272b0e9b64.tar.gz systemtap-steved-bb788f9f3b8c22489a5dc5659a935e272b0e9b64.tar.xz systemtap-steved-bb788f9f3b8c22489a5dc5659a935e272b0e9b64.zip |
2005-08-24 Frank Ch. Eigler <fche@elastic.org>
* tapsets.cxx (*::emit_probe_entries): Treat NULL and "" last_errors
both as clean early returns, not errors.
* translate.cxx: Revamp last_error handling logic. Remove all
"goto out" paths from expression context.
(visit_statement): Handle last_error exit one nesting level at a time.
(visit_return_statement, visit_functioncall): Set/reset last_error="".
(c_tmpcounter::visit_for_loop): New routine.
(c_unparser::visit_foreach, visit_for_loop): Rewrite to properly
support continue/breaks, non-local exits, (foreach) locks.
(emit_global): Emit lock variable.
(varlock ctor, dtor): Lock/unlock global variable.
(varlock_w, varlock_r): New concrete subclasses. Update all users.
* tapset/builtin_logging.stp (exit): Don't set last_error.
* src/testsuite/buildok/sixteen.stp: New test.
* tapsets.cxx: Temporarily rolled back graydon's changes.
Diffstat (limited to 'tapsets.cxx')
-rw-r--r-- | tapsets.cxx | 792 |
1 files changed, 308 insertions, 484 deletions
diff --git a/tapsets.cxx b/tapsets.cxx index 30f93d46..61811163 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -127,8 +127,8 @@ be_derived_probe::emit_probe_entries (translator_output* o, unsigned j) // NB: locals are initialized by probe function itself o->newline() << "probe_" << j << " (c);"; - o->newline() << "if (c->last_error) {"; - o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "if (c->last_error && c->last_error[0]) {"; + o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; @@ -178,23 +178,6 @@ lex_cast_hex(IN const & in) return out; } -struct -func_info -{ - string name; - Dwarf_Die die; - Dwarf_Addr prologue_end; -}; - -struct -inline_instance_info -{ - string name; - Dwarf_Die die; -}; - -static int -query_cu (Dwarf_Die * cudie, void * arg); // Helper for dealing with selected portions of libdwfl in a more readable @@ -245,7 +228,6 @@ dwflpp { if (!module_dwarf) module_dwarf = dwfl_module_getdwarf(module, &module_bias); - if (module_dwarf == NULL && sess.verbose) clog << "WARNING: dwfl_module_getdwarf() : " << dwfl_errmsg (dwfl_errno ()) << endl; @@ -310,21 +292,21 @@ dwflpp } - void query_cu_containing_global_address(Dwarf_Addr a, void *arg) + void focus_on_cu_containing_global_address(Dwarf_Addr a) { Dwarf_Addr bias; assert(dwfl); get_module_dwarf(); if (false && sess.verbose) clog << "focusing on cu containing global addr " << a << endl; - query_cu (dwfl_module_addrdie(module, a, &bias), arg); + focus_on_cu(dwfl_module_addrdie(module, a, &bias)); assert(bias == module_bias); } - void query_cu_containing_module_address(Dwarf_Addr a, void *arg) + void focus_on_cu_containing_module_address(Dwarf_Addr a) { - query_cu_containing_global_address(module_address_to_global(a), arg); + focus_on_cu_containing_global_address(module_address_to_global(a)); } @@ -392,24 +374,15 @@ dwflpp } - void dwfl_assert(string desc, int rc) // NB: "rc == 0" means OK in this case + void dwflpp_assert(string desc, int rc) // NB: "rc == 0" means OK in this case { - string msg = "libdwfl failure (" + desc + "): "; + string msg = "dwfl failure (" + desc + "): "; if (rc < 0) msg += dwfl_errmsg (rc); else if (rc > 0) msg += strerror (rc); if (rc != 0) throw semantic_error (msg); } - void dwarf_assert(string desc, int rc) // NB: "rc == 0" means OK in this case - { - string msg = "libdw failure (" + desc + "): "; - if (rc < 0) msg += dwarf_errmsg (rc); - else if (rc > 0) msg += strerror (rc); - if (rc != 0) - throw semantic_error (msg); - } - dwflpp(systemtap_session & sess) : @@ -448,27 +421,25 @@ dwflpp if (kernel) { - dwfl = dwfl_begin (&kernel_callbacks); + dwfl = dwfl_begin(&kernel_callbacks); if (!dwfl) - throw semantic_error ("cannot open dwfl"); - dwfl_report_begin (dwfl); + throw semantic_error("cannot open dwfl"); + dwfl_report_begin(dwfl); // XXX: if we have only kernel.* probe points, we shouldn't waste time // looking for module debug-info (and vice versa). - dwfl_assert ("dwfl_linux_kernel_report_kernel", - dwfl_linux_kernel_report_kernel (dwfl)); - dwfl_assert ("dwfl_linux_kernel_report_modules", - dwfl_linux_kernel_report_modules (dwfl)); + dwflpp_assert("find kernel debug-info", dwfl_linux_kernel_report_kernel(dwfl)); + dwflpp_assert("find modules debug-info", dwfl_linux_kernel_report_modules(dwfl)); } else { - dwfl = dwfl_begin (&proc_callbacks); - dwfl_report_begin (dwfl); + dwfl = dwfl_begin(&proc_callbacks); + dwfl_report_begin(dwfl); if (!dwfl) - throw semantic_error ("cannot open dwfl"); + throw semantic_error("cannot open dwfl"); // XXX: Find pids or processes, do userspace stuff. } - dwfl_assert ("dwfl_report_end", dwfl_report_end(dwfl, NULL, NULL)); + dwflpp_assert("report_end", dwfl_report_end(dwfl, NULL, NULL)); } void iterate_over_modules(int (* callback)(Dwfl_Module *, void **, @@ -482,10 +453,9 @@ dwflpp off = dwfl_getmodules (dwfl, callback, data, off); } while (off > 0); - dwfl_assert("dwfl_getmodules", off); + dwflpp_assert("getdwarf", off); } - void iterate_over_cus (int (*callback)(Dwarf_Die * die, void * arg), void * data) { @@ -501,167 +471,162 @@ dwflpp Dwarf_Off off = 0; size_t cuhl; Dwarf_Off noff; - while (dwarf_nextcu (dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) + while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, NULL, NULL) == 0) { Dwarf_Die die_mem; Dwarf_Die *die; - die = dwarf_offdie (dw, off + cuhl, &die_mem); - if (callback (die, data) != DWARF_CB_OK) + die = dwarf_offdie(dw, off + cuhl, &die_mem); + if (callback(die, data) != DWARF_CB_OK) break; off = noff; } } - - bool func_is_inline() + void iterate_over_functions(int (* callback)(Dwarf_Func * func, void * arg), + void * data) { - assert (function); - return dwarf_func_inline (function) != 0; + assert(module); + assert(cu); + dwarf_getfuncs(cu, callback, data, 0); } - void iterate_over_inline_instances (int (* callback)(Dwarf_Die * die, void * arg), - void * data) + bool function_entrypc(Dwarf_Addr * addr) { - assert (function); - assert (func_is_inline ()); - dwarf_assert ("dwarf_func_inline_instances", - dwarf_func_inline_instances (function, callback, data)); + return (dwarf_func_entrypc(function, addr) == 0); } - - void iterate_over_functions (int (* callback)(Dwarf_Func * func, void * arg), - void * data) + bool function_includes_global_addr(Dwarf_Addr addr) { - assert (module); - assert (cu); - dwarf_getfuncs (cu, callback, data, 0); + assert(module_dwarf); + assert(cu); + assert(function); + Dwarf_Addr lo, hi; + if (dwarf_func_lowpc(function, &lo) != 0) + { + if (false && sess.verbose) + clog << "WARNING: cannot find low PC value for function " << function_name << endl; + return false; + } + + if (dwarf_func_highpc(function, &hi) != 0) + { + if (false && sess.verbose) + clog << "WARNING: cannot find high PC value for function " << function_name << endl; + return false; + } + + bool t = lo <= addr && addr <= hi; + if (t && sess.verbose) + clog << "function " << function_name << " = [" << hex << lo << "," << hi << "] " + << "contains global addr " << addr << dec << endl; + return t; } - void iterate_over_srcfile_lines (char const * srcfile, - int lineno, - void (* callback) (Dwarf_Line * line, void * arg), - void *data) + Dwarf_Addr global_addr_of_line_in_cu(int line) { - Dwarf_Line **srcsp; - size_t nsrcs; + Dwarf_Lines * lines; + Dwarf_Addr addr; + size_t nlines; + int best_line = -1; - get_module_dwarf(); + assert(module); + assert(cu); + dwflpp_assert("getsrclines", dwarf_getsrclines(cu, &lines, &nlines)); - dwarf_assert ("dwarf_getsrc_file", - dwarf_getsrc_file (module_dwarf, - srcfile, lineno, 0, - &srcsp, &nsrcs)); - - for (size_t i = 0; i < nsrcs; ++i) + for (size_t i = 0; i < nlines; ++i) + { + int curr_line; + Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); + dwflpp_assert("lineno", dwarf_lineno (line_rec, &curr_line)); + + if (curr_line >= line && (best_line == -1 || curr_line < best_line)) + { + best_line = curr_line; + dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, &addr)); + } + } + + if (best_line != -1) { - callback (srcsp[i], data); + if (sess.verbose) + clog << "line " << best_line + << " (given query line " << line << ")" + << " of CU " << cu_name + << " has module address " << hex << addr + << " in " << module_name << dec << endl; + return module_address_to_global(addr); } + + if (sess.verbose) + clog << "WARNING: could not find line " << line + << " in CU " << cu_name << endl; + return 0; } - void collect_srcfiles_matching (string const & pattern, - set<char const *> & filtered_srcfiles) + bool function_prologue_end(Dwarf_Addr * addr) { - assert (module); - assert (cu); + Dwarf_Lines * lines; + size_t nlines; - size_t nfiles; - Dwarf_Files *srcfiles; + assert(addr); + dwflpp_assert("getsrclines", dwarf_getsrclines(cu, &lines, &nlines)); - dwarf_assert ("dwarf_getsrcfiles", - dwarf_getsrcfiles (cu, &srcfiles, &nfiles)); - { - for (size_t i = 0; i < nfiles; ++i) + + // If GCC output the right information we would do this: + /* + + for (size_t i = 0; i < nlines; ++i) { - char const * fname = dwarf_filesrc (srcfiles, i, NULL, NULL); - if (fnmatch (pattern.c_str(), fname, 0) == 0) + bool flag; + Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); + + dwflpp_assert("lineprologueend", dwarf_lineprologueend (line_rec, &flag)); + + if (sess.verbose) + clog << "checked line record " << i + << ", is " << (flag ? "" : " not") + << " prologue end" << endl; + + if (flag) { - filtered_srcfiles.insert (fname); - if (sess.verbose) - clog << "selected source file '" << fname << "'" << endl; + dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, addr)); + return true; } } - } - } + return false; + */ - void resolve_prologue_endings (map<Dwarf_Addr, func_info> & funcs) - { - assert(module); - assert(cu); + // Since GCC does not output the right information, we do this: - size_t nlines; - Dwarf_Lines *lines; - Dwarf_Addr previous_addr; - bool choose_next_line = false; + Dwarf_Addr entrypc; + if (!function_entrypc(&entrypc)) + return false; - dwarf_assert ("dwarf_getsrclines", - dwarf_getsrclines(cu, &lines, &nlines)); + bool choose_next_line = false; for (size_t i = 0; i < nlines; ++i) { - Dwarf_Addr addr; + Dwarf_Addr line_addr; Dwarf_Line * line_rec = dwarf_onesrcline(lines, i); - dwarf_lineaddr (line_rec, &addr); - + dwflpp_assert("lineaddr", dwarf_lineaddr(line_rec, &line_addr)); if (choose_next_line) { - map<Dwarf_Addr, func_info>::iterator i = funcs.find (previous_addr); - assert (i != funcs.end()); - i->second.prologue_end = addr; - choose_next_line = false; - } - - else - { - map<Dwarf_Addr, func_info>::const_iterator i = funcs.find (addr); - if (i != funcs.end()) - choose_next_line = true; + *addr = line_addr; + if (sess.verbose) + clog << "function " << function_name + << " entrypc: " << hex << entrypc + << " prologue-end: " << line_addr << dec + << endl; + return true; } - previous_addr = addr; + else if (line_addr == entrypc) + choose_next_line = true; } + return false; } - - bool function_entrypc (Dwarf_Addr * addr) - { - assert (function); - return (dwarf_func_entrypc (function, addr) == 0); - } - - - bool die_entrypc (Dwarf_Die * die, Dwarf_Addr * addr) - { - Dwarf_Attribute attr_mem; - Dwarf_Attribute *attr = dwarf_attr (die, DW_AT_entry_pc, &attr_mem); - if (attr != NULL) - return (dwarf_formaddr (attr, addr) == 0); - - return ( dwarf_lowpc (die, addr) == 0); - } - - - char const * function_srcfile () - { - assert (function); - return dwarf_func_file (function); - } - - void function_die (Dwarf_Die *d) - { - assert (function); - dwarf_func_die (function, d); - } - - bool die_has_pc (Dwarf_Die * die, Dwarf_Addr pc) - { - int res = dwarf_haspc (die, pc); - if (res == -1) - dwarf_assert ("dwarf_haspc", res); - return res == 1; - } - - static void loc2c_error (void *arg, const char *fmt, ...) { char *msg = NULL; @@ -672,7 +637,6 @@ dwflpp throw semantic_error (msg); } - static void loc2c_emit_address (void *arg, struct obstack *pool, Dwarf_Addr address) { @@ -736,13 +700,8 @@ dwflpp Dwarf_Attribute attr_mem; if (dwarf_attr_integrate (&vardie, DW_AT_location, &attr_mem) == NULL) - { - throw semantic_error("failed to retrieve location " - "attribute for local '" + local - + "' (dieoffset: " - + lex_cast_hex<string>(dwarf_dieoffset (&vardie)) - + ")"); - } + throw semantic_error("failed to retrieve location " + "attribute for local '" + local + "'"); #define obstack_chunk_alloc malloc #define obstack_chunk_free free @@ -1017,14 +976,6 @@ dwarf_query string file; int line; - set<char const *> filtered_srcfiles; - - // Map official entrypc -> func_info object - map<Dwarf_Addr, inline_instance_info> filtered_inlines; - map<Dwarf_Addr, func_info> filtered_functions; - bool choose_next_line; - Dwarf_Addr entrypc_for_next_line; - probe * base_probe; probe_point * base_loc; dwflpp & dw; @@ -1187,35 +1138,8 @@ dwarf_query::parse_function_spec(string & spec) } - - // The critical determining factor when interpreting a pattern - // string is, perhaps surprisingly: "presence of a lineno". The - // presence of a lineno changes the search strategy completely. - // - // Compare the two cases: - // - // 1. {statement,function}(foo@file.c:lineno) - // - find the files matching file.c - // - in each file, find the functions matching foo - // - query the file for line records matching lineno - // - iterate over the line records, - // - and iterate over the functions, - // - if(haspc(function.DIE, line.addr)) - // - if looking for statements: probe(lineno.addr) - // - if looking for functions: probe(function.{entrypc,return,etc.}) - // - // 2. {statement,function}(foo@file.c) - // - find the files matching file.c - // - in each file, find the functions matching foo - // - probe(function.{entrypc,return,etc.}) - // - // Thus the first decision we make is based on the presence of a - // lineno, and we enter entirely different sets of callbacks - // depending on that decision. - - static void -query_statement (Dwarf_Addr stmt_addr, dwarf_query * q) +query_statement(Dwarf_Addr stmt_addr, dwarf_query * q) { try { @@ -1232,195 +1156,129 @@ query_statement (Dwarf_Addr stmt_addr, dwarf_query * q) } } -static void -query_inline_instance_info (Dwarf_Addr entrypc, - inline_instance_info const & ii, - dwarf_query * q) -{ - if (q->has_return) - { - throw semantic_error ("cannot probe .return of inline function '" + ii.name + "'"); - } - else - { - if (q->sess.verbose) - clog << "querying entrypc " - << hex << entrypc << dec - << " of instance of inline '" << ii.name << "'" << endl; - query_statement (entrypc, q); - } -} - -static void -query_func_info (Dwarf_Addr entrypc, - func_info const & fi, - dwarf_query * q) -{ - if (q->has_return) - { - // NB. dwarf_derived_probe::emit_registrations will emit a - // kretprobe based on the entrypc in this case. - if (q->sess.verbose) - clog << "querying entrypc of function '" << fi.name << "' for return probe" << endl; - query_statement (entrypc, q); - } - else - { - if (q->sess.verbose) - clog << "querying prologue-end of function '" << fi.name << "'" << endl; - query_statement (fi.prologue_end, q); - } -} - - -static void -query_srcfile_line (Dwarf_Line * line, void * arg) -{ - dwarf_query * q = static_cast<dwarf_query *>(arg); - - Dwarf_Addr addr; - dwarf_lineaddr(line, &addr); - - for (map<Dwarf_Addr, func_info>::iterator i = q->filtered_functions.begin(); - i != q->filtered_functions.end(); ++i) - { - if (q->dw.die_has_pc (&(i->second.die), addr)) - { - if (q->sess.verbose) - clog << "function DIE lands on srcfile" << endl; - query_func_info (i->first, i->second, q); - } - } - - for (map<Dwarf_Addr, inline_instance_info>::iterator i = q->filtered_inlines.begin(); - i != q->filtered_inlines.end(); ++i) - { - if (q->dw.die_has_pc (&(i->second.die), addr)) - { - if (q->sess.verbose) - clog << "inline instance DIE lands on srcfile" << endl; - query_inline_instance_info (i->first, i->second, q); - } - } -} - - static int -query_dwarf_inline_instance (Dwarf_Die * die, void * arg) +query_function(Dwarf_Func * func, void * arg) { dwarf_query * q = static_cast<dwarf_query *>(arg); - assert (!q->has_statement_num); - - try - { - - bool record_this_inline = false; - - if (q->sess.verbose) - clog << "examining inline instance of " << q->dw.function_name << endl; - - if (q->has_function_str || q->has_statement_str) - record_this_inline = true; - else if (q->has_function_num) - { - Dwarf_Addr query_addr = q->function_num_val; - - if (q->has_module) - query_addr = q->dw.module_address_to_global(query_addr); - - if (q->dw.die_has_pc (die, query_addr)) - record_this_inline = true; - } - - if (record_this_inline) - { - if (q->sess.verbose) - clog << "selected inline instance of " << q->dw.function_name << endl; - - Dwarf_Addr entrypc; - if (q->dw.die_entrypc (die, &entrypc)) - { - inline_instance_info inl; - inl.die = *die; - inl.name = q->dw.function_name; - q->filtered_inlines[entrypc] = inl; - } - } - return DWARF_CB_OK; - } - catch (const semantic_error& e) - { - q->sess.print_error (e); - return DWARF_CB_ABORT; - } -} - -static int -query_dwarf_func (Dwarf_Func * func, void * arg) -{ - dwarf_query * q = static_cast<dwarf_query *>(arg); - assert (!q->has_statement_num); try { // XXX: implement if (q->has_callees) - throw semantic_error ("incomplete: do not know how to interpret .callees", - q->base_probe->tok); - + throw semantic_error("incomplete: do not know how to interpret .callees", + q->base_probe->tok); + if (q->has_label) - throw semantic_error ("incomplete: do not know how to interpret .label", - q->base_probe->tok); - - q->dw.focus_on_function (func); - - if (q->dw.func_is_inline () - && (((q->has_statement_str || q->has_function_str) - && q->dw.function_name_matches(q->function)) - || q->has_function_num)) - { - if (q->sess.verbose) - clog << "checking instances of inline " << q->dw.function_name << endl; - q->dw.iterate_over_inline_instances (query_dwarf_inline_instance, arg); - } + throw semantic_error("incomplete: do not know how to interpret .label", + q->base_probe->tok); + + q->dw.focus_on_function(func); + + Dwarf_Addr entry_addr; + + if (q->has_statement_str || q->has_function_str) + { + if (q->dw.function_name_matches(q->function)) + { + if (q->sess.verbose) + clog << "focused on function '" << q->dw.function_name + << "', in CU '" << q->dw.cu_name + << "', module '" << q->dw.module_name << "'" << endl; + + // XXX: This code is duplicated below, but it's important + // for performance reasons to test things in this order. + + if (q->has_statement_str) + { + // XXX: look up address corresponding to statement string, + // which could be any old line within a function definition. + cerr << "WARNING: cannot handle statement " + << q->statement_str_val << " address" << endl; + return DWARF_CB_OK; + } + if (q->has_return) + { + bool ok = q->dw.function_entrypc (& entry_addr); + if (! ok) + { + if (q->sess.verbose) + cerr << "WARNING: cannot find entry-pc for function " + << q->dw.function_name << endl; + return DWARF_CB_OK; + } + if (q->sess.verbose) + clog << "function " << q->dw.function_name + << " entrypc: " << hex << entry_addr << dec << endl; + } + else + { + bool ok = q->dw.function_prologue_end(& entry_addr); + if (! ok) + { + // XXX: but this is actually OK for inlined function instances + if (q->sess.verbose) + cerr << "WARNING: cannot find prologue-end PC for function " + << q->dw.function_name << endl; + return DWARF_CB_OK; + } + } + + // If this function's name matches a function or statement + // pattern, we use its entry pc, but we do not abort iteration + // since there might be other functions matching the pattern. + query_statement(entry_addr, q); + } + } else - { - bool record_this_function = false; - - if ((q->has_statement_str || q->has_function_str) - && q->dw.function_name_matches(q->function)) - { - record_this_function = true; - } - else if (q->has_function_num) - { - Dwarf_Addr query_addr = q->function_num_val; - - if (q->has_module) - query_addr = q->dw.module_address_to_global(query_addr); - - Dwarf_Die d; - q->dw.function_die (&d); - - if (q->dw.die_has_pc (&d, query_addr)) - record_this_function = true; - } - - if (record_this_function) - { - if (q->sess.verbose) - clog << "selected function " << q->dw.function_name << endl; - - Dwarf_Addr entrypc; - if (q->dw.function_entrypc (&entrypc)) - { - func_info func; - q->dw.function_die (&func.die); - func.name = q->dw.function_name; - q->filtered_functions[entrypc] = func; - } - } - } + { + if (q->has_function_num || q->has_statement_num) + { + Dwarf_Addr query_addr = (q->has_function_num + ? q->function_num_val + : q->statement_num_val); + + // Adjust module-relative address to global + + if (q->has_module) + query_addr = q->dw.module_address_to_global(query_addr); + + if (q->dw.function_includes_global_addr(query_addr)) + { + if (q->has_statement_num) // has_statement + entry_addr = 0; // unused, see below + else if (q->has_return) // has_function + { + bool ok = q->dw.function_entrypc (& entry_addr); + if (! ok) + { + if (q->sess.verbose) + cerr << "WARNING: cannot find entry-pc for function " + << q->dw.function_name << endl; + return DWARF_CB_OK; + } + if (q->sess.verbose) + clog << "function " << q->dw.function_name + << " entrypc: " << hex << entry_addr << dec << endl; + } + else // has_function + { + bool ok = q->dw.function_prologue_end(& entry_addr); + if (! ok) + { + // XXX: but this is actually OK for inlined function instances + if (q->sess.verbose) + cerr << "WARNING: cannot find prologue-end PC for function " + << q->dw.function_name << endl; + return DWARF_CB_OK; + } + } + + query_statement(q->has_function_num ? entry_addr : query_addr, q); + return DWARF_CB_ABORT; + } + } + } + return DWARF_CB_OK; } catch (const semantic_error& e) @@ -1437,77 +1295,52 @@ query_cu (Dwarf_Die * cudie, void * arg) try { - q->dw.focus_on_cu (cudie); + q->dw.focus_on_cu(cudie); + + // If we have enough information in the pattern to skip a CU + // and the CU does not match that information, return early. + if ((q->has_statement_str || q->has_function_str) + && (q->spec_type == function_file_and_line || + q->spec_type == function_and_file) + && (!q->dw.cu_name_matches(q->file))) + return DWARF_CB_OK; if (false && q->sess.verbose) clog << "focused on CU '" << q->dw.cu_name << "', in module '" << q->dw.module_name << "'" << endl; - if (q->has_statement_str || q->has_function_str || q->has_function_num) - { - q->filtered_srcfiles.clear(); - q->filtered_functions.clear(); - q->filtered_inlines.clear(); - - // In this path, we find "abstract functions", record - // information about them, and then (depending on lineno - // matching) possibly emit one or more of the function's - // associated addresses. Unfortunately the control of this - // cannot easily be turned inside out. - - if ((q->has_statement_str || q->has_function_str) - && (q->spec_type != function_alone)) - { - // If we have a pattern string with a filename, we need - // to elaborate the srcfile mask in question first. - q->dw.collect_srcfiles_matching (q->file, q->filtered_srcfiles); - - // If we have a file pattern and *no* srcfile matches, there's - // no need to look further into this CU, so skip. - if (q->filtered_srcfiles.empty()) - return DWARF_CB_OK; - } - - // Pick up [entrypc, name, DIE] tuples for all the functions - // matching the query, and fill in the prologue endings of them - // all in a single pass. - q->dw.iterate_over_functions (query_dwarf_func, q); - q->dw.resolve_prologue_endings (q->filtered_functions); - - if ((q->has_statement_str || q->has_function_str) - && (q->spec_type == function_file_and_line)) - { - // If we have a pattern string with target *line*, we - // have to look at lines in all the matched srcfiles. - for (set<char const *>::const_iterator i = q->filtered_srcfiles.begin(); - i != q->filtered_srcfiles.end(); ++i) - q->dw.iterate_over_srcfile_lines (*i, q->line, query_srcfile_line, q); - } - else - { - // Otherwise, simply probe all resolved functions... - for (map<Dwarf_Addr, func_info>::const_iterator i = q->filtered_functions.begin(); - i != q->filtered_functions.end(); ++i) - query_func_info (i->first, i->second, q); - - // And all inline instances. - for (map<Dwarf_Addr, inline_instance_info>::const_iterator i - = q->filtered_inlines.begin(); i != q->filtered_inlines.end(); ++i) - query_inline_instance_info (i->first, i->second, q); - - } - } + if (q->has_statement_str + && (q->spec_type == function_file_and_line) + && q->dw.cu_name_matches(q->file)) + { + // If we have a complete file:line statement + // functor (not function functor) landing on + // this CU, we can look up a specific address + // for the statement, and skip scanning + // the remaining functions within the CU. + query_statement(q->dw.global_addr_of_line_in_cu(q->line), q); + } + else if (q->has_function_str + && (q->spec_type == function_file_and_line) + && q->dw.cu_name_matches(q->file)) + { + // If we have a complete file:line *function* functor + // landing on this CU, we need to select only the functions + // which land on the line in question. We *could* check each + // function individually but the line->addr lookup is + // expensive, so we do it once here, then temporarily switch + // to a .function(addr) query for the remaining function + // iteration, switching back when we complete. + q->function_num_val = q->dw.global_addr_of_line_in_cu(q->line); + swap(q->has_function_str, q->has_function_num); + q->dw.iterate_over_functions(&query_function, q); + swap(q->has_function_str, q->has_function_num); + } else { - // Otherwise we have a statement number, and we can just - // query it directly within this module. - - assert (q->has_statement_num); - Dwarf_Addr query_addr = q->statement_num_val; - if (q->has_module) - query_addr = q->dw.module_address_to_global(query_addr); - - query_statement (query_addr, q); + // Otherwise we need to scan all the functions in this CU, + // matching by function name or address, as requested. + q->dw.iterate_over_functions(&query_function, q); } return DWARF_CB_OK; } @@ -1551,38 +1384,35 @@ query_module (Dwfl_Module *mod __attribute__ ((unused)), // module("foo").statement(0xbeef), the address is relative // to the start of the module, so we seek the function // number plus the module's bias. - Dwarf_Addr addr; if (q->has_function_num) addr = q->function_num_val; else addr = q->statement_num_val; - // NB: We should not have kernel.* here; global addresses - // should have bypassed query_module in dwarf_builder::build - // and gone directly to query_cu. + if (q->has_kernel) + q->dw.focus_on_cu_containing_global_address(addr); + else + q->dw.focus_on_cu_containing_module_address(addr); - assert (!q->has_kernel); - assert (q->has_module); - q->dw.query_cu_containing_module_address(addr, q); + q->dw.iterate_over_functions(&query_function, q); } else { // Otherwise if we have a function("foo") or statement("foo") // specifier, we have to scan over all the CUs looking for - // the function(s) in question - + // the function in question assert(q->has_function_str || q->has_statement_str); q->dw.iterate_over_cus(&query_cu, q); - - // If we just processed the module "kernel", and the user asked for - // the kernel pattern, there's no need to iterate over any further - // modules - - if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL)) - return DWARF_CB_ABORT; } + // If we just processed the module "kernel", and the user asked for + // the kernel pattern, there's no need to iterate over any further + // modules + + if (q->has_kernel && q->dw.module_name_matches(TOK_KERNEL)) + return DWARF_CB_ABORT; + return DWARF_CB_OK; } catch (const semantic_error& e) @@ -1822,11 +1652,6 @@ probe_entry_struct_kprobe_name(unsigned probenum) void dwarf_derived_probe::emit_registrations (translator_output* o, unsigned probenum) { - if (! (module_name.empty() || module_name == "kernel")) - { - // XXX: lock module_name in memory - } - if (has_return) { o->newline() << probe_entry_struct_kprobe_name(probenum) @@ -1856,11 +1681,6 @@ dwarf_derived_probe::emit_deregistrations (translator_output* o, unsigned proben o->newline() << "unregister_kprobe (& " << probe_entry_struct_kprobe_name(probenum) << ");"; - - if (! (module_name.empty() || module_name == "kernel")) - { - // XXX: unlock module_name - } } void @@ -1901,11 +1721,11 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum // NB: locals are initialized by probe function itself o->newline() << "probe_" << probenum << " (c);"; - o->newline() << "if (c->last_error) {"; - o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "if (c->last_error && c->last_error[0]) {"; + o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; - + o->newline() << "c->busy --;"; o->newline() << "mb ();"; @@ -1919,7 +1739,9 @@ dwarf_derived_probe::emit_probe_entries (translator_output* o, unsigned probenum << probe_entry_struct_kprobe_name(probenum) << "= {"; o->newline(1) << ".kp.addr = 0," ; - o->newline() << ".handler = &" << probe_entry_function_name(probenum); + o->newline() << ".handler = &" + << probe_entry_function_name(probenum) << ","; + o->newline() << ".maxactive = 1"; o->newline(-1) << "};"; } else @@ -1949,7 +1771,8 @@ dwarf_builder::build(systemtap_session & sess, dw.setup(q.has_kernel || q.has_module); - if (q.has_kernel && (q.has_function_num || q.has_statement_num)) + if (q.has_kernel + && (q.has_function_num || q.has_statement_num)) { // If we have kernel.function(0xbeef), or // kernel.statement(0xbeef) the address is global (relative to @@ -1959,7 +1782,8 @@ dwarf_builder::build(systemtap_session & sess, ? q.function_num_val : q.statement_num_val); dw.focus_on_module_containing_global_address(a); - dw.query_cu_containing_global_address(a, &q); + dw.focus_on_cu_containing_global_address(a); + dw.iterate_over_functions(&query_function, &q); } else { @@ -2067,8 +1891,8 @@ timer_derived_probe::emit_probe_entries (translator_output* o, unsigned j) // NB: locals are initialized by probe function itself o->newline() << "probe_" << j << " (c);"; - o->newline() << "if (c->last_error) {"; - o->newline(1) << "if (c->last_error[0]) _stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; + o->newline() << "if (c->last_error && c->last_error[0]) {"; + o->newline(1) << "_stp_error (\"%s near %s\", c->last_error, c->last_stmt);"; o->newline() << "atomic_set (& session_state, STAP_SESSION_ERROR);"; o->newline(-1) << "}"; |