diff options
-rw-r--r-- | dwflpp.cxx | 84 | ||||
-rw-r--r-- | dwflpp.h | 4 | ||||
-rw-r--r-- | loc2c-test.c | 40 | ||||
-rw-r--r-- | loc2c.c | 41 | ||||
-rw-r--r-- | loc2c.h | 7 | ||||
-rw-r--r-- | tapset/ioblock.stp | 9 | ||||
-rw-r--r-- | tapset/nfs_proc.stp | 16 | ||||
-rw-r--r-- | tapset/scsi.stp | 6 | ||||
-rw-r--r-- | tapset/task.stp | 30 | ||||
-rw-r--r-- | tapsets.cxx | 49 | ||||
-rw-r--r-- | tapsets.h | 1 | ||||
-rw-r--r-- | testsuite/systemtap.exelib/exelib.exp | 8 | ||||
-rw-r--r-- | translate.cxx | 59 |
13 files changed, 262 insertions, 92 deletions
@@ -63,16 +63,16 @@ using namespace __gnu_cxx; static string TOK_KERNEL("kernel"); -dwflpp::dwflpp(systemtap_session & session, const string& user_module): +dwflpp::dwflpp(systemtap_session & session, const string& name, bool kernel_p): sess(session), module(NULL), module_bias(0), mod_info(NULL), module_start(0), module_end(0), cu(NULL), dwfl(NULL), module_dwarf(NULL), function(NULL), blacklist_enabled(false), pc_cached_scopes(0), num_cached_scopes(0), cached_scopes(NULL) { - if (user_module.empty()) - setup_kernel(); + if (kernel_p) + setup_kernel(name); else - setup_user(user_module); + setup_user(name); } @@ -250,8 +250,32 @@ dwflpp::function_name_final_match(const string& pattern) } +static const char *offline_search_modname = NULL; +static int offline_search_match_p = 0; + +static int dwfl_report_offline_predicate (const char* modname, const char* filename) +{ + if (pending_interrupts) + return -1; + + if (offline_search_match_p) + return -1; + + assert (offline_search_modname); + + /* Reject mismatching module names */ + if (strcmp(modname, offline_search_modname)) + return 0; + else + { + offline_search_match_p ++; + return 1; + } +} + + void -dwflpp::setup_kernel(bool debuginfo_needed) +dwflpp::setup_kernel(const string& name, bool debuginfo_needed) { // XXX: See also translate.cxx:emit_symbol_data @@ -289,21 +313,31 @@ dwflpp::setup_kernel(bool debuginfo_needed) else elfutils_kernel_path = sess.kernel_build_tree; + offline_search_modname = name.c_str(); + offline_search_match_p = 0; int rc = dwfl_linux_kernel_report_offline (dwfl, elfutils_kernel_path.c_str(), &dwfl_report_offline_predicate); + offline_search_modname = NULL; + + (void) rc; /* Ignore since the predicate probably returned -1 at some point, + And libdwfl interprets that as "whole query failed" rather than + "found it already, stop looking". */ - if (debuginfo_needed) { - if (rc) { - // Suggest a likely kernel dir to find debuginfo rpm for - string dir = string("/lib/modules/" + sess.kernel_release ); - find_debug_rpms(sess, dir.c_str()); + /* But we still need to check whether the module was itself found. One could + do an iterate_modules() search over the resulting dwfl and count hits. Or + one could rely on the match_p flag being set just before. */ + if (! offline_search_match_p) + { + if (debuginfo_needed) { + // Suggest a likely kernel dir to find debuginfo rpm for + string dir = string("/lib/modules/" + sess.kernel_release ); + find_debug_rpms(sess, dir.c_str()); + } + throw semantic_error (string("missing ") + sess.architecture + + string(" kernel/module debuginfo under '") + + sess.kernel_build_tree + string("'")); } - dwfl_assert (string("missing ") + sess.architecture + - string(" kernel/module debuginfo under '") + - sess.kernel_build_tree + string("'"), - rc); - } // XXX: it would be nice if we could do a single // ..._report_offline call for an entire systemtap script, so @@ -1415,6 +1449,24 @@ dwflpp::translate_location(struct obstack *pool, struct location **tail, const target_symbol *e) { + + /* DW_AT_data_member_location, can be either constant offsets + (struct member fields), or full blown location expressions. */ + if (dwarf_whatattr (attr) == DW_AT_data_member_location) + { + unsigned int form = dwarf_whatform (attr); + if (form == DW_FORM_data1 || form == DW_FORM_data2 + || form == DW_FORM_sdata || form == DW_FORM_udata) + { + Dwarf_Sword off; + if (dwarf_formsdata (attr, &off) != 0) + throw semantic_error (string ("dwarf_formsdata failed, ") + + string (dwarf_errmsg (-1)), e->tok); + c_translate_add_offset (pool, 1, NULL, off, tail); + return *tail; + } + } + Dwarf_Op *expr; size_t len; @@ -1436,7 +1488,7 @@ dwflpp::translate_location(struct obstack *pool, default: /* Shouldn't happen. */ case -1: - throw semantic_error (string ("dwarf_getlocation_addr failed") + + throw semantic_error (string ("dwarf_getlocation_addr failed, ") + string (dwarf_errmsg (-1)), e->tok); } @@ -166,7 +166,7 @@ struct dwflpp std::string cu_name; std::string function_name; - dwflpp(systemtap_session & session, const std::string& user_module=""); + dwflpp(systemtap_session & session, const std::string& user_module, bool kernel_p); ~dwflpp(); void get_module_dwarf(bool required = false, bool report = true); @@ -280,7 +280,7 @@ private: Dwarf * module_dwarf; Dwarf_Die * function; - void setup_kernel(bool debuginfo_needed = true); + void setup_kernel(const std::string& module_name, bool debuginfo_needed = true); void setup_user(const std::string& module_name, bool debuginfo_needed = true); typedef std::map<Dwarf*, std::vector<Dwarf_Die>*> module_cu_cache_t; diff --git a/loc2c-test.c b/loc2c-test.c index 01edc805..688f4a8b 100644 --- a/loc2c-test.c +++ b/loc2c-test.c @@ -214,10 +214,35 @@ handle_variable (Dwarf_Die *scopes, int nscopes, int out, } else { - locexpr = get_location (cubias, pc, &attr_mem, &locexpr_len); - c_translate_location (&pool, NULL, NULL, NULL, - 1, cubias, pc, locexpr, locexpr_len, - &tail, NULL); + /* We are expection a block, constant or loclistptr. */ + unsigned int form = dwarf_whatform (&attr_mem); + Dwarf_Sword off; + switch (form) + { + /* constant */ + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_sdata: + case DW_FORM_udata: + if (dwarf_formsdata (&attr_mem, &off) != 0) + error (2, 0, _("Bad offset for %s %s: %s"), + typetag == DW_TAG_union_type ? "union" : "struct", + dwarf_diename_integrate (die) ?: "<anonymous>", + dwarf_errmsg (-1)); + if (off != 0) + c_translate_add_offset (&pool, 1, + dwarf_diename_integrate (die) + ?: "", off, &tail); + break; + + default: + locexpr = get_location (cubias, pc, &attr_mem, + &locexpr_len); + c_translate_location (&pool, NULL, NULL, NULL, + 1, cubias, pc, locexpr, locexpr_len, + &tail, NULL); + break; + } } ++fields; break; @@ -378,6 +403,9 @@ static void print_vars (unsigned int indent, Dwarf_Die *die) { Dwarf_Die child; + Dwarf_Attribute attr_mem; + Dwarf_Die typedie_mem; + Dwarf_Die *typedie; if (dwarf_child (die, &child) == 0) do switch (dwarf_tag (&child)) @@ -387,9 +415,7 @@ print_vars (unsigned int indent, Dwarf_Die *die) printf ("%*s%-30s[%6" PRIx64 "]", indent, "", dwarf_diename (&child), (uint64_t) dwarf_dieoffset (&child)); - Dwarf_Attribute attr_mem; - Dwarf_Die typedie_mem; - Dwarf_Die *typedie = dwarf_formref_die + typedie = dwarf_formref_die (dwarf_attr_integrate (&child, DW_AT_type, &attr_mem), &typedie_mem); print_type (typedie, '\t'); @@ -251,9 +251,11 @@ translate (struct obstack *pool, int indent, Dwarf_Addr addrbias, break; case DW_OP_drop: - POP (ignore); - emit ("%*s/* drop " STACKFMT "*/\n", indent * 2, "", ignore); - break; + { + POP (ignore); + emit ("%*s/* drop " STACKFMT "*/\n", indent * 2, "", ignore); + break; + } case DW_OP_pick: sp = expr[i].number; @@ -622,7 +624,7 @@ location_relative (struct obstack *pool, const Dwarf_Op *expr, size_t len, Dwarf_Addr address, struct location **input, Dwarf_Attribute *fb_attr) { - Dwarf_Sword *stack; + Dwarf_Sword *stack = NULL; unsigned int stack_depth = 0, max_stack = 0; inline void deepen (void) { @@ -1667,7 +1669,38 @@ c_translate_pointer_store (struct obstack *pool, int indent, } +/* Translate a fragment to add an offset to the currently calculated + address of the input location. Used for struct fields. Only works + when location is already an actual base address. +*/ + +void +c_translate_add_offset (struct obstack *pool, int indent, const char *comment, + Dwarf_Sword off, struct location **input) +{ + indent++; + if (comment == NULL || comment[0] == '\0') + comment = "field offset"; + switch ((*input)->type) + { + case loc_address: + obstack_printf (pool, "%*saddr += " SFORMAT "; // %s\n", + indent * 2 + 2, "", off, comment); + *input = (*input)->next = new_synthetic_loc (pool, *input, false); + break; + case loc_register: + FAIL (*input, N_("cannot add offset of object in register")); + break; + case loc_noncontiguous: + FAIL (*input, N_("cannot add offset of noncontiguous object")); + break; + + default: + abort (); + break; + } +} /* Determine the element stride of an array type. */ static Dwarf_Word @@ -85,6 +85,13 @@ c_translate_pointer_store (struct obstack *pool, int indent, Dwarf_Die *typedie, struct location **input, const char *rvalue); +/* Translate a fragment to add an offset to the currently calculated + address of the input location. Used for struct fields. Only works + when location is already an actual base address. */ +void +c_translate_add_offset (struct obstack *pool, int indent, const char *comment, + Dwarf_Sword off, struct location **input); + /* Translate a C fragment for a direct argument VALUE. On errors, call FAIL, which should not return. Any later errors will use FAIL and FAIL_ARG from this translate call. On success, return the fragment created. */ diff --git a/tapset/ioblock.stp b/tapset/ioblock.stp index 4bf7ad92..bc64c425 100644 --- a/tapset/ioblock.stp +++ b/tapset/ioblock.stp @@ -47,9 +47,12 @@ function bio_rw_str(rw) /* returns start sector */ function __bio_start_sect:long(bio:long) %{ /* pure */ - struct bio *bio = (struct bio *)(long)THIS->bio; - struct block_device *bi_bdev = bio? kread(&(bio->bi_bdev)) : NULL; - struct hd_struct *bd_part = bi_bdev? kread(&(bi_bdev->bd_part)) : NULL; + struct bio *bio; + struct block_device *bi_bdev; + struct hd_struct *bd_part; + bio = (struct bio *)(long)THIS->bio; + bi_bdev = bio? kread(&(bio->bi_bdev)) : NULL; + bd_part = bi_bdev? kread(&(bi_bdev->bd_part)) : NULL; if (bd_part == NULL) THIS->__retvalue = -1; else diff --git a/tapset/nfs_proc.stp b/tapset/nfs_proc.stp index 11463e9a..e3d9a78f 100644 --- a/tapset/nfs_proc.stp +++ b/tapset/nfs_proc.stp @@ -84,12 +84,18 @@ function get_prot_from_client:long(clnt:long) %{ /* pure */ 1:get proto */ function __i2n_ip_proto :long(dir:long,index:long) %{ /* pure */ - int index = (int) (THIS->index); - struct inode * dir = (struct inode *)(uintptr_t)(THIS->dir); - struct rpc_clnt * clnt = NFS_CLIENT(dir); /* FIXME: deref hazard! */ - struct rpc_xprt * cl_xprt = kread(&(clnt->cl_xprt)); + int index; + struct inode * dir; + struct rpc_clnt * clnt; + struct rpc_xprt * cl_xprt; + struct sockaddr_in *addr; + + index = (int) (THIS->index); + dir = (struct inode *)(uintptr_t)(THIS->dir); + clnt = NFS_CLIENT(dir); /* FIXME: deref hazard! */ + cl_xprt = kread(&(clnt->cl_xprt)); /* sockaddr_storage is used since 2.6.19. Need cast*/ - struct sockaddr_in *addr = (struct sockaddr_in *)&(cl_xprt->addr); + addr = (struct sockaddr_in *)&(cl_xprt->addr); if(index == 0) { if (kread(&(addr->sin_family)) == AF_INET) { diff --git a/tapset/scsi.stp b/tapset/scsi.stp index e1457739..5758f315 100644 --- a/tapset/scsi.stp +++ b/tapset/scsi.stp @@ -130,8 +130,10 @@ function scsi_timer_pending:long(var:long) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) THIS->__retvalue = timer_pending(&cmd->eh_timeout); /* FIXME: deref hazard! */ #else - struct request *req = (struct request *)kread(&cmd->request); - struct request_queue *rq = (struct request_queue *)kread(&req->q); + struct request *req; + struct request_queue *rq; + req = (struct request *)kread(&cmd->request); + rq = (struct request_queue *)kread(&req->q); THIS->__retvalue = timer_pending(&rq->timeout); /* FIXME: deref hazard! */ CATCH_DEREF_FAULT(); #endif diff --git a/tapset/task.stp b/tapset/task.stp index f1a10b0a..1f4e0e6f 100644 --- a/tapset/task.stp +++ b/tapset/task.stp @@ -189,10 +189,13 @@ function task_cpu:long (task:long) function task_open_file_handles:long (task:long) %( kernel_v >= "2.6.15" %? %{ /* pure */ - struct task_struct *t = (struct task_struct *)(long)THIS->task; - struct files_struct *fs = kread(&(t->files)); - struct fdtable *f = kread(&(fs->fdt)); unsigned int count=0, fd, max; + struct task_struct *t; + struct files_struct *fs; + struct fdtable *f; + t = (struct task_struct *)(long)THIS->task; + fs = kread(&(t->files)); + f = kread(&(fs->fdt)); rcu_read_lock(); max = kread(&(f->max_fds)); for (fd = 0; fd < max; fd++) { @@ -205,9 +208,11 @@ function task_open_file_handles:long (task:long) %} %: %{ /* pure */ - struct task_struct *t = (struct task_struct *)(long)THIS->task; - struct files_struct *f = kread(&(t->files)); unsigned int count=0, fd, max; + struct task_struct *t; + struct files_struct *f; + t = (struct task_struct *)(long)THIS->task; + f = kread(&(t->files)); rcu_read_lock(); max = kread(&(f->max_fds)); for (fd = 0; fd < max; fd++) { @@ -225,9 +230,12 @@ function task_open_file_handles:long (task:long) function task_max_file_handles:long (task:long) %( kernel_v >= "2.6.15" %? %{ /* pure */ - struct task_struct *t = (struct task_struct *)(long)THIS->task; - struct files_struct *fs = kread (&(t->files)); - struct fdtable *f = kread(&(fs->fdt)); + struct task_struct *t; + struct files_struct *fs; + struct fdtable *f; + t = (struct task_struct *)(long)THIS->task; + fs = kread (&(t->files)); + f = kread(&(fs->fdt)); rcu_read_lock(); THIS->__retvalue = kread(&(f->max_fds)); rcu_read_unlock(); @@ -235,8 +243,10 @@ function task_max_file_handles:long (task:long) %} %: %{ /* pure */ - struct task_struct *t = (struct task_struct *)(long)THIS->task; - struct files_struct *f = kread(&(t->files)); + struct task_struct *t; + struct files_struct *f; + t = (struct task_struct *)(long)THIS->task; + f = kread(&(t->files)); rcu_read_lock(); THIS->__retvalue = kread(&(f->max_fds)); rcu_read_unlock(); diff --git a/tapsets.cxx b/tapsets.cxx index 766cb39f..6ef1e188 100644 --- a/tapsets.cxx +++ b/tapsets.cxx @@ -312,15 +312,6 @@ static bool null_die(Dwarf_Die *die) } -// PR 9941 introduces the need for a predicate - -int dwfl_report_offline_predicate (const char* modname, const char* filename) -{ - if (pending_interrupts) { return -1; } - return 1; -} - - enum function_spec_type { @@ -601,34 +592,36 @@ struct dwarf_query : public base_query struct dwarf_builder: public derived_probe_builder { - dwflpp *kern_dw; + map <string,dwflpp*> kern_dw; map <string,dwflpp*> user_dw; - dwarf_builder(): kern_dw(0) {} + dwarf_builder() {} - dwflpp *get_kern_dw(systemtap_session& sess) + dwflpp *get_kern_dw(systemtap_session& sess, const string& module) { - if (!kern_dw) - kern_dw = new dwflpp(sess); - return kern_dw; + if (kern_dw.find(module) == kern_dw.end()) + kern_dw[module] = new dwflpp(sess, module, true); + return kern_dw[module]; } dwflpp *get_user_dw(systemtap_session& sess, const string& module) { if (user_dw.find(module) == user_dw.end()) - user_dw[module] = new dwflpp(sess, module); + user_dw[module] = new dwflpp(sess, module, false); return user_dw[module]; } /* NB: not virtual, so can be called from dtor too: */ void dwarf_build_no_more (bool verbose) { - if (kern_dw) + for (map<string,dwflpp*>::iterator udi = kern_dw.begin(); + udi != kern_dw.end(); + udi ++) { if (verbose) - clog << "dwarf_builder releasing kernel dwflpp" << endl; - delete kern_dw; - kern_dw = 0; + clog << "dwarf_builder releasing kernel dwflpp " << udi->first << endl; + delete udi->second; } + kern_dw.erase (kern_dw.begin(), kern_dw.end()); for (map<string,dwflpp*>::iterator udi = user_dw.begin(); udi != user_dw.end(); @@ -2721,7 +2714,7 @@ void dwarf_cast_expanding_visitor::visit_cast_op (cast_op* e) if (module.find('/') == string::npos) { // kernel or kernel module target - dw = db.get_kern_dw(s); + dw = db.get_kern_dw(s, module); } else { @@ -3453,11 +3446,13 @@ dwarf_builder::build(systemtap_session & sess, dwflpp* dw = 0; string module_name; - if (has_null_param (parameters, TOK_KERNEL) - || get_param (parameters, TOK_MODULE, module_name)) + if (has_null_param (parameters, TOK_KERNEL)) + { + dw = get_kern_dw(sess, "kernel"); + } + else if (get_param (parameters, TOK_MODULE, module_name)) { - // kernel or kernel module target - dw = get_kern_dw(sess); + dw = get_kern_dw(sess, module_name); } else if (get_param (parameters, TOK_PROCESS, module_name)) { @@ -5711,7 +5706,7 @@ tracepoint_builder::init_dw(systemtap_session& s) if (s.verbose > 2) clog << "Pass 2: using cached " << s.tracequery_path << endl; - dw = new dwflpp(s, s.tracequery_path); + dw = new dwflpp(s, s.tracequery_path, false); close(fd); return true; } @@ -5736,7 +5731,7 @@ tracepoint_builder::init_dw(systemtap_session& s) << s.tracequery_path << "\"): " << strerror(errno) << endl; } - dw = new dwflpp(s, tracequery_ko); + dw = new dwflpp(s, tracequery_ko, false); return true; } @@ -15,7 +15,6 @@ void register_standard_tapsets(systemtap_session& sess); std::vector<derived_probe_group*> all_session_groups(systemtap_session& s); -int dwfl_report_offline_predicate (const char* modname, const char* filename); void common_probe_entryfn_prologue (translator_output* o, std::string statestr, std::string new_pp, bool overload_processing = true); void common_probe_entryfn_epilogue (translator_output* o, bool overload_processing = true); diff --git a/testsuite/systemtap.exelib/exelib.exp b/testsuite/systemtap.exelib/exelib.exp index d3ade2b6..c4ca8fc0 100644 --- a/testsuite/systemtap.exelib/exelib.exp +++ b/testsuite/systemtap.exelib/exelib.exp @@ -95,10 +95,10 @@ foreach arch $arches { set res [target_compile $testsrclib $testso executable $testlibflags] if { $res != "" } { verbose "target_compile for $testso failed: $res" 2 - fail "$libname compile $testsrclib" + fail "$libname compile [file tail $testsrclib]" return } else { - pass "$libname compile $testsrclib" + pass "$libname compile [file tail $testsrclib]" } # seperate debuginfo before prelinking @@ -147,10 +147,10 @@ foreach arch $arches { set res [target_compile $testsrc $testexe executable $testexeflags] if { $res != "" } { verbose "target_compile for $testexe failed: $res" 2 - fail "$exename compile $testsrc" + fail "$exename compile [file tail $testsrc]" return } else { - pass "$exename compile $testsrc" + pass "$exename compile [file tail $testsrc]" } if {$exedebug == "sep"} { diff --git a/translate.cxx b/translate.cxx index f4c2412b..ddd96938 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4908,6 +4908,27 @@ dump_unwindsyms (Dwfl_Module *m, // them with the runtime. void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); + +static set<string> offline_search_modules; +static int dwfl_report_offline_predicate2 (const char* modname, const char* filename) +{ + if (pending_interrupts) + return -1; + + if (offline_search_modules.empty()) + return -1; + + /* Reject mismatching module names */ + if (offline_search_modules.find(modname) == offline_search_modules.end()) + return 0; + else + { + offline_search_modules.erase(modname); + return 1; + } +} + + void emit_symbol_data (systemtap_session& s) { @@ -4960,22 +4981,38 @@ emit_symbol_data (systemtap_session& s) else elfutils_kernel_path = s.kernel_build_tree; + + // Set up our offline search for kernel modules. As in dwflpp.cxx, + // we don't want the offline search iteration to do a complete search + // of the kernel build tree, since that's wasteful. + offline_search_modules.erase (offline_search_modules.begin(), + offline_search_modules.end()); + for (set<string>::iterator it = s.unwindsym_modules.begin(); + it != s.unwindsym_modules.end(); + it++) + { + string foo = *it; + if (foo[0] != '/') /* Omit user-space, since we're only using this for + kernel space offline searches. */ + offline_search_modules.insert (foo); + } + int rc = dwfl_linux_kernel_report_offline (dwfl, elfutils_kernel_path.c_str(), - &dwfl_report_offline_predicate); + & dwfl_report_offline_predicate2); + + (void) rc; // As in dwflpp.cxx, we ignore rc here. + dwfl_report_end (dwfl, NULL, NULL); - if (rc == 0) // tolerate missing data; will warn user about it anyway + ptrdiff_t off = 0; + do { - ptrdiff_t off = 0; - do - { - if (pending_interrupts) return; - if (ctx.undone_unwindsym_modules.empty()) break; - off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); - } - while (off > 0); - dwfl_assert("dwfl_getmodules", off == 0); + if (pending_interrupts) return; + if (ctx.undone_unwindsym_modules.empty()) break; + off = dwfl_getmodules (dwfl, &dump_unwindsyms, (void *) &ctx, 0); } + while (off > 0); + dwfl_assert("dwfl_getmodules", off == 0); dwfl_end(dwfl); |