blackmagic-debug / blackmagic

In application debugger for ARM Cortex microcontrollers.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

riscv: missing FPU register declaration makes gdb flatly reject the file

mean00 opened this issue · comments

Hi,
With a RV32 binary generated using hw fp ( such as available on the ch32v3xxx), the resulting binary is flatly rejected by blackmagic + gdb (tried several versions including gdb 13.2)

It seems the underlying reason is that gdb is trying to find the relevant registers in the xml description, does not find them, and then let the descriptor incomplete and full of null pointers.

As a result it sort of asserts with a message along "bfd requires flen 4, but target has flen 0"

I have an incomplete patch, which declares the relevant registers (in single precision) if the single fp extension is there, so that gdb is happy and loads the file.

It is incomplete, accessing the FPU registers ends up with warnings/errors (no crash though)

I dont know if submitting that incomplete patch is better than nothing or if you prefer to wait till someone (may take some times in my case ) provides a fully operational patch.

Thank you

The RISC-V FPU handling in BMD is purely a stub, and we had absolute heck trying to figure out what GDB considers the RISC-V FPU to look like for a register description and how any of that would work and look as none of our test parts have one. Any information you can share that gets that improved or fixed is welcome!

To be more specific,

/* XXX: TODO - implement generation of the FPU feature and registers */
needs replacing with a FPU description builder routine like
static size_t cortexar_build_target_fpu_description(char *const buffer, size_t max_length)
{
size_t print_size = max_length;
/* Terminate the previous feature block and start the new */
int offset = snprintf(buffer, print_size, "</feature><feature name=\"org.gnu.gdb.arm.vfp\">");
/* Build the FPU general purpose register descriptions for d0-d15 */
for (uint8_t i = 0; i < 16U; ++i) {
if (max_length != 0)
print_size = max_length - (size_t)offset;
offset += snprintf(buffer + offset, print_size, "<reg name=\"d%u\" bitsize=\"64\" type=\"ieee_double\"/>", i);
}
/* Build the FPU status/control register (fpscr) description */
if (max_length != 0)
print_size = max_length - (size_t)offset;
offset += snprintf(buffer + offset, print_size, "<reg name=\"fpscr\" bitsize=\"32\"/>");
/* offset is now the total length of the string created, discard the sign and return it. */
return (size_t)offset;
}
called like
/* Handle when the core has a FPU (VFP) */
if (has_fpu) {
if (max_length != 0)
print_size = max_length - (size_t)offset;
offset += cortexar_build_target_fpu_description(buffer + offset, print_size);
}
based on the data in https://github.com/bminor/binutils-gdb/blob/1d506c2/gdb/features/riscv/32bit-fpu.xml most likely

My approach was to look in actual gdb code (13.2) and the initial report from sifive
( https://patchwork.kernel.org/project/qemu-devel/patch/20181228220731.4753-1-jimw@sifive.com/ )

The relevant part are these (full patch attached for reference)

static const char *riscv_fpu_regs[] ={"t0","t1","t2", "t3","t4","t5","t6","t7",
"s0","s1","a0","a1","a2","a3","a4",
"a5","a6","a7","s2","s3","s4","s5",
"s6","s7","s8","s9","s10","s11","t8",
"t9","t10","t11"};

static const char *riscv_fpu_ctrl_regs[]={"flags","rm","csr"};

   /* Basic single precision support */
   if (extensions & RV_ISA_EXT_SINGLE_FLOAT) {
           const int first_fpu_register = 33;         // fixme!
           const int first_fpu_control_register = 66; // fixme!

           if (max_length != 0)
                   print_size = max_length - (size_t)offset;
           offset += snprintf(buffer + offset, print_size, "</feature><feature name=\"org.gnu.gdb.riscv.fpu\">");

           for (int i = 0; i < sizeof(riscv_fpu_regs) / sizeof(riscv_fpu_regs[0]); i++) {
                   if (max_length != 0)
                           print_size = max_length - (size_t)offset;
                   offset += snprintf(buffer + offset, print_size,
                           "<reg name=\"f%s\" bitsize=\"32\" type=\"ieee_single\" regnum=\"%u\" group=\"float\"/>",
                           riscv_fpu_regs[i], i + first_fpu_register);
           }
           for (int i = 0; i < sizeof(riscv_fpu_ctrl_regs) / sizeof(riscv_fpu_ctrl_regs[0]); i++) {
                   if (max_length != 0)
                           print_size = max_length - (size_t)offset;
                   offset += snprintf(buffer + offset, print_size,
                           "<reg name=\"f%s\" bitsize=\"32\" type=\"int\" regnum=\"%u\" group=\"float\" save-restore=\"no\"/>",
                           riscv_fpu_ctrl_regs[i], i + first_fpu_control_register);
           }
   }

with that, gdb accepts the binary and i can debug it. Of course everything related to the fpu registers is not working.
I've seen that the csrs related to the fpu (fflags etc.. ) MAY be duplicated also in the csr sections, it's not crystal clear.

Thank you.

blackmagic_riscv_single_fp_support.patch.gz
related

(and it is 32 bits only)