• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //  Copyright 2016 Klemens Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
8 #define BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
9 
10 #include <boost/dll/detail/demangling/mangled_storage_base.hpp>
11 #include <iterator>
12 #include <algorithm>
13 #include <boost/type_traits/is_const.hpp>
14 #include <boost/type_traits/is_volatile.hpp>
15 #include <boost/type_traits/is_lvalue_reference.hpp>
16 #include <boost/type_traits/is_rvalue_reference.hpp>
17 #include <boost/type_traits/function_traits.hpp>
18 #include <boost/type_traits/remove_reference.hpp>
19 
20 #include <boost/spirit/home/x3.hpp>
21 
22 namespace boost { namespace dll { namespace detail {
23 
24 class mangled_storage_impl  : public mangled_storage_base
25 {
26     template<typename T>
27     struct dummy {};
28 
29     template<typename Return, typename ...Args>
get_func_params(dummy<Return (Args...)>) const30     std::vector<std::string> get_func_params(dummy<Return(Args...)>) const
31     {
32         return {get_name<Args>()...};
33     }
34     template<typename Return, typename ...Args>
get_return_type(dummy<Return (Args...)>) const35     std::string get_return_type(dummy<Return(Args...)>) const
36     {
37         return get_name<Return>();
38     }
39     //function to remove preceding 'class ' or 'struct ' if the are given in this format.
40 
41     inline static void trim_typename(std::string & val);
42 public:
43     using ctor_sym = std::string;
44     using dtor_sym = std::string;
45 
46     using mangled_storage_base::mangled_storage_base;
47 
48     template<typename T>
49     std::string get_variable(const std::string &name) const;
50 
51     template<typename Func>
52     std::string get_function(const std::string &name) const;
53 
54     template<typename Class, typename Func>
55     std::string get_mem_fn(const std::string &name) const;
56 
57     template<typename Signature>
58     ctor_sym get_constructor() const;
59 
60     template<typename Class>
61     dtor_sym get_destructor() const;
62 
63     template<typename T> //overload, does not need to virtual.
get_name() const64     std::string get_name() const
65     {
66         auto nm = mangled_storage_base::get_name<T>();
67         trim_typename(nm);
68         return nm;
69     }
70 
71     template<typename T>
72     std::string get_vtable() const;
73 
74     template<typename T>
75     std::vector<std::string> get_related() const;
76 
77 };
78 
trim_typename(std::string & val)79 void mangled_storage_impl::trim_typename(std::string & val)
80 {
81     //remove preceding class or struct, because you might want to use a struct as class, et vice versa
82     if (val.size() >= 6)
83     {
84         using namespace std;
85         static constexpr char class_ [7] = "class ";
86         static constexpr char struct_[8] = "struct ";
87 
88         if (equal(begin(class_), end(class_)-1, val.begin())) //aklright, starts with 'class '
89             val.erase(0, 6);
90         else if (val.size() >= 7)
91             if (equal(begin(struct_), end(struct_)-1, val.begin()))
92                 val.erase(0, 7);
93     }
94 }
95 
96 
97 namespace parser
98 {
99     namespace x3 = spirit::x3;
100 
ptr_rule_impl(std::integral_constant<std::size_t,32>)101     inline auto ptr_rule_impl(std::integral_constant<std::size_t, 32>)
102     {
103         return -((-x3::space) >> "__ptr32");
104     }
ptr_rule_impl(std::integral_constant<std::size_t,64>)105     inline auto ptr_rule_impl(std::integral_constant<std::size_t, 64>)
106     {
107         return -((-x3::space) >> "__ptr64");
108     }
109 
ptr_rule()110     inline auto ptr_rule() {
111         return ptr_rule_impl(std::integral_constant<std::size_t, sizeof(std::size_t)*8>());
112     }
113 
114     auto const visibility = ("public:" | x3::lit("protected:") | "private:");
115     auto const virtual_ = x3::space >> "virtual";
116     auto const static_     = x3::space >> x3::lit("static") ;
117 
const_rule_impl(true_type)118     inline auto const_rule_impl(true_type )  {return x3::space >> "const";};
const_rule_impl(false_type)119     inline auto const_rule_impl(false_type)  {return x3::eps;};
120     template<typename T>
const_rule()121     auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());}
122 
volatile_rule_impl(true_type)123     inline auto volatile_rule_impl(true_type )  {return x3::space >> "volatile";};
volatile_rule_impl(false_type)124     inline auto volatile_rule_impl(false_type)  {return x3::eps;};
125     template<typename T>
volatile_rule()126     auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());}
127 
128 
inv_const_rule_impl(true_type)129     inline auto inv_const_rule_impl(true_type )  {return "const" >>  x3::space ;};
inv_const_rule_impl(false_type)130     inline auto inv_const_rule_impl(false_type)  {return x3::eps;};
131     template<typename T>
inv_const_rule()132     auto inv_const_rule() {using t = is_const<typename remove_reference<T>::type>; return inv_const_rule_impl(t());}
133 
inv_volatile_rule_impl(true_type)134     inline auto inv_volatile_rule_impl(true_type )  {return "volatile" >> x3::space;};
inv_volatile_rule_impl(false_type)135     inline auto inv_volatile_rule_impl(false_type)  {return x3::eps;};
136     template<typename T>
inv_volatile_rule()137     auto inv_volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return inv_volatile_rule_impl(t());}
138 
139 
reference_rule_impl(false_type,false_type)140     inline auto reference_rule_impl(false_type, false_type) {return x3::eps;}
reference_rule_impl(true_type,false_type)141     inline auto reference_rule_impl(true_type,  false_type) {return x3::space >>"&"  ;}
reference_rule_impl(false_type,true_type)142     inline auto reference_rule_impl(false_type, true_type ) {return x3::space >>"&&" ;}
143 
144 
145     template<typename T>
reference_rule()146     auto reference_rule() {using t_l = is_lvalue_reference<T>; using t_r = is_rvalue_reference<T>; return reference_rule_impl(t_l(), t_r());}
147 
148     auto const class_ = ("class" | x3::lit("struct"));
149 
150     //it takes a string, because it may be overloaded.
151     template<typename T>
type_rule(const std::string & type_name)152     auto type_rule(const std::string & type_name)
153     {
154         using namespace std;
155 
156         return -(class_ >> x3::space)>> x3::string(type_name) >>
157                 const_rule<T>() >>
158                 volatile_rule<T>() >>
159                 reference_rule<T>() >>
160                 ptr_rule();
161     }
162     template<>
type_rule(const std::string &)163     inline auto type_rule<void>(const std::string &) { return x3::string("void"); };
164 
165     auto const cdecl_   = "__cdecl"     >> x3::space;
166     auto const stdcall  = "__stdcall"     >> x3::space;
167 #if defined(_WIN64)//seems to be necessary by msvc 14-x64
168     auto const thiscall = "__cdecl"     >> x3::space;
169 #else
170     auto const thiscall = "__thiscall"     >> x3::space;
171 #endif
172 
173     template<typename Return, typename Arg>
arg_list(const mangled_storage_impl & ms,Return (*)(Arg))174     auto arg_list(const mangled_storage_impl & ms, Return (*)(Arg))
175     {
176         using namespace std;
177 
178         return type_rule<Arg>(ms.get_name<Arg>());
179     }
180 
181     template<typename Return, typename First, typename Second, typename ...Args>
arg_list(const mangled_storage_impl & ms,Return (*)(First,Second,Args...))182     auto arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...))
183     {
184 
185         using next_type = Return (*)(Second, Args...);
186         return type_rule<First>(ms.get_name<First>()) >> x3::char_(',') >> arg_list(ms, next_type());
187     }
188 
189     template<typename Return>
arg_list(const mangled_storage_impl &,Return (*)())190     auto arg_list(const mangled_storage_impl& /*ms*/, Return (*)())
191     {
192         return x3::string("void");
193     }
194 }
195 
196 
get_variable(const std::string & name) const197 template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) const
198 {
199     using namespace std;
200     using namespace boost;
201 
202     namespace x3 = spirit::x3;
203     using namespace parser;
204 
205     auto type_name = get_name<T>();
206 
207     auto matcher =
208             -(visibility >> static_ >> x3::space) >> //it may be a static class-member
209             parser::type_rule<T>(type_name) >> x3::space >>
210             name;
211 
212     auto predicate = [&](const mangled_storage_base::entry & e)
213         {
214             if (e.demangled == name)//maybe not mangled,
215                 return true;
216 
217             auto itr = e.demangled.begin();
218             auto end = e.demangled.end();
219             auto res = x3::parse(itr, end, matcher);
220             return res && (itr == end);
221         };
222 
223     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
224 
225     if (found != storage_.end())
226         return found->mangled;
227     else
228         return "";
229 }
230 
get_function(const std::string & name) const231 template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) const
232 {
233     namespace x3 = spirit::x3;
234     using namespace parser;
235     using func_type = Func*;
236     using return_type = typename function_traits<Func>::result_type;
237     std::string return_type_name = get_name<return_type>();
238 
239 
240     auto matcher =
241                 -(visibility >> static_ >> x3::space) >> //it may be a static class-member, which does however not have the static attribute.
242                 parser::type_rule<return_type>(return_type_name) >>  x3::space >>
243                 cdecl_ >> //cdecl declaration for methods. stdcall cannot be
244                 name >> x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >>  parser::ptr_rule();
245 
246 
247     auto predicate = [&](const mangled_storage_base::entry & e)
248             {
249                 if (e.demangled == name)//maybe not mangled,
250                     return true;
251 
252                 auto itr = e.demangled.begin();
253                 auto end = e.demangled.end();
254                 auto res = x3::parse(itr, end, matcher);
255 
256                 return res && (itr == end);
257             };
258 
259     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
260 
261     if (found != storage_.end())
262         return found->mangled;
263     else
264         return "";
265 
266 }
267 
268 template<typename Class, typename Func>
get_mem_fn(const std::string & name) const269 std::string mangled_storage_impl::get_mem_fn(const std::string &name) const
270 {
271     namespace x3 = spirit::x3;
272     using namespace parser;
273     using func_type = Func*;
274     using return_type = typename function_traits<Func>::result_type;
275     auto return_type_name = get_name<return_type>();
276 
277 
278     auto cname = get_name<Class>();
279 
280     auto matcher =
281                 visibility >> -virtual_ >> x3::space >>
282                 parser::type_rule<return_type>(return_type_name) >>  x3::space >>
283                 thiscall >> //cdecl declaration for methods. stdcall cannot be
284                 cname >> "::" >> name >>
285                 x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >>
286                 inv_const_rule<Class>() >> inv_volatile_rule<Class>() >> parser::ptr_rule();
287 
288     auto predicate = [&](const mangled_storage_base::entry & e)
289             {
290                 auto itr = e.demangled.begin();
291                 auto end = e.demangled.end();
292                 auto res = x3::parse(itr, end, matcher);
293 
294                 return res && (itr == end);
295             };
296 
297     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
298 
299     if (found != storage_.end())
300         return found->mangled;
301     else
302         return "";
303 }
304 
305 
306 template<typename Signature>
get_constructor() const307 auto mangled_storage_impl::get_constructor() const -> ctor_sym
308 {
309     namespace x3 = spirit::x3;
310     using namespace parser;
311 
312     using func_type = Signature*;
313 
314 
315     std::string ctor_name; // = class_name + "::" + name;
316     std::string unscoped_cname; //the unscoped class-name
317     {
318         auto class_name = get_return_type(dummy<Signature>());
319         auto pos = class_name.rfind("::");
320         if (pos == std::string::npos)
321         {
322             ctor_name = class_name+ "::" + class_name ;
323             unscoped_cname = class_name;
324         }
325         else
326         {
327             unscoped_cname = class_name.substr(pos+2) ;
328             ctor_name = class_name+ "::" + unscoped_cname;
329         }
330     }
331 
332     auto matcher =
333                 visibility >> x3::space >>
334                 thiscall >> //cdecl declaration for methods. stdcall cannot be
335                 ctor_name >>
336                 x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule();
337 
338 
339     auto predicate = [&](const mangled_storage_base::entry & e)
340             {
341                 auto itr = e.demangled.begin();
342                 auto end = e.demangled.end();
343                 auto res = x3::parse(itr, end, matcher);
344 
345                 return res && (itr == end);
346             };
347 
348     auto f = std::find_if(storage_.begin(), storage_.end(), predicate);
349 
350     if (f != storage_.end())
351         return f->mangled;
352     else
353         return "";
354 }
355 
356 template<typename Class>
get_destructor() const357 auto mangled_storage_impl::get_destructor() const -> dtor_sym
358 {
359     namespace x3 = spirit::x3;
360     using namespace parser;
361     std::string dtor_name; // = class_name + "::" + name;
362     std::string unscoped_cname; //the unscoped class-name
363     {
364         auto class_name = get_name<Class>();
365         auto pos = class_name.rfind("::");
366         if (pos == std::string::npos)
367         {
368             dtor_name = class_name+ "::~" + class_name  + "(void)";
369             unscoped_cname = class_name;
370         }
371         else
372         {
373             unscoped_cname = class_name.substr(pos+2) ;
374             dtor_name = class_name+ "::~" + unscoped_cname + "(void)";
375         }
376     }
377 
378     auto matcher =
379                 visibility >> -virtual_ >> x3::space >>
380                 thiscall >> //cdecl declaration for methods. stdcall cannot be
381                 dtor_name >> parser::ptr_rule();
382 
383 
384     auto predicate = [&](const mangled_storage_base::entry & e)
385                 {
386                     auto itr = e.demangled.begin();
387                     auto end = e.demangled.end();
388                     auto res = x3::parse(itr, end, matcher);
389 
390                     return res && (itr == end);
391                 };
392 
393     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
394 
395 
396     if (found != storage_.end())
397         return found->mangled;
398     else
399         return "";
400 }
401 
402 template<typename T>
get_vtable() const403 std::string mangled_storage_impl::get_vtable() const
404 {
405     std::string id = "const " + get_name<T>() + "::`vftable'";
406 
407     auto predicate = [&](const mangled_storage_base::entry & e)
408                 {
409                     return e.demangled == id;
410                 };
411 
412     auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
413 
414 
415     if (found != storage_.end())
416         return found->mangled;
417     else
418         return "";
419 }
420 
421 template<typename T>
get_related() const422 std::vector<std::string> mangled_storage_impl::get_related() const
423 {
424     std::vector<std::string> ret;
425     auto name = get_name<T>();
426 
427     for (auto & c : storage_)
428     {
429         if (c.demangled.find(name) != std::string::npos)
430             ret.push_back(c.demangled);
431     }
432 
433     return ret;
434 }
435 
436 
437 }}}
438 
439 
440 
441 #endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */
442