]>
Commit | Line | Data |
---|---|---|
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> | |
30 | std::vector<std::string> get_func_params(dummy<Return(Args...)>) const | |
31 | { | |
32 | return {get_name<Args>()...}; | |
33 | } | |
34 | template<typename Return, typename ...Args> | |
35 | std::string get_return_type(dummy<Return(Args...)>) const | |
36 | { | |
37 | return get_name<Return>(); | |
38 | } | |
39 | //function to remove preceeding '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. | |
64 | 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 | ||
79 | void mangled_storage_impl::trim_typename(std::string & val) | |
80 | { | |
81 | //remove preceeding 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 | ||
101 | auto ptr_rule_impl(std::integral_constant<std::size_t, 32>) | |
102 | { | |
103 | return -((-x3::space) >> "__ptr32"); | |
104 | } | |
105 | auto ptr_rule_impl(std::integral_constant<std::size_t, 64>) | |
106 | { | |
107 | return -((-x3::space) >> "__ptr64"); | |
108 | } | |
109 | ||
110 | auto ptr_rule() { return ptr_rule_impl(std::integral_constant<std::size_t, sizeof(std::size_t)*8>());} | |
111 | ||
112 | auto const visibility = ("public:" | x3::lit("protected:") | "private:"); | |
113 | auto const virtual_ = x3::space >> "virtual"; | |
114 | auto const static_ = x3::space >> x3::lit("static") ; | |
115 | ||
116 | auto const_rule_impl(true_type ) {return x3::space >> "const";}; | |
117 | auto const_rule_impl(false_type) {return x3::eps;}; | |
118 | template<typename T> | |
119 | auto const_rule() {using t = is_const<typename remove_reference<T>::type>; return const_rule_impl(t());} | |
120 | ||
121 | auto volatile_rule_impl(true_type ) {return x3::space >> "volatile";}; | |
122 | auto volatile_rule_impl(false_type) {return x3::eps;}; | |
123 | template<typename T> | |
124 | auto volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return volatile_rule_impl(t());} | |
125 | ||
126 | ||
127 | auto inv_const_rule_impl(true_type ) {return "const" >> x3::space ;}; | |
128 | auto inv_const_rule_impl(false_type) {return x3::eps;}; | |
129 | template<typename T> | |
130 | auto inv_const_rule() {using t = is_const<typename remove_reference<T>::type>; return inv_const_rule_impl(t());} | |
131 | ||
132 | auto inv_volatile_rule_impl(true_type ) {return "volatile" >> x3::space;}; | |
133 | auto inv_volatile_rule_impl(false_type) {return x3::eps;}; | |
134 | template<typename T> | |
135 | auto inv_volatile_rule() {using t = is_volatile<typename remove_reference<T>::type>; return inv_volatile_rule_impl(t());} | |
136 | ||
137 | ||
138 | auto reference_rule_impl(false_type, false_type) {return x3::eps;} | |
139 | auto reference_rule_impl(true_type, false_type) {return x3::space >>"&" ;} | |
140 | auto reference_rule_impl(false_type, true_type ) {return x3::space >>"&&" ;} | |
141 | ||
142 | ||
143 | template<typename T> | |
144 | 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());} | |
145 | ||
146 | auto const class_ = ("class" | x3::lit("struct")); | |
147 | ||
148 | //it takes a string, because it may be overloaded. | |
149 | template<typename T> | |
150 | auto type_rule(const std::string & type_name) | |
151 | { | |
152 | using namespace std; | |
153 | ||
154 | return -(class_ >> x3::space)>> x3::string(type_name) >> | |
155 | const_rule<T>() >> | |
156 | volatile_rule<T>() >> | |
157 | reference_rule<T>() >> | |
158 | ptr_rule(); | |
159 | } | |
160 | template<> | |
161 | auto type_rule<void>(const std::string &) { return x3::string("void"); }; | |
162 | ||
163 | auto const cdecl_ = "__cdecl" >> x3::space; | |
164 | auto const stdcall = "__stdcall" >> x3::space; | |
165 | #if defined(_WIN64)//seems to be necessary by msvc 14-x64 | |
166 | auto const thiscall = "__cdecl" >> x3::space; | |
167 | #else | |
168 | auto const thiscall = "__thiscall" >> x3::space; | |
169 | #endif | |
170 | ||
171 | template<typename Return, typename Arg> | |
172 | auto arg_list(const mangled_storage_impl & ms, Return (*)(Arg)) | |
173 | { | |
174 | using namespace std; | |
175 | ||
176 | return type_rule<Arg>(ms.get_name<Arg>()); | |
177 | } | |
178 | ||
179 | template<typename Return, typename First, typename Second, typename ...Args> | |
180 | auto arg_list(const mangled_storage_impl & ms, Return (*)(First, Second, Args...)) | |
181 | { | |
182 | ||
183 | using next_type = Return (*)(Second, Args...); | |
184 | return type_rule<First>(ms.get_name<First>()) >> x3::char_(',') >> arg_list(ms, next_type()); | |
185 | } | |
186 | ||
187 | template<typename Return> | |
188 | auto arg_list(const mangled_storage_impl & ms, Return (*)()) | |
189 | { | |
190 | return x3::string("void"); | |
191 | } | |
192 | } | |
193 | ||
194 | ||
195 | template<typename T> std::string mangled_storage_impl::get_variable(const std::string &name) const | |
196 | { | |
197 | using namespace std; | |
198 | using namespace boost; | |
199 | ||
200 | namespace x3 = spirit::x3; | |
201 | using namespace parser; | |
202 | ||
203 | auto type_name = get_name<T>(); | |
204 | ||
205 | auto matcher = | |
206 | -(visibility >> static_ >> x3::space) >> //it may be a static class-member | |
207 | parser::type_rule<T>(type_name) >> x3::space >> | |
208 | name; | |
209 | ||
210 | auto predicate = [&](const mangled_storage_base::entry & e) | |
211 | { | |
212 | if (e.demangled == name)//maybe not mangled, | |
213 | return true; | |
214 | ||
215 | auto itr = e.demangled.begin(); | |
216 | auto end = e.demangled.end(); | |
217 | auto res = x3::parse(itr, end, matcher); | |
218 | return res && (itr == end); | |
219 | }; | |
220 | ||
221 | auto found = std::find_if(storage_.begin(), storage_.end(), predicate); | |
222 | ||
223 | if (found != storage_.end()) | |
224 | return found->mangled; | |
225 | else | |
226 | return ""; | |
227 | } | |
228 | ||
229 | template<typename Func> std::string mangled_storage_impl::get_function(const std::string &name) const | |
230 | { | |
231 | namespace x3 = spirit::x3; | |
232 | using namespace parser; | |
233 | using func_type = Func*; | |
234 | using return_type = typename function_traits<Func>::result_type; | |
235 | std::string return_type_name = get_name<return_type>(); | |
236 | ||
237 | ||
238 | auto matcher = | |
239 | -(visibility >> static_ >> x3::space) >> //it may be a static class-member, which does however not have the static attribute. | |
240 | parser::type_rule<return_type>(return_type_name) >> x3::space >> | |
241 | cdecl_ >> //cdecl declaration for methods. stdcall cannot be | |
242 | name >> x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule(); | |
243 | ||
244 | ||
245 | auto predicate = [&](const mangled_storage_base::entry & e) | |
246 | { | |
247 | if (e.demangled == name)//maybe not mangled, | |
248 | return true; | |
249 | ||
250 | auto itr = e.demangled.begin(); | |
251 | auto end = e.demangled.end(); | |
252 | auto res = x3::parse(itr, end, matcher); | |
253 | ||
254 | return res && (itr == end); | |
255 | }; | |
256 | ||
257 | auto found = std::find_if(storage_.begin(), storage_.end(), predicate); | |
258 | ||
259 | if (found != storage_.end()) | |
260 | return found->mangled; | |
261 | else | |
262 | return ""; | |
263 | ||
264 | } | |
265 | ||
266 | template<typename Class, typename Func> | |
267 | std::string mangled_storage_impl::get_mem_fn(const std::string &name) const | |
268 | { | |
269 | namespace x3 = spirit::x3; | |
270 | using namespace parser; | |
271 | using func_type = Func*; | |
272 | using return_type = typename function_traits<Func>::result_type; | |
273 | auto return_type_name = get_name<return_type>(); | |
274 | ||
275 | ||
276 | auto cname = get_name<Class>(); | |
277 | ||
278 | auto matcher = | |
279 | visibility >> -virtual_ >> x3::space >> | |
280 | parser::type_rule<return_type>(return_type_name) >> x3::space >> | |
281 | thiscall >> //cdecl declaration for methods. stdcall cannot be | |
282 | cname >> "::" >> name >> | |
283 | x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> | |
284 | inv_const_rule<Class>() >> inv_volatile_rule<Class>() >> parser::ptr_rule(); | |
285 | ||
286 | auto predicate = [&](const mangled_storage_base::entry & e) | |
287 | { | |
288 | auto itr = e.demangled.begin(); | |
289 | auto end = e.demangled.end(); | |
290 | auto res = x3::parse(itr, end, matcher); | |
291 | ||
292 | return res && (itr == end); | |
293 | }; | |
294 | ||
295 | auto found = std::find_if(storage_.begin(), storage_.end(), predicate); | |
296 | ||
297 | if (found != storage_.end()) | |
298 | return found->mangled; | |
299 | else | |
300 | return ""; | |
301 | } | |
302 | ||
303 | ||
304 | template<typename Signature> | |
305 | auto mangled_storage_impl::get_constructor() const -> ctor_sym | |
306 | { | |
307 | namespace x3 = spirit::x3; | |
308 | using namespace parser; | |
309 | ||
310 | using func_type = Signature*; | |
311 | ||
312 | ||
313 | std::string ctor_name; // = class_name + "::" + name; | |
314 | std::string unscoped_cname; //the unscoped class-name | |
315 | { | |
316 | auto class_name = get_return_type(dummy<Signature>()); | |
317 | auto pos = class_name.rfind("::"); | |
318 | if (pos == std::string::npos) | |
319 | { | |
320 | ctor_name = class_name+ "::" + class_name ; | |
321 | unscoped_cname = class_name; | |
322 | } | |
323 | else | |
324 | { | |
325 | unscoped_cname = class_name.substr(pos+2) ; | |
326 | ctor_name = class_name+ "::" + unscoped_cname; | |
327 | } | |
328 | } | |
329 | ||
330 | auto matcher = | |
331 | visibility >> x3::space >> | |
332 | thiscall >> //cdecl declaration for methods. stdcall cannot be | |
333 | ctor_name >> | |
334 | x3::lit('(') >> parser::arg_list(*this, func_type()) >> x3::lit(')') >> parser::ptr_rule(); | |
335 | ||
336 | ||
337 | auto predicate = [&](const mangled_storage_base::entry & e) | |
338 | { | |
339 | auto itr = e.demangled.begin(); | |
340 | auto end = e.demangled.end(); | |
341 | auto res = x3::parse(itr, end, matcher); | |
342 | ||
343 | return res && (itr == end); | |
344 | }; | |
345 | ||
346 | auto f = std::find_if(storage_.begin(), storage_.end(), predicate); | |
347 | ||
348 | if (f != storage_.end()) | |
349 | return f->mangled; | |
350 | else | |
351 | return ""; | |
352 | } | |
353 | ||
354 | template<typename Class> | |
355 | auto mangled_storage_impl::get_destructor() const -> dtor_sym | |
356 | { | |
357 | namespace x3 = spirit::x3; | |
358 | using namespace parser; | |
359 | std::string dtor_name; // = class_name + "::" + name; | |
360 | std::string unscoped_cname; //the unscoped class-name | |
361 | { | |
362 | auto class_name = get_name<Class>(); | |
363 | auto pos = class_name.rfind("::"); | |
364 | if (pos == std::string::npos) | |
365 | { | |
366 | dtor_name = class_name+ "::~" + class_name + "(void)"; | |
367 | unscoped_cname = class_name; | |
368 | } | |
369 | else | |
370 | { | |
371 | unscoped_cname = class_name.substr(pos+2) ; | |
372 | dtor_name = class_name+ "::~" + unscoped_cname + "(void)"; | |
373 | } | |
374 | } | |
375 | ||
376 | auto matcher = | |
377 | visibility >> -virtual_ >> x3::space >> | |
378 | thiscall >> //cdecl declaration for methods. stdcall cannot be | |
379 | dtor_name >> parser::ptr_rule(); | |
380 | ||
381 | ||
382 | auto predicate = [&](const mangled_storage_base::entry & e) | |
383 | { | |
384 | auto itr = e.demangled.begin(); | |
385 | auto end = e.demangled.end(); | |
386 | auto res = x3::parse(itr, end, matcher); | |
387 | ||
388 | return res && (itr == end); | |
389 | }; | |
390 | ||
391 | auto found = std::find_if(storage_.begin(), storage_.end(), predicate); | |
392 | ||
393 | ||
394 | if (found != storage_.end()) | |
395 | return found->mangled; | |
396 | else | |
397 | return ""; | |
398 | } | |
399 | ||
400 | template<typename T> | |
401 | std::string mangled_storage_impl::get_vtable() const | |
402 | { | |
403 | std::string id = "const " + get_name<T>() + "::`vftable'"; | |
404 | ||
405 | auto predicate = [&](const mangled_storage_base::entry & e) | |
406 | { | |
407 | return e.demangled == id; | |
408 | }; | |
409 | ||
410 | auto found = std::find_if(storage_.begin(), storage_.end(), predicate); | |
411 | ||
412 | ||
413 | if (found != storage_.end()) | |
414 | return found->mangled; | |
415 | else | |
416 | return ""; | |
417 | } | |
418 | ||
419 | template<typename T> | |
420 | std::vector<std::string> mangled_storage_impl::get_related() const | |
421 | { | |
422 | std::vector<std::string> ret; | |
423 | auto name = get_name<T>(); | |
424 | ||
425 | for (auto & c : storage_) | |
426 | { | |
427 | if (c.demangled.find(name) != std::string::npos) | |
428 | ret.push_back(c.demangled); | |
429 | } | |
430 | ||
431 | return ret; | |
432 | } | |
433 | ||
434 | ||
435 | }}} | |
436 | ||
437 | ||
438 | ||
439 | #endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */ |