Merge pull request #12105 from Jamiras/read_core_memory

add READ/WRITE_CORE_MEMORY network commands
This commit is contained in:
Autechre 2021-03-06 17:08:04 +01:00 committed by GitHub
commit d06bd7fffd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 151 additions and 2 deletions

View File

@ -10309,6 +10309,149 @@ static bool command_write_ram(const char *arg)
}
#endif
static const rarch_memory_descriptor_t* command_memory_get_descriptor(const rarch_memory_map_t* mmap, unsigned address)
{
const rarch_memory_descriptor_t* desc = mmap->descriptors;
const rarch_memory_descriptor_t* end = desc + mmap->num_descriptors;
for (; desc < end; desc++)
{
if (desc->core.select == 0)
{
/* if select is 0, attempt to explicitly match the address */
if (address >= desc->core.start && address < desc->core.start + desc->core.len)
return desc;
}
else
{
/* otherwise, attempt to match the address by matching the select bits */
if (((desc->core.start ^ address) & desc->core.select) == 0)
{
/* sanity check - make sure the descriptor is large enough to hold the target address */
if (address - desc->core.start < desc->core.len)
return desc;
}
}
}
return NULL;
}
static uint8_t* command_memory_get_pointer(unsigned address, unsigned int* max_bytes, int for_write, char* reply_at, size_t len)
{
const rarch_system_info_t* system = runloop_get_system_info();
if (!system || system->mmaps.num_descriptors == 0)
{
strlcpy(reply_at, " -1 no memory map defined\n", len);
}
else
{
const rarch_memory_descriptor_t* desc = command_memory_get_descriptor(&system->mmaps, address);
if (!desc)
{
strlcpy(reply_at, " -1 no descriptor for address\n", len);
}
else if (!desc->core.ptr)
{
strlcpy(reply_at, " -1 no data for descriptor\n", len);
}
else if (for_write && (desc->core.flags & RETRO_MEMDESC_CONST))
{
strlcpy(reply_at, " -1 descriptor data is readonly\n", len);
}
else
{
const size_t offset = address - desc->core.start;
*max_bytes = (desc->core.len - offset);
return (uint8_t*)desc->core.ptr + desc->core.offset + offset;
}
}
*max_bytes = 0;
return NULL;
}
static bool command_read_memory(const char *arg)
{
char* reply = NULL;
char* reply_at = NULL;
const uint8_t* data = NULL;
unsigned int nbytes = 0;
unsigned int alloc_size = 0;
unsigned int address = -1;
unsigned int len = 0;
struct rarch_state *p_rarch = &rarch_st;
unsigned int max_bytes = 0;
unsigned i;
if (sscanf(arg, "%x %u", &address, &nbytes) != 2)
return false;
/* Ensure large enough to return all requested bytes or an error message */
alloc_size = 64 + nbytes * 3;
reply = (char*)malloc(alloc_size);
reply_at = reply + snprintf(reply, alloc_size - 1, "READ_CORE_MEMORY %x", address);
data = command_memory_get_pointer(address, &max_bytes, 0, reply_at, alloc_size - strlen(reply));
if (data)
{
if (nbytes > max_bytes)
nbytes = max_bytes;
for (i = 0; i < nbytes; i++)
snprintf(reply_at + 3 * i, 4, " %02X", data[i]);
reply_at[3 * nbytes] = '\n';
len = reply_at + 3 * nbytes + 1 - reply;
}
else
{
len = strlen(reply);
}
command_reply(p_rarch, reply, len);
free(reply);
return true;
}
static bool command_write_memory(const char *arg)
{
unsigned int address = (unsigned int)strtoul(arg, (char**)&arg, 16);
uint8_t* data = NULL;
unsigned int max_bytes = 0;
struct rarch_state *p_rarch = &rarch_st;
char reply[128] = "";
char* reply_at = NULL;
reply_at = reply + snprintf(reply, sizeof(reply) - 1, "WRITE_CORE_MEMORY %x", address);
data = command_memory_get_pointer(address, &max_bytes, 1, reply_at, sizeof(reply) - strlen(reply) - 1);
if (data)
{
uint8_t* start = data;
while (*arg && max_bytes > 0)
{
--max_bytes;
*data = strtoul(arg, (char**)&arg, 16);
data++;
}
snprintf(reply_at, sizeof(reply) - strlen(reply) - 1, " %u\n", (unsigned)(data - start));
#ifdef HAVE_CHEEVOS
if (rcheevos_hardcore_active())
{
RARCH_LOG("Achievements hardcore mode disabled by WRITE_CORE_MEMORY\n");
rcheevos_pause_hardcore();
}
#endif
}
command_reply(p_rarch, reply, strlen(reply));
return true;
}
#ifdef HAVE_NETWORK_CMD
static bool command_get_arg(const char *tok,
const char **arg, unsigned *index)

View File

@ -2691,6 +2691,8 @@ static bool command_show_osd_msg(const char* arg);
static bool command_read_ram(const char *arg);
static bool command_write_ram(const char *arg);
#endif
static bool command_read_memory(const char *arg);
static bool command_write_memory(const char *arg);
static const struct cmd_action_map action_map[] = {
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
@ -2701,9 +2703,13 @@ static const struct cmd_action_map action_map[] = {
{ "GET_CONFIG_PARAM", command_get_config_param, "<param name>" },
{ "SHOW_MSG", command_show_osd_msg, "No argument" },
#if defined(HAVE_CHEEVOS)
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
/* These functions use achievement addresses and only work if a game with achievements is
* loaded. READ_CORE_MEMORY and WRITE_CORE_MEMORY are preferred and use system addresses. */
{ "READ_CORE_RAM", command_read_ram, "<address> <number of bytes>" },
{ "WRITE_CORE_RAM", command_write_ram, "<address> <byte1> <byte2> ..." },
#endif
{ "READ_CORE_MEMORY", command_read_memory, "<address> <number of bytes>" },
{ "WRITE_CORE_MEMORY",command_write_memory, "<address> <byte1> <byte2> ..." },
};
static const struct cmd_map map[] = {