rizin/librz/arch/platform_profile.c
Giovanni b5fee3471c
Move RzAnalysis as private and force usage of C API (#6123)
* Hide RzAnalysis structure to force the usage of the C APIs.

* Fix rop code & test

* Fix linter

* Fix rz_analysis_free to return void
2026-04-06 16:07:53 +00:00

212 lines
6 KiB
C

// SPDX-FileCopyrightText: 2021 RizinOrg <info@rizin.re>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_platform.h>
/**
* \brief Frees an RzPlatformProfile type
*
* Frees the hashtables used for MMIO and extended
* registers
*/
RZ_API void rz_platform_profile_free(RZ_NULLABLE RzPlatformProfile *p) {
if (!p) {
return;
}
ht_up_free(p->registers_mmio);
ht_up_free(p->registers_extended);
free(p);
}
/**
* \brief Creates a new RzPlatformProfile type
*/
RZ_API RZ_OWN RzPlatformProfile *rz_platform_profile_new() {
RzPlatformProfile *profile = RZ_NEW0(RzPlatformProfile);
if (!profile) {
return NULL;
}
profile->registers_mmio = ht_up_new((HtUPDupValue)rz_str_dup, free);
if (!profile->registers_mmio) {
free(profile);
return NULL;
}
profile->registers_extended = ht_up_new((HtUPDupValue)rz_str_dup, free);
if (!profile->registers_extended) {
ht_up_free(profile->registers_mmio);
free(profile);
return NULL;
}
return profile;
}
/**
* \brief Creates a new RzPlatformTarget type
*/
RZ_API RZ_OWN RzPlatformTarget *rz_platform_target_new() {
RzPlatformTarget *profile = RZ_NEW0(RzPlatformTarget);
if (!profile) {
return NULL;
}
profile->profile = rz_platform_profile_new();
if (!profile->profile) {
free(profile);
return NULL;
}
return profile;
}
/**
* \brief Frees an RzPlatformTarget type
*
* Frees the pointer to the SDB and the RzPlatformProfile
*/
RZ_API void rz_platform_target_free(RZ_NULLABLE RzPlatformTarget *t) {
if (!t) {
return;
}
rz_platform_profile_free(t->profile);
free(t->cpu);
free(t->arch);
free(t);
}
/**
* \brief Resolves an address and returns the linked mmio
*/
RZ_API RZ_BORROW const char *rz_platform_profile_resolve_mmio(RZ_NONNULL RzPlatformProfile *profile, ut64 address) {
rz_return_val_if_fail(profile, NULL);
return ht_up_find(profile->registers_mmio, (ut64)address, NULL);
}
/**
* \brief Resolves an address and returns the linked extended register
*/
RZ_API RZ_BORROW const char *rz_platform_profile_resolve_extended_register(RZ_NONNULL RzPlatformProfile *profile, ut64 address) {
rz_return_val_if_fail(profile, NULL);
return ht_up_find(profile->registers_extended, (ut64)address, NULL);
}
static inline bool cpu_reload_needed(RzPlatformTarget *c, const char *cpu, const char *arch) {
if (!c->arch || strcmp(c->arch, arch)) {
return true;
}
return !c->cpu || strcmp(c->cpu, cpu);
}
static bool sdb_load_arch_profile(RzPlatformTarget *t, Sdb *sdb) {
rz_return_val_if_fail(t && sdb, false);
RzPlatformProfile *c = rz_platform_profile_new();
if (!c) {
return false;
}
void **iter;
RzPVector *items = sdb_get_items(sdb, false);
rz_pvector_foreach (items, iter) {
SdbKv *kv = *iter;
if (!strcmp(sdbkv_key(kv), "PC")) {
c->pc = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "EEPROM_SIZE")) {
c->eeprom_size = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "IO_SIZE")) {
c->io_size = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "SRAM_START")) {
c->sram_start = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "SRAM_SIZE")) {
c->sram_size = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "PAGE_SIZE")) {
c->page_size = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "ROM_SIZE")) {
c->rom_size = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "ROM_ADDRESS")) {
c->rom_address = rz_num_math(NULL, sdbkv_value(kv));
} else if (!strcmp(sdbkv_key(kv), "RAM_SIZE")) {
c->ram_size = rz_num_math(NULL, sdbkv_value(kv));
}
if (!strcmp(sdbkv_value(kv), "io")) {
const char *io_name = sdbkv_key(kv);
char *argument_key = rz_str_newf("%s.address", io_name);
ut64 io_address = sdb_num_get(sdb, argument_key);
free(argument_key);
ht_up_insert(c->registers_mmio, io_address, (char *)io_name);
}
if (!strcmp(sdbkv_value(kv), "ext_io")) {
const char *ext_io_name = sdbkv_key(kv);
char *argument_key = rz_str_newf("%s.address", ext_io_name);
ut64 ext_io_address = sdb_num_get(sdb, argument_key);
free(argument_key);
ht_up_insert(c->registers_extended, ext_io_address, (char *)ext_io_name);
}
}
rz_pvector_free(items);
rz_platform_profile_free(t->profile);
t->profile = c;
return true;
}
static bool sdb_load_arch_profile_by_path(RZ_NONNULL RzPlatformTarget *t, const char *path) {
Sdb *db = sdb_new(0, path, 0);
bool result = sdb_load_arch_profile(t, db);
sdb_close(db);
sdb_free(db);
return result;
}
/**
* \brief Loads the contents of the CPU Profile to the RzPlatformProfile
*
* \param t reference to RzPlatformTarget
* \param path reference to path of the SDB file
*/
RZ_API bool rz_platform_load_profile_sdb(RZ_NONNULL RzPlatformTarget *t, RZ_NONNULL const char *path) {
rz_return_val_if_fail(t && path, false);
if (!rz_file_exists(path)) {
return false;
}
return sdb_load_arch_profile_by_path(t, path);
}
/**
* \brief Initializes RzPlatformProfile by loading the path to the SDB file
* of the CPU profile
*
* \param t reference to RzPlatformTarget
* \param cpu reference to the selected CPU (value of `asm.cpu`)
* \param arch reference to the selected architecture (value of `asm.arch`)
* \param cpus_dir reference to the directory containing cpu files
*/
RZ_API bool rz_platform_profiles_init(RZ_NULLABLE RzPlatformTarget *t, RZ_NULLABLE const char *cpu, RZ_NULLABLE const char *arch, RZ_NULLABLE const char *cpus_dir) {
if (!t || !arch || !cpu || !cpus_dir) {
return false;
}
if (!cpu_reload_needed(t, cpu, arch)) {
return false;
}
if (cpu && RZ_STR_EQ(cpu, "avr")) {
cpu = "ATmega8";
}
if (t->arch && RZ_STR_EQ(t->arch, arch) &&
t->cpu && RZ_STR_EQ(t->cpu, cpu)) {
// already loaded.
return true;
}
char buf[50];
char *path = rz_file_path_join(cpus_dir, rz_strf(buf, "%s-%s.sdb", arch, cpu));
if (!path) {
return false;
}
free(t->cpu);
free(t->arch);
t->cpu = rz_str_dup(cpu);
t->arch = rz_str_dup(arch);
rz_platform_load_profile_sdb(t, path);
free(path);
return true;
}