c++ 单元测试中的打桩

2023-02-17  本文已影响0人  呆呆的张先生

gmock

借助于C++运行时多态实现,派生需要打桩的类,使用桩函数覆盖原来的实现,将指向原类的指针指向桩类

mockcpp

// src/UnixCodeModifier.cpp
bool CodeModifier::modify(void *dest, const void *src, size_t size)
{
    // 将 TEXT 段访问权限修改从 x 修改为 rwx
    if(::mprotect(ALIGN_TO_PAGE_BOUNDARY(dest), PAGE_SIZE * 2, PROT_EXEC | PROT_WRITE | PROT_READ ) != 0)
    {
       return false;
    }
    ::memcpy(dest, src, size);
}
// src/JmpCodeX86.h, 相对跳转指令
const unsigned char jmpCodeTemplate[]  = { 0xE9, 0x00, 0x00, 0x00, 0x00 };
#define SET_JMP_CODE(base, from, to) do { \
        *(unsigned long*)(base + 1) = \
            (unsigned long)to - (unsigned long)from - sizeof(jmpCodeTemplate); \
   } while(0)
//  src/JmpCodeX64.h 绝对跳转指令
// FF 25 : JMP /4   jmp absolute indirect
// bytes 2 ~ 5 : operand of jmp, relative to the memory that recorded the thunk addr. it should be zero.
// bytes 6 ~ 13 : the absolute addr of thunk.
const unsigned char jmpCodeTemplate[]  =
   { 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

#define SET_JMP_CODE(base, from, to) do { \
       *(uintptr_t *)(base + 6) = (uintptr_t)to; \
   } while(0)

mockcpp打桩c++成员函数

gtest+mockcpp,修改mockcpp以支持C++中类成员函数的mock_XiaoH0_0的博客-CSDN博客_mocker_cpp_virtual

通过成员函数指针获取成员函数的存储位置,然后使用 mockcpp 的打桩机制,将成员函数的入口替换为跳转到桩函数的跳转指令

探究C++中的成员函数指针和虚函数表


class A
{
    public:
        A(int a): a(a) { cnt++; }
        virtual ~A() {}

        string _A() { return "in A"; }

        virtual string str()
        {
            stringstream ss;
            ss << a;
            return ss.str();
        }

        static int getCnt() { return cnt; }
    protected:
        int a;
        static int cnt;
};

int A::cnt = 0;

class B : public A
{
    public:
        B(int a): A(a) {}
        virtual ~B() {}

        string _B() { return "in B"; }

        virtual string str()
        {
            stringstream ss;
            ss << "0x" << std::hex << a << std::dec;
            return ss.str();
        }
};
int main()
{
    A a(1);
    B b(2);

    // 静态成员函数的函数指针, 可以认为是普通的函数指针
    int (*pgetCnt)() = &A::getCnt;
    36f9:       48 8d 05 b7 09 00 00    lea    0x9b7(%rip),%rax        # 40b7 <_ZN1A6getCntEv>
    3700:       48 89 85 50 ff ff ff    mov    %rax,-0xb0(%rbp)
    // 非 virtual 的成员函数
    string (A::*p_A)() = &A::_A;
    3707:       48 8d 05 4a 08 00 00    lea    0x84a(%rip),%rax        # 3f58 <_ZN1A2_AB5cxx11Ev>
    370e:       48 89 45 80             mov    %rax,-0x80(%rbp)
    3712:       48 c7 45 88 00 00 00    movq   $0x0,-0x78(%rbp)
    3719:       00

    // virtual 的成员函数
    string (A::*p_Astr)() = &A::str;
    3747:       48 c7 45 80 11 00 00    movq   $0x11,-0x80(%rbp)
    374e:       00
    374f:       48 c7 45 88 00 00 00    movq   $0x0,-0x78(%rbp)
    3756:       00
    string (B::*p_Bstr)() = &B::str;
    3757:       48 c7 45 90 11 00 00    movq   $0x11,-0x70(%rbp)
    375e:       00
    375f:       48 c7 45 98 00 00 00    movq   $0x0,-0x68(%rbp)
    ((&b)->*p_Astr)();
    3767:       48 8b 45 88             mov    -0x78(%rbp),%rax
    376b:       48 89 c2                mov    %rax,%rdx
    376e:       48 8d 85 50 ff ff ff    lea    -0xb0(%rbp),%rax
    3775:       48 8d 0c 10             lea    (%rax,%rdx,1),%rcx
    3779:       48 8b 45 80             mov    -0x80(%rbp),%rax
    377d:       83 e0 01                and    $0x1,%eax
    3780:       48 85 c0                test   %rax,%rax
    3783:       74 24                   je     37a9 <main+0xf7>
    3785:       48 8b 45 88             mov    -0x78(%rbp),%rax
    3789:       48 89 c2                mov    %rax,%rdx
    378c:       48 8d 85 50 ff ff ff    lea    -0xb0(%rbp),%rax
    3793:       48 01 d0                add    %rdx,%rax
    3796:       48 8b 00                mov    (%rax),%rax
    3799:       48 8b 55 80             mov    -0x80(%rbp),%rdx
    379d:       48 83 ea 01             sub    $0x1,%rdx
    37a1:       48 01 d0                add    %rdx,%rax
    37a4:       48 8b 00                mov    (%rax),%rax
    37a7:       eb 04                   jmp    37ad <main+0xfb>
    37a9:       48 8b 45 80             mov    -0x80(%rbp),%rax
    37ad:       48 8d 55 a0             lea    -0x60(%rbp),%rdx
    37b1:       48 89 ce                mov    %rcx,%rsi
    37b4:       48 89 d7                mov    %rdx,%rdi
    37b7:       ff d0                   callq  *%rax
    37b9:       48 8d 45 a0             lea    -0x60(%rbp),%rax
    37bd:       48 89 c7                mov    %rax,%rdi
    37c0:       e8 0b fb ff ff          callq  32d0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@plt>
    ((&a)->*p_Astr)();
    37c5:       48 8b 45 88             mov    -0x78(%rbp),%rax
    37c9:       48 89 c2                mov    %rax,%rdx
    37cc:       48 8d 85 40 ff ff ff    lea    -0xc0(%rbp),%rax
    37d3:       48 8d 0c 10             lea    (%rax,%rdx,1),%rcx
    37d7:       48 8b 45 80             mov    -0x80(%rbp),%rax
    37db:       83 e0 01                and    $0x1,%eax
    37de:       48 85 c0                test   %rax,%rax
    37e1:       74 24                   je     3807 <main+0x155>
    37e3:       48 8b 45 88             mov    -0x78(%rbp),%rax
    37e7:       48 89 c2                mov    %rax,%rdx
    37ea:       48 8d 85 40 ff ff ff    lea    -0xc0(%rbp),%rax
    37f1:       48 01 d0                add    %rdx,%rax
    37f4:       48 8b 00                mov    (%rax),%rax
    37f7:       48 8b 55 80             mov    -0x80(%rbp),%rdx
    37fb:       48 83 ea 01             sub    $0x1,%rdx
    37ff:       48 01 d0                add    %rdx,%rax
    3802:       48 8b 00                mov    (%rax),%rax
    3805:       eb 04                   jmp    380b <main+0x159>
    3807:       48 8b 45 80             mov    -0x80(%rbp),%rax
    380b:       48 8d 55 c0             lea    -0x40(%rbp),%rdx
    380f:       48 89 ce                mov    %rcx,%rsi
    3812:       48 89 d7                mov    %rdx,%rdi
    3815:       ff d0                   callq  *%rax
    3817:       48 8d 45 c0             lea    -0x40(%rbp),%rax
    381b:       48 89 c7                mov    %rax,%rdi
    381e:       e8 ad fa ff ff          callq  32d0 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev@plt>

    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读