mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
feat(libSceLibreSsl): implement historical error strings and newest peeking
This commit is contained in:
1 parent
ca32e706e8
commit
562e68e6ae
16 files changed
+434
-43
No files matched your search
@@ -1,6 +1,9 @@
|
||||
[submodule "3rdparty/SDL2"]
|
||||
path = 3rdparty/SDL2
|
||||
url = https://github.com/libsdl-org/SDL.git
|
||||
[submodule "3rdparty/libressl-openbsd"]
|
||||
path = 3rdparty/libressl-openbsd
|
||||
url = https://github.com/libressl/openbsd.git
|
||||
[submodule "3rdparty/Vulkan-Headers"]
|
||||
path = 3rdparty/Vulkan-Headers
|
||||
url = https://github.com/KhronosGroup/Vulkan-Headers.git
|
||||
|
||||
+1
Submodule 3rdparty/libressl-openbsd added at 078b3d1df8.
@@ -186,6 +186,7 @@ foreach(LIB_DIR ${LIBS_DIRS})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
include(prx/libSceLibreSsl/ErrorQueue.cmake)
|
||||
target_link_libraries(libSceUsbStorageDialog PRIVATE libSceUserService)
|
||||
|
||||
if(APS5_ENABLE_TRACY)
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
add_library(libSceLibreSsl SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Error.cpp)
|
||||
target_include_directories(libSceLibreSsl PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceLibreSsl)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_libressl_error_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslError.cpp)
|
||||
target_include_directories(guest_libressl_error_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_libressl_error_tests PRIVATE libSceLibreSsl libc)
|
||||
configure_windows_unwind(guest_libressl_error_tests)
|
||||
add_test(NAME guest_libressl_error COMMAND guest_libressl_error_tests)
|
||||
set_tests_properties(guest_libressl_error PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_libressl_error PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,37 @@
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
set(libreSslSource ${PROJECT_SOURCE_DIR}/3rdparty/libressl-openbsd/src/lib/libcrypto)
|
||||
if(NOT EXISTS ${libreSslSource}/err/err.c)
|
||||
message(FATAL_ERROR "Initialize 3rdparty/libressl-openbsd with git submodule update --init")
|
||||
endif()
|
||||
file(GLOB_RECURSE libreSslStringSources CONFIGURE_DEPENDS ${libreSslSource}/*.h ${libreSslSource}/*.c)
|
||||
set(libreSslStrings ${CMAKE_CURRENT_BINARY_DIR}/prx/libSceLibreSsl/ErrorStrings.inc)
|
||||
add_custom_command(OUTPUT ${libreSslStrings}
|
||||
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/GenerateErrorStrings.py ${libreSslSource} ${libreSslStrings}
|
||||
DEPENDS ${CMAKE_CURRENT_LIST_DIR}/GenerateErrorStrings.py ${libreSslStringSources}
|
||||
VERBATIM)
|
||||
target_sources(libSceLibreSsl PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/Error.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/ErrorQueue.cpp ${libreSslStrings})
|
||||
target_include_directories(libSceLibreSsl PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/prx/libSceLibreSsl)
|
||||
target_link_libraries(libSceLibreSsl3 PRIVATE libSceLibreSsl)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_libressl_error_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslError.cpp)
|
||||
target_include_directories(guest_libressl_error_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_libressl_error_tests PRIVATE libSceLibreSsl libSceLibreSsl3)
|
||||
configure_windows_unwind(guest_libressl_error_tests)
|
||||
add_test(NAME guest_libressl_error COMMAND guest_libressl_error_tests)
|
||||
add_test_executable(guest_libressl_error_string_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslErrors.cpp)
|
||||
target_include_directories(guest_libressl_error_string_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_libressl_error_string_tests PRIVATE libSceLibreSsl libSceLibreSsl3)
|
||||
configure_windows_unwind(guest_libressl_error_string_tests)
|
||||
add_test(NAME guest_libressl_errors COMMAND guest_libressl_error_string_tests)
|
||||
add_test(NAME guest_libressl_free_strings COMMAND guest_libressl_error_string_tests free)
|
||||
add_test(NAME guest_libressl_free_strings_first COMMAND guest_libressl_error_string_tests free-first)
|
||||
set_tests_properties(guest_libressl_error guest_libressl_errors guest_libressl_free_strings
|
||||
guest_libressl_free_strings_first PROPERTIES TIMEOUT 15)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_libressl_error guest_libressl_errors guest_libressl_free_strings
|
||||
guest_libressl_free_strings_first PROPERTIES
|
||||
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "ErrorQueue.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
extern "C" int APS5_VABI strerror_r_nid_postfix(int error, char* buffer, std::size_t length);
|
||||
|
||||
namespace {
|
||||
struct ErrorString {
|
||||
std::uint32_t code;
|
||||
const char* text;
|
||||
};
|
||||
|
||||
#include "ErrorStrings.inc"
|
||||
|
||||
enum class StringState { Uninitialized, Loaded, Freed };
|
||||
std::atomic<StringState> stringState{StringState::Uninitialized};
|
||||
char errorBuffer[256];
|
||||
|
||||
constexpr std::uint64_t Pack(int library, int function, int reason) {
|
||||
return ((static_cast<std::uint64_t>(library) & 255) << 24) |
|
||||
((static_cast<std::uint64_t>(function) & 4095) << 12) |
|
||||
(static_cast<std::uint64_t>(reason) & 4095);
|
||||
}
|
||||
|
||||
const char* Lookup(std::uint32_t code) {
|
||||
const auto entry = std::lower_bound(std::begin(CryptoStrings), std::end(CryptoStrings), code,
|
||||
[](const ErrorString& value, std::uint32_t key) { return value.code < key; });
|
||||
return entry != std::end(CryptoStrings) && entry->code == code ? entry->text : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void LibreSslLoadErrorStrings_nid_no_patch() {
|
||||
auto expected = StringState::Uninitialized;
|
||||
stringState.compare_exchange_strong(expected, StringState::Loaded);
|
||||
}
|
||||
|
||||
char* APS5_VABI ERR_error_string_nid_postfix(std::uint64_t error, char* buffer) {
|
||||
if (buffer == nullptr) buffer = errorBuffer;
|
||||
ERR_error_string_n_nid_postfix(error, buffer, sizeof(errorBuffer));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void APS5_VABI ERR_error_string_n_nid_postfix(std::uint64_t error, char* buffer, std::size_t length) {
|
||||
if (buffer == nullptr && length != 0) NotImplemented_nid_no_patch(__func__);
|
||||
const int library = (error >> 24) & 255;
|
||||
const int function = (error >> 12) & 4095;
|
||||
const int reason = error & 4095;
|
||||
LibreSslLoadErrorStrings_nid_no_patch();
|
||||
const bool loaded = stringState.load() == StringState::Loaded;
|
||||
const char* libraryText = loaded ? Lookup(static_cast<std::uint32_t>(Pack(library, 0, 0))) : nullptr;
|
||||
const char* functionText = loaded ? Lookup(static_cast<std::uint32_t>(Pack(library, function, 0))) : nullptr;
|
||||
const char* reasonText = loaded ? Lookup(static_cast<std::uint32_t>(Pack(library, 0, reason))) : nullptr;
|
||||
char libraryBuffer[30];
|
||||
char functionBuffer[30];
|
||||
char reasonBuffer[32];
|
||||
if (loaded && library == 2 && reason >= 1 && reason <= 127) {
|
||||
char message[128];
|
||||
strerror_r_nid_postfix(reason, message, sizeof(message));
|
||||
std::memcpy(reasonBuffer, message, std::min(std::strlen(message) + 1, sizeof(reasonBuffer)));
|
||||
reasonBuffer[sizeof(reasonBuffer) - 1] = '\0';
|
||||
reasonText = reasonBuffer;
|
||||
}
|
||||
if (reasonText == nullptr && loaded) reasonText = Lookup(reason);
|
||||
if (libraryText == nullptr) {
|
||||
std::snprintf(libraryBuffer, sizeof(libraryBuffer), "lib(%d)", library);
|
||||
libraryText = libraryBuffer;
|
||||
}
|
||||
if (functionText == nullptr) {
|
||||
std::snprintf(functionBuffer, sizeof(functionBuffer), "func(%d)", function);
|
||||
functionText = functionBuffer;
|
||||
}
|
||||
if (reasonText == nullptr) {
|
||||
std::snprintf(reasonBuffer, sizeof(reasonBuffer), "reason(%d)", reason);
|
||||
reasonText = reasonBuffer;
|
||||
}
|
||||
const int written = std::snprintf(buffer, length, "error:%08llX:%s:%s:%s",
|
||||
static_cast<unsigned long long>(error), libraryText, functionText, reasonText);
|
||||
if (written >= 0 && static_cast<std::size_t>(written) >= length && length > 4) {
|
||||
char* next = buffer;
|
||||
for (std::size_t index = 0; index < 4; ++index) {
|
||||
char* colon = std::strchr(next, ':');
|
||||
char* last = buffer + length - 5 + index;
|
||||
if (colon == nullptr || colon > last) {
|
||||
colon = last;
|
||||
*colon = ':';
|
||||
}
|
||||
next = colon + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void APS5_VABI ERR_free_strings_nid_postfix() {
|
||||
LibreSslLoadErrorStrings_nid_no_patch();
|
||||
stringState.store(StringState::Freed);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CORE_LIBS_PRX_LIBSCELIBRESSL_ERRORQUEUE_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCELIBRESSL_ERRORQUEUE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "include/Error.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
|
||||
extern "C" {
|
||||
std::uint64_t LibreSslPeekLastError_nid_no_patch();
|
||||
void LibreSslLoadErrorStrings_nid_no_patch();
|
||||
|
||||
void APS5_VABI ERR_clear_error_nid_postfix();
|
||||
char* APS5_VABI ERR_error_string_nid_postfix(std::uint64_t error, char* buffer);
|
||||
void APS5_VABI ERR_error_string_n_nid_postfix(std::uint64_t error, char* buffer, std::size_t length);
|
||||
void APS5_VABI ERR_free_strings_nid_postfix();
|
||||
std::uint64_t APS5_VABI ERR_get_error_nid_postfix();
|
||||
std::uint64_t APS5_VABI ERR_peek_error_nid_postfix();
|
||||
void APS5_VABI ERR_remove_thread_state_nid_postfix(const void* id);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -506,21 +506,6 @@ int APS5_VABI ENGINE_set_default_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_error_string_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_error_string_n_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_free_strings_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI EVP_CIPHER_CTX_cleanup_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import ast
|
||||
import json
|
||||
import operator
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
source = Path(sys.argv[1])
|
||||
destination = Path(sys.argv[2])
|
||||
macros = {}
|
||||
operations = {ast.BitOr: operator.or_, ast.BitAnd: operator.and_, ast.LShift: operator.lshift,
|
||||
ast.RShift: operator.rshift, ast.Add: operator.add, ast.Sub: operator.sub}
|
||||
|
||||
|
||||
def uncomment(text):
|
||||
return re.sub(r"/\*.*?\*/", "", text, flags=re.S)
|
||||
|
||||
|
||||
for header in sorted(source.rglob("*.h")):
|
||||
for name, value in re.findall(r"^#\s*define\s+(\w+)\s+([^\n]+)", uncomment(header.read_text(encoding="utf-8")), re.M):
|
||||
if re.fullmatch(r"ERR_(?:LIB|R)_\w+|\w+_[RF]_\w+", name):
|
||||
if name in macros and macros[name] != value.strip():
|
||||
raise ValueError(f"Conflicting definition: {name}")
|
||||
macros[name] = value.strip()
|
||||
|
||||
|
||||
def evaluate(expression):
|
||||
def visit(node):
|
||||
if isinstance(node, ast.Constant) and type(node.value) is int:
|
||||
return node.value
|
||||
if isinstance(node, ast.Name):
|
||||
return evaluate(macros[node.id])
|
||||
if isinstance(node, ast.BinOp) and type(node.op) in operations:
|
||||
return operations[type(node.op)](visit(node.left), visit(node.right))
|
||||
raise ValueError(f"Unsupported constant: {expression}")
|
||||
return visit(ast.parse(expression, mode="eval").body)
|
||||
|
||||
|
||||
def pack(library, function, reason):
|
||||
return ((library & 255) << 24) | ((function & 4095) << 12) | (reason & 4095)
|
||||
|
||||
|
||||
def code(expression, library):
|
||||
call = re.fullmatch(r"ERR_(PACK|FUNC|REASON)\((.*)\)", expression.strip())
|
||||
if call:
|
||||
values = [evaluate(value.strip()) for value in call[2].split(",")]
|
||||
if call[1] == "PACK":
|
||||
return pack(*values)
|
||||
if call[1] == "FUNC":
|
||||
return pack(library, values[0], 0)
|
||||
return pack(library, 0, values[0])
|
||||
return evaluate(expression.strip())
|
||||
|
||||
|
||||
loader = uncomment((source / "err/err_all.c").read_text(encoding="utf-8"))
|
||||
loaded = set(re.findall(r"\bERR_load_(\w+)_strings\(\);", loader)) - {"ERR"}
|
||||
strings = {}
|
||||
licenses = []
|
||||
found = set()
|
||||
for path in sorted(source.rglob("*.c")):
|
||||
text = path.read_text(encoding="latin-1")
|
||||
clean = uncomment(text)
|
||||
library = 0
|
||||
if path != source / "err/err.c":
|
||||
names = set(re.findall(r"\bERR_load_(\w+)_strings\(void\)", clean)) & loaded
|
||||
if not names:
|
||||
continue
|
||||
found.update(names)
|
||||
library_name = re.search(r"#define ERR_FUNC\(func\)\s+ERR_PACK\((\w+),", clean)
|
||||
if not library_name:
|
||||
raise ValueError(f"Missing library: {path}")
|
||||
library = evaluate(library_name[1])
|
||||
licenses.append(text[:text.index("#include")])
|
||||
tables = re.findall(r"static ERR_STRING_DATA (\w+)\[\]\s*=\s*\{(.*?)\n\};", clean, re.S)
|
||||
if not tables:
|
||||
raise ValueError(f"Missing string tables: {path}")
|
||||
for name, body in tables:
|
||||
entries = re.findall(r'\{\s*([^{}]+?),\s*("(?:[^"\\]|\\.)*"|NULL)\s*\}', body, re.S)
|
||||
remainder = re.sub(r'\{\s*([^{}]+?),\s*("(?:[^"\\]|\\.)*"|NULL)\s*\}', "", body, flags=re.S)
|
||||
if remainder.strip(" \t\r\n,"):
|
||||
raise ValueError(f"Unsupported table: {path}: {name}")
|
||||
for expression, message in entries:
|
||||
value = code(expression, library)
|
||||
if value == 0 and message == "NULL":
|
||||
continue
|
||||
if message == "NULL":
|
||||
raise ValueError(f"Missing message: {path}: {expression}")
|
||||
if name == "ERR_str_functs":
|
||||
value |= pack(evaluate("ERR_LIB_SYS"), 0, 0)
|
||||
strings[value] = json.loads(message)
|
||||
if found != loaded:
|
||||
raise ValueError(f"Missing libraries: {loaded - found}")
|
||||
destination.parent.mkdir(parents=True, exist_ok=True)
|
||||
destination.write_text("\n".join(licenses) + "\nconstexpr ErrorString CryptoStrings[] = {\n" +
|
||||
"".join(f" {{0x{value:08X}, {json.dumps(message)}}},\n"
|
||||
for value, message in sorted(strings.items())) + "};\n", encoding="utf-8")
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
void LibreSslPutError_nid_no_patch(int library, int function, int reason);
|
||||
void LibreSslPutError_nid_no_patch(int library, int function, int reason, const char* file = nullptr, int line = 0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <array>
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include "prx/libSceLibreSsl/include/Error.hpp"
|
||||
@@ -9,6 +10,8 @@ constexpr int QueueSize = 16;
|
||||
|
||||
struct ErrorQueue {
|
||||
std::array<std::uint64_t, QueueSize> codes;
|
||||
std::array<const char*, QueueSize> files;
|
||||
std::array<int, QueueSize> lines;
|
||||
int top;
|
||||
int bottom;
|
||||
};
|
||||
@@ -24,6 +27,8 @@ std::uint64_t Oldest(bool remove) {
|
||||
if (remove) {
|
||||
queue.bottom = index;
|
||||
queue.codes[index] = 0;
|
||||
queue.files[index] = nullptr;
|
||||
queue.lines[index] = 0;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
@@ -35,12 +40,20 @@ void Clear() {
|
||||
|
||||
extern "C" {
|
||||
|
||||
void LibreSslPutError_nid_no_patch(int library, int function, int reason) {
|
||||
void LibreSslPutError_nid_no_patch(int library, int function, int reason, const char* file, int line) {
|
||||
const int savedError = errno;
|
||||
queue.top = (queue.top + 1) % QueueSize;
|
||||
if (queue.top == queue.bottom) queue.bottom = (queue.bottom + 1) % QueueSize;
|
||||
queue.codes[queue.top] = (static_cast<std::uint64_t>(library) & 0xff) << 24 |
|
||||
(static_cast<std::uint64_t>(function) & 0xfff) << 12 |
|
||||
(static_cast<std::uint64_t>(reason) & 0xfff);
|
||||
queue.files[queue.top] = file;
|
||||
queue.lines[queue.top] = line;
|
||||
errno = savedError;
|
||||
}
|
||||
|
||||
std::uint64_t LibreSslPeekLastError_nid_no_patch() {
|
||||
return queue.top == queue.bottom ? 0 : queue.codes[queue.top];
|
||||
}
|
||||
|
||||
std::uint64_t APS5_VABI ERR_get_error_nid_postfix() {
|
||||
@@ -56,7 +69,7 @@ void APS5_VABI ERR_clear_error_nid_postfix() {
|
||||
}
|
||||
|
||||
void APS5_VABI ERR_remove_thread_state_nid_postfix(const void* threadId) {
|
||||
if (threadId != nullptr) NotImplemented_nid_no_patch("ERR_remove_thread_state of a CRYPTO_THREADID");
|
||||
if (threadId != nullptr) NotImplemented_nid_no_patch(__func__);
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libSceLibreSsl/ErrorQueue.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
@@ -61,14 +62,12 @@ int APS5_VABI EC_KEY_up_ref_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_load_crypto_strings_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
void APS5_VABI ERR_load_crypto_strings_nid_postfix() {
|
||||
LibreSslLoadErrorStrings_nid_no_patch();
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_peek_last_error_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
std::uint64_t APS5_VABI ERR_peek_last_error_nid_postfix() {
|
||||
return LibreSslPeekLastError_nid_no_patch();
|
||||
}
|
||||
|
||||
int APS5_VABI ERR_print_errors_cb_nid_postfix(void) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include "prx/libSceLibreSsl/include/Error.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -10,7 +11,6 @@ std::uint64_t APS5_VABI ERR_get_error_nid_postfix();
|
||||
std::uint64_t APS5_VABI ERR_peek_error_nid_postfix();
|
||||
void APS5_VABI ERR_clear_error_nid_postfix();
|
||||
void APS5_VABI ERR_remove_thread_state_nid_postfix(const void*);
|
||||
void LibreSslPutError_nid_no_patch(int library, int function, int reason);
|
||||
}
|
||||
|
||||
static void Require(bool value, const char* what) {
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
#include "prx/libSceLibreSsl/ErrorQueue.hpp"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
extern "C" {
|
||||
void APS5_VABI ERR_load_crypto_strings_nid_postfix();
|
||||
std::uint64_t APS5_VABI ERR_peek_last_error_nid_postfix();
|
||||
int* APS5_VABI __error_nid_postfix();
|
||||
}
|
||||
|
||||
static void Require(bool value, const char* message) {
|
||||
if (value) return;
|
||||
std::fputs(message, stderr);
|
||||
std::fputc('\n', stderr);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
static void ExpectString(std::uint64_t code, const char* expected) {
|
||||
std::array<char, 256> buffer{};
|
||||
Require(ERR_error_string_nid_postfix(code, buffer.data()) == buffer.data(), "caller buffer returned");
|
||||
Require(std::strcmp(buffer.data(), expected) == 0, buffer.data());
|
||||
}
|
||||
|
||||
static void TestStrings() {
|
||||
ERR_load_crypto_strings_nid_postfix();
|
||||
ExpectString(0, "error:00000000:lib(0):func(0):reason(0)");
|
||||
ExpectString(0x20fff043, "error:20FFF043:BIO routines:CRYPTO_internal:passed a null parameter");
|
||||
ExpectString(0x20fff07e, "error:20FFF07E:BIO routines:CRYPTO_internal:write to read only BIO");
|
||||
ExpectString(0x03fff06c, "error:03FFF06C:bignum routines:CRYPTO_internal:no inverse");
|
||||
ExpectString(0xe1abc789, "error:E1ABC789:lib(225):func(2748):reason(1929)");
|
||||
ExpectString(0x12345678e1abc789, "error:12345678E1ABC789:lib(225):func(2748):reason(1929)");
|
||||
ExpectString(0x02002023, "error:02002023:system library:connect:Resource temporarily unavailabl");
|
||||
auto* shared = ERR_error_string_nid_postfix(0xe1abc789, nullptr);
|
||||
Require(shared != nullptr, "static buffer exists");
|
||||
Require(ERR_error_string_nid_postfix(0, nullptr) == shared, "static buffer reused");
|
||||
Require(std::strcmp(shared, "error:00000000:lib(0):func(0):reason(0)") == 0, "static buffer overwritten");
|
||||
constexpr auto expected = "error:E1ABC789:lib(225):func(2748):reason(1929)";
|
||||
for (std::size_t size = 0; size <= std::strlen(expected) + 2; ++size) {
|
||||
std::array<char, 260> buffer;
|
||||
buffer.fill('#');
|
||||
ERR_error_string_n_nid_postfix(0xe1abc789, buffer.data() + 1, size);
|
||||
Require(buffer.front() == '#' && buffer[size + 1] == '#', "bounded formatting canaries");
|
||||
if (size == 0) continue;
|
||||
const auto count = std::strlen(buffer.data() + 1);
|
||||
Require(count < size, "bounded formatting terminates");
|
||||
if (size > 4 && size <= std::strlen(expected)) {
|
||||
std::size_t colons = 0;
|
||||
for (std::size_t index = 1; index <= count; ++index) colons += buffer[index] == ':';
|
||||
Require(colons == 4, "truncation keeps four colons");
|
||||
}
|
||||
if (size > std::strlen(expected)) Require(std::strcmp(buffer.data() + 1, expected) == 0, "full bounded string");
|
||||
}
|
||||
char tiny[6]{};
|
||||
ERR_error_string_n_nid_postfix(0xe1abc789, tiny, sizeof(tiny));
|
||||
Require(std::strcmp(tiny, "e::::") == 0, "historical truncation placement");
|
||||
ERR_error_string_n_nid_postfix(0, nullptr, 0);
|
||||
}
|
||||
|
||||
static void TestQueue() {
|
||||
ERR_clear_error_nid_postfix();
|
||||
Require(ERR_get_error_nid_postfix() == 0 && ERR_peek_error_nid_postfix() == 0 &&
|
||||
ERR_peek_last_error_nid_postfix() == 0, "initially empty");
|
||||
auto* guestError = __error_nid_postfix();
|
||||
errno = EDOM;
|
||||
const int savedGuestError = *guestError;
|
||||
LibreSslPutError_nid_no_patch(32, 0xfff, 67, "producer", 19);
|
||||
Require(errno == EDOM, "publication preserves host errno");
|
||||
Require(*guestError == savedGuestError, "publication preserves guest errno");
|
||||
LibreSslPutError_nid_no_patch(3, 0xfff, 108, nullptr, 0);
|
||||
Require(ERR_peek_error_nid_postfix() == 0x20fff043 && ERR_peek_error_nid_postfix() == 0x20fff043, "peek oldest without removal");
|
||||
Require(ERR_peek_last_error_nid_postfix() == 0x03fff06c && ERR_peek_last_error_nid_postfix() == 0x03fff06c, "cross-library peek newest");
|
||||
Require(ERR_get_error_nid_postfix() == 0x20fff043 && ERR_get_error_nid_postfix() == 0x03fff06c, "FIFO removal");
|
||||
Require(ERR_get_error_nid_postfix() == 0 && ERR_peek_last_error_nid_postfix() == 0, "drained queue");
|
||||
LibreSslPutError_nid_no_patch(-1, -1, -1, nullptr, 0);
|
||||
Require(ERR_get_error_nid_postfix() == 0xffffffff, "pack masks negative fields");
|
||||
LibreSslPutError_nid_no_patch(0x132, 0x2345, 0x3456, nullptr, 0);
|
||||
Require(ERR_get_error_nid_postfix() == 0x32345456, "pack masks oversized fields");
|
||||
LibreSslPutError_nid_no_patch(0, 0, 0, nullptr, 0);
|
||||
LibreSslPutError_nid_no_patch(0, 0, 1, nullptr, 0);
|
||||
Require(ERR_get_error_nid_postfix() == 0 && ERR_get_error_nid_postfix() == 1, "zero code occupies a slot");
|
||||
for (int index = 1; index <= 100; ++index) LibreSslPutError_nid_no_patch(128, index, index, nullptr, index);
|
||||
for (std::uint64_t index = 86; index <= 100; ++index) {
|
||||
Require(ERR_get_error_nid_postfix() == (0x80000000 | (index << 12) | index), "retain newest fifteen after overflow");
|
||||
}
|
||||
Require(ERR_get_error_nid_postfix() == 0, "overflow queue drained");
|
||||
LibreSslPutError_nid_no_patch(3, 1, 2, nullptr, 0);
|
||||
ERR_clear_error_nid_postfix();
|
||||
Require(ERR_peek_error_nid_postfix() == 0 && ERR_peek_last_error_nid_postfix() == 0, "clear both queue ends");
|
||||
LibreSslPutError_nid_no_patch(32, 0xfff, 67, nullptr, 0);
|
||||
ERR_remove_thread_state_nid_postfix(nullptr);
|
||||
Require(ERR_get_error_nid_postfix() == 0, "remove current state");
|
||||
LibreSslPutError_nid_no_patch(32, 0xfff, 67, nullptr, 0);
|
||||
Require(ERR_get_error_nid_postfix() == 0x20fff043, "reuse after remove");
|
||||
}
|
||||
|
||||
static void TestThreads() {
|
||||
ERR_clear_error_nid_postfix();
|
||||
LibreSslPutError_nid_no_patch(128, 7, 19, nullptr, 0);
|
||||
std::atomic<int> ready{0};
|
||||
std::array<std::thread, 8> threads;
|
||||
for (std::size_t index = 0; index < threads.size(); ++index) {
|
||||
threads[index] = std::thread([&, index] {
|
||||
Require(ERR_get_error_nid_postfix() == 0, "new thread starts empty");
|
||||
LibreSslPutError_nid_no_patch(129, 0, static_cast<int>(index + 1), nullptr, 0);
|
||||
++ready;
|
||||
while (ready.load() != static_cast<int>(threads.size())) std::this_thread::yield();
|
||||
Require(ERR_peek_last_error_nid_postfix() == 0x81000001 + index, "thread-local newest");
|
||||
if (index % 2) ERR_clear_error_nid_postfix();
|
||||
else ERR_remove_thread_state_nid_postfix(nullptr);
|
||||
Require(ERR_get_error_nid_postfix() == 0, "thread-local cleanup");
|
||||
LibreSslPutError_nid_no_patch(130, 1, 3, nullptr, 0);
|
||||
});
|
||||
}
|
||||
for (auto& thread : threads) thread.join();
|
||||
Require(ERR_get_error_nid_postfix() == 0x80007013, "child queues leave parent unchanged");
|
||||
std::thread replacement([] { Require(ERR_get_error_nid_postfix() == 0, "no stale state after thread exit"); });
|
||||
replacement.join();
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc == 2) {
|
||||
if (std::strcmp(argv[1], "free") == 0) TestStrings();
|
||||
LibreSslPutError_nid_no_patch(32, 0xfff, 67, nullptr, 0);
|
||||
ERR_free_strings_nid_postfix();
|
||||
ERR_free_strings_nid_postfix();
|
||||
ERR_load_crypto_strings_nid_postfix();
|
||||
ExpectString(0x20fff043, "error:20FFF043:lib(32):func(4095):reason(67)");
|
||||
Require(ERR_get_error_nid_postfix() == 0x20fff043, "free strings preserves queue");
|
||||
return 0;
|
||||
}
|
||||
TestStrings();
|
||||
TestQueue();
|
||||
TestThreads();
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
# libSceLibreSsl technical debt
|
||||
|
||||
### Functional
|
||||
|
||||
- [ERR queues and strings](../../../core/libs/prx/libSceLibreSsl/ErrorQueue.cpp) have no PS5 equivalence verification. Contracts follow LibreSSL 3.4.1's [err.c](https://github.com/libressl/openbsd/blob/078b3d1df8ca2011c1605cd40418c58fa0f5b143/src/lib/libcrypto/err/err.c), err.h, crypto.h and err_all.c at that revision: LP64 error arguments/results, 15 queued errors and historical crypto strings. System reasons use guest libc's FreeBSD errno messages, truncated to 31 bytes; console wording is unverified. Explicit thread IDs in `ERR_remove_thread_state` throw because guest pthread identity mapping is unverified. Null IDs clear the calling thread. SSL-specific strings are not loaded; SSL initialization remains unimplemented.
|
||||
- [Error publication](../../../core/libs/prx/libSceLibreSsl/ErrorQueue.hpp) has no implemented production callers on this branch. BIOs and the digest, AES, allocator/RAND, DES, BIGNUM and EVP/HMAC work in pending branches require separate integration. `LibreSslPutError_nid_no_patch(int library, int function, int reason, const char* file, int line)` has C linkage and the native host calling convention, accepts upstream numeric fields and publishes to the calling thread's queue. Three-argument source calls default file/line to null/zero. It stores file/line without taking ownership; producers must supply a filename with static lifetime. Guest ERR entry points use `APS5_VABI`. Unsupported producer exports continue throwing; the local tests publish through this helper.
|
||||
|
||||
### Unknown function info
|
||||
|
||||
- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 395 named callable exports are listed in the [PS5 3.20 export table](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceLibreSsl.c) and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through `NotImplemented_nid_no_patch`.
|
||||
- [ERR_get_error, ERR_peek_error, ERR_clear_error, ERR_remove_thread_state](../../../core/libs/prx/libSceLibreSsl/src/Error.cpp) (libSceLibreSsl) - no export of this library adds an error yet, so the queue stays empty for guest code. The per-thread queue of 16 slots holding 15 codes, its order and the `ERR_PACK` layout follow LibreSSL's [err.c](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.c) and [err.h](https://github.com/libressl/openbsd/blob/bc9483725c5815efb64b6d9acc52fc5fba139212/src/lib/libcrypto/err/err.h); the module's LibreSSL version is unknown and nothing is checked on the console. The queue keeps no file, line or data, as no export reads them. `ERR_remove_thread_state` with a thread id throws: that version asserts a null id, while older versions remove the state of the thread the id names
|
||||
- [libSceLibreSsl pending exports](../../../core/libs/prx/libSceLibreSsl/Export.cpp) - 399 named callable exports are listed in the [PS5 3.20 export table](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceLibreSsl.c) and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through `NotImplemented_nid_no_patch`.
|
||||
@@ -1,5 +1,9 @@
|
||||
# libSceLibreSsl3 technical debt
|
||||
|
||||
### Functional
|
||||
|
||||
- [ERR_load_crypto_strings and ERR_peek_last_error](../../../core/libs/prx/libSceLibreSsl3/Export.cpp) share libSceLibreSsl's string registry and calling-thread queue. This relationship and PS5 equivalence are unverified; the public contracts follow LibreSSL 3.4.1 at OpenBSD commit `078b3d1df8ca2011c1605cd40418c58fa0f5b143`. `ERR_print_errors_cb` remains throwing: the public callback contract is known, but PS5 thread identifiers and diagnostic metadata have not been established.
|
||||
|
||||
### Unknown function info
|
||||
|
||||
- [libSceLibreSsl3 pending exports](../../../core/libs/prx/libSceLibreSsl3/Export.cpp) - 87 named callable exports are listed in the [PS5 3.20 export table](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceLibreSsl3.c) and were cross-checked against the same module in PS5 firmware 13.60. Their signatures and behaviour are unverified; the declarations use the no-parameter unknown-signature convention and throw through `NotImplemented_nid_no_patch`.
|
||||
Reference in new issue
Block a user