/* SPDX-License-Identifier: GPL-3.0-or-later */ #include "probe.h" #include #include typedef struct fake_probe { size_t resolve_calls; size_t close_calls; size_t log_calls; int fail_open; int fail_lookup; int fail_close; int saw_address_text; } fake_probe; static int failures; #define CHECK(expression) \ do { \ if (!(expression)) { \ (void)fprintf(stderr, "%s:%d: check failed: %s\n", __FILE__, \ __LINE__, #expression); \ failures += 1; \ } \ } while (0) static int fake_open(void *userdata, const char *module_name) { fake_probe *probe = (fake_probe *)userdata; CHECK(strcmp(module_name, "libSceGnmDriver.sprx") == 0); return probe->fail_open != 0 ? -1 : 0; } static int fake_resolve(void *userdata, const char *symbol_name, int *present) { fake_probe *probe = (fake_probe *)userdata; probe->resolve_calls += 1u; if (probe->fail_lookup != 0) { return -1; } *present = strcmp(symbol_name, "sceGnmSubmitCommandBuffers") != 0 ? 1 : 0; return 0; } static int fake_close(void *userdata) { fake_probe *probe = (fake_probe *)userdata; probe->close_calls += 1u; return probe->fail_close != 0 ? -1 : 0; } static void fake_log(void *userdata, const char *line) { fake_probe *probe = (fake_probe *)userdata; probe->log_calls += 1u; if (strstr(line, "0x") != NULL) { probe->saw_address_text = 1; } } static chimera_gfx_probe_ops make_ops(fake_probe *probe) { chimera_gfx_probe_ops ops; ops.userdata = probe; ops.open_module = fake_open; ops.resolve_symbol = fake_resolve; ops.close_module = fake_close; ops.log_line = fake_log; return ops; } static void test_partial_success(void) { fake_probe probe = {0}; chimera_gfx_probe_ops ops = make_ops(&probe); chimera_gfx_probe_report report; CHECK(chimera_gfx_ps5_probe_symbols(&ops, &report) == CHIMERA_GFX_STATUS_OK); CHECK(report.symbol_count == 21u); CHECK(report.resolved_count == 20u); CHECK(report.module_opened == 0); CHECK(probe.resolve_calls == report.symbol_count); CHECK(probe.close_calls == 1u); CHECK(probe.log_calls == report.symbol_count + 3u); CHECK(probe.saw_address_text == 0); } static void test_fail_closed_paths(void) { fake_probe probe = {0}; chimera_gfx_probe_ops ops = make_ops(&probe); chimera_gfx_probe_report report; probe.fail_open = 1; CHECK(chimera_gfx_ps5_probe_symbols(&ops, &report) == CHIMERA_GFX_STATUS_BACKEND_UNAVAILABLE); CHECK(probe.resolve_calls == 0u); CHECK(probe.close_calls == 0u); probe = (fake_probe){0}; probe.fail_lookup = 1; ops = make_ops(&probe); CHECK(chimera_gfx_ps5_probe_symbols(&ops, &report) == CHIMERA_GFX_STATUS_INTERNAL_ERROR); CHECK(probe.resolve_calls == 1u); CHECK(probe.close_calls == 1u); probe = (fake_probe){0}; probe.fail_close = 1; ops = make_ops(&probe); CHECK(chimera_gfx_ps5_probe_symbols(&ops, &report) == CHIMERA_GFX_STATUS_INTERNAL_ERROR); CHECK(report.module_opened == 1); CHECK(probe.resolve_calls == report.symbol_count); CHECK(probe.close_calls == 1u); CHECK(chimera_gfx_ps5_probe_symbols(NULL, &report) == CHIMERA_GFX_STATUS_INVALID_ARGUMENT); } int main(void) { test_partial_success(); test_fail_closed_paths(); return failures == 0 ? 0 : 1; }