MIT License

项目介绍

coolxv/cpp-stub 是一个托管在 GitHub 上的开源项目,主要使用 C++ 编写,采用 MIT License 许可证,目前获得 330 个 Star、95 次 Fork。

仓库全名
coolxv/cpp-stub
开源许可证
MIT License
Star 数
330
Fork 数
95
未关闭 Issue
17

README 摘要

中文|English Principle How to get the original function address (addrpri.h, addrany.h) How to replace the original function with stub function (stub.h) Supported Supported operating systems: [x] Windows [x] Linux [x] MacOS — both Intel (x86-64) and Apple Silicon (arm64). Because macOS enforces W^X on TEXT and caps mprotect at each segment's maxprot, every binary that uses cpp-stub needs a tiny post-link adjustment…

完整内容见 GitHub 原始 README 或本页 。

常见问题

cpp-stub 用什么语言开发?

主要使用 C++ 编写,采用 MIT License 许可证,目前有 330 个 Star。

cpp-stub 可以免费商用吗?

仓库采用 MIT License 许可证,可免费使用与修改,商业使用请遵守许可证条款(例如保留版权声明与许可声明)。

如何获取 cpp-stub 的源码?

可以直接克隆仓库:git clone https://github.com/coolxv/cpp-stub.git,默认分支为 master;安装与运行步骤见仓库 README。

cpp-stub 最近还在维护吗?

仓库最近一次更新为 2 周前,当前有 17 个未关闭 Issue;Star 数为 330,可作为社区活跃度的参考。

关于

GitHub 原始描述(英文)

Inline hook or detour without trampoline for C++ unit test

描述取自 GitHub 官方 API,保持仓库作者书写的原文。

简要分析

热度分
540
价值分
227
活跃状态
活跃

语言占比

C
C++
CMake
Makefile
Shell

Release

README

building and running workflow

中文|English

Principle

  • How to get the original function address (addr_pri.h, addr_any.h)
  • How to replace the original function with stub function (stub.h)

Supported

Description of the unit test

Cannot stub

  • Can’t stub the exit function, the compiler has made special optimizations.
  • Can’t stub pure virtual functions, pure virtual functions not have the address.
  • Can’t stub lambda functions, lambda functions not get the address.(You can try to use addr_any.h api.)
  • Can’t stub static functions, static function address is not visible.(You can try to use addr_any.h api.)

Unit test compilation option for linux g++

  • -fno-access-control
  • -fno-inline
  • -Wno-pmf-conversions
  • -Wl,–allow-multiple-definition
  • -no-pie -fno-stack-protector
  • -fprofile-arcs
  • -ftest-coverage

macOS integration

macOS requires every binary that uses cpp-stub to have its __TEXT segment’s maxprot lifted to rwx and be ad-hoc re-signed once, after link. The library ships helpers that wire this up for you; on Linux and Windows the same helpers do nothing.

CMake (zero manual steps)

add_subdirectory(third_party/cpp-stub)
add_executable(my_test test.cpp)
target_link_libraries(my_test PRIVATE cpp-stub)

The root CMakeLists.txt installs a deferred hook that finds every executable that links cpp-stub and automatically attaches the post-build patch step on Apple platforms. For the rare case where an executable only links cpp-stub transitively through a static library, call it explicitly:

cpp_stub_enable(my_test)

Makefile

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) expands to the enable-stub command on macOS and to a no-op (:) on Linux/Windows, so the same rule works cross-platform.

Xcode / Bazel / other

Add a run-script / genrule that invokes the helper once per built executable:

third_party/cpp-stub/tool/macos_enable_stub.sh "$TARGET_BUILD_DIR/$EXECUTABLE_PATH"

Why this step exists

See issue #49 and the __APPLE__ branch of src/stub.h for the full story: the kernel will not let mprotect/mach_vm_protect raise __TEXT above its Mach-O maxprot, and Apple Silicon further enforces W^X at the page-table level even when maxprot=rwx. tool/macos_enable_stub.sh raises maxprot so that cpp-stub can obtain a writable alias of __TEXT at runtime via mach_vm_remap.

Code coverage statistics for linux g++

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

Code coverage statistics for windows

OpenCppCoverage

OpenCppCoverage.exe --sources MySourcePath* -- YourProgram.exe arg1 arg2

Interface description

stub.h

Stub stub
stub.set(addr, addr_stub)
stub.reset(addr)

addr_pri.h

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();

addr_any.h(linux)

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)

addr_any.h(windows)

AddrAny any //for all
int get_func_addr(std::string func_name, std::map<std::string,void*>& result)

addr_any.h(darwin)

not implement

评论

暂无评论