Qualcomm is upstreaming support for our new Xqci riscv-32 extension. It’s a RISC-V version of a very successful microcontroller that we’ve had for years. The primary method of debugging crashes on hardware is to use a core dump, which gets written in 32 bit Linux format. We want to do the same moving forward, so we’ll be upstreaming 32 bit RISC-V Linux core dump support. The hardware guys also want CSR (Control and Status Registers) support, but it doesn’t look like anyone has done that.
There are 4096 CSRs (many unused), and we don’t want to save all of them in a core dump, so we’ve come up with a note called NT_CSREGMAP that uses key/value pairs. 32 bit key/value for riscv-32, and 32 bit key/64 bit value for riscv-64.
We’re talking to RVI and GDB about this, but I wanted to get the LLDB community’s take on this.
We spoke a bit before about this, glad to see the coordination happening.
Something that didn’t occur to me before, I think this would be the first core note we support that has truly dynamic contents. Someone correct me if I’m wrong there. There is AArch64 TLS, but that’s just sometimes it’s larger and has more (but in a fixed order) registers.
I wonder if this new note would be more like a minidump, which I assume from its more flexible format would be able to have a varied set of registers.
This is an LLDB internal detail though, not a knock against the proposed format.
Someone might wonder when a CPU that has CSR Foo but the core doesn’t include it, whether it in fact has CSR Foo at all. However, handling that would mean each debugger carrying a set of hardware definitions to fill in the gaps. This is likely not going to happen for any open source tool. It’s something I have done with proprietary tools in the past though.
Users will have access to the hardware manual and the manual of the debugger itself. That should be enough for anyone (probably just me ) who is curious.
This is like register fields. On some platforms we do try to detect what is present, but sometimes we cannot and we show all possibly valid fields according to the architecture manual. Trusting that users will cross check and prefer the vendor’s materials.
So you might want to document that “strategy” somewhere - but otherwise not take any technical steps to address it.
Downstream, our Hexagon simulator produces a core dump. New versions of the Hexagon core will often add new registers. So the simulator writes out qRegisterInfo data into a note, and lldb reads that and creates a DynamicRegInfo with those. I figure we could do the same for NT_CSREGMAP - read the key/value pairs, and create a DynamicRegInfo. We’re not sure if we want a sparse table in the debugger with register info, or RegInfo data. We’re still in the early stages.
My thought is “you get what’s in the dump”. If it’s not there, we don’t show it.
I chose 32 bit key because it’s a convenient size. It could be smaller; there are 4096 CSRs. We’d define the registers by name that have names, and use something like CSR_4030 for registers that don’t.
So if I had an older debugger but new hardware, it might write out CSR_4030 and I’d see that generic name in lldb. I have access to the hardware manual so I can look up what 4030 is, and new versions of lldb might later give it its proper name.
Also if I have a custom extension to my core, I wouldn’t have to modify LLDB as long as I know what number to look for (and changing this in LLDB will be pretty easy anyway).
There is some precedent too from the compiler side. You can access new system registers in assembly by using their generic names.
We’ve added support for facilitating postmortem debug of 32-bit RISC-V core dump images downstream, and are planning to upstream it in multiple phases –
The first phase will add general support for facilitating postmortem debug of 32-bit RISC-V core dump images
The second phase will add support for handling subsets of CSRs in 32-bit RISC-V core dump images
We will put these up for review immediately.
The third phase will add support for updating the register information for CSRs specified by custom extensions dynamically since CSRs specified by a custom extension could overlap with those specified by another custom extension
The fourth phase will switch to dynamic register information in the support for facilitating postmortem debug of 64-bit RISC-V core dump images; additionally, it will add support for handling subsets of CSRs in 64-bit RISC-V core dump images
These are under development and will be put up for review soon.
I need to be clear that although I can do general review of these PRs, for various reasons, I am not a RISC-V expert.
So make sure that you are aligned with whatever is happening in other debug tools like GDB (and cite those discussions if they exist), and get some of the other RISC-V llvm folks to review so you have some expert feedback.
That’s great advice, David. We’ve talked to a lot of different stakeholders (GDB, RISC-V tools, etc), and the response we’ve received has been “nobody’s doing that, so go ahead”.
Hi, just catching up and I had a little question, just curiosity nothing that needs would prevent this moving forward.
Your core creator knows which of the CSR registers are live & their names on this core, but a JTAG like controller that can create corefiles probably wouldn’t have that information for a random rv32/rv64 core. Will there be an allowance for storing the entire 16k/32kbyte CSR set for these? This approach is kind of combining two things: Reducing the size of the corefile (which could be significant in a microcontroller which may not have a lot of memory, I could imagine) and optionally documenting names for those CSR entries, right.
Nothing (other than inefficiency) keeps an NT_CSREGMAP note from having all 4096 CSRs. That would double the size of the 32 bit, and add 50% to a 64 bit, CSR chunk, though. One reason we named the note “NT_CSREGMAP” is to allow for an alternate definition, say “NT_CSR”, which would have the entire CSR register set. You probably wouldn’t want to have both!
There’s an extension that adds to the standard 4096 CSRs. A CSREGMAP could support those, using indices > 4096. We’re not proposing that support now; we’re just not precluding it.