- 如何获取原函数的地址(addr_pri.h、addr_any.h)
- 如何用桩函数替换原函数(stub.h)
-
支持的操作系统 :
- Windows
- Linux
- MacOS —— 同时支持 Intel (x86-64) 与 Apple Silicon (arm64)。由于 macOS
对
__TEXT段施加 W^X 限制,并且mprotect不能超过段的maxprot, 使用 cpp-stub 的每个可执行文件都需要在链接后做一次小处理(把__TEXT.maxprot抬到rwx并 ad-hoc 重新签名,见 issue #49)。 本仓库提供了构建系统集成助手,下游通常不需要手动调用任何脚本。 详见下文的 macOS 集成说明。
-
支持的硬件平台 :
- x86
- x86-64
- arm32
- arm64
- arm thumb
- riscv32
- riscv64
- loongarch64
- mips64
- ppc64 (由chatgpt 生成,需要验证)
- s390x (由chatgpt 生成,需要验证)
- alpha (由chatgpt 生成,需要验证)
- sparc (由chatgpt 生成,需要验证)
- sw_64 (由chatgpt 生成,需要验证n)
-
支持的编译器 :
- msvc
- gcc
- clang
-
支持函数类型:
- 常规函数
- 可变参函数
- 模板函数
- 重载函数
- lambda函数
- 静态函数(使用 addr_any.h)
- 内联函数(通过编译选项)
- 类的构造函数
- 类的析构函数
- 类的成员函数
- 类的静态成员函数
- 类的成员虚函数(非纯虚函数)
- 类的虚函数并且重载
- 仿函数
- 类的私有成员函数(使用 addr_pri.h)
- 类的私有成员函数(cpp17)
- 动态库里的函数(使用 dlsym()获取)
- 不能对 exit 函数打桩(部分系统调用)
- 不能对纯虚函数打桩, 纯虚函数没有地址
- 不能对 lambda 函数打桩, lambda 函数获取不到地址(但可以尝试使用 addr_any.h 接口获取地址)
- 不能对静态函数打桩, 静态函数地址不可见.(但可以尝试使用 addr_any.h 接口获取地址)
- -fno-access-control
- -fno-inline
- -Wno-pmf-conversions
- -Wl,--allow-multiple-definition
- -no-pie -fno-stack-protector
- -fprofile-arcs
- -ftest-coverage
macOS 下每个使用 cpp-stub 的可执行文件都需要在链接完成后做一次小处理:
把 __TEXT.maxprot 抬到 rwx,并用 ad-hoc 重新签名。本仓库自带构建系统
助手帮你自动做这件事;Linux / Windows 下这些助手是空操作。
add_subdirectory(third_party/cpp-stub)
add_executable(my_test test.cpp)
target_link_libraries(my_test PRIVATE cpp-stub)仓库根部的 CMakeLists.txt 会注册一个 deferred hook:在配置阶段结束时
遍历所有 executable,对每个直接链接 cpp-stub 的目标自动挂 POST_BUILD
步骤。只有当可执行文件通过中间静态库间接链接 cpp-stub 时,才需要
显式调用:
cpp_stub_enable(my_test)CPP_STUB_DIR := third_party/cpp-stub
include $(CPP_STUB_DIR)/mk/cpp-stub.mk
my_test: my_test.cpp
$(CXX) $(addprefix -I,$(CPP_STUB_INCLUDE)) ... -o $@ $<
@$(CPP_STUB_POSTLINK)$(CPP_STUB_POSTLINK) 在 macOS 上展开为 enable-stub 命令,
在 Linux/Windows 上展开为空操作 (:),同一份 Makefile 跨平台可用。
加一条 run-script / genrule,对每个可执行文件调一次:
third_party/cpp-stub/tool/macos_enable_stub.sh "$TARGET_BUILD_DIR/$EXECUTABLE_PATH"参见 issue #49 以及
src/stub.h 的 __APPLE__ 分支:内核不允许
mprotect/mach_vm_protect 把 __TEXT 的权限提升到 Mach-O 里
maxprot 之上,而 Apple Silicon 还在页表层面强制 W^X。
tool/macos_enable_stub.sh 负责把 maxprot 抬到 rwx,这样
cpp-stub 运行时才能通过 mach_vm_remap 拿到 __TEXT 的可写别名。
lcov -d build/ -z
lcov -d build/ -b ../../src1 --no-external -rc lcov_branch_coverage=1 -t ut -c -o ut_1.info
lcov -d build/ -b ../../src2 --no-external -rc lcov_branch_coverage=1 -t ut -c -o ut_2.info
lcov -a ut_1.info -a ut_2.info -o ut.info
genhtml -o report/ --prefix=`pwd` --branch-coverage --function-coverage ut.info
OpenCppCoverage.exe --sources MySourcePath* -- YourProgram.exe arg1 arg2
Stub stub
stub.set(addr, addr_stub)
stub.reset(addr)
Declaration:
ACCESS_PRIVATE_FIELD(ClassName, TypeName, FieldName)
ACCESS_PRIVATE_FUN(ClassName, TypeName, FunName)
ACCESS_PRIVATE_STATIC_FIELD(ClassName, TypeName, FieldName)
ACCESS_PRIVATE_STATIC_FUN(ClassName, TypeName, FunName)
Use:
access_private_field::ClassNameFieldName(object);
access_private_static_field::ClassName::ClassNameFieldName();
call_private_fun::ClassNameFunName(object,parameters...);
call_private_static_fun::ClassName::ClassNameFunName(parameters...);
get_private_fun::ClassNameFunName();
get_private_static_fun::ClassName::ClassNameFunName();
AddrAny any //for exe
AddrAny any(libname) //for lib
int get_local_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
int get_global_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map<std::string,void*>& result)
int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map<std::string,void*>& result)
int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map<std::string,void*>& result)
AddrAny any //for all
int get_func_addr(std::string func_name, std::map<std::string,void*>& result)
没实现