Skip to content

Commit

Permalink
PR20042: support tracepoints with function-pointer args
Browse files Browse the repository at this point in the history
For example, tracepoint "cpuhp_enter" has "int (*fun)(unsigned int))",
but since dwarf_type_name() didn't handle DW_TAG_subroutine_type, it
would call this "void*", and then the whole tracepoint function
signature would fail -Werror=incompatible-pointer-types.

We can now expand function-pointers in dwarf_type_name(), but we also
need a new dwarf_type_decl() which knows how to insert the name in the
middle of the type string.
  • Loading branch information
cuviper committed May 6, 2016
1 parent 6d25ab3 commit b6e49c9
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 28 deletions.
102 changes: 94 additions & 8 deletions dwarf_wrappers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ dwarf_decl_line_integrate (Dwarf_Die *die, int *linep)


static bool
dwarf_type_name(Dwarf_Die *type_die, ostream& o)
dwarf_type_name(Dwarf_Die *type_die, ostream& o, Dwarf_Die& subroutine)
{
// if we've gotten down to a basic type, then we're done
bool done = true;
Expand Down Expand Up @@ -121,6 +121,14 @@ dwarf_type_name(Dwarf_Die *type_die, ostream& o)
done = false;
break;

case DW_TAG_subroutine_type:
// Subroutine types (function pointers) are a weird case. The modifiers
// we've recursed so far need to go in the middle, with the return type
// on the left and parameter types on the right. We'll back out now to
// get those modifiers, getting the return and parameters separately.
subroutine = *type_die;
return true;

// unknown tag
default:
return false;
Expand Down Expand Up @@ -152,7 +160,7 @@ dwarf_type_name(Dwarf_Die *type_die, ostream& o)

// if it can't be named, just call it "void"
if (subtype_die == NULL ||
!dwarf_type_name(subtype_die, o))
!dwarf_type_name(subtype_die, o, subroutine))
o << "void";

switch (dwarf_tag(type_die))
Expand Down Expand Up @@ -191,21 +199,99 @@ dwarf_type_name(Dwarf_Die *type_die, ostream& o)
}


static bool
dwarf_subroutine_name(Dwarf_Die *subroutine, ostream& o, const string& modifier)
{
// First add the return value.
Dwarf_Die ret_type;
string ret_string;
if (dwarf_attr_die (subroutine, DW_AT_type, &ret_type) == NULL)
o << "void";
else if (dwarf_type_name (&ret_type, ret_string))
o << ret_string;
else
return false;

// Now the subroutine modifiers.
o << " (" << modifier << ")";

// Then write each parameter.
o << " (";
bool first = true;
Dwarf_Die child;
if (dwarf_child (subroutine, &child) == 0)
do
{
auto tag = dwarf_tag (&child);
if (tag == DW_TAG_unspecified_parameters
|| tag == DW_TAG_formal_parameter)
{
if (first)
first = false;
else
o << ", ";

if (tag == DW_TAG_unspecified_parameters)
o << "...";
else if (tag == DW_TAG_formal_parameter)
{
Dwarf_Die param_type;
string param_string;
if (dwarf_attr_die (&child, DW_AT_type, &param_type) == NULL)
o << "void";
else if (dwarf_type_name (&param_type, param_string))
o << param_string;
else
return false;
}
}
}
while (dwarf_siblingof (&child, &child) == 0);
if (first)
o << "void";
o << ")";

return true;
}


bool
dwarf_type_decl(Dwarf_Die *type_die, const string& var_name, string& decl)
{
ostringstream o;
Dwarf_Die subroutine = { 0, 0, 0, 0 };
if (!dwarf_type_name (type_die, o, subroutine))
return false;

if (!var_name.empty())
o << " " << var_name;

if (subroutine.addr != 0)
{
ostringstream subo;
if (!dwarf_subroutine_name (&subroutine, subo, o.str()))
return false;
decl = subo.str();
}
else
decl = o.str();

return true;
}


bool
dwarf_type_name(Dwarf_Die *type_die, string& type_name)
{
ostringstream o;
bool ret = dwarf_type_name(type_die, o);
type_name = o.str();
return ret;
return dwarf_type_decl(type_die, "", type_name);
}


string
dwarf_type_name(Dwarf_Die *type_die)
{
ostringstream o;
return dwarf_type_name(type_die, o) ? o.str() : "<unknown>";
string o;
return dwarf_type_name (type_die, o) ? o : "<unknown>";
}


Expand Down
3 changes: 3 additions & 0 deletions dwarf_wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,9 @@ int dwarf_decl_line_integrate (Dwarf_Die *die, int *linep)
#endif // !_ELFUTILS_PREREQ(0, 143)


// Resolve a C declaration for dwarf types
bool dwarf_type_decl(Dwarf_Die *type_die, const std::string& var_name, std::string& decl);

// Resolve a full name for dwarf types
bool dwarf_type_name(Dwarf_Die *type_die, std::string& type_name);
std::string dwarf_type_name(Dwarf_Die *type_die);
Expand Down
50 changes: 30 additions & 20 deletions tapsets.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -10131,10 +10131,10 @@ hwbkpt_builder::build(systemtap_session & sess,

struct tracepoint_arg
{
string name, c_type, typecast;
string name, c_type, c_decl, typecast;
bool usable, used, isptr;
Dwarf_Die type_die;
tracepoint_arg(): usable(false), used(false), isptr(false), type_die() {}
tracepoint_arg(const string& tracepoint_name, Dwarf_Die *arg);
};

struct tracepoint_derived_probe: public derived_probe
Expand Down Expand Up @@ -10514,6 +10514,26 @@ resolve_tracepoint_arg_type(tracepoint_arg& arg)
}


tracepoint_arg::tracepoint_arg(const string& tracepoint_name, Dwarf_Die *arg)
: usable(false), used(false), isptr(false), type_die()
{
name = dwarf_diename(arg) ?: "";

// read the type of this parameter
if (!dwarf_attr_die (arg, DW_AT_type, &type_die)
|| !dwarf_type_name(&type_die, c_type))
throw SEMANTIC_ERROR (_F("cannot get type of parameter '%s' of tracepoint '%s'",
name.c_str(), tracepoint_name.c_str()));

// build the C declaration
if (!dwarf_type_decl(&type_die, "__tracepoint_arg_" + name, c_decl))
throw SEMANTIC_ERROR (_F("cannot get declaration of parameter '%s' of tracepoint '%s'",
name.c_str(), tracepoint_name.c_str()));

usable = resolve_tracepoint_arg_type(*this);
}


void
tracepoint_derived_probe::build_args(dwflpp&, Dwarf_Die& func_die)
{
Expand All @@ -10523,21 +10543,14 @@ tracepoint_derived_probe::build_args(dwflpp&, Dwarf_Die& func_die)
if (dwarf_tag(&arg) == DW_TAG_formal_parameter)
{
// build a tracepoint_arg for this parameter
tracepoint_arg tparg;
tparg.name = dwarf_diename(&arg) ?: "";

// read the type of this parameter
if (!dwarf_attr_die (&arg, DW_AT_type, &tparg.type_die)
|| !dwarf_type_name(&tparg.type_die, tparg.c_type))
throw SEMANTIC_ERROR (_F("cannot get type of parameter '%s' of tracepoint '%s'",
tparg.name.c_str(), tracepoint_name.c_str()));

tparg.usable = resolve_tracepoint_arg_type(tparg);
args.push_back(tparg);
args.emplace_back(tracepoint_name, &arg);
if (sess.verbose > 4)
clog << _F("found parameter for tracepoint '%s': type:'%s' name:'%s' %s",
tracepoint_name.c_str(), tparg.c_type.c_str(), tparg.name.c_str(),
tparg.usable ? "ok" : "unavailable") << endl;
{
auto& tparg = args.back();
clog << _F("found parameter for tracepoint '%s': type:'%s' name:'%s' decl:'%s' %s",
tracepoint_name.c_str(), tparg.c_type.c_str(), tparg.name.c_str(),
tparg.c_decl.c_str(), tparg.usable ? "ok" : "unavailable") << endl;
}
}
while (dwarf_siblingof(&arg, &arg) == 0);
}
Expand Down Expand Up @@ -10952,10 +10965,7 @@ tracepoint_derived_probe_group::emit_module_decls (systemtap_session& s)
tpop->newline() << "static STP_TRACE_ENTER(" << enter_fn;
s.op->indent(2);
for (unsigned j = 0; j < p->args.size(); ++j)
{
tpop->newline() << ", " << p->args[j].c_type
<< " __tracepoint_arg_" << p->args[j].name;
}
tpop->newline() << ", " << p->args[j].c_decl;
tpop->newline() << ")";
s.op->indent(-2);
}
Expand Down

0 comments on commit b6e49c9

Please sign in to comment.