MIPS: Correct heuristic prologue termination conditions

This change addresses a regression in gdb.dwarf2/dw2-skip-prologue.exp
across MIPS16 multilibs:

(gdb) file .../gdb.dwarf2/dw2-skip-prologue
Reading symbols from .../gdb.d/gdb.dwarf2/dw2-skip-prologue...done.
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break main
warning: Breakpoint address adjusted from 0x00400725 to 0x00400721.
Breakpoint 1 at 0x400721
(gdb) set remotetimeout 5
(gdb) kill
The program is not being run.
(gdb)
[...]
target remote ...:2345
Reading symbols from .../mips16/lib/ld.so.1...done.
warning: Breakpoint address adjusted from 0x00400725 to 0x00400721.
warning: Breakpoint address adjusted from 0x00400725 to 0x00400721.
0x2aaa8e81 in __start () from .../mips16/lib/ld.so.1
(gdb) continue
Continuing.
warning: Breakpoint address adjusted from 0x00400725 to 0x00400721.
warning: Breakpoint 1 address previously adjusted from 0x00400725 to
0x00400721.
Breakpoint 1, 0x00400721 in main ()
(gdb) break func
Breakpoint 2 at 0x4006a1: func. (2 locations)
(gdb) continue
Continuing.
warning: GDB can't find the start of the function at 0x4006dd.

    GDB is unable to find the start of the function at 0x4006dd
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0x4006dd for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.

Program received signal SIGBUS, Bus error.
0x0040072b in main ()
(gdb) FAIL: gdb.dwarf2/dw2-skip-prologue.exp: continue to breakpoint: func

-- notice the breakpoint adjustment messages that are already a bad
sign.  These happen when a breakpoint is requested in a branch delay
slot and are not supposed to happen unless explicitly requested with an
address pointing to a branch delay slot instruction.  No symbol or line
debug information is supposed to direct GDB to place a breakpoint in a
delay slot.

Here's how `main' looks like:

00400718 <main>:
  400718:	64f5      	save	40,ra,s0-s1
  40071a:	1a00 01a8 	jal	4006a0 <func>
  40071e:	0104      	addiu	s1,sp,16
  400720:	1a00 01b7 	jal	4006dc <func+0x3c>
  400724:	6702      	move	s0,v0
  400726:	e049      	addu	v0,s0,v0
  400728:	65b9      	move	sp,s1
  40072a:	6473      	restore	24,ra,s0-s1
  40072c:	e8a0      	jrc	ra
  40072e:	6500      	nop

-- so 0x400725 is the MIPS16 instruction address of the first MOVE
instruction seen above, in a delay slot of the preceding JAL instruction
indeed.  This test case arranges for `main' to have no debug information
so it is one of the heuristic prologue scanners, `mips16_scan_prologue'
specifically in this case, that is responsible for finding the right
location for the breakpoint to place.

In this case the prologue really ends with the ADDIU instruction,
reordered into the delay slot of the first JAL instruction.  Of course
we can't place the breakpoint for `main' after it as by doing so we'll
let `func' to be called before hitting this breakpoint.  So the
breakpoint has to go at the JAL instruction instead, or 0x40071b.

To make a general case out of it we must never consider any jump or
branch instruction to be a part of a function's prologue.  In the
presence of a jump or branch at the beginning of a function the furthest
instruction examined for the purpose of constructing frame information
can be one in the delay slot of that jump or branch if present, and
otherwise -- that is when the jump or branch is compact and has no delay
slot -- the instruction immediately preceding the jump or branch.

This change implements that approach across prologue scanners for the
three instruction ISAs.  In implementing it I have factored out code
from the existing `*_instruction_has_delay_slot' handlers to be shared
and a side effect for the microMIPS implementation is it now always
fetches the second 16-bit halfword of 32-bit instructions even if it
eventually is not going to be needed.  I think it's an acceptable
tradeoff for the purpose of code sharing.

To make things more consistent I also carried logic from
`micromips_scan_prologue' over to the other two scanners to accept (and
ignore) a single non-prologue non-control transfer instruction reordered
by the compiler into the prologue.  While doing this I simplified the
exit path from the scan loop such that `end_prologue_addr' is set only
once.  This made some concerns expressed in comments no longer
applicable, although even before they were not valid.

I have not fixed the logic around `load_immediate_bytes' in
`mips32_scan_prologue' though, it remains broken, although I took care
not to break it more.  An approach similar to one taken for handling
larger stack adjustments in `micromips_scan_prologue' will have to be
eventually implemented here.

For regression testing I used my usual choice of the mips-linux-gnu
target and the following multilibs:

-EB
-EB -msoft-float
-EB -mips16
-EB -mips16 -msoft-float
-EB -mmicromips
-EB -mmicromips -msoft-float
-EB -mabi=n32
-EB -mabi=n32 -msoft-float
-EB -mabi=64
-EB -mabi=64 -msoft-float

and the -EL variants of same.

That removed gdb.dwarf2/dw2-skip-prologue.exp failures across MIPS16
multilibs, the test log now shows:

(gdb) file .../gdb.dwarf2/dw2-skip-prologue
Reading symbols from .../gdb.d/gdb.dwarf2/dw2-skip-prologue...done.
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break main
Breakpoint 1 at 0x40071b
(gdb) set remotetimeout 5
(gdb) kill
The program is not being run.
(gdb)
[...]
target remote ...:2345
Reading symbols from .../mips16/lib/ld.so.1...done.
0x2aaa8e81 in __start () from .../mips16/lib/ld.so.1
(gdb) continue
Continuing.

Breakpoint 1, 0x0040071b in main ()
(gdb) break func
Breakpoint 2 at 0x4006a1: func. (2 locations)
(gdb) continue
Continuing.

Breakpoint 2, func (param=0) at main.c:5
5	   This program is free software; you can redistribute it and/or modify
(gdb) PASS: gdb.dwarf2/dw2-skip-prologue.exp: continue to breakpoint: func

-- so things look like intended.

That also did regress, again across MIPS16 multilibs, another test case,
gdb.base/step-symless.exp:

(gdb) file .../gdb.d/gdb.base/step-symless
Reading symbols from .../gdb.base/step-symless...done.
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break main
Breakpoint 1 at 0x4006d3
(gdb) set remotetimeout 5
(gdb) kill
The program is not being run.
(gdb)
[...]
target remote ...:2345
Reading symbols from .../mips16/lib/ld.so.1...done.
0x2aaa8e81 in __start () from .../mips16/lib/ld.so.1
(gdb) continue
Continuing.

Breakpoint 1, 0x004006d3 in main ()
(gdb) break symful
Breakpoint 2 at 0x4006a5
(gdb) step
Single stepping until exit from function main,
which has no line number information.
warning: GDB can't find the start of the function at 0x4006b9.

    GDB is unable to find the start of the function at 0x4006b9
and thus can't determine the size of that function's stack frame.
This means that GDB may be unable to access that stack frame, or
the frames below it.
    This problem is most likely caused by an invalid program counter or
stack pointer.
    However, if you think GDB should simply search farther back
from 0x4006b9 for code which looks like the beginning of a
function, you can increase the range of the search using the `set
heuristic-fence-post' command.
0x004006b9 in ?? ()
(gdb) FAIL: gdb.base/step-symless.exp: step

-- but that is actually a good sign.  Here `main', again, has no debug
information and code involved looks like:

004006a0 <symful>:
  4006a0:	6491      	save	8,s1
  4006a2:	673d      	move	s1,sp
  4006a4:	b204      	lw	v0,4006b4 <symful+0x14>
  4006a6:	9a40      	lw	v0,0(v0)
  4006a8:	4261      	addiu	v1,v0,1
  4006aa:	b203      	lw	v0,4006b4 <symful+0x14>
  4006ac:	da60      	sw	v1,0(v0)
  4006ae:	65b9      	move	sp,s1
  4006b0:	6411      	restore	8,s1
  4006b2:	e8a0      	jrc	ra
  4006b4:	0041      	addiu	s0,sp,260
  4006b6:	0860      	la	s0,400834 <__libc_start_main@mips16plt+0x54>
  4006b8:	6491      	save	8,s1
  4006ba:	673d      	move	s1,sp
  4006bc:	b204      	lw	v0,4006cc <symful+0x2c>
  4006be:	9a40      	lw	v0,0(v0)
  4006c0:	4261      	addiu	v1,v0,1
  4006c2:	b203      	lw	v0,4006cc <symful+0x2c>
  4006c4:	da60      	sw	v1,0(v0)
  4006c6:	65b9      	move	sp,s1
  4006c8:	6411      	restore	8,s1
  4006ca:	e8a0      	jrc	ra
  4006cc:	0041      	addiu	s0,sp,260
  4006ce:	0860      	la	s0,40084c <__libc_start_main@mips16plt+0x6c>

004006d0 <main>:
  4006d0:	64d4      	save	32,ra,s1
  4006d2:	1a00 01ae 	jal	4006b8 <symful+0x18>
  4006d6:	0104      	addiu	s1,sp,16
  4006d8:	1a00 01a8 	jal	4006a0 <symful>
  4006dc:	6500      	nop
  4006de:	6740      	move	v0,zero
  4006e0:	65b9      	move	sp,s1
  4006e2:	6452      	restore	16,ra,s1
  4006e4:	e8a0      	jrc	ra
  4006e6:	6500      	nop
  4006e8:	6500      	nop
  4006ea:	6500      	nop
  4006ec:	6500      	nop
  4006ee:	6500      	nop

-- and the original log:

(gdb) file .../gdb.base/step-symless
Reading symbols from .../gdb.base/step-symless...done.
(gdb) delete breakpoints
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) break main
warning: Breakpoint address adjusted from 0x004006dd to 0x004006d9.
Breakpoint 1 at 0x4006d9
(gdb) set remotetimeout 5
(gdb) kill
The program is not being run.
(gdb)
[...]
target remote ...:2345
Reading symbols from .../mips16/lib/ld.so.1...done.
warning: Breakpoint address adjusted from 0x004006dd to 0x004006d9.
warning: Breakpoint address adjusted from 0x004006dd to 0x004006d9.
0x2aaa8e81 in __start () from .../mips16/lib/ld.so.1
(gdb) continue
Continuing.
warning: Breakpoint address adjusted from 0x004006dd to 0x004006d9.
warning: Breakpoint 1 address previously adjusted from 0x004006dd to
0x004006d9.
Breakpoint 1, 0x004006d9 in main ()
(gdb) break symful
Breakpoint 2 at 0x4006a5
(gdb) step
Single stepping until exit from function main,
which has no line number information.

Breakpoint 2, 0x004006a5 in symful ()
(gdb) PASS: gdb.base/step-symless.exp: step

So the breakpoint at `main' was actually set at an instruction after the
call to `symful+0x18' aka `symless' and the test only passed because
single-stepping through `symless' wasn't actually done at all.  With
this change in place this test fails for MIPS16 multilibs consistently
with all the other multilibs where it already failed in this manner
previously.

	* mips-tdep.c (mips16_instruction_is_compact_branch): New
	function.
	(micromips_instruction_is_compact_branch): Likewise.
	(mips16_scan_prologue): Terminate scanning upon seeing a branch
	or a compact jump, reaching a jump delay slot, or seeing a
	second non-prologue instruction.
	(micromips_scan_prologue): Also terminate scanning upon seeing a
	compact branch or jump, or reaching a branch or jump delay slot.
	(mips32_scan_prologue): Terminate scanning upon reaching a branch
	or jump delay slot, or seeing a second non-prologue instruction.
	(mips32_instruction_has_delay_slot): Retain instruction
	examination code only, update arguments accordingly and move
	instruction fetch pieces to...
	(mips32_insn_at_pc_has_delay_slot): ... this new function.
	(micromips_instruction_has_delay_slot): Likewise and to...
	(micromips_insn_at_pc_has_delay_slot): ... this new function.
	(mips16_instruction_has_delay_slot): Likewise and to...
	(mips16_insn_at_pc_has_delay_slot): ... this new function.
	(mips_single_step_through_delay): Update accordingly.
	(mips_adjust_breakpoint_address): Likewise.
This commit is contained in:
Maciej W. Rozycki 2014-10-05 22:39:52 +01:00
parent ae79065284
commit ab50adb6a6
2 changed files with 318 additions and 147 deletions

View file

@ -1,3 +1,26 @@
2014-10-05 Maciej W. Rozycki <macro@codesourcery.com>
* mips-tdep.c (mips16_instruction_is_compact_branch): New
function.
(micromips_instruction_is_compact_branch): Likewise.
(mips16_scan_prologue): Terminate scanning upon seeing a branch
or a compact jump, reaching a jump delay slot, or seeing a
second non-prologue instruction.
(micromips_scan_prologue): Also terminate scanning upon seeing a
compact branch or jump, or reaching a branch or jump delay slot.
(mips32_scan_prologue): Terminate scanning upon reaching a branch
or jump delay slot, or seeing a second non-prologue instruction.
(mips32_instruction_has_delay_slot): Retain instruction
examination code only, update arguments accordingly and move
instruction fetch pieces to...
(mips32_insn_at_pc_has_delay_slot): ... this new function.
(micromips_instruction_has_delay_slot): Likewise and to...
(micromips_insn_at_pc_has_delay_slot): ... this new function.
(mips16_instruction_has_delay_slot): Likewise and to...
(mips16_insn_at_pc_has_delay_slot): ... this new function.
(mips_single_step_through_delay): Update accordingly.
(mips_adjust_breakpoint_address): Likewise.
2014-10-05 Maciej W. Rozycki <macro@codesourcery.com>
* mips-tdep.c (micromips_instruction_has_delay_slot): When

View file

@ -60,11 +60,18 @@ static const struct objfile_data *mips_pdr_data;
static struct type *mips_register_type (struct gdbarch *gdbarch, int regnum);
static int mips32_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR);
static int micromips_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR,
int);
static int mips16_instruction_has_delay_slot (struct gdbarch *, CORE_ADDR,
int);
static int mips32_instruction_has_delay_slot (struct gdbarch *gdbarch,
ULONGEST inst);
static int micromips_instruction_has_delay_slot (ULONGEST insn, int mustbe32);
static int mips16_instruction_has_delay_slot (unsigned short inst,
int mustbe32);
static int mips32_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr);
static int micromips_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr, int mustbe32);
static int mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr, int mustbe32);
/* A useful bit in the CP0 status register (MIPS_PS_REGNUM). */
/* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip. */
@ -2256,6 +2263,48 @@ mips_next_pc (struct frame_info *frame, CORE_ADDR pc)
return mips32_next_pc (frame, pc);
}
/* Return non-zero if the MIPS16 instruction INSN is a compact branch
or jump. */
static int
mips16_instruction_is_compact_branch (unsigned short insn)
{
switch (insn & 0xf800)
{
case 0xe800:
return (insn & 0x009f) == 0x80; /* JALRC/JRC */
case 0x6000:
return (insn & 0x0600) == 0; /* BTNEZ/BTEQZ */
case 0x2800: /* BNEZ */
case 0x2000: /* BEQZ */
case 0x1000: /* B */
return 1;
default:
return 0;
}
}
/* Return non-zero if the microMIPS instruction INSN is a compact branch
or jump. */
static int
micromips_instruction_is_compact_branch (unsigned short insn)
{
switch (micromips_op (insn))
{
case 0x11: /* POOL16C: bits 010001 */
return (b5s5_op (insn) == 0x18
/* JRADDIUSP: bits 010001 11000 */
|| b5s5_op (insn) == 0xd);
/* JRC: bits 010011 01101 */
case 0x10: /* POOL32I: bits 010000 */
return (b5s5_op (insn) & 0x1d) == 0x5;
/* BEQZC/BNEZC: bits 010000 001x1 */
default:
return 0;
}
}
struct mips_frame_cache
{
CORE_ADDR base;
@ -2333,6 +2382,10 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
struct frame_info *this_frame,
struct mips_frame_cache *this_cache)
{
int prev_non_prologue_insn = 0;
int this_non_prologue_insn;
int non_prologue_insns = 0;
CORE_ADDR prev_pc;
CORE_ADDR cur_pc;
CORE_ADDR frame_addr = 0; /* Value of $r17, used as frame pointer. */
CORE_ADDR sp;
@ -2343,11 +2396,13 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
unsigned inst = 0; /* current instruction */
unsigned entry_inst = 0; /* the entry instruction */
unsigned save_inst = 0; /* the save instruction */
int prev_delay_slot = 0;
int in_delay_slot;
int reg, offset;
int extend_bytes = 0;
int prev_extend_bytes;
CORE_ADDR end_prologue_addr = 0;
int prev_extend_bytes = 0;
CORE_ADDR end_prologue_addr;
/* Can be called when there's no process, and hence when there's no
THIS_FRAME. */
@ -2360,9 +2415,16 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
if (limit_pc > start_pc + 200)
limit_pc = start_pc + 200;
prev_pc = start_pc;
/* Permit at most one non-prologue non-control-transfer instruction
in the middle which may have been reordered by the compiler for
optimisation. */
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN16_SIZE)
{
this_non_prologue_insn = 0;
in_delay_slot = 0;
/* Save the previous instruction. If it's an EXTEND, we'll extract
the immediate offset extension from it in mips16_get_imm. */
prev_inst = inst;
@ -2452,21 +2514,40 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
if (prev_extend_bytes) /* extend */
save_inst |= prev_inst << 16;
}
else if ((inst & 0xf800) == 0x1800) /* jal(x) */
cur_pc += MIPS_INSN16_SIZE; /* 32-bit instruction */
else if ((inst & 0xff1c) == 0x6704) /* move reg,$a0-$a3 */
{
/* This instruction is part of the prologue, but we don't
need to do anything special to handle it. */
}
else if (mips16_instruction_has_delay_slot (inst, 0))
/* JAL/JALR/JALX/JR */
{
/* The instruction in the delay slot can be a part
of the prologue, so move forward once more. */
in_delay_slot = 1;
if (mips16_instruction_has_delay_slot (inst, 1))
/* JAL/JALX */
{
prev_extend_bytes = MIPS_INSN16_SIZE;
cur_pc += MIPS_INSN16_SIZE; /* 32-bit instruction */
}
}
else
{
/* This instruction is not an instruction typically found
in a prologue, so we must have reached the end of the
prologue. */
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc - prev_extend_bytes;
this_non_prologue_insn = 1;
}
non_prologue_insns += this_non_prologue_insn;
/* A jump or branch, or enough non-prologue insns seen? If so,
then we must have reached the end of the prologue by now. */
if (prev_delay_slot || non_prologue_insns > 1
|| mips16_instruction_is_compact_branch (inst))
break;
prev_non_prologue_insn = this_non_prologue_insn;
prev_delay_slot = in_delay_slot;
prev_pc = cur_pc - prev_extend_bytes;
}
/* The entry instruction is typically the first instruction in a function,
@ -2619,11 +2700,12 @@ mips16_scan_prologue (struct gdbarch *gdbarch,
= this_cache->saved_regs[gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM];
}
/* If we didn't reach the end of the prologue when scanning the function
instructions, then set end_prologue_addr to the address of the
instruction immediately after the last one we scanned. */
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
/* Set end_prologue_addr to the address of the instruction immediately
after the last one we scanned. Unless the last one looked like a
non-prologue instruction (and we looked ahead), in which case use
its address instead. */
end_prologue_addr = (prev_non_prologue_insn || prev_delay_slot
? prev_pc : cur_pc - prev_extend_bytes);
return end_prologue_addr;
}
@ -2760,7 +2842,7 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
struct frame_info *this_frame,
struct mips_frame_cache *this_cache)
{
CORE_ADDR end_prologue_addr = 0;
CORE_ADDR end_prologue_addr;
int prev_non_prologue_insn = 0;
int frame_reg = MIPS_SP_REGNUM;
int this_non_prologue_insn;
@ -2768,6 +2850,8 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
long frame_offset = 0; /* Size of stack frame. */
long frame_adjust = 0; /* Offset of FP from SP. */
CORE_ADDR frame_addr = 0; /* Value of $30, used as frame pointer. */
int prev_delay_slot = 0;
int in_delay_slot;
CORE_ADDR prev_pc;
CORE_ADDR cur_pc;
ULONGEST insn; /* current instruction */
@ -2804,6 +2888,7 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += loc)
{
this_non_prologue_insn = 0;
in_delay_slot = 0;
sp_adj = 0;
loc = 0;
insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, cur_pc, NULL);
@ -2956,9 +3041,15 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
break;
default:
this_non_prologue_insn = 1;
/* The instruction in the delay slot can be a part
of the prologue, so move forward once more. */
if (micromips_instruction_has_delay_slot (insn, 0))
in_delay_slot = 1;
else
this_non_prologue_insn = 1;
break;
}
insn >>= 16;
break;
/* 16-bit instructions. */
@ -3013,7 +3104,12 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
break;
default:
this_non_prologue_insn = 1;
/* The instruction in the delay slot can be a part
of the prologue, so move forward once more. */
if (micromips_instruction_has_delay_slot (insn << 16, 0))
in_delay_slot = 1;
else
this_non_prologue_insn = 1;
break;
}
break;
@ -3022,13 +3118,16 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
frame_offset -= sp_adj;
non_prologue_insns += this_non_prologue_insn;
/* Enough non-prologue insns seen or positive stack adjustment? */
if (end_prologue_addr == 0 && (non_prologue_insns > 1 || sp_adj > 0))
{
end_prologue_addr = prev_non_prologue_insn ? prev_pc : cur_pc;
break;
}
/* A jump or branch, enough non-prologue insns seen or positive
stack adjustment? If so, then we must have reached the end
of the prologue by now. */
if (prev_delay_slot || non_prologue_insns > 1 || sp_adj > 0
|| micromips_instruction_is_compact_branch (insn))
break;
prev_non_prologue_insn = this_non_prologue_insn;
prev_delay_slot = in_delay_slot;
prev_pc = cur_pc;
}
@ -3046,13 +3145,12 @@ micromips_scan_prologue (struct gdbarch *gdbarch,
= this_cache->saved_regs[gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM];
}
/* If we didn't reach the end of the prologue when scanning the function
instructions, then set end_prologue_addr to the address of the
instruction immediately after the last one we scanned. Unless the
last one looked like a non-prologue instruction (and we looked ahead),
in which case use its address instead. */
if (end_prologue_addr == 0)
end_prologue_addr = prev_non_prologue_insn ? prev_pc : cur_pc;
/* Set end_prologue_addr to the address of the instruction immediately
after the last one we scanned. Unless the last one looked like a
non-prologue instruction (and we looked ahead), in which case use
its address instead. */
end_prologue_addr
= prev_non_prologue_insn || prev_delay_slot ? prev_pc : cur_pc;
return end_prologue_addr;
}
@ -3200,17 +3298,22 @@ mips32_scan_prologue (struct gdbarch *gdbarch,
struct frame_info *this_frame,
struct mips_frame_cache *this_cache)
{
CORE_ADDR cur_pc;
int prev_non_prologue_insn;
int this_non_prologue_insn;
int non_prologue_insns;
CORE_ADDR frame_addr = 0; /* Value of $r30. Used by gcc for
frame-pointer. */
int prev_delay_slot;
CORE_ADDR prev_pc;
CORE_ADDR cur_pc;
CORE_ADDR sp;
long frame_offset;
int frame_reg = MIPS_SP_REGNUM;
CORE_ADDR end_prologue_addr = 0;
CORE_ADDR end_prologue_addr;
int seen_sp_adjust = 0;
int load_immediate_bytes = 0;
int in_delay_slot = 0;
int in_delay_slot;
int regsize_is_64_bits = (mips_abi_regsize (gdbarch) == 8);
/* Can be called when there's no process, and hence when there's no
@ -3226,13 +3329,23 @@ mips32_scan_prologue (struct gdbarch *gdbarch,
limit_pc = start_pc + 200;
restart:
prev_non_prologue_insn = 0;
non_prologue_insns = 0;
prev_delay_slot = 0;
prev_pc = start_pc;
/* Permit at most one non-prologue non-control-transfer instruction
in the middle which may have been reordered by the compiler for
optimisation. */
frame_offset = 0;
for (cur_pc = start_pc; cur_pc < limit_pc; cur_pc += MIPS_INSN32_SIZE)
{
unsigned long inst, high_word, low_word;
int reg;
this_non_prologue_insn = 0;
in_delay_slot = 0;
/* Fetch the instruction. */
inst = (unsigned long) mips_fetch_instruction (gdbarch, ISA_MIPS,
cur_pc, NULL);
@ -3349,6 +3462,7 @@ restart:
initialize a local variable, so we accept them only before
a stack adjustment instruction was seen. */
else if (!seen_sp_adjust
&& !prev_delay_slot
&& (high_word == 0x3c01 /* lui $at,n */
|| high_word == 0x3c08 /* lui $t0,n */
|| high_word == 0x3421 /* ori $at,$at,n */
@ -3357,31 +3471,32 @@ restart:
|| high_word == 0x3408 /* ori $t0,$zero,n */
))
{
if (end_prologue_addr == 0)
load_immediate_bytes += MIPS_INSN32_SIZE; /* FIXME! */
load_immediate_bytes += MIPS_INSN32_SIZE; /* FIXME! */
}
/* Check for branches and jumps. The instruction in the delay
slot can be a part of the prologue, so move forward once more. */
else if (mips32_instruction_has_delay_slot (gdbarch, inst))
{
in_delay_slot = 1;
}
/* This instruction is not an instruction typically found
in a prologue, so we must have reached the end of the
prologue. */
else
{
/* This instruction is not an instruction typically found
in a prologue, so we must have reached the end of the
prologue. */
/* FIXME: brobecker/2004-10-10: Can't we just break out of this
loop now? Why would we need to continue scanning the function
instructions? */
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
/* Check for branches and jumps. For now, only jump to
register are caught (i.e. returns). */
if ((itype_op (inst) & 0x07) == 0 && rtype_funct (inst) == 8)
in_delay_slot = 1;
this_non_prologue_insn = 1;
}
/* If the previous instruction was a jump, we must have reached
the end of the prologue by now. Stop scanning so that we do
not go past the function return. */
if (in_delay_slot)
non_prologue_insns += this_non_prologue_insn;
/* A jump or branch, or enough non-prologue insns seen? If so,
then we must have reached the end of the prologue by now. */
if (prev_delay_slot || non_prologue_insns > 1)
break;
prev_non_prologue_insn = this_non_prologue_insn;
prev_delay_slot = in_delay_slot;
prev_pc = cur_pc;
}
if (this_cache != NULL)
@ -3399,14 +3514,12 @@ restart:
+ MIPS_RA_REGNUM];
}
/* If we didn't reach the end of the prologue when scanning the function
instructions, then set end_prologue_addr to the address of the
instruction immediately after the last one we scanned. */
/* brobecker/2004-10-10: I don't think this would ever happen, but
we may as well be careful and do our best if we have a null
end_prologue_addr. */
if (end_prologue_addr == 0)
end_prologue_addr = cur_pc;
/* Set end_prologue_addr to the address of the instruction immediately
after the last one we scanned. Unless the last one looked like a
non-prologue instruction (and we looked ahead), in which case use
its address instead. */
end_prologue_addr
= prev_non_prologue_insn || prev_delay_slot ? prev_pc : cur_pc;
/* In a frameless function, we might have incorrectly
skipped some load immediate instructions. Undo the skipping
@ -6370,11 +6483,11 @@ mips_single_step_through_delay (struct gdbarch *gdbarch,
int size;
if ((mips_pc_is_mips (pc)
&& !mips32_instruction_has_delay_slot (gdbarch, pc))
&& !mips32_insn_at_pc_has_delay_slot (gdbarch, pc))
|| (mips_pc_is_micromips (gdbarch, pc)
&& !micromips_instruction_has_delay_slot (gdbarch, pc, 0))
&& !micromips_insn_at_pc_has_delay_slot (gdbarch, pc, 0))
|| (mips_pc_is_mips16 (gdbarch, pc)
&& !mips16_instruction_has_delay_slot (gdbarch, pc, 0)))
&& !mips16_insn_at_pc_has_delay_slot (gdbarch, pc, 0)))
return 0;
isa = mips_pc_isa (gdbarch, pc);
@ -6964,23 +7077,17 @@ mips_remote_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr,
*kindptr = 4;
}
/* Return non-zero if the ADDR instruction has a branch delay slot
(i.e. it is a jump or branch instruction). This function is based
on mips32_next_pc. */
/* Return non-zero if the standard MIPS instruction INST has a branch
delay slot (i.e. it is a jump or branch instruction). This function
is based on mips32_next_pc. */
static int
mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, ULONGEST inst)
{
unsigned long inst;
int status;
int op;
int rs;
int rt;
inst = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
if (status)
return 0;
op = itype_op (inst);
if ((inst & 0xe0000000) != 0)
{
@ -7020,13 +7127,90 @@ mips32_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
}
}
/* Return non-zero if the ADDR instruction, which must be a 32-bit
instruction if MUSTBE32 is set or can be any instruction otherwise,
has a branch delay slot (i.e. it is a non-compact jump instruction). */
/* Return non-zero if a standard MIPS instruction at ADDR has a branch
delay slot (i.e. it is a jump or branch instruction). */
static int
micromips_instruction_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr, int mustbe32)
mips32_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr)
{
ULONGEST insn;
int status;
insn = mips_fetch_instruction (gdbarch, ISA_MIPS, addr, &status);
if (status)
return 0;
return mips32_instruction_has_delay_slot (gdbarch, insn);
}
/* Return non-zero if the microMIPS instruction INSN, comprising the
16-bit major opcode word in the high 16 bits and any second word
in the low 16 bits, has a branch delay slot (i.e. it is a non-compact
jump or branch instruction). The instruction must be 32-bit if
MUSTBE32 is set or can be any instruction otherwise. */
static int
micromips_instruction_has_delay_slot (ULONGEST insn, int mustbe32)
{
ULONGEST major = insn >> 16;
switch (micromips_op (major))
{
/* 16-bit instructions. */
case 0x33: /* B16: bits 110011 */
case 0x2b: /* BNEZ16: bits 101011 */
case 0x23: /* BEQZ16: bits 100011 */
return !mustbe32;
case 0x11: /* POOL16C: bits 010001 */
return (!mustbe32
&& ((b5s5_op (major) == 0xc
/* JR16: bits 010001 01100 */
|| (b5s5_op (major) & 0x1e) == 0xe)));
/* JALR16, JALRS16: bits 010001 0111x */
/* 32-bit instructions. */
case 0x3d: /* JAL: bits 111101 */
case 0x3c: /* JALX: bits 111100 */
case 0x35: /* J: bits 110101 */
case 0x2d: /* BNE: bits 101101 */
case 0x25: /* BEQ: bits 100101 */
case 0x1d: /* JALS: bits 011101 */
return 1;
case 0x10: /* POOL32I: bits 010000 */
return ((b5s5_op (major) & 0x1c) == 0x0
/* BLTZ, BLTZAL, BGEZ, BGEZAL: 010000 000xx */
|| (b5s5_op (major) & 0x1d) == 0x4
/* BLEZ, BGTZ: bits 010000 001x0 */
|| (b5s5_op (major) & 0x1d) == 0x11
/* BLTZALS, BGEZALS: bits 010000 100x1 */
|| ((b5s5_op (major) & 0x1e) == 0x14
&& (major & 0x3) == 0x0)
/* BC2F, BC2T: bits 010000 1010x xxx00 */
|| (b5s5_op (major) & 0x1e) == 0x1a
/* BPOSGE64, BPOSGE32: bits 010000 1101x */
|| ((b5s5_op (major) & 0x1e) == 0x1c
&& (major & 0x3) == 0x0)
/* BC1F, BC1T: bits 010000 1110x xxx00 */
|| ((b5s5_op (major) & 0x1c) == 0x1c
&& (major & 0x3) == 0x1));
/* BC1ANY*: bits 010000 111xx xxx01 */
case 0x0: /* POOL32A: bits 000000 */
return (b0s6_op (insn) == 0x3c
/* POOL32Axf: bits 000000 ... 111100 */
&& (b6s10_ext (insn) & 0x2bf) == 0x3c);
/* JALR, JALR.HB: 000000 000x111100 111100 */
/* JALRS, JALRS.HB: 000000 010x111100 111100 */
default:
return 0;
}
}
/* Return non-zero if a microMIPS instruction at ADDR has a branch delay
slot (i.e. it is a non-compact jump instruction). The instruction
must be 32-bit if MUSTBE32 is set or can be any instruction otherwise. */
static int
micromips_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr, int mustbe32)
{
ULONGEST insn;
int status;
@ -7034,62 +7218,28 @@ micromips_instruction_has_delay_slot (struct gdbarch *gdbarch,
insn = mips_fetch_instruction (gdbarch, ISA_MICROMIPS, addr, &status);
if (status)
return 0;
/* 16-bit instructions. */
if ((micromips_op (insn) == 0x11
/* POOL16C: bits 010001 */
&& (b5s5_op (insn) == 0xc
/* JR16: bits 010001 01100 */
|| (b5s5_op (insn) & 0x1e) == 0xe))
/* JALR16, JALRS16: bits 010001 0111x */
|| (micromips_op (insn) & 0x37) == 0x23
/* BEQZ16, BNEZ16: bits 10x011 */
|| micromips_op (insn) == 0x33)
/* B16: bits 110011 */
return !mustbe32;
/* 32-bit instructions. */
if (micromips_op (insn) == 0x0)
/* POOL32A: bits 000000 */
insn <<= 16;
if (mips_insn_size (ISA_MICROMIPS, insn) == 2 * MIPS_INSN16_SIZE)
{
insn <<= 16;
insn |= mips_fetch_instruction (gdbarch, ISA_MICROMIPS, addr, &status);
if (status)
return 0;
return b0s6_op (insn) == 0x3c
/* POOL32Axf: bits 000000 ... 111100 */
&& (b6s10_ext (insn) & 0x2bf) == 0x3c;
/* JALR, JALR.HB: 000000 000x111100 111100 */
/* JALRS, JALRS.HB: 000000 010x111100 111100 */
}
return (micromips_op (insn) == 0x10
/* POOL32I: bits 010000 */
&& ((b5s5_op (insn) & 0x1c) == 0x0
/* BLTZ, BLTZAL, BGEZ, BGEZAL: 010000 000xx */
|| (b5s5_op (insn) & 0x1d) == 0x4
/* BLEZ, BGTZ: bits 010000 001x0 */
|| (b5s5_op (insn) & 0x1d) == 0x11
/* BLTZALS, BGEZALS: bits 010000 100x1 */
|| ((b5s5_op (insn) & 0x1e) == 0x14
&& (insn & 0x3) == 0x0)
/* BC2F, BC2T: bits 010000 1010x xxx00 */
|| (b5s5_op (insn) & 0x1e) == 0x1a
/* BPOSGE64, BPOSGE32: bits 010000 1101x */
|| ((b5s5_op (insn) & 0x1e) == 0x1c
&& (insn & 0x3) == 0x0)
/* BC1F, BC1T: bits 010000 1110x xxx00 */
|| ((b5s5_op (insn) & 0x1c) == 0x1c
&& (insn & 0x3) == 0x1)))
/* BC1ANY*: bits 010000 111xx xxx01 */
|| (micromips_op (insn) & 0x1f) == 0x1d
/* JALS, JAL: bits x11101 */
|| (micromips_op (insn) & 0x37) == 0x25
/* BEQ, BNE: bits 10x101 */
|| micromips_op (insn) == 0x35
/* J: bits 110101 */
|| micromips_op (insn) == 0x3c;
/* JALX: bits 111100 */
return micromips_instruction_has_delay_slot (insn, mustbe32);
}
/* Return non-zero if the MIPS16 instruction INST, which must be
a 32-bit instruction if MUSTBE32 is set or can be any instruction
otherwise, has a branch delay slot (i.e. it is a non-compact jump
instruction). This function is based on mips16_next_pc. */
static int
mips16_instruction_has_delay_slot (unsigned short inst, int mustbe32)
{
if ((inst & 0xf89f) == 0xe800) /* JR/JALR (16-bit instruction) */
return !mustbe32;
return (inst & 0xf800) == 0x1800; /* JAL/JALX (32-bit instruction) */
}
/* Return non-zero if a MIPS16 instruction at ADDR has a branch delay
@ -7097,19 +7247,17 @@ micromips_instruction_has_delay_slot (struct gdbarch *gdbarch,
must be 32-bit if MUSTBE32 is set or can be any instruction otherwise. */
static int
mips16_instruction_has_delay_slot (struct gdbarch *gdbarch, CORE_ADDR addr,
int mustbe32)
mips16_insn_at_pc_has_delay_slot (struct gdbarch *gdbarch,
CORE_ADDR addr, int mustbe32)
{
unsigned short inst;
unsigned short insn;
int status;
inst = mips_fetch_instruction (gdbarch, ISA_MIPS16, addr, &status);
insn = mips_fetch_instruction (gdbarch, ISA_MIPS16, addr, &status);
if (status)
return 0;
if ((inst & 0xf89f) == 0xe800) /* JR/JALR (16-bit instruction) */
return !mustbe32;
return (inst & 0xf800) == 0x1800; /* JAL/JALX (32-bit instruction) */
return mips16_instruction_has_delay_slot (insn, mustbe32);
}
/* Calculate the starting address of the MIPS memory segment BPADDR is in.
@ -7203,12 +7351,12 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
/* If the previous instruction has a branch delay slot, we have
to move the breakpoint to the branch instruction. */
prev_addr = bpaddr - 4;
if (mips32_instruction_has_delay_slot (gdbarch, prev_addr))
if (mips32_insn_at_pc_has_delay_slot (gdbarch, prev_addr))
bpaddr = prev_addr;
}
else
{
int (*instruction_has_delay_slot) (struct gdbarch *, CORE_ADDR, int);
int (*insn_at_pc_has_delay_slot) (struct gdbarch *, CORE_ADDR, int);
CORE_ADDR addr, jmpaddr;
int i;
@ -7222,9 +7370,9 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
2 bytes, so the idea is the same.
FIXME: We have to assume that bpaddr is not the second half
of an extended instruction. */
instruction_has_delay_slot = (mips_pc_is_micromips (gdbarch, bpaddr)
? micromips_instruction_has_delay_slot
: mips16_instruction_has_delay_slot);
insn_at_pc_has_delay_slot = (mips_pc_is_micromips (gdbarch, bpaddr)
? micromips_insn_at_pc_has_delay_slot
: mips16_insn_at_pc_has_delay_slot);
jmpaddr = 0;
addr = bpaddr;
@ -7233,12 +7381,12 @@ mips_adjust_breakpoint_address (struct gdbarch *gdbarch, CORE_ADDR bpaddr)
if (unmake_compact_addr (addr) == boundary)
break;
addr -= MIPS_INSN16_SIZE;
if (i == 1 && instruction_has_delay_slot (gdbarch, addr, 0))
if (i == 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 0))
/* Looks like a JR/JALR at [target-1], but it could be
the second word of a previous JAL/JALX, so record it
and check back one more. */
jmpaddr = addr;
else if (i > 1 && instruction_has_delay_slot (gdbarch, addr, 1))
else if (i > 1 && insn_at_pc_has_delay_slot (gdbarch, addr, 1))
{
if (i == 2)
/* Looks like a JAL/JALX at [target-2], but it could also