Skip to content

coolxv/cpp-stub

Repository files navigation

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

Packages

 
 
 

Contributors

Languages