cmake_policy(SET CMP0054 NEW) set(positional) set(afterSeparator FALSE) math(EXPR lastArgument "${CMAKE_ARGC} - 1") foreach(index RANGE 0 ${lastArgument}) if(afterSeparator) list(APPEND positional "${CMAKE_ARGV${index}}") elseif("${CMAKE_ARGV${index}}" STREQUAL "--") set(afterSeparator TRUE) endif() endforeach() list(LENGTH positional positionalCount) if(NOT positionalCount EQUAL 3) message(FATAL_ERROR "Expected owner, HTTP client and AvPlayer test executables after --") endif() list(GET positional 0 OWNER_TEST) list(GET positional 1 CLIENT_TEST) list(GET positional 2 PLAYER_TEST) foreach(required PYTHON SERVER PATCHER OWNER_TEST CLIENT_TEST PLAYER_TEST LIBC KERNEL INTERNAL HTTP AVPLAYER NATIVE OBJDUMP WORK_DIR) if(NOT DEFINED ${required} OR "${${required}}" STREQUAL "") message(FATAL_ERROR "Missing ${required}") endif() endforeach() set(httpNids Xa86mkDT770 FcAd67QjrVw T+Un3eukNLs mh7PrvIiVtk WN6ypk6qEnU T8if7aGBDYs 7EfcZqAehgI M3Qx8MdigHk) string(RANDOM LENGTH 16 ALPHABET abcdef0123456789 stageId) set(stage "${WORK_DIR}/run-${stageId}") file(MAKE_DIRECTORY "${stage}") execute_process(COMMAND "${PATCHER}" --write-export-list "${LIBC}" "${stage}/libc.exports" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Normal libc export listing failed: ${output}${error}") endif() message("${output}${error}") set(moduleNames libc libkernel libSceLibcInternal libSceHttp libSceAvPlayer libSceAvPlayer.native) set(moduleVariables LIBC KERNEL INTERNAL HTTP AVPLAYER NATIVE) foreach(index RANGE 0 5) list(GET moduleNames ${index} module) list(GET moduleVariables ${index} variable) file(COPY_FILE "${${variable}}" "${stage}/${module}.prx") if(module STREQUAL "libc") execute_process(COMMAND "${PATCHER}" "${module}" "${stage}/${module}.prx" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) else() execute_process(COMMAND "${PATCHER}" "${module}" --preserve-export-list "${stage}/libc.exports" "${stage}/${module}.prx" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) endif() if(NOT status STREQUAL "0") message(FATAL_ERROR "Normal ${module} patching failed: ${output}${error}") endif() message("${output}${error}") endforeach() if(WIN32 AND DEFINED ALLOCATOR_DIRECTORY) foreach(allocator mimalloc.dll mimalloc-redirect.dll) file(COPY_FILE "${ALLOCATOR_DIRECTORY}/${allocator}" "${stage}/${allocator}") endforeach() execute_process(COMMAND "${IMPORT_FIRST}" "${stage}/mimalloc.dll" mimalloc-redirect.dll RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Normal allocator import ordering failed: ${output}${error}") endif() message("${output}${error}") endif() function(read_module file prefix) execute_process(COMMAND "${OBJDUMP}" -p "${file}" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Module import inspection failed: ${output}${error}") endif() set(${prefix}_header "${output}" PARENT_SCOPE) if(WIN32) string(FIND "${output}" "[Ordinal/Name Pointer] Table" exportsAt) if(exportsAt EQUAL -1) message(FATAL_ERROR "Missing PE export table in ${file}") endif() string(SUBSTRING "${output}" ${exportsAt} -1 exports) set(${prefix}_exports "${exports}" PARENT_SCOPE) else() execute_process(COMMAND "${OBJDUMP}" -T "${file}" RESULT_VARIABLE status OUTPUT_VARIABLE symbols ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Module symbol inspection failed: ${symbols}${error}") endif() set(${prefix}_symbols "${symbols}" PARENT_SCOPE) endif() endfunction() read_module("${stage}/libSceHttp.prx" http) foreach(module libSceAvPlayer libSceAvPlayer.native) read_module("${stage}/${module}.prx" player) if(WIN32) set(httpImports) set(inHttp FALSE) string(REPLACE "\n" ";" importLines "${player_header}") foreach(line IN LISTS importLines) string(STRIP "${line}" line) if(line MATCHES "^DLL Name: (.+)$") if(CMAKE_MATCH_1 STREQUAL "libSceHttp.prx") set(inHttp TRUE) else() set(inHttp FALSE) endif() elseif(line MATCHES "^The Export Tables") set(inHttp FALSE) elseif(inHttp) string(APPEND httpImports "${line}\n") endif() endforeach() foreach(nid IN LISTS httpNids) string(FIND "${httpImports}" "${nid}" importAt) string(FIND "${http_exports}" "${nid}" providerAt) string(FIND "${player_exports}" "${nid}" playerAt) if(importAt EQUAL -1 OR providerAt EQUAL -1 OR NOT playerAt EQUAL -1) message(FATAL_ERROR "Incorrect patched HTTP import/provider ${nid} in ${module}") endif() endforeach() else() if(NOT player_header MATCHES "NEEDED[ \t]+libSceHttp\\.prx") message(FATAL_ERROR "${module} has no dynamic libSceHttp dependency") endif() string(REPLACE "\n" ";" playerLines "${player_symbols}") string(REPLACE "\n" ";" providerLines "${http_symbols}") foreach(nid IN LISTS httpNids) set(importFound FALSE) set(providerFound FALSE) foreach(line IN LISTS playerLines) string(FIND "${line}" "${nid}" nameAt) if(NOT nameAt EQUAL -1) string(FIND "${line}" "*UND*" undefinedAt) if(undefinedAt EQUAL -1) message(FATAL_ERROR "HTTP helper ${nid} is defined in ${module}") endif() set(importFound TRUE) endif() endforeach() foreach(line IN LISTS providerLines) string(FIND "${line}" "${nid}" nameAt) string(FIND "${line}" "*UND*" undefinedAt) if(NOT nameAt EQUAL -1 AND undefinedAt EQUAL -1) set(providerFound TRUE) endif() endforeach() if(NOT importFound OR NOT providerFound) message(FATAL_ERROR "Incorrect patched HTTP import/provider ${nid} in ${module}") endif() endforeach() endif() endforeach() foreach(kind OWNER CLIENT PLAYER) get_filename_component(name "${${kind}_TEST}" NAME) file(COPY_FILE "${${kind}_TEST}" "${stage}/${name}") set(${kind}_COPY "${stage}/${name}") if(NOT kind STREQUAL "OWNER") execute_process(COMMAND "${PATCHER}" --exec --only-sce "${stage}/${name}" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Test import patching failed: ${output}${error}") endif() endif() endforeach() if(WIN32) set(libraryEnvironment "PATH=${stage};$ENV{PATH}") else() set(libraryEnvironment "LD_LIBRARY_PATH=${stage}:$ENV{LD_LIBRARY_PATH}") endif() foreach(module libSceAvPlayer libSceAvPlayer.native) execute_process(COMMAND "${CMAKE_COMMAND}" -E env "${libraryEnvironment}" "${OWNER_COPY}" "${stage}" "${module}.prx" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Patched module ownership failed: ${output}${error}") endif() message("${output}${error}") endforeach() file(MAKE_DIRECTORY "${stage}/client" "${stage}/player") execute_process(COMMAND "${CMAKE_COMMAND}" -E env "${libraryEnvironment}" "${PYTHON}" "${SERVER}" "${CLIENT_COPY}" client WORKING_DIRECTORY "${stage}/client" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Patched HTTP client behavior failed: ${output}${error}") endif() message("${output}${error}") execute_process(COMMAND "${CMAKE_COMMAND}" -E env "${libraryEnvironment}" "${PYTHON}" "${SERVER}" "${PLAYER_COPY}" WORKING_DIRECTORY "${stage}/player" RESULT_VARIABLE status OUTPUT_VARIABLE output ERROR_VARIABLE error) if(NOT status STREQUAL "0") message(FATAL_ERROR "Patched AvPlayer HTTP behavior failed: ${output}${error}") endif() message("${output}${error}") message(STATUS "Patched HTTP stage ${stage}")