* Hide RzAnalysis structure to force the usage of the C APIs. * Fix rop code & test * Fix linter * Fix rz_analysis_free to return void
212 lines
6 KiB
C
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;
|
|
}
|