msvc.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. #ifndef BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
  7. #define BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_
  8. #include <boost/dll/detail/demangling/mangled_storage_base.hpp>
  9. #include <boost/core/detail/string_view.hpp>
  10. #include <iterator>
  11. #include <algorithm>
  12. #include <type_traits>
  13. namespace boost { namespace dll { namespace detail {
  14. class mangled_storage_impl : public mangled_storage_base
  15. {
  16. template<typename T>
  17. struct dummy {};
  18. template<typename Return, typename ...Args>
  19. std::string get_return_type(dummy<Return(Args...)>) const
  20. {
  21. return get_name<Return>();
  22. }
  23. //function to remove preceding 'class ' or 'struct ' if the are given in this format.
  24. inline static void trim_typename(std::string & val);
  25. public:
  26. using ctor_sym = std::string;
  27. using dtor_sym = std::string;
  28. using mangled_storage_base::mangled_storage_base;
  29. template<typename T>
  30. std::string get_variable(const std::string &name) const;
  31. template<typename Func>
  32. std::string get_function(const std::string &name) const;
  33. template<typename Class, typename Func>
  34. std::string get_mem_fn(const std::string &name) const;
  35. template<typename Signature>
  36. ctor_sym get_constructor() const;
  37. template<typename Class>
  38. dtor_sym get_destructor() const;
  39. template<typename T> //overload, does not need to virtual.
  40. std::string get_name() const
  41. {
  42. auto nm = mangled_storage_base::get_name<T>();
  43. trim_typename(nm);
  44. return nm;
  45. }
  46. template<typename T>
  47. std::string get_vtable() const;
  48. template<typename T>
  49. std::vector<std::string> get_related() const;
  50. };
  51. void mangled_storage_impl::trim_typename(std::string & val)
  52. {
  53. //remove preceding class or struct, because you might want to use a struct as class, et vice versa
  54. if (val.size() >= 6)
  55. {
  56. using namespace std;
  57. static constexpr char class_ [7] = "class ";
  58. static constexpr char struct_[8] = "struct ";
  59. if (equal(begin(class_), end(class_)-1, val.begin()))
  60. val.erase(0, 6);
  61. else if (val.size() >= 7)
  62. if (equal(begin(struct_), end(struct_)-1, val.begin()))
  63. val.erase(0, 7);
  64. }
  65. }
  66. namespace parser {
  67. inline bool try_consume_prefix(boost::core::string_view& s, boost::core::string_view prefix) {
  68. const bool result = s.starts_with(prefix);
  69. if (result) {
  70. s.remove_prefix(prefix.size());
  71. }
  72. return result;
  73. }
  74. inline bool ignore_prefix(boost::core::string_view& s, boost::core::string_view prefix) {
  75. parser::try_consume_prefix(s, prefix);
  76. return true;
  77. }
  78. inline void consume_ptrs(boost::core::string_view& s) {
  79. do {
  80. while (parser::try_consume_prefix(s, " ")) {}
  81. } while (parser::try_consume_prefix(s, "__ptr32") || parser::try_consume_prefix(s, "__ptr64"));
  82. }
  83. inline bool ignore_ptrs(boost::core::string_view& s) {
  84. parser::consume_ptrs(s);
  85. return true;
  86. }
  87. inline bool try_consume_visibility(boost::core::string_view& s) {
  88. return parser::try_consume_prefix(s, "public:")
  89. || parser::try_consume_prefix(s, "protected:")
  90. || parser::try_consume_prefix(s, "private:");
  91. }
  92. template<typename T>
  93. bool try_consume_type(boost::core::string_view& s, const mangled_storage_impl& ms) {
  94. if (std::is_void<T>::value) {
  95. return parser::try_consume_prefix(s, "void");
  96. }
  97. parser::ignore_prefix(s, "class ");
  98. parser::ignore_prefix(s, "struct ");
  99. const auto& mangled_name = ms.get_name<T>();
  100. static_assert(
  101. !std::is_function<typename std::remove_pointer<T>::type>::value,
  102. "boost::dll::smart_library on Windows platform does not support "
  103. "functions that accept functions. If you wish to see such support "
  104. "- please provide a working PR on github with sufficient tests. "
  105. "Otherwise simplify the function. For example, use `void*` "
  106. "parameter instead of a function pointer. "
  107. );
  108. if (!parser::try_consume_prefix(s, mangled_name)) {
  109. return false;
  110. }
  111. if (std::is_const<typename std::remove_reference<T>::type>::value) {
  112. if (!parser::try_consume_prefix(s, " const")) {
  113. return false;
  114. }
  115. }
  116. if (std::is_volatile<typename std::remove_reference<T>::type>::value) {
  117. if (!parser::try_consume_prefix(s, " volatile")) {
  118. return false;
  119. }
  120. }
  121. if (std::is_rvalue_reference<T>::value) {
  122. if (!parser::try_consume_prefix(s, " &&")) {
  123. return false;
  124. }
  125. }
  126. if (std::is_lvalue_reference<T>::value) {
  127. if (!parser::try_consume_prefix(s, " &")) {
  128. return false;
  129. }
  130. }
  131. return parser::ignore_ptrs(s);
  132. }
  133. inline bool try_consume_thiscall(boost::core::string_view& s) {
  134. parser::try_consume_prefix(s, " ");
  135. return parser::try_consume_prefix(s, "__cdecl ") // Win 64bit
  136. || parser::try_consume_prefix(s, "__thiscall "); // Win 32bit
  137. }
  138. template<typename Return, typename Arg>
  139. bool try_consume_arg_list(boost::core::string_view& s, const mangled_storage_impl& ms, Return (*)(Arg)) {
  140. return parser::try_consume_type<Arg>(s, ms);
  141. }
  142. template<typename Return, typename First, typename Second, typename ...Args>
  143. bool try_consume_arg_list(boost::core::string_view& s, const mangled_storage_impl& ms, Return (*)(First, Second, Args...)) {
  144. using next_type = Return (*)(Second, Args...);
  145. return parser::try_consume_type<First>(s, ms)
  146. && parser::try_consume_prefix(s, ",")
  147. && parser::try_consume_arg_list(s, ms, next_type());
  148. }
  149. template<typename Return>
  150. bool try_consume_arg_list(boost::core::string_view& s, const mangled_storage_impl& ms, Return (*)()) {
  151. return parser::try_consume_type<void>(s, ms);
  152. }
  153. class is_destructor_with_name {
  154. const std::string& dtor_name_;
  155. public:
  156. explicit is_destructor_with_name(const std::string& dtor_name)
  157. : dtor_name_(dtor_name) {}
  158. inline bool operator()(boost::core::string_view s) const {
  159. return parser::try_consume_visibility(s)
  160. && parser::ignore_prefix(s, " virtual")
  161. && parser::try_consume_thiscall(s)
  162. && parser::try_consume_prefix(s, dtor_name_)
  163. && parser::ignore_ptrs(s)
  164. && s.empty();
  165. }
  166. inline bool operator()(const mangled_storage_base::entry& e) const {
  167. return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size()));
  168. }
  169. };
  170. template<typename T>
  171. class is_variable_with_name {
  172. const std::string& variable_name_;
  173. const mangled_storage_impl& ms_;
  174. public:
  175. is_variable_with_name(const std::string& variable_name, const mangled_storage_impl& ms)
  176. : variable_name_(variable_name), ms_(ms) {}
  177. inline bool operator()(boost::core::string_view s) const {
  178. if (parser::try_consume_visibility(s) && !parser::try_consume_prefix(s, " static ")) {
  179. return false;
  180. }
  181. return parser::try_consume_type<T>(s, ms_)
  182. && parser::try_consume_prefix(s, variable_name_)
  183. && s.empty();
  184. }
  185. inline bool operator()(const mangled_storage_base::entry& e) const {
  186. return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size()));
  187. }
  188. };
  189. template <class Signature>
  190. class is_constructor_with_name {
  191. const std::string& ctor_name_;
  192. const mangled_storage_impl& ms_;
  193. public:
  194. is_constructor_with_name(const std::string& ctor_name, const mangled_storage_impl& ms)
  195. : ctor_name_(ctor_name), ms_(ms) {}
  196. inline bool operator()(boost::core::string_view s) const {
  197. return parser::try_consume_visibility(s)
  198. && parser::try_consume_thiscall(s)
  199. && parser::try_consume_prefix(s, ctor_name_)
  200. && parser::try_consume_prefix(s, "(")
  201. && parser::try_consume_arg_list(s, ms_, Signature())
  202. && parser::try_consume_prefix(s, ")")
  203. && parser::ignore_ptrs(s)
  204. && s.empty();
  205. }
  206. inline bool operator()(const mangled_storage_base::entry& e) const {
  207. return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size()));
  208. }
  209. };
  210. template <class Signature>
  211. class is_function_with_name;
  212. template <class Result, class... Args>
  213. class is_function_with_name<Result(*)(Args...)> {
  214. const std::string& function_name_;
  215. const mangled_storage_impl& ms_;
  216. public:
  217. is_function_with_name(const std::string& function_name, const mangled_storage_impl& ms)
  218. : function_name_(function_name), ms_(ms) {}
  219. inline bool operator()(boost::core::string_view s) const {
  220. if (parser::try_consume_visibility(s) && !parser::try_consume_prefix(s, " static ")) {
  221. return false;
  222. }
  223. using Signature = Result(*)(Args...);
  224. return parser::try_consume_type<Result>(s, ms_)
  225. && parser::ignore_prefix(s, " ")
  226. && parser::try_consume_prefix(s, "__cdecl ")
  227. && parser::try_consume_prefix(s, function_name_)
  228. && parser::try_consume_prefix(s, "(")
  229. && parser::try_consume_arg_list(s, ms_, Signature())
  230. && parser::try_consume_prefix(s, ")")
  231. && parser::ignore_ptrs(s)
  232. && s.empty();
  233. }
  234. inline bool operator()(const mangled_storage_base::entry& e) const {
  235. return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size()));
  236. }
  237. };
  238. template <typename Class, typename Func>
  239. class is_mem_fn_with_name;
  240. template <typename Class, class Result, class... Args>
  241. class is_mem_fn_with_name<Class, Result(*)(Args...)> {
  242. const std::string& function_name_;
  243. const mangled_storage_impl& ms_;
  244. public:
  245. is_mem_fn_with_name(const std::string& function_name, const mangled_storage_impl& ms)
  246. : function_name_(function_name), ms_(ms) {}
  247. inline bool operator()(boost::core::string_view s) const {
  248. using Signature = Result(*)(Args...);
  249. return parser::try_consume_visibility(s)
  250. && parser::ignore_prefix(s, " virtual")
  251. && parser::try_consume_prefix(s, " ")
  252. && parser::try_consume_type<Result>(s, ms_)
  253. && parser::try_consume_thiscall(s)
  254. && parser::try_consume_type<typename std::remove_cv<Class>::type>(s, ms_)
  255. && parser::try_consume_prefix(s, "::")
  256. && parser::try_consume_prefix(s, function_name_)
  257. && parser::try_consume_prefix(s, "(")
  258. && parser::try_consume_arg_list(s, ms_, Signature())
  259. && parser::try_consume_prefix(s, ")")
  260. && (!std::is_const<Class>::value || parser::try_consume_prefix(s, "const "))
  261. && (!std::is_volatile<Class>::value || parser::try_consume_prefix(s, "volatile "))
  262. && parser::ignore_ptrs(s)
  263. && s.empty();
  264. }
  265. inline bool operator()(const mangled_storage_base::entry& e) const {
  266. return (*this)(boost::core::string_view(e.demangled.data(), e.demangled.size()));
  267. }
  268. };
  269. } // namespace parser
  270. template<typename T>
  271. std::string mangled_storage_impl::get_variable(const std::string &name) const {
  272. const auto found = std::find_if(storage_.begin(), storage_.end(), parser::is_variable_with_name<T>(name, *this));
  273. if (found != storage_.end())
  274. return found->mangled;
  275. else
  276. return "";
  277. }
  278. template<typename Func>
  279. std::string mangled_storage_impl::get_function(const std::string &name) const {
  280. const auto found = std::find_if(storage_.begin(), storage_.end(), parser::is_function_with_name<Func*>(name, *this));
  281. if (found != storage_.end())
  282. return found->mangled;
  283. else
  284. return "";
  285. }
  286. template<typename Class, typename Func>
  287. std::string mangled_storage_impl::get_mem_fn(const std::string &name) const {
  288. const auto found = std::find_if(storage_.begin(), storage_.end(), parser::is_mem_fn_with_name<Class, Func*>(name, *this));
  289. if (found != storage_.end())
  290. return found->mangled;
  291. else
  292. return "";
  293. }
  294. template<typename Signature>
  295. auto mangled_storage_impl::get_constructor() const -> ctor_sym {
  296. std::string ctor_name; // = class_name + "::" + name;
  297. std::string unscoped_cname; //the unscoped class-name
  298. {
  299. auto class_name = get_return_type(dummy<Signature>());
  300. auto pos = class_name.rfind("::");
  301. if (pos == std::string::npos)
  302. {
  303. ctor_name = class_name+ "::" + class_name ;
  304. unscoped_cname = class_name;
  305. }
  306. else
  307. {
  308. unscoped_cname = class_name.substr(pos+2) ;
  309. ctor_name = class_name+ "::" + unscoped_cname;
  310. }
  311. }
  312. const auto f = std::find_if(storage_.begin(), storage_.end(), parser::is_constructor_with_name<Signature*>(ctor_name, *this));
  313. if (f != storage_.end())
  314. return f->mangled;
  315. else
  316. return "";
  317. }
  318. template<typename Class>
  319. auto mangled_storage_impl::get_destructor() const -> dtor_sym {
  320. std::string dtor_name; // = class_name + "::" + name;
  321. std::string unscoped_cname; //the unscoped class-name
  322. {
  323. auto class_name = get_name<Class>();
  324. auto pos = class_name.rfind("::");
  325. if (pos == std::string::npos)
  326. {
  327. dtor_name = class_name+ "::~" + class_name + "(void)";
  328. unscoped_cname = class_name;
  329. }
  330. else
  331. {
  332. unscoped_cname = class_name.substr(pos+2) ;
  333. dtor_name = class_name+ "::~" + unscoped_cname + "(void)";
  334. }
  335. }
  336. const auto found = std::find_if(storage_.begin(), storage_.end(), parser::is_destructor_with_name(dtor_name));
  337. if (found != storage_.end())
  338. return found->mangled;
  339. else
  340. return "";
  341. }
  342. template<typename T>
  343. std::string mangled_storage_impl::get_vtable() const {
  344. std::string id = "const " + get_name<T>() + "::`vftable'";
  345. auto predicate = [&](const mangled_storage_base::entry & e)
  346. {
  347. return e.demangled == id;
  348. };
  349. auto found = std::find_if(storage_.begin(), storage_.end(), predicate);
  350. if (found != storage_.end())
  351. return found->mangled;
  352. else
  353. return "";
  354. }
  355. template<typename T>
  356. std::vector<std::string> mangled_storage_impl::get_related() const {
  357. std::vector<std::string> ret;
  358. auto name = get_name<T>();
  359. for (auto & c : storage_)
  360. {
  361. if (c.demangled.find(name) != std::string::npos)
  362. ret.push_back(c.demangled);
  363. }
  364. return ret;
  365. }
  366. }}}
  367. #endif /* BOOST_DLL_DETAIL_DEMANGLING_MSVC_HPP_ */