From: Andrew Cagney <cagney@gnu.org>
To: Joel Brobecker <brobecker@gnat.com>
Cc: gdb-patches@sources.redhat.com
Subject: Re: [RFA/RFC] fix problems with unwinder on mips-irix
Date: Fri, 03 Sep 2004 20:17:00 -0000 [thread overview]
Message-ID: <4138D0F8.1000106@gnu.org> (raw)
In-Reply-To: <20040902230928.GF1216@gnat.com>
> Andrew,
>
> FYI: This is something I have started investigating but can't finish
> just yet because I have to move off to something else. You said:
>
>
>>> This kernel_trap stuff isn't applicable here.
>>>
>>
>>>> > kernel_trap = PROC_REG_MASK (proc_desc) & 1;
>>>> > gen_mask = kernel_trap ? 0xFFFFFFFF : PROC_REG_MASK (proc_desc);
>>>> > float_mask = kernel_trap ? 0xFFFFFFFF : PROC_FREG_MASK (proc_desc);
Ok, first here's why this ``can't happen'':
If mips_insn32_frame_cache gets all the calls inlined we find the
sequence (taking a birds eye view):
-- from mips32_heuristic_proc_desc
clear PROC_DESC
for (pc = func_start; pc < magic; pc+=4)
fetch INSN at PC
set PROC_DESC* and TEMP_SAVED_REGS according to INSN
-- from mips_insn32_frame_cache
if (in prologue && !``kernel_trap'')
for (pc = func_start; pc < current_instruction; pc+=4)
fetch INSN at PC
set GEN_MASK according to INSN
else
set GEN_MASK according to PROC_DESC
-- from mips_insn32_frame_cache
for (reg in gen_mask)
set saved regs according to GEN_MASK
what we notice (if bits are examined in detail):
- mips32_heuristic_proc_desc _never_ sets MIPS_REG_MASK&1 (i.e.,
kernel_flag) i.e., for kernel_flag to be set, a true proc_desc or
- TEMP_SAVED_REGS is never read!
- the code packs the saved register information into a scratch PROC_DESC
only to immediatly turn around and unpack that same information (dumb!)
- when !``In any frame other than the innermost or a frame interrupted
by a signal, we assume that all registers have been saved. This assumes
that all register saves in a function happen before the first function
call.'' (i.e., when sitting in a prologue) the instructions are iterated
over _twice_: first using the extreemly complex
mips32_heuristic_proc_desc; and second by a remarkably simple algorithm.
- regardless of ``In any frame other than the innermost or a frame
interrupted by a signal, we assume that all registers have been saved.
This assumes that all register saves in a function happen before the
first function call.'', the list of saved registers is determined by
examining the prologue.
From other architectures we know that there's no reason to
differentiate between the in and out-of prologue cases and all the above
can be reduced to:
for (pc = func_start; pc < current-pc && pc in prologue; pc+=4)
fetch instruction at pc
according to INSN set saved-regs directly
where the saved reg table is updated directly and PROC_DESC /
kernel_flag are both eliminated.
--
Now why the theory appears broken:
> But in fact for a reason I don't completely understand just yet, we
> do have kernel_trap set occasionally (I measured ~300+ times in our
> testsuite). For instance, in all-bin.exp, debugging all-types:
>
> (gdb) break main
> (gdb) run
> Starting program: /[...]/all-types
>
> Breakpoint 1, main () at all-types.c:35
> 35 dummy();
> (gdb) next
> !! -> *** DEBUG: kernel_trap in mips_insn32_frame_cache ***
> 36 return 0;
>
> I don't have all the details just yet, but my semi-educated guess
> is that the sequence of events that lead to this is the following:
> . User enters next command
> . GDB does a next, and waits for events
> . We land inside dummy (unverified)
That would trigger a frame unwind (to get the caller PC so that the
return-address breakpoint can be set) which most likely goes through
this path:
> static const struct frame_unwind *
> mips_mdebug_frame_sniffer (struct frame_info *next_frame)
> ...
> /* In any frame other than the innermost or a frame interrupted by a
> signal, we assume that all registers have been saved. This
> assumes that all register saves in a function happen before the
> first function call. */
> if (!in_prologue (pc, PROC_LOW_ADDR (proc_desc)))
> return &mips_mdebug_frame_unwind;
>
> return NULL;
and lead to mips_insn32* being chosen. mips_insn32 would then end up
going through this path:
>
> static mips_extra_func_info_t
> find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame)
> {
> mips_extra_func_info_t proc_desc;
> CORE_ADDR startaddr = 0;
>
> proc_desc = non_heuristic_proc_desc (pc, &startaddr);
>
> if (proc_desc)
> {
> /* IF this is the topmost frame AND
> * (this proc does not have debugging information OR
> * the PC is in the procedure prologue)
> * THEN create a "heuristic" proc_desc (by analyzing
> * the actual code) to replace the "official" proc_desc.
> */
> if (next_frame == NULL)
> {
> struct symtab_and_line val;
> struct symbol *proc_symbol =
> PROC_DESC_IS_DUMMY (proc_desc) ? 0 : PROC_SYMBOL (proc_desc);
>
> if (proc_symbol)
> {
> val = find_pc_line (BLOCK_START
> (SYMBOL_BLOCK_VALUE (proc_symbol)), 0);
> val.pc = val.end ? val.end : pc;
> }
> if (!proc_symbol || pc < val.pc)
> {
> mips_extra_func_info_t found_heuristic =
> heuristic_proc_desc (PROC_LOW_ADDR (proc_desc),
> pc, next_frame, cur_frame);
> if (found_heuristic)
> proc_desc = found_heuristic;
> }
> }
> }
> else
Remember: there is an mdebug PROC_DESC but it was being ignored;
next_frame is never NULL. That leads to the mdebug PROC_DESC being
used. Outch!
What I don't get is how come this bit of:
> /* Not sure exactly what kernel_trap means, but if it means the
> kernel saves the registers without a prologue doing it, we better
> not examine the prologue to see whether registers have been saved
> yet. */
> kernel_trap = PROC_REG_MASK (proc_desc) & 1;
> if (kernel_trap)
> return &mips_mdebug_frame_unwind;
didn't kick in forcing the use of the mdebug unwinder.
Anyway, eew!
This is where we need to be ruthless with the code - just inline the lot
because (even when the testresults regress) we can see that it is more
correct and more maintainable then what we're currently looking at. We
need to push the mips-tdep.c file out of the local minima that it has
become trapped in.
Andrew
prev parent reply other threads:[~2004-09-03 20:17 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-07-23 1:11 Joel Brobecker
2004-07-30 0:22 ` Andrew Cagney
2004-08-03 4:44 ` Joel Brobecker
2004-08-04 1:43 ` Andrew Cagney
2004-08-06 18:31 ` Joel Brobecker
2004-08-06 19:13 ` Andrew Cagney
2004-08-30 18:18 ` Joel Brobecker
2004-08-30 19:32 ` Andrew Cagney
2004-08-31 23:44 ` Joel Brobecker
2004-09-01 14:57 ` Andrew Cagney
2004-09-02 23:09 ` Joel Brobecker
2004-09-03 20:17 ` Andrew Cagney [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4138D0F8.1000106@gnu.org \
--to=cagney@gnu.org \
--cc=brobecker@gnat.com \
--cc=gdb-patches@sources.redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox