Apply an iffy heuristic to detect a valid switchframe on the stack and
extract the register state from this for the live kernel case. If there is no switchframe then use the frame pointer to get enough state for crash dump case. More information needs to be saved by savectx to avoid this mess. Should fix PR/35118
This commit is contained in:
parent
089d34fd42
commit
ba85386518
47
gnu/dist/gdb6/gdb/i386nbsd-nat.c
vendored
47
gnu/dist/gdb6/gdb/i386nbsd-nat.c
vendored
@ -41,33 +41,58 @@ i386nbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
|
||||
{
|
||||
struct switchframe sf;
|
||||
|
||||
/* The following is true for NetBSD 1.6.2:
|
||||
/* The following is true for NetBSD 1.6.2 and after:
|
||||
|
||||
The pcb contains %esp and %ebp at the point of the context switch
|
||||
in cpu_switch(). At that point we have a stack frame as
|
||||
described by `struct switchframe', which for NetBSD 1.6.2 has the
|
||||
described by `struct switchframe', which for NetBSD has the
|
||||
following layout:
|
||||
|
||||
interrupt level
|
||||
%edi
|
||||
%esi
|
||||
%ebx
|
||||
%eip
|
||||
return address
|
||||
|
||||
we reconstruct the register state as it would look when we just
|
||||
returned from cpu_switch(). */
|
||||
returned from cpu_switch().
|
||||
|
||||
For core dumps the pcb is saved by savectx() and contains the
|
||||
stack pointer and frame pointer. In this case extract a return
|
||||
address from the stack. */
|
||||
|
||||
/* The stack pointer shouldn't be zero. */
|
||||
if (pcb->pcb_esp == 0)
|
||||
return 0;
|
||||
|
||||
read_memory (pcb->pcb_esp + 4, (gdb_byte *)&sf, sizeof sf);
|
||||
regcache_raw_supply (regcache, I386_EDI_REGNUM, &sf.sf_edi);
|
||||
regcache_raw_supply (regcache, I386_ESI_REGNUM, &sf.sf_esi);
|
||||
regcache_raw_supply (regcache, I386_EBP_REGNUM, &pcb->pcb_ebp);
|
||||
regcache_raw_supply (regcache, I386_ESP_REGNUM, &pcb->pcb_esp);
|
||||
regcache_raw_supply (regcache, I386_EBX_REGNUM, &sf.sf_ebx);
|
||||
regcache_raw_supply (regcache, I386_EIP_REGNUM, &sf.sf_eip);
|
||||
read_memory (pcb->pcb_esp, (gdb_byte *) &sf, sizeof sf);
|
||||
|
||||
if ( (unsigned long)sf.sf_eip >= (unsigned long)0xc0100000 )
|
||||
{
|
||||
/* Yes, we have a frame that matches cpu_switch(). */
|
||||
|
||||
pcb->pcb_esp += sizeof (struct switchframe);
|
||||
regcache_raw_supply (regcache, I386_EDI_REGNUM, &sf.sf_edi);
|
||||
regcache_raw_supply (regcache, I386_ESI_REGNUM, &sf.sf_esi);
|
||||
regcache_raw_supply (regcache, I386_EBP_REGNUM, &pcb->pcb_ebp);
|
||||
regcache_raw_supply (regcache, I386_ESP_REGNUM, &pcb->pcb_esp);
|
||||
regcache_raw_supply (regcache, I386_EBX_REGNUM, &sf.sf_ebx);
|
||||
regcache_raw_supply (regcache, I386_EIP_REGNUM, &sf.sf_eip);
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE_ADDR pc, fp;
|
||||
|
||||
/* No, the pcb must have been last updated by savectx() in
|
||||
dumpsys. Use the frame pointer to recover enough state. */
|
||||
|
||||
read_memory (pcb->pcb_ebp, (gdb_byte *) &fp, sizeof(fp));
|
||||
read_memory (pcb->pcb_ebp + 4, (gdb_byte *) &pc, sizeof(pc));
|
||||
|
||||
regcache_raw_supply (regcache, I386_ESP_REGNUM, &pcb->pcb_ebp);
|
||||
regcache_raw_supply (regcache, I386_EBP_REGNUM, &fp);
|
||||
regcache_raw_supply (regcache, I386_EIP_REGNUM, &pc);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user