From 5cc5056844a402c6cf466c8ca45119a4540b5900 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 7 Jul 2009 20:19:40 +0200 Subject: PR10348 Compilation failure with gcc 4.5 snapshot: switch jumps over vars. * loc2c-test.c (print_vars): Define attr_mem, typedie_mem and typedie before switch. * loc2c.c (translate): Wrap case DW_OP_drop in block brackets. (location_relative): Initialize stack. --- loc2c-test.c | 7 ++++--- loc2c.c | 10 ++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/loc2c-test.c b/loc2c-test.c index 01edc805..01108573 100644 --- a/loc2c-test.c +++ b/loc2c-test.c @@ -378,6 +378,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 +390,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'); diff --git a/loc2c.c b/loc2c.c index 7cae16cd..f95400bb 100644 --- a/loc2c.c +++ b/loc2c.c @@ -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) { -- cgit From ae2552daf405ab1f59ddc862cfe0fcb4d90f8174 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 7 Jul 2009 14:36:53 -0400 Subject: PR3498: speed up pass-2 and pass-3 for kernel offline dwfl module searching * dwflpp.cxx (dwflpp ctor): Parametrize for user/kernel modes. Update callers. (dwfl_report_offline_predicate): New function. Filter and abort searches early if possible. (setup_kernel): Use new predicate. * dwflpp.h: Corresponding changes. * tapsets.cxx (dwfl_report_offline_predicate): Remove this shared implementation. (dwarf_builder): Turn kern_dw into module_name->dwflpp* map, just like user_dw. (get_kern_dw): Adapt. (dwarf_build_no_more): Adapt. * tapsets.h: Remove old shared predicate. * translate.cxx (dwfl_report_offline_predicate2): New function. Filter and abort searches early if possible. (emit_symbol_data): Use it. --- dwflpp.cxx | 64 +++++++++++++++++++++++++++++++++++++++++++++-------------- dwflpp.h | 4 ++-- tapsets.cxx | 49 ++++++++++++++++++++------------------------- tapsets.h | 1 - translate.cxx | 59 ++++++++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 121 insertions(+), 56 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index b2532246..de994c18 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -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 diff --git a/dwflpp.h b/dwflpp.h index ec6c5a0c..d6d97cd0 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -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*> module_cu_cache_t; diff --git a/tapsets.cxx b/tapsets.cxx index 4f172506..4988b7e7 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 { @@ -598,34 +589,36 @@ struct dwarf_query : public base_query struct dwarf_builder: public derived_probe_builder { - dwflpp *kern_dw; + map kern_dw; map 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::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::iterator udi = user_dw.begin(); udi != user_dw.end(); @@ -2715,7 +2708,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 { @@ -3445,11 +3438,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)) { @@ -5703,7 +5698,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; } @@ -5728,7 +5723,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; } diff --git a/tapsets.h b/tapsets.h index 7a74ad31..115f2ccf 100644 --- a/tapsets.h +++ b/tapsets.h @@ -15,7 +15,6 @@ void register_standard_tapsets(systemtap_session& sess); std::vector 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/translate.cxx b/translate.cxx index 378395b8..9c901065 100644 --- a/translate.cxx +++ b/translate.cxx @@ -4907,6 +4907,27 @@ dump_unwindsyms (Dwfl_Module *m, // them with the runtime. void emit_symbol_data_done (unwindsym_dump_context*, systemtap_session&); + +static set 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) { @@ -4959,22 +4980,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::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); -- cgit From 6b5e36b0fe03b9be11194916c066664d98153a14 Mon Sep 17 00:00:00 2001 From: "Frank Ch. Eigler" Date: Tue, 7 Jul 2009 20:17:48 -0400 Subject: canonicalize exelib.exp test case names by [file tail /full/path] --- testsuite/systemtap.exelib/exelib.exp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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"} { -- cgit From 51305196f1d078849da1718bb6ccfbed5af182ed Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 8 Jul 2009 09:38:33 +0200 Subject: More gcc 4.5 'jump skips variable initialization' fixlets. * tapset/ioblock.stp (__bio_start_sect): Declare, then initialize variables that could (through kread) take an early jump. * tapset/nfs_proc.stp (get_prot_from_client): Likewise. * tapset/scsi.stp (scsi_timer_pending): Likewise. * tapset/task.stp (task_cpu): Likewise. (task_open_file_handles): Likewise. --- tapset/ioblock.stp | 9 ++++++--- tapset/nfs_proc.stp | 16 +++++++++++----- tapset/scsi.stp | 6 ++++-- tapset/task.stp | 30 ++++++++++++++++++++---------- 4 files changed, 41 insertions(+), 20 deletions(-) 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(); -- cgit From 619d9aaf011c975159a79d34259083a596162bf1 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Tue, 7 Jul 2009 14:35:10 +0200 Subject: Add support for constant struct member field offsets. * loc2c.h (c_translate_add_offset): New function prototype. * loc2c.c (c_translate_add_offset): New function implementation. * loc2c-test.c (handle_variable): Use c_translate_add_offset if appropriate. * dwflpp.cxx (translate_location): Likewise. --- dwflpp.cxx | 20 +++++++++++++++++++- loc2c-test.c | 33 +++++++++++++++++++++++++++++---- loc2c.c | 31 +++++++++++++++++++++++++++++++ loc2c.h | 7 +++++++ 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index de994c18..17bce608 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -1449,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; @@ -1470,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); } diff --git a/loc2c-test.c b/loc2c-test.c index 01108573..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) ?: "", + 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; diff --git a/loc2c.c b/loc2c.c index f95400bb..5f4e4495 100644 --- a/loc2c.c +++ b/loc2c.c @@ -1669,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 diff --git a/loc2c.h b/loc2c.h index 0ad5ae99..eb1f39d6 100644 --- a/loc2c.h +++ b/loc2c.h @@ -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. */ -- cgit