summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib/util/mfpresolve.h
blob: eb3fba2b85da4c8befc43adebc1bb6e95ba32bcb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/***************************************************************************

    mfpresolve.h

    Helpers for resolving member function pointers to entry points.

***************************************************************************/
#ifndef MAME_LIB_UTIL_MFPRESOLVE_H
#define MAME_LIB_UTIL_MFPRESOLVE_H

#pragma once

#include "abi.h"

#include <cassert>
#include <cstddef>
#include <cstdint>
#include <tuple>
#include <utility>


namespace util {

namespace detail {

struct mfp_itanium_equiv
{
	std::uintptr_t function;
	std::ptrdiff_t delta;

	constexpr std::ptrdiff_t this_delta() const noexcept { return delta >> ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? 1 : 0); }
	constexpr bool is_virtual() const noexcept { return ((MAME_ABI_CXX_ITANIUM_MFP_TYPE == MAME_ABI_CXX_ITANIUM_MFP_ARM) ? delta : function) & 1; }
};

struct mfp_msvc_single_equiv { std::uintptr_t entrypoint; };
struct mfp_msvc_multi_equiv { std::uintptr_t entrypoint; int delta; };
struct mfp_msvc_virtual_equiv { std::uintptr_t entrypoint; int delta; int vindex; };
struct mfp_msvc_unknown_equiv { std::uintptr_t entrypoint; int delta; int voffset; int vindex; };

std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_itanium(std::uintptr_t function, std::ptrdiff_t delta, void const *object) noexcept;
std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_itanium(std::uintptr_t function, std::ptrdiff_t delta) noexcept;
std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function_msvc(void const *funcptr, std::size_t size, void const *object) noexcept;
std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function_msvc(void const *funcptr, std::size_t size) noexcept;
std::uintptr_t bypass_member_function_thunks(std::uintptr_t entrypoint, void const *object) noexcept;
std::pair<std::uintptr_t, bool> bypass_member_function_thunks(std::uintptr_t entrypoint) noexcept;

} // namespace detail


template <typename T, typename U>
inline T bypass_member_function_thunks(T entrypoint, U const *object) noexcept
{
	return reinterpret_cast<T>(
			detail::bypass_member_function_thunks(
				reinterpret_cast<std::uintptr_t>(entrypoint),
				reinterpret_cast<void const *>(object)));
}


template <typename T, typename Ret, typename... Params>
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...), T &object) noexcept
{
	if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
	{
		detail::mfp_itanium_equiv equiv;
		assert(sizeof(function) == sizeof(equiv));
		*reinterpret_cast<decltype(function) *>(&equiv) = function;
		return detail::resolve_member_function_itanium(equiv.function, equiv.delta, &object);
	}
	else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
	{
		return detail::resolve_member_function_msvc(&function, sizeof(function), &object);
	}
	else
	{
		return std::make_pair(
				std::uintptr_t(static_cast<void (*)()>(nullptr)),
				std::uintptr_t(static_cast<void *>(nullptr)));
	}
}


template <typename T, typename Ret, typename... Params>
inline std::pair<std::uintptr_t, std::uintptr_t> resolve_member_function(Ret (T::*function)(Params...) const, T const &object) noexcept
{
	if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
	{
		detail::mfp_itanium_equiv equiv;
		assert(sizeof(function) == sizeof(equiv));
		*reinterpret_cast<decltype(function) *>(&equiv) = function;
		return detail::resolve_member_function_itanium(equiv.function, equiv.delta, &object);
	}
	else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
	{
		return detail::resolve_member_function_msvc(&function, sizeof(function), &object);
	}
	else
	{
		return std::make_pair(
				std::uintptr_t(static_cast<void (*)()>(nullptr)),
				std::uintptr_t(static_cast<void *>(nullptr)));
	}
}


template <typename T, typename Ret, typename... Params>
inline std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function(Ret (T::*function)(Params...)) noexcept
{
	if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
	{
		detail::mfp_itanium_equiv equiv;
		assert(sizeof(function) == sizeof(equiv));
		*reinterpret_cast<decltype(function) *>(&equiv) = function;
		return detail::resolve_member_function_itanium(equiv.function, equiv.delta);
	}
	else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
	{
		return detail::resolve_member_function_msvc(&function, sizeof(function));
	}
	else
	{
		return std::make_tuple(std::uintptr_t(static_cast<void (*)()>(nullptr)), std::ptrdiff_t(0), false);
	}
}


template <typename T, typename Ret, typename... Params>
inline std::tuple<std::uintptr_t, std::ptrdiff_t, bool> resolve_member_function(Ret (T::*function)(Params...) const) noexcept
{
	if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_ITANIUM)
	{
		detail::mfp_itanium_equiv equiv;
		assert(sizeof(function) == sizeof(equiv));
		*reinterpret_cast<decltype(function) *>(&equiv) = function;
		return detail::resolve_member_function_itanium(equiv.function, equiv.delta);
	}
	else if (MAME_ABI_CXX_TYPE == MAME_ABI_CXX_MSVC)
	{
		return detail::resolve_member_function_msvc(&function, sizeof(function));
	}
	else
	{
		return std::make_tuple(std::uintptr_t(static_cast<void (*)()>(nullptr)), std::ptrdiff_t(0), false);
	}
}

} // namespace util

#endif // MAME_LIB_UTIL_MFPRESOLVE_H