From 335d8786b2de5cefdeeffd6cf00642fe5393f252 Mon Sep 17 00:00:00 2001 From: Dodji Seketeli Date: Wed, 14 May 2014 11:03:42 +0200 Subject: [PATCH] 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 --- include/abg-ir.h | 6 + include/abg-libxml-utils.h | 3 +- src/abg-ir.cc | 58 ++++++++++ src/abg-libxml-utils.cc | 28 +++++ src/abg-reader.cc | 133 +++++++++++++++++++++- src/abg-writer.cc | 161 ++++++++++++++++++++++++++- tests/data/test-read-dwarf/test0.abi | 10 +- tests/data/test-read-dwarf/test1.abi | 5 + 8 files changed, 397 insertions(+), 7 deletions(-) diff --git a/include/abg-ir.h b/include/abg-ir.h index 53d204e8..0461e054 100644 --- a/include/abg-ir.h +++ b/include/abg-ir.h @@ -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); diff --git a/include/abg-libxml-utils.h b/include/abg-libxml-utils.h index d1e76fd6..aff50d12 100644 --- a/include/abg-libxml-utils.h +++ b/include/abg-libxml-utils.h @@ -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); diff --git a/src/abg-ir.cc b/src/abg-ir.cc index e5f57c74..147d28d8 100644 --- a/src/abg-ir.cc +++ b/src/abg-ir.cc @@ -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; +} + // struct elf_symbol::version::priv diff --git a/src/abg-libxml-utils.cc b/src/abg-libxml-utils.cc index 10fdb476..7ca07f73 100644 --- a/src/abg-libxml-utils.cc +++ b/src/abg-libxml-utils.cc @@ -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. diff --git a/src/abg-reader.cc b/src/abg-reader.cc index f221a3ba..f442d4b5 100644 --- a/src/abg-reader.cc +++ b/src/abg-reader.cc @@ -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); -// +// // // 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 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 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; } diff --git a/src/abg-writer.cc b/src/abg-writer.cc index 2264e3ed..f786c4af 100644 --- a/src/abg-writer.cc +++ b/src/abg-writer.cc @@ -211,6 +211,8 @@ static void write_layout_offset(var_decl_sptr, ostream&); static void write_layout_offset(shared_ptr, 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, ostream&); static void write_is_struct(const shared_ptr, ostream&); @@ -230,6 +232,8 @@ static bool write_enum_type_decl(const shared_ptr, write_context&, unsigned); static bool write_typedef_decl(const shared_ptr, write_context&, unsigned); +static bool write_elf_symbol(const shared_ptr, + write_context&, unsigned); static bool write_var_decl(const shared_ptr, write_context&, bool, unsigned); static bool write_function_decl(const shared_ptr, @@ -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 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 sym, + write_context& ctxt, + unsigned indent) +{ + if (!sym) + return false; + + ostream &o = ctxt.get_ostream(); + + do_indent(o, indent); + o << "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 decl, write_context& ctxt, do_indent(o, indent); + bool has_children = false; + o << " 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 << ""; + } + else + o << "/>"; return true; } @@ -1265,6 +1416,14 @@ write_function_decl(const shared_ptr 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 >::const_iterator pi = decl->get_parameters().begin(); for ((skip_first_parm && pi != decl->get_parameters().end()) ? ++pi: pi; diff --git a/tests/data/test-read-dwarf/test0.abi b/tests/data/test-read-dwarf/test0.abi index 71b7d48d..669d854b 100644 --- a/tests/data/test-read-dwarf/test0.abi +++ b/tests/data/test-read-dwarf/test0.abi @@ -2,10 +2,12 @@ + + @@ -14,14 +16,17 @@ + + + @@ -36,8 +41,11 @@ + - + + + diff --git a/tests/data/test-read-dwarf/test1.abi b/tests/data/test-read-dwarf/test1.abi index 7121ea08..11f3adc6 100644 --- a/tests/data/test-read-dwarf/test1.abi +++ b/tests/data/test-read-dwarf/test1.abi @@ -17,18 +17,21 @@ + + + @@ -59,9 +62,11 @@ + +