Started testing virtual inheritance
This commit is contained in:
parent
ad98b346ab
commit
f53076ad68
|
@ -107,7 +107,7 @@ void GOTEntry::initialise(int argc, char** argv)
|
||||||
|
|
||||||
// base + rela.plt if symbol is found and defined
|
// base + rela.plt if symbol is found and defined
|
||||||
// base + rela.dyn if symbol is found and undefined
|
// base + rela.dyn if symbol is found and undefined
|
||||||
void* GOTEntry::set(void* function)
|
void* GOTEntry::set(void* function, const char* name)
|
||||||
{
|
{
|
||||||
if (entries_.empty()) {
|
if (entries_.empty()) {
|
||||||
auto address = reinterpret_cast<unsigned char*>(function);
|
auto address = reinterpret_cast<unsigned char*>(function);
|
||||||
|
@ -153,7 +153,7 @@ void* GOTEntry::set(void* function)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!defined) {
|
if (!defined) {
|
||||||
Report() << "cannot find definition of function " << function;
|
Report() << "cannot find definition of function " << name;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// find entries where the symbol is used in other ELF functions
|
// find entries where the symbol is used in other ELF functions
|
||||||
|
|
|
@ -22,9 +22,10 @@ public:
|
||||||
GOTEntry() = default;
|
GOTEntry() = default;
|
||||||
/**
|
/**
|
||||||
* @param function address of function
|
* @param function address of function
|
||||||
|
* @param name name of function
|
||||||
* @return original unaltered address of function
|
* @return original unaltered address of function
|
||||||
*/
|
*/
|
||||||
void* set(void* function);
|
void* set(void* function, const char* name);
|
||||||
/**
|
/**
|
||||||
* replace function with other function and reference count
|
* replace function with other function and reference count
|
||||||
* @param function to enter in Global Offset Tables instead of original
|
* @param function to enter in Global Offset Tables instead of original
|
||||||
|
|
18
Hook.h
18
Hook.h
|
@ -42,11 +42,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* construct from function pointer
|
* construct from function pointer
|
||||||
*/
|
*/
|
||||||
Hook(ReturnType (*function)(ArgTypes...));
|
Hook(const char* name, ReturnType (*function)(ArgTypes...));
|
||||||
/**
|
/**
|
||||||
* construct from method pointer
|
* construct from method pointer
|
||||||
*/
|
*/
|
||||||
Hook(MethodInfo<ReturnType, ArgTypes...> method);
|
Hook(const char* name, MethodInfo<ReturnType, ArgTypes...> method);
|
||||||
/// restore original function
|
/// restore original function
|
||||||
~Hook();
|
~Hook();
|
||||||
/**
|
/**
|
||||||
|
@ -60,19 +60,24 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static GOTEntry got_entry_;
|
static GOTEntry got_entry_;
|
||||||
|
static const char* name_;
|
||||||
using Base = HookImpl<CRTP, ReturnType, ArgTypes...>;
|
using Base = HookImpl<CRTP, ReturnType, ArgTypes...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
||||||
GOTEntry Hook<CRTP, ReturnType, ArgTypes...>::got_entry_;
|
GOTEntry Hook<CRTP, ReturnType, ArgTypes...>::got_entry_;
|
||||||
|
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
||||||
|
const char* Hook<CRTP, ReturnType, ArgTypes...>::name_ = "no name";
|
||||||
|
|
||||||
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
||||||
Hook<CRTP, ReturnType, ArgTypes...>::Hook(ReturnType (*function)(ArgTypes...))
|
Hook<CRTP, ReturnType, ArgTypes...>::Hook(const char* name,
|
||||||
|
ReturnType (*function)(ArgTypes...))
|
||||||
{
|
{
|
||||||
|
name_ = name;
|
||||||
// use union to get and convert address of function
|
// use union to get and convert address of function
|
||||||
Function<ReturnType, ArgTypes...> converter;
|
Function<ReturnType, ArgTypes...> converter;
|
||||||
converter.address_ = function;
|
converter.address_ = function;
|
||||||
got_entry_.set(converter.pointer_);
|
got_entry_.set(converter.pointer_, name);
|
||||||
converter.address_ = &Base::thunk;
|
converter.address_ = &Base::thunk;
|
||||||
converter.pointer_ = got_entry_.spy_with(converter.pointer_);
|
converter.pointer_ = got_entry_.spy_with(converter.pointer_);
|
||||||
Base::patch_ = Base::real_ = converter.address_;
|
Base::patch_ = Base::real_ = converter.address_;
|
||||||
|
@ -80,9 +85,10 @@ Hook<CRTP, ReturnType, ArgTypes...>::Hook(ReturnType (*function)(ArgTypes...))
|
||||||
|
|
||||||
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
template <typename CRTP, typename ReturnType, typename... ArgTypes>
|
||||||
inline Hook<CRTP, ReturnType, ArgTypes...>::
|
inline Hook<CRTP, ReturnType, ArgTypes...>::
|
||||||
Hook(MethodInfo<ReturnType, ArgTypes...> method)
|
Hook(const char* name, MethodInfo<ReturnType, ArgTypes...> method)
|
||||||
{
|
{
|
||||||
got_entry_.set(method.address_);
|
name_ = name;
|
||||||
|
got_entry_.set(method.address_, name);
|
||||||
if (method.vtable_entry_) {
|
if (method.vtable_entry_) {
|
||||||
got_entry_.make_entry(method.vtable_entry_);
|
got_entry_.make_entry(method.vtable_entry_);
|
||||||
}
|
}
|
||||||
|
|
27
SPY.h
27
SPY.h
|
@ -27,7 +27,10 @@ struct Function
|
||||||
struct Instance : public Hook<Instance<FUNC>, R, Args...>
|
struct Instance : public Hook<Instance<FUNC>, R, Args...>
|
||||||
{
|
{
|
||||||
using Base = Hook<Instance<FUNC>, R, Args...>;
|
using Base = Hook<Instance<FUNC>, R, Args...>;
|
||||||
Instance() : Base(FUNC) { }
|
Instance(const char* name)
|
||||||
|
:Base(name, FUNC)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +49,10 @@ struct MutableMethod
|
||||||
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
||||||
{
|
{
|
||||||
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
||||||
Instance() : Base(Method<R, T, Args...>(METHOD).resolve()) { }
|
Instance(const char* name)
|
||||||
|
:Base(name, Method<R, T, Args...>(METHOD).resolve())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,7 +71,10 @@ struct ConstMethod
|
||||||
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
||||||
{
|
{
|
||||||
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
||||||
Instance() : Base(Method<R, T, Args...>(METHOD).resolve()) { }
|
Instance(const char* name)
|
||||||
|
:Base(name, Method<R, T, Args...>(METHOD).resolve())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,7 +93,10 @@ struct VolatileMethod
|
||||||
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
||||||
{
|
{
|
||||||
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
||||||
Instance() : Base(Method<R, T, Args...>(METHOD).resolve()) { }
|
Instance(const char* name)
|
||||||
|
:Base(name, Method<R, T, Args...>(METHOD).resolve())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,7 +115,10 @@ struct ConstVolatileMethod
|
||||||
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
struct Instance : public Hook<Instance<METHOD>, R, T*, Args...>
|
||||||
{
|
{
|
||||||
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
using Base = Hook<Instance<METHOD>, R, T*, Args...>;
|
||||||
Instance() : Base(Method<R, T, Args...>(METHOD).resolve()) { }
|
Instance(const char* name)
|
||||||
|
:Base(name, Method<R, T, Args...>(METHOD).resolve())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,6 +151,6 @@ auto create(R (T::*)(Args...) const volatile)
|
||||||
* SPY returns a (derived) instance of Hook that can be used to add Hooks to.
|
* SPY returns a (derived) instance of Hook that can be used to add Hooks to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SPY(F) decltype(spy::impl::create(F))::Instance<F>()
|
#define SPY(F) decltype(spy::impl::create(F))::Instance<F>(#F)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
63
demo.cpp
63
demo.cpp
|
@ -1,6 +1,7 @@
|
||||||
#include "elfspy/demo.h"
|
#include "elfspy/demo.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
int f()
|
int f()
|
||||||
{
|
{
|
||||||
|
@ -51,3 +52,65 @@ void MyDerivedClass::virtual_method()
|
||||||
method(2);
|
method(2);
|
||||||
std::cout << "MyDerivedClass::virtual_method" << std::endl;
|
std::cout << "MyDerivedClass::virtual_method" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void One::one_method()
|
||||||
|
{
|
||||||
|
std::cout << "One::one" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Two::one_method()
|
||||||
|
{
|
||||||
|
std::cout << "Two::one" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check2_ == 0xdeafa1de);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Two::two_method()
|
||||||
|
{
|
||||||
|
std::cout << "Two::two" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check2_ == 0xdeafa1de);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Three::one_method()
|
||||||
|
{
|
||||||
|
std::cout << "Three::one" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check3_ == 0xdeadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Three::three_method()
|
||||||
|
{
|
||||||
|
std::cout << "Three::three" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check3_ == 0xdeadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Four::one_method()
|
||||||
|
{
|
||||||
|
std::cout << "Four::one" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check2_ == 0xdeafa1de);
|
||||||
|
assert(check3_ == 0xdeadbeef);
|
||||||
|
assert(check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Four::two_method()
|
||||||
|
{
|
||||||
|
std::cout << "Four::two" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check2_ == 0xdeafa1de);
|
||||||
|
assert(check3_ == 0xdeadbeef);
|
||||||
|
assert(check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Four::three_method()
|
||||||
|
{
|
||||||
|
std::cout << "Four::three" << std::endl;
|
||||||
|
assert(check1_ == 0xe110e110);
|
||||||
|
assert(check2_ == 0xdeafa1de);
|
||||||
|
assert(check3_ == 0xdeadbeef);
|
||||||
|
assert(check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
41
demo.h
41
demo.h
|
@ -23,4 +23,45 @@ public:
|
||||||
virtual void virtual_method();
|
virtual void virtual_method();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class One
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~One() = default;
|
||||||
|
virtual void one_method();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
long check1_ = 0xe110e110;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Two : virtual public One
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void one_method() override;
|
||||||
|
virtual void two_method();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
long check2_ = 0xdeafa1de;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Three : virtual public One
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void one_method() override;
|
||||||
|
virtual void three_method();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
long check3_ = 0xdeadbeef;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Four : public Two, public Three
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void one_method() override;
|
||||||
|
virtual void two_method() override;
|
||||||
|
virtual void three_method() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
long check4_ = 0xbadfeed;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
91
example7.cpp
91
example7.cpp
|
@ -5,6 +5,8 @@
|
||||||
#include "elfspy/Arg.h"
|
#include "elfspy/Arg.h"
|
||||||
#include "elfspy/Fake.h"
|
#include "elfspy/Fake.h"
|
||||||
|
|
||||||
|
#define private public
|
||||||
|
#define protected public
|
||||||
#include "elfspy/demo.h"
|
#include "elfspy/demo.h"
|
||||||
|
|
||||||
void func(MyClass*)
|
void func(MyClass*)
|
||||||
|
@ -12,6 +14,67 @@ void func(MyClass*)
|
||||||
std::cout << "func()" << std::endl;
|
std::cout << "func()" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void one_method1(One* one)
|
||||||
|
{
|
||||||
|
std::cout << "1::1" << std::endl;
|
||||||
|
assert(one->check1_ == 0xe110e110);
|
||||||
|
}
|
||||||
|
|
||||||
|
void one_method2(Two* two)
|
||||||
|
{
|
||||||
|
std::cout << "2::1" << std::endl;
|
||||||
|
assert(two->check1_ == 0xe110e110);
|
||||||
|
assert(two->check2_ == 0xdeafa1de);
|
||||||
|
}
|
||||||
|
|
||||||
|
void two_method2(Two* two)
|
||||||
|
{
|
||||||
|
std::cout << "2::2" << std::endl;
|
||||||
|
assert(two->check1_ == 0xe110e110);
|
||||||
|
assert(two->check2_ == 0xdeafa1de);
|
||||||
|
}
|
||||||
|
|
||||||
|
void one_method3(Three* three)
|
||||||
|
{
|
||||||
|
std::cout << "3::1" << std::endl;
|
||||||
|
assert(three->check1_ == 0xe110e110);
|
||||||
|
assert(three->check3_ == 0xdeadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void three_method3(Three* three)
|
||||||
|
{
|
||||||
|
std::cout << "3::3" << std::endl;
|
||||||
|
assert(three->check1_ == 0xe110e110);
|
||||||
|
assert(three->check3_ == 0xdeadbeef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void one_method4(Four* four)
|
||||||
|
{
|
||||||
|
std::cout << "4::1" << std::endl;
|
||||||
|
assert(four->check1_ == 0xe110e110);
|
||||||
|
assert(four->check2_ == 0xdeafa1de);
|
||||||
|
assert(four->check3_ == 0xdeadbeef);
|
||||||
|
assert(four->check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void two_method4(Four* four)
|
||||||
|
{
|
||||||
|
std::cout << "4::2" << std::endl;
|
||||||
|
assert(four->check1_ == 0xe110e110);
|
||||||
|
assert(four->check2_ == 0xdeafa1de);
|
||||||
|
assert(four->check3_ == 0xdeadbeef);
|
||||||
|
assert(four->check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void three_method4(Four* four)
|
||||||
|
{
|
||||||
|
std::cout << "4::3" << std::endl;
|
||||||
|
assert(four->check1_ == 0xe110e110);
|
||||||
|
assert(four->check2_ == 0xdeafa1de);
|
||||||
|
assert(four->check3_ == 0xdeadbeef);
|
||||||
|
assert(four->check4_ == 0xbadfeed);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
spy::initialise(argc, argv);
|
spy::initialise(argc, argv);
|
||||||
|
@ -27,5 +90,33 @@ int main(int argc, char** argv)
|
||||||
MyClass* my_heap_object = new MyClass;
|
MyClass* my_heap_object = new MyClass;
|
||||||
my_heap_object->virtual_method();
|
my_heap_object->virtual_method();
|
||||||
assert(method_this.value(1) == my_heap_object);
|
assert(method_this.value(1) == my_heap_object);
|
||||||
|
auto spy11 = SPY(&One::one_method);
|
||||||
|
auto spy21 = SPY(&Two::one_method);
|
||||||
|
auto spy22 = SPY(&Two::two_method);
|
||||||
|
auto spy31 = SPY(&Three::one_method);
|
||||||
|
auto spy33 = SPY(&Three::three_method);
|
||||||
|
auto spy41 = SPY(&Four::one_method);
|
||||||
|
auto spy42 = SPY(&Four::two_method);
|
||||||
|
auto spy43 = SPY(&Four::three_method);
|
||||||
|
auto fake11 = spy::fake(spy11, &one_method1);
|
||||||
|
auto fake21 = spy::fake(spy21, &one_method2);
|
||||||
|
auto fake22 = spy::fake(spy22, &two_method2);
|
||||||
|
auto fake31 = spy::fake(spy31, &one_method3);
|
||||||
|
auto fake33 = spy::fake(spy33, &three_method3);
|
||||||
|
auto fake41 = spy::fake(spy41, &one_method4);
|
||||||
|
auto fake42 = spy::fake(spy42, &two_method4);
|
||||||
|
auto fake43 = spy::fake(spy43, &three_method4);
|
||||||
|
One* one = new One;
|
||||||
|
Two* two = new Two;
|
||||||
|
Three* three = new Three;
|
||||||
|
Four* four = new Four;
|
||||||
|
one->one_method();
|
||||||
|
two->one_method();
|
||||||
|
two->two_method();
|
||||||
|
three->one_method();
|
||||||
|
three->three_method();
|
||||||
|
four->one_method();
|
||||||
|
four->two_method();
|
||||||
|
four->three_method();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue