From 85cde238b39f38707f08e9ebd4077faf709ecad2 Mon Sep 17 00:00:00 2001 From: Anastasiya Chernikova Date: Thu, 6 Jul 2023 10:04:39 +0300 Subject: [PATCH] target/riscv: Adding register tables to make register names consistent #31163 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 | 22 +- src/target/riscv/riscv.c | 668 +++++++++++------------------------ src/target/riscv/riscv.h | 11 +- 5 files changed, 237 insertions(+), 472 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 e4e6e43b45..4b8cc92da0 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1042,7 +1042,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; } @@ -1243,7 +1243,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; } @@ -1318,7 +1318,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 817d65f6cf..d05bc45c95 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -966,7 +966,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); } @@ -1202,7 +1202,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"); @@ -1222,7 +1222,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; } @@ -1480,7 +1480,7 @@ static int register_read_progbuf(struct target *target, uint64_t *value, if (riscv_program_csrr(&program, S0, number) != ERROR_OK) return ERROR_FAIL; } else { - LOG_TARGET_ERROR(target, "Unsupported register: %s", gdb_regno_name(number)); + LOG_TARGET_ERROR(target, "Unsupported register: %s", gdb_regno_name(target, number)); return ERROR_FAIL; } @@ -1594,7 +1594,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); @@ -1612,7 +1612,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; @@ -1622,7 +1622,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); @@ -1641,7 +1641,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; @@ -2327,7 +2327,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; } } @@ -4604,7 +4604,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; @@ -4634,7 +4634,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 7962a47dca..3d1e0e89d4 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -36,6 +36,7 @@ #define DTMCONTROL_VERSION (0xf) #define DBUS 0x11 +#define REG_NAME_MAX_LENGTH 32u static uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; struct scan_field select_dtmcontrol = { @@ -493,7 +494,7 @@ static void riscv_deinit_target(struct target *target) free(entry); } - free(info->reg_names); + free(info->custom_register_names.reg_names); free(target->arch_info); target->arch_info = NULL; @@ -2551,7 +2552,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; } @@ -4765,7 +4767,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); } @@ -4849,7 +4851,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); } @@ -4990,7 +4992,7 @@ int riscv_dmi_write_u64_bits(struct target *target) * 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); @@ -5084,189 +5086,140 @@ int riscv_enumerate_triggers(struct target *target) return ERROR_OK; } -const char *gdb_regno_name(enum gdb_regno regno) +struct reg_name { + char name[REG_NAME_MAX_LENGTH]; +}; + +struct csr_info { + unsigned int number; + const char *name; +}; + +struct csr_info_table { + unsigned int records_num; + const struct csr_info *csr_records; +}; + +static void initialize_reg_name(struct reg_name *buf, const char *name_prefix) { - static char buf[32]; + const unsigned int size_buf = ARRAY_SIZE(buf->name); - 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); + int read_symbols = snprintf(buf->name, size_buf, "%s", name_prefix); + assert(read_symbols > 0 && "register name is too long"); +} + +static void initialize_reg_name_with_prefixed_name(struct reg_name *buf, const char *name_prefix, + unsigned int num_in_name) +{ + const unsigned int size_buf = ARRAY_SIZE(buf->name); + + int read_symbols = snprintf(buf->name, size_buf, "%s%d", name_prefix, num_in_name); + assert(read_symbols > 0 && "register name is too long"); +} + +const char *gdb_regno_name(struct target *target, enum gdb_regno regno) +{ + if (regno >= GDB_REGNO_COUNT) { + RISCV_INFO(info); + assert(info->custom_register_names.reg_names); + assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.names_num); + return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT].name; + } + + static struct reg_name buf[GDB_REGNO_COUNT] = { + [GDB_REGNO_ZERO] = { .name = "zero" }, + [GDB_REGNO_RA] = { .name = "ra" }, + [GDB_REGNO_SP] = { .name = "sp" }, + [GDB_REGNO_GP] = { .name = "gp" }, + [GDB_REGNO_TP] = { .name = "tp" }, + [GDB_REGNO_T0] = { .name = "t0" }, + [GDB_REGNO_T1] = { .name = "t1" }, + [GDB_REGNO_T2] = { .name = "t2" }, + [GDB_REGNO_FP] = { .name = "fp" }, + [GDB_REGNO_S1] = { .name = "s1" }, + [GDB_REGNO_A0] = { .name = "a0" }, + [GDB_REGNO_A1] = { .name = "a1" }, + [GDB_REGNO_A2] = { .name = "a2" }, + [GDB_REGNO_A3] = { .name = "a3" }, + [GDB_REGNO_A4] = { .name = "a4" }, + [GDB_REGNO_A5] = { .name = "a5" }, + [GDB_REGNO_A6] = { .name = "a6" }, + [GDB_REGNO_A7] = { .name = "a7" }, + [GDB_REGNO_S2] = { .name = "s2" }, + [GDB_REGNO_S3] = { .name = "s3" }, + [GDB_REGNO_S4] = { .name = "s4" }, + [GDB_REGNO_S5] = { .name = "s5" }, + [GDB_REGNO_S6] = { .name = "s6" }, + [GDB_REGNO_S7] = { .name = "s7" }, + [GDB_REGNO_S8] = { .name = "s8" }, + [GDB_REGNO_S9] = { .name = "s9" }, + [GDB_REGNO_S10] = { .name = "s10" }, + [GDB_REGNO_S11] = { .name = "s11" }, + [GDB_REGNO_T3] = { .name = "t3" }, + [GDB_REGNO_T4] = { .name = "t4" }, + [GDB_REGNO_T5] = { .name = "t5" }, + [GDB_REGNO_T6] = { .name = "t6" }, + [GDB_REGNO_PC] = { .name = "pc" }, + [GDB_REGNO_CSR0] = { .name = "csr0" }, + [GDB_REGNO_PRIV] = { .name = "priv" }, + [GDB_REGNO_FT0] = { .name = "ft0" }, + [GDB_REGNO_FT1] = { .name = "ft1" }, + [GDB_REGNO_FT2] = { .name = "ft2" }, + [GDB_REGNO_FT3] = { .name = "ft3" }, + [GDB_REGNO_FT4] = { .name = "ft4" }, + [GDB_REGNO_FT5] = { .name = "ft5" }, + [GDB_REGNO_FT6] = { .name = "ft6" }, + [GDB_REGNO_FT7] = { .name = "ft7" }, + [GDB_REGNO_FS0] = { .name = "fs0" }, + [GDB_REGNO_FS1] = { .name = "fs1" }, + [GDB_REGNO_FA0] = { .name = "fa0" }, + [GDB_REGNO_FA1] = { .name = "fa1" }, + [GDB_REGNO_FA2] = { .name = "fa2" }, + [GDB_REGNO_FA3] = { .name = "fa3" }, + [GDB_REGNO_FA4] = { .name = "fa4" }, + [GDB_REGNO_FA5] = { .name = "fa5" }, + [GDB_REGNO_FA6] = { .name = "fa6" }, + [GDB_REGNO_FA7] = { .name = "fa7" }, + [GDB_REGNO_FS2] = { .name = "fs2" }, + [GDB_REGNO_FS3] = { .name = "fs3" }, + [GDB_REGNO_FS4] = { .name = "fs4" }, + [GDB_REGNO_FS5] = { .name = "fs5" }, + [GDB_REGNO_FS6] = { .name = "fs6" }, + [GDB_REGNO_FS7] = { .name = "fs7" }, + [GDB_REGNO_FS8] = { .name = "fs8" }, + [GDB_REGNO_FS9] = { .name = "fs9" }, + [GDB_REGNO_FS10] = { .name = "fs10" }, + [GDB_REGNO_FS11] = { .name = "fs11" }, + [GDB_REGNO_FT8] = { .name = "ft8" }, + [GDB_REGNO_FT9] = { .name = "ft9" }, + [GDB_REGNO_FT10] = { .name = "ft10" }, + [GDB_REGNO_FT11] = { .name = "ft11" }, + + #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = { .name = #csr_name }, + #include "encoding.h" + #undef DECLARE_CSR + }; + + static bool initialized; + + if (!initialized) { + for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i) { + if (buf[i].name[0]) + continue; + else if (i <= GDB_REGNO_XPR31) + initialize_reg_name_with_prefixed_name(&buf[i], "x", i - GDB_REGNO_ZERO); + else if (i <= GDB_REGNO_V31 && i >= GDB_REGNO_V0) + initialize_reg_name_with_prefixed_name(&buf[i], "v", i - GDB_REGNO_V0); + else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) + initialize_reg_name_with_prefixed_name(&buf[i], "csr", i - GDB_REGNO_CSR0); else - sprintf(buf, "gdb_regno_%d", regno); - return buf; + assert(!"The table must already be filled out"); + } + initialized = true; } + return buf[regno].name; } - /** * This function is the handler of user's request to read a register. */ @@ -5365,14 +5318,39 @@ static struct reg_arch_type riscv_reg_arch_type = { .set = register_set }; -struct csr_info { - unsigned number; - const char *name; -}; - -static int cmp_csr_info(const void *p1, const void *p2) +static int initialize_custom_register_names(struct list_head *expose_custom, + struct reg_name_table *custom_register_names) { - return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); + 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; + + custom_register_names->reg_names = calloc(custom_regs_num, sizeof(struct reg_name)); + custom_register_names->names_num = custom_regs_num; + if (!custom_register_names->reg_names) { + LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names"); + return ERROR_FAIL; + } + struct reg_name *additional_regs = custom_register_names->reg_names; + range_list_t *range; + unsigned int custom_registers_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) + initialize_reg_name(&additional_regs[custom_registers_index], range->name); + else + initialize_reg_name_with_prefixed_name(&additional_regs[custom_registers_index], + "custom", custom_number); + ++custom_registers_index; + } + } + return ERROR_OK; } int riscv_init_registers(struct target *target) @@ -5382,32 +5360,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 (initialize_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) { + LOG_TARGET_ERROR(target, "initialize_custom_register_names failed"); + return ERROR_FAIL; } + target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.names_num; 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" @@ -5539,152 +5512,46 @@ 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; @@ -5698,119 +5565,20 @@ 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; + unsigned int csr_number = reg_num - GDB_REGNO_CSR0; + 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 + }; - 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); + assert(csr_number < ARRAY_SIZE(is_csr_in_buf)); + if (!is_csr_in_buf[csr_number]) { /* 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 @@ -6011,12 +5779,11 @@ int riscv_init_registers(struct target *target) 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); + LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", + csr_number, r->name); r->exist = true; break; @@ -6031,45 +5798,44 @@ int riscv_init_registers(struct target *target) } } - } 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. */ + struct reg_name *additional_regs = info->custom_register_names.reg_names; + const unsigned int custom_register_index = reg_num - GDB_REGNO_COUNT; + assert(!list_empty(&info->expose_custom)); + assert(custom_register_index < info->custom_register_names.names_num); range_list_t *range = list_first_entry(&info->expose_custom, range_list_t, list); - unsigned custom_number = range->low + custom_within_range; + 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); + r->name = additional_regs[custom_register_index].name; + + 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) { @@ -6078,12 +5844,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 6afd3c1647..730a2e3802 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -111,6 +111,13 @@ typedef struct { char *name; } range_list_t; +struct reg_name; + +struct reg_name_table { + unsigned int names_num; + struct reg_name *reg_names; +}; + struct riscv_info { unsigned int common_magic; @@ -119,9 +126,7 @@ 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; /* It's possible that each core has a different supported ISA set. */ int xlen;