From 6fcc2aa1bdf349c8c343a0ac003dad90b249a807 Mon Sep 17 00:00:00 2001 From: Mark Wielaard Date: Wed, 4 Jun 2014 15:24:41 +0200 Subject: [PATCH] Improve not accessible at this address error message. Add dwflpp::pc_die_location_as_string and dwflpp::pc_die_location_as_string to provide more human readable PC and DWARF DIE offset names and source locations (including which function was inlined where) to help track down why an argument or variable isn't accessible at a certain address. --- dwflpp.cxx | 193 +++++++++++++++++++++++++++++++++++++++++++++++++++-- dwflpp.h | 3 + 2 files changed, 192 insertions(+), 4 deletions(-) diff --git a/dwflpp.cxx b/dwflpp.cxx index bea415357..ac32217db 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -10,6 +10,7 @@ #include "dwflpp.h" #include "config.h" +#include #include "staptree.h" #include "elaborate.h" #include "tapsets.h" @@ -2807,6 +2808,187 @@ dwflpp::find_variable_and_frame_base (vector& scopes, return fb_attr; } +/* Produce a human readable name for a DIE. */ +static string +die_name_string (Dwarf_Die *die) +{ + string res; + const char *name = dwarf_linkage_name(die); + if (name == NULL) + name = dwarf_diename (die); + + size_t demangle_buffer_len = 0; + char *demangle_buffer = NULL; + if (name != NULL && name[0] == '_' && name[1] == 'Z') + { + int status = -1; + char *dsymname = abi::__cxa_demangle (name, demangle_buffer, + &demangle_buffer_len, &status); + if (status == 0) + name = demangle_buffer = dsymname; + } + if (name != NULL) + res = name; + else + res = _(" 0) + { + linestr += ":" + lex_cast(lineno); + if (col > 0) + linestr += ":" + lex_cast(col); + } + } + else + linestr += _("unknown source"); + + return linestr; +} + +/* Returns a human readable PC and DIE offset for use in error messages. + Includes PC, DIE offset, DWARF file used and (inlined) source locations. */ +string +dwflpp::pc_die_location_as_string(Dwarf_Addr pc, Dwarf_Die *die) +{ + string locstr; + + /* PC */ + locstr = _("pc: "); + locstr += lex_cast_hex(pc); + locstr += ", "; + + /* DIE offset */ + locstr += _("dieoffset: "); + locstr += lex_cast_hex(dwarf_dieoffset(die)); + + /* DWARF file */ + const char *debugfile; + if (dwfl_module_info (module, NULL, NULL, NULL, NULL, NULL, NULL, + &debugfile) == NULL) + debugfile = _(""); + + locstr += _(" from "); + locstr += debugfile; + + /* Find the first function-like DIE with a name in scope. */ + Dwarf_Die funcdie_mem; + Dwarf_Die *funcdie = NULL; + const char *funcname = NULL; + Dwarf_Die *scopes = NULL; + int nscopes = dwarf_getscopes (cu, pc, &scopes); + for (int i = 0; funcname == NULL && i < nscopes; i++) + { + Dwarf_Die *scope = &scopes[i]; + int tag = dwarf_tag (scope); + if (tag == DW_TAG_subprogram + || tag == DW_TAG_inlined_subroutine + || tag == DW_TAG_entry_point) + funcname = die_name_string (scope).c_str(); + if (funcname != NULL) + { + funcdie_mem = *scope; + funcdie = &funcdie_mem; + } + } + free (scopes); + + /* source location */ + if (funcname == NULL) + locstr += _(" in unknown function at ") + pc_die_line_string (pc, NULL); + else + { + int nscopes = dwarf_getscopes_die (funcdie, &scopes); + if (nscopes > 0) + { + /* scopes[0] == funcdie, the lowest level, for which we already have + the name. This is the actual source location where it + happened. */ + locstr += _(" in "); + locstr += funcname; + locstr += _(" at "); + locstr += pc_die_line_string (pc, NULL); + + /* last_scope is the source location where the next inlined frame/function + call was done. */ + Dwarf_Die *last_scope = &scopes[0]; + for (int i = 1; i < nscopes; i++) + { + Dwarf_Die *scope = &scopes[i]; + int tag = dwarf_tag (scope); + if (tag != DW_TAG_inlined_subroutine + && tag != DW_TAG_entry_point + && tag != DW_TAG_subprogram) + continue; + + locstr += _(" inlined by "); + locstr += die_name_string (scope); + locstr += _(" at "); + locstr += pc_die_line_string (pc, last_scope); + + /* Found the "top-level" in which everything was inlined. */ + if (tag == DW_TAG_subprogram) + break; + + last_scope = scope; + } + } + else + _(" in unknown function at ") + pc_die_line_string (pc, NULL); + free (scopes); + } + + return locstr; +} struct location * dwflpp::translate_location(struct obstack *pool, @@ -2855,13 +3037,16 @@ dwflpp::translate_location(struct obstack *pool, } /* FALLTHROUGH */ - throw SEMANTIC_ERROR (_F("not accessible at this address [man error::dwarf] (%s, dieoffset: %s)", - lex_cast_hex(pc).c_str(), lex_cast_hex(dwarf_dieoffset(die)).c_str()), - e->tok); + throw SEMANTIC_ERROR(_F("not accessible at this address [man error::dwarf] (%s)", + pc_die_location_as_string(pc, die).c_str()), + e->tok); default: /* Shouldn't happen. */ case -1: - throw SEMANTIC_ERROR (_F("dwarf_getlocation_addr failed [man error::dwarf] , %s", dwarf_errmsg(-1)), e->tok); + throw SEMANTIC_ERROR (_F("dwarf_getlocation_addr failed [man error::dwarf] , %s (%s)", + dwarf_errmsg(-1), + pc_die_location_as_string(pc, die).c_str()), + e->tok); } Dwarf_Op *cfa_ops; diff --git a/dwflpp.h b/dwflpp.h index 2d4a6562a..6ff053fb6 100644 --- a/dwflpp.h +++ b/dwflpp.h @@ -583,6 +583,9 @@ private: Dwarf_Die *vardie, Dwarf_Attribute *fb_attr_mem); + std::string pc_die_location_as_string(Dwarf_Addr, Dwarf_Die*); + std::string pc_die_line_string(Dwarf_Addr, Dwarf_Die*); + struct location *translate_location(struct obstack *pool, Dwarf_Attribute *attr, Dwarf_Die *die, -- 2.43.5