Serialize and de-serialize elf symbols for var & function decls

* abg-ir.h (string_to_elf_symbol_type, string_to_elf_symbol_binding):
	Declare new entry points.
	* src/abg-ir.cc (string_to_elf_symbol_type)
	(string_to_elf_symbol_binding): Define new entry points.
	* include/abg-libxml-utils.h (xml_char_sptr_to_string): Declare
	new entry points.
	* src/abg-libxml-utils.cc (xml_char_sptr_to_string): Define new
	entry points.
	* src/abg-reader.cc (read_elf_symbol_type)
	(read_elf_symbol_binding, build_elf_symbol): Define new static
	functions.
	(build_function_decl, build_var_decl): Use the new
	build_elf_symbol and set the symbol to the function.  Flag the
	function as having a public symbol in the symbol table if the
	symbol is public.
	* src/abg-writer.cc (write_elf_symbol_type)
	(write_elf_symbol_binding, write_elf_symbol): Define new static
	functions.
	(write_var_decl, write_function_decl): Use the new
	write_elf_symbol to serialize the symbol for the decl.
	* tests/data/test-read-dwarf/test[01].abi: Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2014-05-14 11:03:42 +02:00
parent 3e9cd9cd81
commit 335d8786b2
8 changed files with 397 additions and 7 deletions

View File

@ -303,6 +303,12 @@ operator<<(std::ostream& o, elf_symbol::type t);
std::ostream&
operator<<(std::ostream& o, elf_symbol::binding t);
bool
string_to_elf_symbol_type(const string&, elf_symbol::type&);
bool
string_to_elf_symbol_binding(const string&, elf_symbol::binding&);
bool
operator==(const elf_symbol_sptr lhs, const elf_symbol_sptr rhs);

View File

@ -56,8 +56,7 @@ struct charDeleter
reader_sptr new_reader_from_file(const std::string& path);
reader_sptr new_reader_from_buffer(const std::string& buffer);
reader_sptr new_reader_from_istream(std::istream*);
xml_char_sptr build_xml_char_sptr(xmlChar*);
bool xml_char_sptr_to_string(xml_char_sptr, std::string&);
int get_xml_node_depth(xmlNodePtr);

View File

@ -534,6 +534,64 @@ operator<<(std::ostream& o, elf_symbol::binding b)
return o;
}
/// Convert a string representing a symbol type into an
/// elf_symbol::type.
///
///@param s the string to convert.
///
///@param t the resulting elf_symbol::type.
///
/// @return true iff the conversion completed successfully.
bool
string_to_elf_symbol_type(const string& s, elf_symbol::type& t)
{
if (s == "no-type")
t = elf_symbol::NOTYPE_TYPE;
else if (s == "object-type")
t = elf_symbol::OBJECT_TYPE;
else if (s == "func-type")
t = elf_symbol::FUNC_TYPE;
else if (s == "section-type")
t = elf_symbol::SECTION_TYPE;
else if (s == "file-type")
t = elf_symbol::FILE_TYPE;
else if (s == "common-type")
t = elf_symbol::COMMON_TYPE;
else if (s == "tls-type")
t = elf_symbol::TLS_TYPE;
else if (s == "gnu-ifunc-type")
t = elf_symbol::GNU_IFUNC_TYPE;
else
return false;
return true;
}
/// Convert a string representing a an elf symbol binding into an
/// elf_symbol::binding.
///
/// @param s the string to convert.
///
/// @param b the resulting elf_symbol::binding.
///
/// @return true iff the conversion completed successfully.
bool
string_to_elf_symbol_binding(const string& s, elf_symbol::binding& b)
{
if (s == "local-binding")
b = elf_symbol::LOCAL_BINDING;
else if (s == "global-binding")
b = elf_symbol::GLOBAL_BINDING;
else if (s == "weak-binding")
b = elf_symbol::WEAK_BINDING;
else if (s == "gnu-unique-binding")
b = elf_symbol::GNU_UNIQUE_BINDING;
else
return false;
return true;
}
// <elf_symbol::version stuff>
struct elf_symbol::version::priv

View File

@ -130,6 +130,34 @@ new_reader_from_istream(std::istream* in)
return p;
}
/// Convert a shared pointer to xmlChar into an std::string.
///
/// If the xmlChar is NULL, set "" to the string.
///
/// @param ssptr the shared point to xmlChar to convert.
///
/// @param s the output string.
///
/// @return true if the shared pointer to xmlChar contained a non NULL
/// string, false otherwise.
bool
xml_char_sptr_to_string(xml_char_sptr ssptr, std::string& s)
{
bool non_nil = false;
if (CHAR_STR(ssptr))
{
s = CHAR_STR(ssptr);
non_nil = true;
}
else
{
s = "";
non_nil = false;
}
return non_nil;
}
/// Return the depth of an xml element node.
///
/// Note that the node must be attached to an XML document.

View File

@ -513,15 +513,22 @@ static bool read_cdtor_const(xmlNodePtr, bool&, bool&, bool&);
static bool read_is_declaration_only(xmlNodePtr, bool&);
static bool read_is_virtual(xmlNodePtr, bool&);
static bool read_is_struct(xmlNodePtr, bool&);
static bool read_elf_symbol_type(xmlNodePtr, elf_symbol::type&);
static bool read_elf_symbol_binding(xmlNodePtr, elf_symbol::binding&);
static namespace_decl_sptr
build_namespace_decl(read_context&, const xmlNodePtr, bool);
// <build a c++ class from an instance of xmlNodePtr>
// <build a c++ class from an instance of xmlNodePtr>
//
// Note that whenever a new function to build a type is added here,
// you should make sure to call it from the build_type function, which
// should be the last function of the list of declarated function below.
// should be the last function of the list of declarated function
// below.
static elf_symbol_sptr
build_elf_symbol(read_context&, const xmlNodePtr);
static shared_ptr<function_decl::parameter>
build_function_parameter (read_context&, const xmlNodePtr);
@ -721,6 +728,7 @@ walk_xml_node_to_map_type_ids(read_context& ctxt,
walk_xml_node_to_map_type_ids(ctxt, n->children);
}
}
/// Parse the input XML document containing a translation_unit,
/// represented by an 'abi-instr' element node, associated to the current
/// context.
@ -1255,6 +1263,48 @@ read_is_struct(xmlNodePtr node, bool& is_struct)
return false;
}
/// Read the 'type' attribute of the 'elf-symbol' element.
///
/// @param node the XML node to read the attribute from.
///
/// @param t the resulting elf_symbol::type.
///
/// @return true iff the function completed successfully.
static bool
read_elf_symbol_type(xmlNodePtr node, elf_symbol::type& t)
{
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "type"))
{
string str;
xml::xml_char_sptr_to_string(s, str);
if (!string_to_elf_symbol_type(str, t))
return false;
return true;
}
return false;
}
/// Read the 'binding' attribute of the of the 'elf-symbol' element.
///
/// @param node the XML node to read the attribute from.
///
/// @param b the XML the resulting elf_symbol::binding.
///
/// @return true iff the function completed successfully.
static bool
read_elf_symbol_binding(xmlNodePtr node, elf_symbol::binding& b)
{
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "binding"))
{
string str;
xml::xml_char_sptr_to_string(s, str);
if (!string_to_elf_symbol_binding(str, b))
return false;
return true;
}
return false;
}
/// Build a @ref namespace_decl from an XML element node which name is
/// "namespace-decl". Note that this function recursively reads the
/// content of the namespace and builds the proper IR nodes
@ -1309,6 +1359,62 @@ build_namespace_decl(read_context& ctxt,
return decl;
}
/// Build an instance of @ref elf_symbol from an XML element node
/// which name is 'elf-symbol'.
///
/// @param node the XML node to read.
///
/// @return the @ref elf_symbol built, or nil if it couldn't be built.
static elf_symbol_sptr
build_elf_symbol(read_context&, const xmlNodePtr node)
{
elf_symbol_sptr nil;
if (!node || !xmlStrEqual(node->name, BAD_CAST("elf-symbol")))
return nil;
string name;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "name"))
xml::xml_char_sptr_to_string(s, name);
bool is_defined = true;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "is-defined"))
{
string value;
xml::xml_char_sptr_to_string(s, value);
if (value == "true" || value == "yes")
is_defined = true;
else
is_defined = false;
}
string version_string;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "version"))
xml::xml_char_sptr_to_string(s, version_string);
bool is_default_version = false;
if (xml_char_sptr s = XML_NODE_GET_ATTRIBUTE(node, "is-default-version"))
{
string value;
xml::xml_char_sptr_to_string(s, value);
if (value == "true" || value == "yes")
is_default_version = true;
}
elf_symbol::type type = elf_symbol::NOTYPE_TYPE;
read_elf_symbol_type(node, type);
elf_symbol::binding binding;
read_elf_symbol_binding(node, binding);
elf_symbol::version version(version_string, is_default_version);
elf_symbol_sptr e(new elf_symbol(/*index=*/0, name,
type, binding,
is_defined, version));
return e;
}
/// Build a function parameter from a 'parameter' xml element node.
///
/// @param ctxt the contexte of the xml parsing.
@ -1442,7 +1548,12 @@ build_function_decl(read_context& ctxt,
if (n->type != XML_ELEMENT_NODE)
continue;
if (xmlStrEqual(n->name, BAD_CAST("parameter")))
if (xmlStrEqual(n->name, BAD_CAST("elf-symbol")))
{
if (elf_symbol_sptr sym = build_elf_symbol(ctxt, n))
fn_decl->set_symbol(sym);
}
else if (xmlStrEqual(n->name, BAD_CAST("parameter")))
{
if (shared_ptr<function_decl::parameter> p =
build_function_parameter(ctxt, n))
@ -1460,6 +1571,9 @@ build_function_decl(read_context& ctxt,
}
}
if (fn_decl->get_symbol() && fn_decl->get_symbol()->is_public())
fn_decl->set_is_in_public_symbol_table(true);
return fn_decl;
}
@ -1509,8 +1623,21 @@ build_var_decl(read_context& ctxt,
locus, mangled_name,
vis, bind));
for (xmlNodePtr n = node->children; n; n = n->next)
{
if (n->type != XML_ELEMENT_NODE)
continue;
if (xmlStrEqual(n->name, BAD_CAST("elf-symbol")))
{
if (elf_symbol_sptr sym = build_elf_symbol(ctxt, n))
decl->set_symbol(sym);
}
}
ctxt.push_decl_to_current_scope(decl, add_to_current_scope);
if (decl->get_symbol() && decl->get_symbol()->is_public())
decl->set_is_in_public_symbol_table(true);
return decl;
}

View File

@ -211,6 +211,8 @@ static void write_layout_offset(var_decl_sptr, ostream&);
static void write_layout_offset(shared_ptr<class_decl::base_spec>, ostream&);
static void write_cdtor_const_static(bool, bool, bool, bool, ostream&);
static void write_voffset(function_decl_sptr, ostream&);
static void write_elf_symbol_type(elf_symbol::type, ostream&);
static void write_elf_symbol_binding(elf_symbol::binding, ostream&);
static void write_class_is_declaration_only(const shared_ptr<class_decl>,
ostream&);
static void write_is_struct(const shared_ptr<class_decl>, ostream&);
@ -230,6 +232,8 @@ static bool write_enum_type_decl(const shared_ptr<enum_type_decl>,
write_context&, unsigned);
static bool write_typedef_decl(const shared_ptr<typedef_decl>,
write_context&, unsigned);
static bool write_elf_symbol(const shared_ptr<elf_symbol>,
write_context&, unsigned);
static bool write_var_decl(const shared_ptr<var_decl>,
write_context&, bool, unsigned);
static bool write_function_decl(const shared_ptr<function_decl>,
@ -541,6 +545,84 @@ write_voffset(function_decl_sptr fn, ostream&o)
o << " vtable-offset='" << voffset << "'";
}
/// Serialize an elf_symbol::type into an XML node attribute named
/// 'type'.
///
/// @param t the elf_symbol::type to serialize.
///
/// @param o the output stream to serialize it to.
static void
write_elf_symbol_type(elf_symbol::type t, ostream& o)
{
string repr;
switch (t)
{
case elf_symbol::NOTYPE_TYPE:
repr = "no-type";
break;
case elf_symbol::OBJECT_TYPE:
repr = "object-type";
break;
case elf_symbol::FUNC_TYPE:
repr = "func-type";
break;
case elf_symbol::SECTION_TYPE:
repr = "section-type";
break;
case elf_symbol::FILE_TYPE:
repr = "file-type";
break;
case elf_symbol::COMMON_TYPE:
repr = "common-type";
break;
case elf_symbol::TLS_TYPE:
repr = "tls-type";
break;
case elf_symbol::GNU_IFUNC_TYPE:
repr = "gnu-ifunc-type";
break;
default:
repr = "no-type";
break;
}
o << "type='" << repr << "'";
}
/// Serialize an elf_symbol::binding into an XML element attribute of
/// name 'binding'.
///
/// @param b the elf_symbol::binding to serialize.
///
/// @param o the output stream to serialize the binding to.
static void
write_elf_symbol_binding(elf_symbol::binding b, ostream& o)
{
string repr;
switch (b)
{
case elf_symbol::LOCAL_BINDING:
repr = "local-binding";
break;
case elf_symbol::GLOBAL_BINDING:
repr = "global-binding";
break;
case elf_symbol::WEAK_BINDING:
repr = "weak-binding";
break;
case elf_symbol::GNU_UNIQUE_BINDING:
repr = "gnu-unique-binding";
break;
default:
repr = "no-binding";
break;
}
o << "binding='" << repr << "'";
}
/// Serialize the attributes "constructor", "destructor" or "static"
/// if they have true value.
///
@ -1117,6 +1199,57 @@ write_enum_type_decl(const shared_ptr<enum_type_decl> decl,
unsigned indent)
{return write_enum_type_decl(decl, "", ctxt, indent);}
/// Serialize an @ref elf_symbol to an XML element of name
/// 'elf-symbol'.
///
/// @param sym the elf symbol to serialize.
///
/// @param ctxt the read context to use.
///
/// @param indent the number of white spaces to use as indentation.
///
/// @return true iff the function completed successfully.
static bool
write_elf_symbol(const shared_ptr<elf_symbol> sym,
write_context& ctxt,
unsigned indent)
{
if (!sym)
return false;
ostream &o = ctxt.get_ostream();
do_indent(o, indent);
o << "<elf-symbol name='" << sym->get_name() << "'";
if (!sym->get_version().is_empty())
{
o << " version='" << sym->get_version().str() << "'";
o << " is-default-version='";
if (sym->get_version().is_default())
o << "yes";
else
o << "no";
o << "'";
}
o << " ";
write_elf_symbol_type(sym->get_type(), o);
o << " ";
write_elf_symbol_binding(sym->get_binding(), o);
o << " is-defined='";
if (sym->get_is_defined())
o << "yes";
else
o << "no";
o << "'";
o << "/>";
return true;
}
/// Serialize a pointer to an instance of typedef_decl.
///
/// @param decl the typedef_decl to serialize.
@ -1200,6 +1333,8 @@ write_var_decl(const shared_ptr<var_decl> decl, write_context& ctxt,
do_indent(o, indent);
bool has_children = false;
o << "<var-decl name='" << decl->get_name() << "'";
o << " type-id='" << ctxt.get_id_for_type(decl->get_type()) << "'";
@ -1216,7 +1351,23 @@ write_var_decl(const shared_ptr<var_decl> decl, write_context& ctxt,
write_location(decl, o);
o << "/>";
elf_symbol_sptr sym = decl->get_symbol();
if (sym)
{
o << ">\n";
write_elf_symbol(sym, ctxt,
indent + ctxt.get_config().get_xml_element_indent());
o << "\n";
has_children = true;
}
if (has_children)
{
do_indent(o, indent);
o << "</var-decl>";
}
else
o << "/>";
return true;
}
@ -1265,6 +1416,14 @@ write_function_decl(const shared_ptr<function_decl> decl, write_context& ctxt,
o << ">\n";
elf_symbol_sptr sym = decl->get_symbol();
if (sym)
{
write_elf_symbol(sym, ctxt,
indent + ctxt.get_config().get_xml_element_indent());
o << "\n";
}
vector<shared_ptr<function_decl::parameter> >::const_iterator pi =
decl->get_parameters().begin();
for ((skip_first_parm && pi != decl->get_parameters().end()) ? ++pi: pi;

View File

@ -2,10 +2,12 @@
<abi-instr version='1.0' address-size='64' path='test0.cc'>
<namespace-decl name='ns0'>
<function-decl name='bar' mangled-name='_ZN3ns03barEiz' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='12' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN3ns03barEiz' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-1'/>
<parameter is-variadic='yes'/>
</function-decl>
<function-decl name='baz' mangled-name='_ZN3ns03bazERi' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='16' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN3ns03bazERi' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-2'/>
</function-decl>
<enum-decl name='E' id='type-id-3'>
@ -14,14 +16,17 @@
<enumerator name='e1' value='1'/>
</enum-decl>
<function-decl name='bar2' mangled-name='_ZN3ns04bar2ERNS_1EE' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='22' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN3ns04bar2ERNS_1EE' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-5'/>
</function-decl>
<typedef-decl name='long_long' type-id='type-id-6' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='25' column='1' id='type-id-7'/>
<function-decl name='baz2' mangled-name='_ZN3ns04baz2ERi' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='28' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN3ns04baz2ERi' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-2'/>
<return type-id='type-id-7'/>
</function-decl>
<function-decl name='foo' mangled-name='_ZN3ns03fooEPcl' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='45' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN3ns03fooEPcl' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-8'/>
<parameter type-id='type-id-9'/>
<return type-id='type-id-9'/>
@ -36,8 +41,11 @@
<type-decl name='char' size-in-bits='8' alignment-in-bits='8' id='type-id-10'/>
<pointer-type-def type-id='type-id-10' size-in-bits='64' alignment-in-bits='64' id='type-id-8'/>
<function-decl name='main' mangled-name='main' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='49' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='main' type='func-type' binding='global-binding' is-defined='yes'/>
<return type-id='type-id-1'/>
</function-decl>
<var-decl name='global' type-id='type-id-1' mangled-name='global' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='3' column='1'/>
<var-decl name='global' type-id='type-id-1' mangled-name='global' visibility='default' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test0.cc' line='3' column='1'>
<elf-symbol name='global' type='object-type' binding='global-binding' is-defined='yes'/>
</var-decl>
</abi-instr>
</abi-corpus>

View File

@ -17,18 +17,21 @@
</data-member>
<member-function access='public' constructor='yes'>
<function-decl name='s0' mangled-name='_ZN2s0C1Ev' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='21' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN2s0C1Ev' type='func-type' binding='weak-binding' is-defined='yes'/>
<parameter type-id='type-id-8' is-artificial='yes'/>
<parameter type-id='type-id-5' is-artificial='yes'/>
</function-decl>
</member-function>
<member-function access='public' destructor='yes'>
<function-decl name='~s0' mangled-name='_ZN2s0D1Ev' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='27' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN2s0D1Ev' type='func-type' binding='weak-binding' is-defined='yes'/>
<parameter type-id='type-id-8' is-artificial='yes'/>
<parameter type-id='type-id-5' is-artificial='yes'/>
</function-decl>
</member-function>
<member-function access='public'>
<function-decl name='mem_fun' mangled-name='_ZN2s07mem_funEv' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='36' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_ZN2s07mem_funEv' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-8' is-artificial='yes'/>
<return type-id='type-id-4'/>
</function-decl>
@ -59,9 +62,11 @@
<reference-type-def kind='lvalue' type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-12'/>
<qualified-type-def type-id='type-id-12' const='yes' id='type-id-13'/>
<function-decl name='foo' mangled-name='_Z3fooR2s0' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='42' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='_Z3fooR2s0' type='func-type' binding='global-binding' is-defined='yes'/>
<parameter type-id='type-id-13' name='s' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='42' column='1'/>
</function-decl>
<function-decl name='main' mangled-name='main' filepath='/home/dodji/git/libabigail/dwarf/tests/data/test-read-dwarf/test1.cc' line='48' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<elf-symbol name='main' type='func-type' binding='global-binding' is-defined='yes'/>
<return type-id='type-id-5'/>
</function-decl>
</abi-instr>