From 805d394ff8c5e1d1d4f543956ed0393087306171 Mon Sep 17 00:00:00 2001 From: Anastasiya Chernikova Date: Thu, 12 Oct 2023 11:29:08 +0300 Subject: [PATCH] target/riscv: Adding register tables to make register names consistent Added the ability to enter dimensionless registers Change-Id: I1b781959ce4690ec65304142bd9a7c6f540b3e86 Signed-off-by: Anastasiya Chernikova --- src/target/riscv/gdb_regs.h | 2 +- src/target/riscv/riscv-011.c | 6 +- src/target/riscv/riscv-013.c | 24 +- src/target/riscv/riscv.c | 738 +++++++++++++---------------------- src/target/riscv/riscv.h | 10 +- 5 files changed, 298 insertions(+), 482 deletions(-) diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index ea0c0145d7..570c50845c 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -120,6 +120,6 @@ enum gdb_regno { GDB_REGNO_COUNT }; -const char *gdb_regno_name(enum gdb_regno regno); +const char *gdb_regno_name(struct target *target, enum gdb_regno regno); #endif diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index dd7676ee78..c958c88026 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1045,7 +1045,7 @@ static int read_remote_csr(struct target *target, uint64_t *value, uint32_t csr) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when reading %s", exception, - gdb_regno_name(GDB_REGNO_CSR0 + csr)); + gdb_regno_name(target, GDB_REGNO_CSR0 + csr)); *value = ~0; return ERROR_FAIL; } @@ -1247,7 +1247,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum)); + LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(target, regnum)); *value = ~0; return ERROR_FAIL; } @@ -1322,7 +1322,7 @@ static int register_write(struct target *target, unsigned int number, uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { LOG_WARNING("Got exception 0x%x when writing %s", exception, - gdb_regno_name(number)); + gdb_regno_name(target, number)); return ERROR_FAIL; } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5697ad2967..fc2a3db345 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -937,7 +937,7 @@ static uint32_t access_register_command(struct target *target, uint32_t number, break; default: LOG_TARGET_ERROR(target, "%d-bit register %s not supported.", - size, gdb_regno_name(number)); + size, gdb_regno_name(target, number)); assert(0); } @@ -1173,7 +1173,7 @@ static int prep_for_register_access(struct target *target, return ERROR_OK; LOG_TARGET_DEBUG(target, "Preparing mstatus to access %s", - gdb_regno_name(regno)); + gdb_regno_name(target, regno)); assert(target->state == TARGET_HALTED && "The target must be halted to modify and then restore mstatus"); @@ -1193,7 +1193,7 @@ static int prep_for_register_access(struct target *target, return ERROR_FAIL; LOG_TARGET_DEBUG(target, "Prepared to access %s (mstatus=0x%" PRIx64 ")", - gdb_regno_name(regno), new_mstatus); + gdb_regno_name(target, regno), new_mstatus); return ERROR_OK; } @@ -1482,7 +1482,7 @@ static int register_read_progbuf(struct target *target, uint64_t *value, return csr_read_progbuf(target, value, number); LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.", - gdb_regno_name(number)); + gdb_regno_name(target, number)); return ERROR_FAIL; } @@ -1628,7 +1628,7 @@ static int register_write_progbuf(struct target *target, enum gdb_regno number, return csr_write_progbuf(target, number, value); LOG_TARGET_ERROR(target, "Unexpected write to %s via program buffer.", - gdb_regno_name(number)); + gdb_regno_name(target, number)); return ERROR_FAIL; } @@ -1640,7 +1640,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, riscv_reg_t value) { LOG_TARGET_DEBUG(target, "Writing 0x%" PRIx64 " to %s", value, - gdb_regno_name(number)); + gdb_regno_name(target, number)); if (target->state != TARGET_HALTED) return register_write_abstract(target, number, value); @@ -1658,7 +1658,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, return ERROR_FAIL; if (result == ERROR_OK) - LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(number), + LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(target, number), value); return result; @@ -1668,7 +1668,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number, static int register_read_direct(struct target *target, riscv_reg_t *value, enum gdb_regno number) { - LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(number)); + LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(target, number)); if (target->state != TARGET_HALTED) return register_read_abstract(target, value, number); @@ -1687,7 +1687,7 @@ static int register_read_direct(struct target *target, riscv_reg_t *value, return ERROR_FAIL; if (result == ERROR_OK) - LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(number), + LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(target, number), *value); return result; @@ -2367,7 +2367,7 @@ static int riscv013_get_register_buf(struct target *target, } else { LOG_TARGET_ERROR(target, "Failed to execute vmv/vslide1down while reading %s", - gdb_regno_name(regno)); + gdb_regno_name(target, regno)); break; } } @@ -4666,7 +4666,7 @@ struct target_type riscv013_target = { static int riscv013_get_register(struct target *target, riscv_reg_t *value, enum gdb_regno rid) { - LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(rid)); + LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(target, rid)); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; @@ -4683,7 +4683,7 @@ static int riscv013_set_register(struct target *target, enum gdb_regno rid, riscv_reg_t value) { LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s", - value, gdb_regno_name(rid)); + value, gdb_regno_name(target, rid)); if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 1a2f35e70e..abe3723304 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -488,6 +488,21 @@ static void riscv_free_registers(struct target *target) } } +static void free_reg_names(struct target *target); + +static void free_custom_register_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->custom_register_names.reg_names) + return; + + for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++) + free(info->custom_register_names.reg_names[i]); + free(info->custom_register_names.reg_names); + info->custom_register_names.reg_names = NULL; +} + static void riscv_deinit_target(struct target *target) { LOG_TARGET_DEBUG(target, "riscv_deinit_target()"); @@ -524,7 +539,7 @@ static void riscv_deinit_target(struct target *target) free(entry); } - free(info->reg_names); + free_reg_names(target); free(target->arch_info); target->arch_info = NULL; @@ -2670,7 +2685,8 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, riscv_reg_t reg_value; if (riscv_get_register(target, ®_value, regno) != ERROR_OK) break; - LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(regno), reg_value); + + LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(target, regno), reg_value); } return ERROR_TARGET_TIMEOUT; } @@ -5011,7 +5027,7 @@ static int riscv_set_or_write_register(struct target *target, assert(!target_was_examined(target)); LOG_TARGET_DEBUG(target, "No cache, writing to target: %s <- 0x%" PRIx64, - gdb_regno_name(regid), value); + gdb_regno_name(target, regid), value); return r->set_register(target, regid, value); } @@ -5106,7 +5122,7 @@ int riscv_get_register(struct target *target, riscv_reg_t *value, if (!target->reg_cache) { assert(!target_was_examined(target)); LOG_TARGET_DEBUG(target, "No cache, reading %s from target", - gdb_regno_name(regid)); + gdb_regno_name(target, regid)); return r->get_register(target, value, regid); } @@ -5143,7 +5159,7 @@ int riscv_save_register(struct target *target, enum gdb_regno regid) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.", - gdb_regno_name(regid)); + gdb_regno_name(target, regid)); return ERROR_FAIL; } assert(gdb_regno_cacheable(regid, /* is write? */ false) && @@ -5322,7 +5338,7 @@ static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1) * something. * Disable any hardware triggers that have dmode set. We can't have set them * ourselves. Maybe they're left over from some killed debug session. - * */ + */ int riscv_enumerate_triggers(struct target *target) { RISCV_INFO(r); @@ -5381,188 +5397,174 @@ int riscv_enumerate_triggers(struct target *target) return ERROR_OK; } -const char *gdb_regno_name(enum gdb_regno regno) +static char *init_reg_name(const char *name) { - static char buf[32]; + const int size_buf = strlen(name) + 1; - switch (regno) { - case GDB_REGNO_ZERO: - return "zero"; - case GDB_REGNO_RA: - return "ra"; - case GDB_REGNO_SP: - return "sp"; - case GDB_REGNO_GP: - return "gp"; - case GDB_REGNO_TP: - return "tp"; - case GDB_REGNO_T0: - return "t0"; - case GDB_REGNO_T1: - return "t1"; - case GDB_REGNO_T2: - return "t2"; - case GDB_REGNO_S0: - return "s0"; - case GDB_REGNO_S1: - return "s1"; - case GDB_REGNO_A0: - return "a0"; - case GDB_REGNO_A1: - return "a1"; - case GDB_REGNO_A2: - return "a2"; - case GDB_REGNO_A3: - return "a3"; - case GDB_REGNO_A4: - return "a4"; - case GDB_REGNO_A5: - return "a5"; - case GDB_REGNO_A6: - return "a6"; - case GDB_REGNO_A7: - return "a7"; - case GDB_REGNO_S2: - return "s2"; - case GDB_REGNO_S3: - return "s3"; - case GDB_REGNO_S4: - return "s4"; - case GDB_REGNO_S5: - return "s5"; - case GDB_REGNO_S6: - return "s6"; - case GDB_REGNO_S7: - return "s7"; - case GDB_REGNO_S8: - return "s8"; - case GDB_REGNO_S9: - return "s9"; - case GDB_REGNO_S10: - return "s10"; - case GDB_REGNO_S11: - return "s11"; - case GDB_REGNO_T3: - return "t3"; - case GDB_REGNO_T4: - return "t4"; - case GDB_REGNO_T5: - return "t5"; - case GDB_REGNO_T6: - return "t6"; - case GDB_REGNO_PC: - return "pc"; - case GDB_REGNO_FPR0: - return "fpr0"; - case GDB_REGNO_FPR31: - return "fpr31"; - case GDB_REGNO_CSR0: - return "csr0"; - case GDB_REGNO_TSELECT: - return "tselect"; - case GDB_REGNO_TDATA1: - return "tdata1"; - case GDB_REGNO_TDATA2: - return "tdata2"; - case GDB_REGNO_MISA: - return "misa"; - case GDB_REGNO_DPC: - return "dpc"; - case GDB_REGNO_DCSR: - return "dcsr"; - case GDB_REGNO_DSCRATCH0: - return "dscratch0"; - case GDB_REGNO_MSTATUS: - return "mstatus"; - case GDB_REGNO_MEPC: - return "mepc"; - case GDB_REGNO_MCAUSE: - return "mcause"; - case GDB_REGNO_PRIV: - return "priv"; - case GDB_REGNO_SATP: - return "satp"; - case GDB_REGNO_VTYPE: - return "vtype"; - case GDB_REGNO_VL: - return "vl"; - case GDB_REGNO_V0: - return "v0"; - case GDB_REGNO_V1: - return "v1"; - case GDB_REGNO_V2: - return "v2"; - case GDB_REGNO_V3: - return "v3"; - case GDB_REGNO_V4: - return "v4"; - case GDB_REGNO_V5: - return "v5"; - case GDB_REGNO_V6: - return "v6"; - case GDB_REGNO_V7: - return "v7"; - case GDB_REGNO_V8: - return "v8"; - case GDB_REGNO_V9: - return "v9"; - case GDB_REGNO_V10: - return "v10"; - case GDB_REGNO_V11: - return "v11"; - case GDB_REGNO_V12: - return "v12"; - case GDB_REGNO_V13: - return "v13"; - case GDB_REGNO_V14: - return "v14"; - case GDB_REGNO_V15: - return "v15"; - case GDB_REGNO_V16: - return "v16"; - case GDB_REGNO_V17: - return "v17"; - case GDB_REGNO_V18: - return "v18"; - case GDB_REGNO_V19: - return "v19"; - case GDB_REGNO_V20: - return "v20"; - case GDB_REGNO_V21: - return "v21"; - case GDB_REGNO_V22: - return "v22"; - case GDB_REGNO_V23: - return "v23"; - case GDB_REGNO_V24: - return "v24"; - case GDB_REGNO_V25: - return "v25"; - case GDB_REGNO_V26: - return "v26"; - case GDB_REGNO_V27: - return "v27"; - case GDB_REGNO_V28: - return "v28"; - case GDB_REGNO_V29: - return "v29"; - case GDB_REGNO_V30: - return "v30"; - case GDB_REGNO_V31: - return "v31"; - default: - if (regno <= GDB_REGNO_XPR31) - sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); - else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) - sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); - else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) - sprintf(buf, "f%d", regno - GDB_REGNO_FPR0); - else - sprintf(buf, "gdb_regno_%d", regno); - return buf; + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; } + strcpy(buf, name); + return buf; } +static char *init_reg_name_with_prefix(const char *name_prefix, + unsigned int num) +{ + const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1; + + char * const buf = calloc(size_buf, sizeof(char)); + if (!buf) { + LOG_ERROR("Failed to allocate memory for a register name."); + return NULL; + } + int result = snprintf(buf, size_buf, "%s%d", name_prefix, num); + assert(result > 0 && result <= (size_buf - 1)); + return buf; +} + +static const char * const default_reg_names[GDB_REGNO_COUNT] = { + [GDB_REGNO_ZERO] = "zero", + [GDB_REGNO_RA] = "ra", + [GDB_REGNO_SP] = "sp", + [GDB_REGNO_GP] = "gp", + [GDB_REGNO_TP] = "tp", + [GDB_REGNO_T0] = "t0", + [GDB_REGNO_T1] = "t1", + [GDB_REGNO_T2] = "t2", + [GDB_REGNO_FP] = "fp", + [GDB_REGNO_S1] = "s1", + [GDB_REGNO_A0] = "a0", + [GDB_REGNO_A1] = "a1", + [GDB_REGNO_A2] = "a2", + [GDB_REGNO_A3] = "a3", + [GDB_REGNO_A4] = "a4", + [GDB_REGNO_A5] = "a5", + [GDB_REGNO_A6] = "a6", + [GDB_REGNO_A7] = "a7", + [GDB_REGNO_S2] = "s2", + [GDB_REGNO_S3] = "s3", + [GDB_REGNO_S4] = "s4", + [GDB_REGNO_S5] = "s5", + [GDB_REGNO_S6] = "s6", + [GDB_REGNO_S7] = "s7", + [GDB_REGNO_S8] = "s8", + [GDB_REGNO_S9] = "s9", + [GDB_REGNO_S10] = "s10", + [GDB_REGNO_S11] = "s11", + [GDB_REGNO_T3] = "t3", + [GDB_REGNO_T4] = "t4", + [GDB_REGNO_T5] = "t5", + [GDB_REGNO_T6] = "t6", + [GDB_REGNO_PC] = "pc", + [GDB_REGNO_CSR0] = "csr0", + [GDB_REGNO_PRIV] = "priv", + [GDB_REGNO_FT0] = "ft0", + [GDB_REGNO_FT1] = "ft1", + [GDB_REGNO_FT2] = "ft2", + [GDB_REGNO_FT3] = "ft3", + [GDB_REGNO_FT4] = "ft4", + [GDB_REGNO_FT5] = "ft5", + [GDB_REGNO_FT6] = "ft6", + [GDB_REGNO_FT7] = "ft7", + [GDB_REGNO_FS0] = "fs0", + [GDB_REGNO_FS1] = "fs1", + [GDB_REGNO_FA0] = "fa0", + [GDB_REGNO_FA1] = "fa1", + [GDB_REGNO_FA2] = "fa2", + [GDB_REGNO_FA3] = "fa3", + [GDB_REGNO_FA4] = "fa4", + [GDB_REGNO_FA5] = "fa5", + [GDB_REGNO_FA6] = "fa6", + [GDB_REGNO_FA7] = "fa7", + [GDB_REGNO_FS2] = "fs2", + [GDB_REGNO_FS3] = "fs3", + [GDB_REGNO_FS4] = "fs4", + [GDB_REGNO_FS5] = "fs5", + [GDB_REGNO_FS6] = "fs6", + [GDB_REGNO_FS7] = "fs7", + [GDB_REGNO_FS8] = "fs8", + [GDB_REGNO_FS9] = "fs9", + [GDB_REGNO_FS10] = "fs10", + [GDB_REGNO_FS11] = "fs11", + [GDB_REGNO_FT8] = "ft8", + [GDB_REGNO_FT9] = "ft9", + [GDB_REGNO_FT10] = "ft10", + [GDB_REGNO_FT11] = "ft11", + + #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name, + #include "encoding.h" + #undef DECLARE_CSR +}; + +static void free_reg_names(struct target *target) +{ + RISCV_INFO(info); + + if (!info->reg_names) + return; + + for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i) + free(info->reg_names[i]); + free(info->reg_names); + info->reg_names = NULL; + + free_custom_register_names(target); +} + +static void init_custom_csr_names(struct target *target) +{ + RISCV_INFO(info); + range_list_t *entry; + + list_for_each_entry(entry, &info->expose_csr, list) { + if (!entry->name) + continue; + assert(entry->low == entry->high); + const unsigned int regno = entry->low + GDB_REGNO_CSR0; + assert(regno <= GDB_REGNO_CSR4095); + if (info->reg_names[regno]) + return; + info->reg_names[regno] = init_reg_name(entry->name); + } +} + +const char *gdb_regno_name(struct target *target, unsigned int regno) +{ + RISCV_INFO(info); + + if (regno >= GDB_REGNO_COUNT) { + assert(info->custom_register_names.reg_names); + assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries); + return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT]; + } + + if (!info->reg_names) + info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *)); + + if (info->reg_names[regno]) + return info->reg_names[regno]; + if (default_reg_names[regno]) + return default_reg_names[regno]; + if (regno <= GDB_REGNO_XPR31) { + info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO); + return info->reg_names[regno]; + } + if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) { + info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0); + return info->reg_names[regno]; + } + if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + init_custom_csr_names(target); + info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); + return info->reg_names[regno]; + } + assert(!"Encountered uninitialized entry in reg_names table"); + + return NULL; +} /** * This function is the handler of user's request to read a register. @@ -5662,14 +5664,54 @@ static struct reg_arch_type riscv_reg_arch_type = { .set = register_set }; -struct csr_info { - unsigned number; - const char *name; -}; +static int init_custom_register_names(struct list_head *expose_custom, + struct reg_name_table *custom_register_names) +{ + unsigned int custom_regs_num = 0; + if (!list_empty(expose_custom)) { + range_list_t *entry; + list_for_each_entry(entry, expose_custom, list) + custom_regs_num += entry->high - entry->low + 1; + } + + if (!custom_regs_num) + return ERROR_OK; -static int cmp_csr_info(const void *p1, const void *p2) + custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *)); + if (!custom_register_names->reg_names) { + LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names"); + return ERROR_FAIL; + } + custom_register_names->num_entries = custom_regs_num; + char **reg_names = custom_register_names->reg_names; + range_list_t *range; + unsigned int next_custom_reg_index = 0; + list_for_each_entry(range, expose_custom, list) { + for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) { + if (range->name) + reg_names[next_custom_reg_index] = init_reg_name(range->name); + else + reg_names[next_custom_reg_index] = + init_reg_name_with_prefix("custom", custom_number); + + if (!reg_names[next_custom_reg_index]) + return ERROR_FAIL; + ++next_custom_reg_index; + } + } + return ERROR_OK; +} + +static bool is_known_standard_csr(unsigned int csr_num) { - return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); + static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = { + #define DECLARE_CSR(csr_name, number)[number] = true, + #include "encoding.h" + #undef DECLARE_CSR + }; + assert(csr_num < ARRAY_SIZE(is_csr_in_buf)); + + return is_csr_in_buf[csr_num]; } int riscv_init_registers(struct target *target) @@ -5679,32 +5721,27 @@ int riscv_init_registers(struct target *target) riscv_free_registers(target); target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - if (!target->reg_cache) + if (!target->reg_cache) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache"); return ERROR_FAIL; + } target->reg_cache->name = "RISC-V Registers"; - target->reg_cache->num_regs = GDB_REGNO_COUNT; - if (!list_empty(&info->expose_custom)) { - range_list_t *entry; - list_for_each_entry(entry, &info->expose_custom, list) - target->reg_cache->num_regs += entry->high - entry->low + 1; + if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) { + LOG_TARGET_ERROR(target, "init_custom_register_names failed"); + return ERROR_FAIL; } + target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries; LOG_TARGET_DEBUG(target, "create register cache for %d registers", target->reg_cache->num_regs); target->reg_cache->reg_list = calloc(target->reg_cache->num_regs, sizeof(struct reg)); - if (!target->reg_cache->reg_list) + if (!target->reg_cache->reg_list) { + LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list"); return ERROR_FAIL; - - const unsigned int max_reg_name_len = 12; - free(info->reg_names); - info->reg_names = - calloc(target->reg_cache->num_regs, max_reg_name_len); - if (!info->reg_names) - return ERROR_FAIL; - char *reg_name = info->reg_names; + } static struct reg_feature feature_cpu = { .name = "org.gnu.gdb.riscv.cpu" @@ -5836,152 +5873,45 @@ int riscv_init_registers(struct target *target) info->type_vector.type_class = REG_TYPE_CLASS_UNION; info->type_vector.reg_type_union = &info->vector_union; - struct csr_info csr_info[] = { -#define DECLARE_CSR(name, number) { number, #name }, -#include "encoding.h" -#undef DECLARE_CSR - }; - /* encoding.h does not contain the registers in sorted order. */ - qsort(csr_info, ARRAY_SIZE(csr_info), sizeof(*csr_info), cmp_csr_info); - unsigned csr_info_index = 0; - - int custom_within_range = 0; - riscv_reg_info_t *shared_reg_info = calloc(1, sizeof(riscv_reg_info_t)); if (!shared_reg_info) return ERROR_FAIL; shared_reg_info->target = target; + int custom_within_range = 0; + /* When gdb requests register N, gdb_get_register_packet() assumes that this * is register at index N in reg_list. So if there are certain registers * that don't exist, we need to leave holes in the list (or renumber, but * it would be nice not to have yet another set of numbers to translate * between). */ - for (uint32_t number = 0; number < target->reg_cache->num_regs; number++) { - struct reg *r = &target->reg_cache->reg_list[number]; + for (uint32_t reg_num = 0; reg_num < target->reg_cache->num_regs; reg_num++) { + struct reg *r = &target->reg_cache->reg_list[reg_num]; r->dirty = false; r->valid = false; r->exist = true; r->type = &riscv_reg_arch_type; r->arch_info = shared_reg_info; - r->number = number; + r->number = reg_num; r->size = riscv_xlen(target); /* r->size is set in riscv_invalidate_register_cache, maybe because the * target is in theory allowed to change XLEN on us. But I expect a lot * of other things to break in that case as well. */ - if (number <= GDB_REGNO_XPR31) { - r->exist = number <= GDB_REGNO_XPR15 || + r->name = gdb_regno_name(target, reg_num); + if (reg_num <= GDB_REGNO_XPR31) { + r->exist = reg_num <= GDB_REGNO_XPR15 || !riscv_supports_extension(target, 'E'); /* TODO: For now we fake that all GPRs exist because otherwise gdb * doesn't work. */ r->exist = true; r->caller_save = true; - switch (number) { - case GDB_REGNO_ZERO: - r->name = "zero"; - break; - case GDB_REGNO_RA: - r->name = "ra"; - break; - case GDB_REGNO_SP: - r->name = "sp"; - break; - case GDB_REGNO_GP: - r->name = "gp"; - break; - case GDB_REGNO_TP: - r->name = "tp"; - break; - case GDB_REGNO_T0: - r->name = "t0"; - break; - case GDB_REGNO_T1: - r->name = "t1"; - break; - case GDB_REGNO_T2: - r->name = "t2"; - break; - case GDB_REGNO_FP: - r->name = "fp"; - break; - case GDB_REGNO_S1: - r->name = "s1"; - break; - case GDB_REGNO_A0: - r->name = "a0"; - break; - case GDB_REGNO_A1: - r->name = "a1"; - break; - case GDB_REGNO_A2: - r->name = "a2"; - break; - case GDB_REGNO_A3: - r->name = "a3"; - break; - case GDB_REGNO_A4: - r->name = "a4"; - break; - case GDB_REGNO_A5: - r->name = "a5"; - break; - case GDB_REGNO_A6: - r->name = "a6"; - break; - case GDB_REGNO_A7: - r->name = "a7"; - break; - case GDB_REGNO_S2: - r->name = "s2"; - break; - case GDB_REGNO_S3: - r->name = "s3"; - break; - case GDB_REGNO_S4: - r->name = "s4"; - break; - case GDB_REGNO_S5: - r->name = "s5"; - break; - case GDB_REGNO_S6: - r->name = "s6"; - break; - case GDB_REGNO_S7: - r->name = "s7"; - break; - case GDB_REGNO_S8: - r->name = "s8"; - break; - case GDB_REGNO_S9: - r->name = "s9"; - break; - case GDB_REGNO_S10: - r->name = "s10"; - break; - case GDB_REGNO_S11: - r->name = "s11"; - break; - case GDB_REGNO_T3: - r->name = "t3"; - break; - case GDB_REGNO_T4: - r->name = "t4"; - break; - case GDB_REGNO_T5: - r->name = "t5"; - break; - case GDB_REGNO_T6: - r->name = "t6"; - break; - } r->group = "general"; r->feature = &feature_cpu; - } else if (number == GDB_REGNO_PC) { + } else if (reg_num == GDB_REGNO_PC) { r->caller_save = true; - sprintf(reg_name, "pc"); r->group = "general"; r->feature = &feature_cpu; - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + } else if (reg_num >= GDB_REGNO_FPR0 && reg_num <= GDB_REGNO_FPR31) { r->caller_save = true; if (riscv_supports_extension(target, 'D')) { r->size = 64; @@ -5995,119 +5925,14 @@ int riscv_init_registers(struct target *target) } else { r->exist = false; } - switch (number) { - case GDB_REGNO_FT0: - r->name = "ft0"; - break; - case GDB_REGNO_FT1: - r->name = "ft1"; - break; - case GDB_REGNO_FT2: - r->name = "ft2"; - break; - case GDB_REGNO_FT3: - r->name = "ft3"; - break; - case GDB_REGNO_FT4: - r->name = "ft4"; - break; - case GDB_REGNO_FT5: - r->name = "ft5"; - break; - case GDB_REGNO_FT6: - r->name = "ft6"; - break; - case GDB_REGNO_FT7: - r->name = "ft7"; - break; - case GDB_REGNO_FS0: - r->name = "fs0"; - break; - case GDB_REGNO_FS1: - r->name = "fs1"; - break; - case GDB_REGNO_FA0: - r->name = "fa0"; - break; - case GDB_REGNO_FA1: - r->name = "fa1"; - break; - case GDB_REGNO_FA2: - r->name = "fa2"; - break; - case GDB_REGNO_FA3: - r->name = "fa3"; - break; - case GDB_REGNO_FA4: - r->name = "fa4"; - break; - case GDB_REGNO_FA5: - r->name = "fa5"; - break; - case GDB_REGNO_FA6: - r->name = "fa6"; - break; - case GDB_REGNO_FA7: - r->name = "fa7"; - break; - case GDB_REGNO_FS2: - r->name = "fs2"; - break; - case GDB_REGNO_FS3: - r->name = "fs3"; - break; - case GDB_REGNO_FS4: - r->name = "fs4"; - break; - case GDB_REGNO_FS5: - r->name = "fs5"; - break; - case GDB_REGNO_FS6: - r->name = "fs6"; - break; - case GDB_REGNO_FS7: - r->name = "fs7"; - break; - case GDB_REGNO_FS8: - r->name = "fs8"; - break; - case GDB_REGNO_FS9: - r->name = "fs9"; - break; - case GDB_REGNO_FS10: - r->name = "fs10"; - break; - case GDB_REGNO_FS11: - r->name = "fs11"; - break; - case GDB_REGNO_FT8: - r->name = "ft8"; - break; - case GDB_REGNO_FT9: - r->name = "ft9"; - break; - case GDB_REGNO_FT10: - r->name = "ft10"; - break; - case GDB_REGNO_FT11: - r->name = "ft11"; - break; - } r->group = "float"; r->feature = &feature_fpu; - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + } else if (reg_num >= GDB_REGNO_CSR0 && reg_num <= GDB_REGNO_CSR4095) { r->group = "csr"; r->feature = &feature_csr; - unsigned csr_number = number - GDB_REGNO_CSR0; + const unsigned int csr_num = reg_num - GDB_REGNO_CSR0; - while (csr_info[csr_info_index].number < csr_number && - csr_info_index < ARRAY_SIZE(csr_info) - 1) { - csr_info_index++; - } - if (csr_info[csr_info_index].number == csr_number) { - r->name = csr_info[csr_info_index].name; - } else { - sprintf(reg_name, "csr%d", csr_number); + if (!is_known_standard_csr(csr_num)) { /* Assume unnamed registers don't exist, unless we have some * configuration that tells us otherwise. That's important * because eg. Eclipse crashes if a target has too many @@ -6116,7 +5941,7 @@ int riscv_init_registers(struct target *target) r->exist = false; } - switch (csr_number) { + switch (csr_num) { case CSR_DCSR: case CSR_MVENDORID: case CSR_MCOUNTINHIBIT: @@ -6306,67 +6131,60 @@ int riscv_init_registers(struct target *target) if (!r->exist && !list_empty(&info->expose_csr)) { range_list_t *entry; list_for_each_entry(entry, &info->expose_csr, list) - if ((entry->low <= csr_number) && (csr_number <= entry->high)) { - if (entry->name) { - *reg_name = 0; - r->name = entry->name; - } - - LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s).", - csr_number, entry->name ? entry->name : reg_name); - + if (entry->low <= csr_num && csr_num <= entry->high) { + LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", + csr_num, r->name); r->exist = true; break; } } else if (r->exist && !list_empty(&info->hide_csr)) { range_list_t *entry; list_for_each_entry(entry, &info->hide_csr, list) - if (entry->low <= csr_number && csr_number <= entry->high) { - LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, r->name); + if (entry->low <= csr_num && csr_num <= entry->high) { + LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_num, r->name); r->hidden = true; break; } } - } else if (number == GDB_REGNO_PRIV) { - sprintf(reg_name, "priv"); + } else if (reg_num == GDB_REGNO_PRIV) { r->group = "general"; r->feature = &feature_virtual; r->size = 8; - } else if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) { + } else if (reg_num >= GDB_REGNO_V0 && reg_num <= GDB_REGNO_V31) { r->caller_save = false; r->exist = (info->vlenb > 0); r->size = info->vlenb * 8; - sprintf(reg_name, "v%d", number - GDB_REGNO_V0); r->group = "vector"; r->feature = &feature_vector; r->reg_data_type = &info->type_vector; - } else if (number >= GDB_REGNO_COUNT) { + } else if (reg_num >= GDB_REGNO_COUNT) { /* Custom registers. */ + const unsigned int custom_reg_index = reg_num - GDB_REGNO_COUNT; + assert(!list_empty(&info->expose_custom)); + assert(custom_reg_index < info->custom_register_names.num_entries); range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list); - unsigned custom_number = range->low + custom_within_range; + const unsigned int custom_number = range->low + custom_within_range; r->group = "custom"; r->feature = &feature_custom; r->arch_info = calloc(1, sizeof(riscv_reg_info_t)); - if (!r->arch_info) + if (!r->arch_info) { + LOG_ERROR("Failed to allocate memory for r->arch_info"); return ERROR_FAIL; - ((riscv_reg_info_t *) r->arch_info)->target = target; - ((riscv_reg_info_t *) r->arch_info)->custom_number = custom_number; - sprintf(reg_name, "custom%d", custom_number); - - if (range->name) { - *reg_name = 0; - r->name = range->name; } + ((riscv_reg_info_t *)r->arch_info)->target = target; + ((riscv_reg_info_t *)r->arch_info)->custom_number = custom_number; - LOG_TARGET_DEBUG(target, "Exposing additional custom register %d (name=%s).", - number, range->name ? range->name : reg_name); + char **reg_names = info->custom_register_names.reg_names; + r->name = reg_names[custom_reg_index]; + + LOG_TARGET_DEBUG(target, "Exposing additional custom register %d (name=%s)", reg_num, r->name); custom_within_range++; if (custom_within_range > range->high - range->low) { @@ -6375,12 +6193,6 @@ int riscv_init_registers(struct target *target) } } - if (reg_name[0]) { - r->name = reg_name; - reg_name += strlen(reg_name) + 1; - assert(reg_name < info->reg_names + target->reg_cache->num_regs * - max_reg_name_len); - } r->value = calloc(1, DIV_ROUND_UP(r->size, 8)); } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 38ef982488..f2a9d688ad 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -113,6 +113,11 @@ typedef struct { #define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) +struct reg_name_table { + unsigned int num_entries; + char **reg_names; +}; + struct riscv_info { unsigned int common_magic; @@ -121,9 +126,8 @@ struct riscv_info { struct command_context *cmd_ctx; void *version_specific; - /* Single buffer that contains all register names, instead of calling - * malloc for each register. Needs to be freed when reg_list is freed. */ - char *reg_names; + struct reg_name_table custom_register_names; + char **reg_names; /* It's possible that each core has a different supported ISA set. */ int xlen;