Re: [PATCH 7/7] DWARF: add the config option

From: Josh Poimboeuf
Date: Fri May 19 2017 - 16:54:53 EST


On Sun, May 07, 2017 at 11:55:24AM -0500, Josh Poimboeuf wrote:
> I'm thinking/hoping that information can be expressed in a simple, easy
> to parse, reasonably sized data structure. Something like a sorted
> array of this:
>
> struct undwarf {
> unsigned int ip; /* instruction pointer (relative offset from base) */
> unsigned prev_frame:13; /* offset to previous frame from current stack pointer */
> unsigned regs:1; /* whether prev_frame contains entry regs (regs->ip) */
> unsigned align:2; /* some details for dealing with gcc stack realignment */
> } __packed;
>
> extern struct undwarf undwarves[];
>
> One instance of the structure would exist for each time the stack
> pointer changes, e.g. for every function entry, push/pop, and rsp
> add/subtract. The data could be assembled and sorted offline, possibly
> derived from DWARF, or more likely, generated by objtool. After doing
> some rough calculations, I think the section size would be comparable to
> the sizes of the DWARF .eh_frame sections it would replace.
>
> If it worked, the "undwarf" unwinder would be a lot simpler than a real
> DWARF unwinder. And validating the sanity of the data at runtime would
> be a lot more straightforward. It could ensure that each stack pointer
> is within the bounds of the current stack, like our current unwinder
> does.

I've been hacking away at this, and so far it's working well. The code
is much simpler than a DWARF unwinder. Right now the kernel piece is
only ~350 lines of code. The vast majority of the changes are in
objtool.

It's now successfully unwinding through entry code and most other asm
files, dumping entry regs, dealing with aligned stacks, dynamic stacks,
etc.

Here's the struct in its current state:

#define UNDWARF_REG_UNDEFINED 0
#define UNDWARF_REG_CFA 1
#define UNDWARF_REG_SP 2
#define UNDWARF_REG_FP 3
#define UNDWARF_REG_SP_INDIRECT 4
#define UNDWARF_REG_FP_INDIRECT 5
#define UNDWARF_REG_R10 6
#define UNDWARF_REG_DI 7
#define UNDWARF_REG_DX 8

#define UNDWARF_TYPE_NORMAL 0
#define UNDWARF_TYPE_REGS 1
#define UNDWARF_TYPE_REGS_IRET 2

struct undwarf_state {
int ip;
unsigned int len;
short cfa_offset;
short fp_offset;
unsigned cfa_reg:4;
unsigned fp_reg:4;
unsigned type:2;
};

With frame pointers disabled, around 300,000 of those structs are needed
for my kernel, which works out to be 4.7M of data. By comparison, the
DWARF eh_frame sections would be 2.1M. I think we should be able to
compress it down to a comparable size by rearranging the data a little
bit.

The entry code needs some annotations to give some hints to objtool
about how to generate the data, but it's not bad:

https://paste.fedoraproject.org/paste/Xq3bPlx5An0Si7AshZTdkF5M1UNdIGYhyRLivL9gydE=

I still have a lot of work to do on the tooling side: module support,
sorting the undwarf table at build time, and a lot of cleanups. But
overall it's looking feasible.

--
Josh