Re: Prologue analysis interface

Daniel Jacobowitz
2005-11-23T02:05:00Z

On Tue, Nov 22, 2005 at 03:49:59PM -0800, Jim Blandy wrote:
> On 11/22/05, Daniel Jacobowitz <drow@false.org> wrote:
> > What I don't know is how much flexibility is needed. Maybe it's more
> > than I thought.
>
> Could be less than I think. I'm interested to see what you come up with.
>
> > I'm penciling in reading the existing s390 analyzer and posted m32c
> > analyzers for tonight's schedule, since this keeps coming up in
> > conversation. I promise I'll get back to you about this soon.
>
> Thanks. The m32c port is blocked on this; I'd like to get it out of the way.

OK, here's what I've got from reading the m32c port. I'm afraid that
I don't have a whole lot of time to build such an interface myself,
just now; what GDB time I have for the next couple of weeks is going to
go to implementing my "target properties query" interface from earlier
this year. But I do still feel that this code should call into the
tdep file rather than the other way around.

Almost everything the analyzer does for m32c is perfectly explainable
as a generic concept. 80% of that is decoding what an instruction
accomplishes. The rest seems to break down into:

- Setting an initial state, by modeling the call instruction.

- Recognizing "frame-related" stores to the stack, to find the real end
of the prologue.

- Recognizing whether a frame pointer has been set up, and if so, what
it is and its relation to the CFA.

- Finding saved registers in the stack after analyzing.

- All of the infrastructure for a frame unwinder based on this data.

The frame pointer bits do involve some target heuristics. I think we
could do away with that, if we had reason to (i.e. an interesting
target which didn't use a fixed register for this). But I'm not
suggesting it until we have such a target, hopefully not for a long
time.

The simplest form of a common-code-driven interface would just call
target supplied routines to initialize state, decode and process an
instruction, and finalize any use of a frame pointer. The common code
would subsume m32c_skip_prologue through m32c_frame_sniffer.
m32c_analyze_prologue would be broken up into the init/decode/fini
hooks, or even (for now this seems just as good) left as containing the
whole loop, but the pv_area_scan call at the end could live in
target-independent code.

I did have a more sophisticated approach in mind but I think it's not
justified yet. I spoke with Alan briefly about supplying some of the
decoding information from the disassembler, which would help, but it's
a big project.

One thing that jumped out at me in the m32c analyzer. You record
pushes of registers as frame related, and you record spills of argument
registers using "mov" as frame related. This seems to me to defeat the
appeal of a code-driven analyzer somewhat; it'll break if the compiler
uses "mov" instead of "push" to save a register. I think all stores of
the original value of registers (or part of that value), to the stack,
are effectively frame related; whether they're arg registers or not is
irrelevant. At that point it's pretty much a target-independent
concept.

The question in my mind is whether the target-independently-describable
tweaks we need for this are good for all targets. And as unlikely as
it may seem, I think it's true. For instance, S/390 has a bit to use
only the stack slot with the highest address if it sees multiple saves.
We could easily enough handle that in the target-dependent part in the
model I described above, but we don't have to (with an appropriate
check for the direction of the stack). It's probably good just about
everywhere.

If time proves me wrong on this, we can migrate checks into targets as
necessary. I'm trying to minimize the amount of "boilerplate" code a
target needs, so that we can (A) make targets easier and smaller,
and (B) improve the template bits and see benefit uniformly.

The S/390 code is a lot less clear-cut than the m32c, not surprisingly.
Most of the tangly bits are related to frameless functions. Some of
this could be further commonized too, but for now my suggested plan
above should work for this also.

Both the S/390 and m32c use heuristics to terminate the frame chain.
I agree that these are necessary, but I've also come to see a bit of
the counterargument that they're in the wrong place. I think what we
need may be an additional method for frames to say "this same unwinder
thinks the stack is finished here". Pathological examples: calling
thread_start() or an optimized noreturn function from gdb.

So, for now, how about that? Just provide something along the lines of
the tramp-frame interface that does the busywork. We can adjust later
what is busywork and what isn't.

--
Daniel Jacobowitz
CodeSourcery, LLC