// Copyright 2016 Klemens Morgenstern // // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ #define BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ #include #include #include #include #include #include #include #include namespace boost { namespace dll { namespace detail { class mangled_storage_impl : public mangled_storage_base { template struct dummy {}; template std::vector get_func_params(dummy) const { return {get_name()...}; } template std::string get_return_type(dummy) const { return get_name(); } public: using mangled_storage_base::mangled_storage_base; struct ctor_sym { std::string C1; std::string C2; std::string C3; bool empty() const { return C1.empty() && C2.empty() && C3.empty(); } }; struct dtor_sym { std::string D0; std::string D1; std::string D2; bool empty() const { return D0.empty() && D1.empty() && D2.empty(); } }; template std::string get_variable(const std::string &name) const; template std::string get_function(const std::string &name) const; template std::string get_mem_fn(const std::string &name) const; template ctor_sym get_constructor() const; template dtor_sym get_destructor() const; template std::string get_type_info() const; template std::vector get_related() const; }; namespace parser { //! declare template struct dummy; template std::string parse_type_helper(const mangled_storage_impl & ms, dummy*); template class Tn> std::string parse_type_helper(const mangled_storage_impl & ms, dummy>*); template class Tn> std::string parse_type(const mangled_storage_impl & ms, dummy>*); template std::string parse_type(const mangled_storage_impl & ms, dummy*); template std::string parse_type(const mangled_storage_impl & ms, dummy*); template std::string parse_type(const mangled_storage_impl & ms, dummy*); std::string parse_type(const mangled_storage_impl & ms, dummy<>*); template std::string type_name(const mangled_storage_impl &); //The purpose of this class template is to separate the pure type from the rule name from the target type template struct pure_type { typedef T type; inline static std::string type_rule() { return ""; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + "*"; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + " const"; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + " volatile"; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + " const volatile"; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + "&"; } }; template struct pure_type { typedef typename pure_type::type type; inline static std::string type_rule() { return pure_type::type_rule() + "&&"; } }; inline std::string const_rule_impl(true_type ) {return " const";} inline std::string const_rule_impl(false_type) {return "";} template std::string const_rule() {using t = is_const::type>; return const_rule_impl(t());} inline std::string volatile_rule_impl(true_type ) {return " volatile";} inline std::string volatile_rule_impl(false_type) {return "";} template std::string volatile_rule() {using t = is_volatile::type>; return volatile_rule_impl(t());} inline std::string reference_rule_impl(false_type, false_type) {return "";} inline std::string reference_rule_impl(true_type, false_type) {return "&" ;} inline std::string reference_rule_impl(false_type, true_type ) {return "&&";} template std::string reference_rule() {using t_l = is_lvalue_reference; using t_r = is_rvalue_reference; return reference_rule_impl(t_l(), t_r());} //it takes a string, because it may be overloaded. template std::string arg_list(const mangled_storage_impl & ms, Return (*)(Arg)) { using namespace std; return type_name(ms); } template std::string arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...)) { using next_type = Return (*)(Second, Args...); return type_name(ms) + ", " + arg_list(ms, next_type()); } template std::string arg_list(const mangled_storage_impl &, Return (*)()) { return ""; } //! implement template inline std::string parse_type_helper(const mangled_storage_impl & ms, dummy*) { return ms.get_name(); } template class Tn> inline std::string parse_type_helper(const mangled_storage_impl & ms, dummy>*) { using type = dummy>*; return parse_type(ms, type()); } template inline std::string parse_type(const mangled_storage_impl & ms, dummy*) { using args_type = dummy*; using return_type = dummy*; return parse_type(ms, return_type()) + " (*)(" + parse_type(ms, args_type()) + ")"; } template inline std::string parse_type(const mangled_storage_impl & ms, dummy*) { using args_type = dummy*; using return_type = dummy*; return parse_type(ms, return_type()) + " (" + parse_type(ms, args_type()) + ")"; } template inline std::string parse_type(const mangled_storage_impl & ms, dummy*) { using type = dummy::type>*; auto str = parse_type_helper(ms, type()); return str + pure_type::type_rule(); } template inline std::string parse_type(const mangled_storage_impl & ms, dummy*) { using first_type = dummy*; using next_type = dummy*; return parse_type(ms, first_type()) + ", " + parse_type(ms, next_type()); } template class Tn> inline std::string parse_type(const mangled_storage_impl & ms, dummy>*) { using next_type = dummy*; std::string str = ms.get_name>(); auto frist = str.find_first_of("<"); std::string template_name = str.substr(0, frist); std::string args_name = parse_type(ms, next_type()); char last_ch = args_name[args_name.size() - 1]; return template_name + "<" + args_name + (last_ch == '>' ? " >" : ">"); } inline std::string parse_type(const mangled_storage_impl &, dummy<>*) { return ""; } template inline std::string type_name(const mangled_storage_impl &ms) { using namespace parser; using type = dummy*; return parse_type(ms, type()); } } template std::string mangled_storage_impl::get_variable(const std::string &name) const { auto found = std::find_if(storage_.begin(), storage_.end(), [&](const entry& e) {return e.demangled == name;}); if (found != storage_.end()) return found->mangled; else return ""; } template std::string mangled_storage_impl::get_function(const std::string &name) const { using func_type = Func*; auto matcher = name + '(' + parser::arg_list(*this, func_type()) + ')'; auto found = std::find_if(storage_.begin(), storage_.end(), [&](const entry& e) {return e.demangled == matcher;}); if (found != storage_.end()) return found->mangled; else return ""; } template std::string mangled_storage_impl::get_mem_fn(const std::string &name) const { using namespace parser; using func_type = Func*; std::string cname = get_name(); const auto matcher = cname + "::" + name + '(' + parser::arg_list(*this, func_type()) + ')' + const_rule() + volatile_rule(); // Linux export table contains int MyClass::Func(), but expected in import_mangled MyClass::Func() without returned type. auto found = std::find_if(storage_.begin(), storage_.end(), [&matcher](const entry& e) { if (e.demangled == matcher) { return true; } const auto pos = e.demangled.rfind(matcher); if (pos == std::string::npos) { // Not found. return false; } if (pos + matcher.size() != e.demangled.size()) { // There are some characters after the `matcher` string. return false; } // Double checking that we matched a full function name return e.demangled[pos - 1] == ' '; // `if (e.demangled == matcher)` makes sure that `pos > 0` }); if (found != storage_.end()) return found->mangled; else return ""; } template auto mangled_storage_impl::get_constructor() const -> ctor_sym { using namespace parser; using func_type = Signature*; std::string ctor_name; // = class_name + "::" + name; std::string unscoped_cname; //the unscoped class-name { auto class_name = get_return_type(dummy()); auto pos = class_name.rfind("::"); if (pos == std::string::npos) { ctor_name = class_name+ "::" +class_name ; unscoped_cname = class_name; } else { unscoped_cname = class_name.substr(pos+2) ; ctor_name = class_name+ "::" + unscoped_cname; } } auto matcher = ctor_name + '(' + parser::arg_list(*this, func_type()) + ')'; std::vector findings; std::copy_if(storage_.begin(), storage_.end(), std::back_inserter(findings), [&](const entry& e) {return e.demangled == matcher;}); ctor_sym ct; for (auto & e : findings) { if (e.mangled.find(unscoped_cname +"C1E") != std::string::npos) ct.C1 = e.mangled; else if (e.mangled.find(unscoped_cname +"C2E") != std::string::npos) ct.C2 = e.mangled; else if (e.mangled.find(unscoped_cname +"C3E") != std::string::npos) ct.C3 = e.mangled; } return ct; } template auto mangled_storage_impl::get_destructor() const -> dtor_sym { std::string dtor_name; // = class_name + "::" + name; std::string unscoped_cname; //the unscoped class-name { auto class_name = get_name(); auto pos = class_name.rfind("::"); if (pos == std::string::npos) { dtor_name = class_name+ "::~" + class_name + "()"; unscoped_cname = class_name; } else { unscoped_cname = class_name.substr(pos+2) ; dtor_name = class_name+ "::~" + unscoped_cname + "()"; } } auto d0 = unscoped_cname + "D0Ev"; auto d1 = unscoped_cname + "D1Ev"; auto d2 = unscoped_cname + "D2Ev"; dtor_sym dt; //this is so simple, i don#t need a predicate for (auto & s : storage_) { //alright, name fits if (s.demangled == dtor_name) { if (s.mangled.find(d0) != std::string::npos) dt.D0 = s.mangled; else if (s.mangled.find(d1) != std::string::npos) dt.D1 = s.mangled; else if (s.mangled.find(d2) != std::string::npos) dt.D2 = s.mangled; } } return dt; } template std::string mangled_storage_impl::get_type_info() const { std::string id = "typeinfo for " + get_name(); auto predicate = [&](const mangled_storage_base::entry & e) { return e.demangled == id; }; auto found = std::find_if(storage_.begin(), storage_.end(), predicate); if (found != storage_.end()) return found->mangled; else return ""; } template std::vector mangled_storage_impl::get_related() const { std::vector ret; auto name = get_name(); for (auto & c : storage_) { if (c.demangled.find(name) != std::string::npos) ret.push_back(c.demangled); } return ret; } }}} #endif /* BOOST_DLL_DETAIL_DEMANGLING_ITANIUM_HPP_ */