diff options
author | Fred Fish <fnf@specifix.com> | 1996-05-26 21:41:40 +0000 |
---|---|---|
committer | Fred Fish <fnf@specifix.com> | 1996-05-26 21:41:40 +0000 |
commit | 9391c9977e934749cd973dd55cde6df7f787b6ec (patch) | |
tree | 749b3887a9a82973c69c3a86853d98ffe7cd5456 /gdb/alpha-tdep.c | |
parent | 9b61d62b9f95e3fbc1783a13811ef7008678204f (diff) | |
download | gdb-9391c9977e934749cd973dd55cde6df7f787b6ec.zip gdb-9391c9977e934749cd973dd55cde6df7f787b6ec.tar.gz gdb-9391c9977e934749cd973dd55cde6df7f787b6ec.tar.bz2 |
Changes from: David Mosberger-Tang <davidm@azstarnet.com>
* NEWS: Add Alpha Linux as a new native configuration.
* mdebugread.c (parse_symbol): When we find a malloc() symbol with
return type VOID, assume no debugging info is available for that
object file and patch the return value into VOID *. Otherwise,
operations requiring an implicit call to malloc() will fail.
* infrun.c (wait_for_inferior): The criterion to detect entering a
sigtramp handler is now: (a) the current pc is inside a sigtramp
handler, (b) the previous pc is not in a sigtramp handler, and (c)
the current stack pointer is "inner" than the old one. Condition
(c) is new to avoid mistaking a return from a signal handler into
sigtramp as a new sigtramp invocation.
* dcache.c (struct dcache_block): Declare addr as CORE_ADDR. An
int may not be big enough to hold an address.
(dcache_hit): Ditto.
(dcache_peek_byte): Fix indentation.
* configure.in (alpha-*-linux*): Add target.
* configure: Rebuild
* config/alpha/tm-alpha.h (PROC_DESC_IS_DYN_SIGTRAMP): New macro.
(SET_PROC_DESC_IS_DYN_SIGTRAMP): Ditto.
(DYNAMIC_SIGTRAMP_OFFSET): Ditto.
(SIGCONTEXT_ADDR): Ditto.
(FRAME_PAST_SIGTRAMP_FRAME): Ditto.
* config/alpha/alpha-linux.mh: New file.
* config/alpha/alpha-linux.mt: Ditto.
* config/alpha/nm-linux.h: Ditto.
* config/alpha/tm-alphalinux.h: Ditto.
* config/alpha/xm-alphalinux.h: Ditto.
* config/alpha/xm-alphaosf.h: Renamed from xm-alpha.h.
* config/alpha/alpha-osf1.mh (XM_FILE): Change from xm-alpha.h to
xm-alphaosf.h.
* config/alpha/alpha-osf2.mh: Ditto.
* blockframe.c (find_pc_partial_function): Pass PC to
SIGTRAMP_START and SIGTRAMP_END macros for the benefit of systems
that detect sigtramp code via designated code sequences (as is the
case for Linux/Alpha, for example).
* config/i386/tm-i386bsd.h: Change SIGTRAMP_START and SIGTRAMP_END
to ignore new PC argument.
* config/m68k/tm-hp300bsd.h: Ditto.
* config/vax/tm-vax.h: Ditto.
* alpha-tdep.c (alpha_linux_sigtramp_offset): New function.
(alpha_osf_skip_sigtramp_frame): Ditto.
(push_sigtramp_desc): Ditto.
(alpha_find_saved_regs): Use SIGCONTEXT_ADDR macro to extract
sigcontext address from frame.
(alpha_saved_pc_after_call): When in sigtramp, use
alpha_frame_saved_pc() instead of read-register().
(after_prologue): When inside a dynamically generated sigtramp
function, there is no prologue, so return address of first
instruction.
(alpha_in_prologue): Fix typo in comment.
(find_proc_desc): Use macro DYNAMIC_SIGTRAMP_OFFSET to determine
whether we're inside a dynamicaly generated sigtramp function. If
so, create and push and appropriate procedure descriptor.
(alpha_frame_chain): Use macro FRAME_PAST_SIGTRAMP_FRAME to obtain
the frame past a sigtramp frame (if the current frame is indeed a
sigtramp function).
(init_extra_frame_info): Don't read next frame register off of
stack-pointer when inside a dynamiccaly generated sigtramp.
(alpha_pop_frame): Also unlink and destroy procedure descriptors
created for dynamically generated sigtramp functions.
* alpha-nat.c: When compiling under Linux, include <asm/reg.h> and
<alpha/ptrace.h> instead of <machine/reg.h>
Diffstat (limited to 'gdb/alpha-tdep.c')
-rw-r--r-- | gdb/alpha-tdep.c | 147 |
1 files changed, 126 insertions, 21 deletions
diff --git a/gdb/alpha-tdep.c b/gdb/alpha-tdep.c index 7fbf642..d778bf2 100644 --- a/gdb/alpha-tdep.c +++ b/gdb/alpha-tdep.c @@ -132,6 +132,110 @@ struct linked_proc_info } *linked_proc_desc_table = NULL; +/* Under Linux, signal handler invocations can be identified by the + designated code sequence that is used to return from a signal + handler. In particular, the return address of a signal handler + points to the following sequence (the first instruction is quadword + aligned): + + bis $30,$30,$16 + addq $31,0x67,$0 + call_pal callsys + + Each instruction has a unique encoding, so we simply attempt to + match the instruction the pc is pointing to with any of the above + instructions. If there is a hit, we know the offset to the start + of the designated sequence and can then check whether we really are + executing in a designated sequence. If not, -1 is returned, + otherwise the offset from the start of the desingated sequence is + returned. + + There is a slight chance of false hits: code could jump into the + middle of the designated sequence, in which case there is no + guarantee that we are in the middle of a sigreturn syscall. Don't + think this will be a problem in praxis, though. +*/ +long +alpha_linux_sigtramp_offset (CORE_ADDR pc) +{ + unsigned int i[3], w; + long off, res; + + if (read_memory_nobpt(pc, (char *) &w, 4) != 0) + return -1; + + off = -1; + switch (w) + { + case 0x47de0410: off = 0; break; /* bis $30,$30,$16 */ + case 0x43ecf400: off = 4; break; /* addq $31,0x67,$0 */ + case 0x00000083: off = 8; break; /* call_pal callsys */ + default: return -1; + } + pc -= off; + if (pc & 0x7) + { + /* designated sequence is not quadword aligned */ + return -1; + } + + if (read_memory_nobpt(pc, (char *) i, sizeof(i)) != 0) + return -1; + + if (i[0] == 0x47de0410 && i[1] == 0x43ecf400 && i[2] == 0x00000083) + return off; + + return -1; +} + + +/* Under OSF/1, the __sigtramp routine is frameless and has a frame + size of zero, but we are able to backtrace through it. */ +CORE_ADDR +alpha_osf_skip_sigtramp_frame (frame, pc) + struct frame_info *frame; + CORE_ADDR pc; +{ + char *name; + find_pc_partial_function (pc, &name, (CORE_ADDR *)NULL, (CORE_ADDR *)NULL); + if (IN_SIGTRAMP (pc, name)) + return frame->frame; + else + return 0; +} + + +/* Dynamically create a signal-handler caller procedure descriptor for + the signal-handler return code starting at address LOW_ADDR. The + descriptor is added to the linked_proc_desc_table. */ + +alpha_extra_func_info_t +push_sigtramp_desc (CORE_ADDR low_addr) +{ + struct linked_proc_info *link; + alpha_extra_func_info_t proc_desc; + + link = (struct linked_proc_info *) + xmalloc (sizeof (struct linked_proc_info)); + link->next = linked_proc_desc_table; + linked_proc_desc_table = link; + + proc_desc = &link->info; + + proc_desc->numargs = 0; + PROC_LOW_ADDR (proc_desc) = low_addr; + PROC_HIGH_ADDR (proc_desc) = low_addr + 3 * 4; + PROC_DUMMY_FRAME (proc_desc) = 0; + PROC_FRAME_OFFSET (proc_desc) = 0x298; /* sizeof(struct sigcontext_struct) */ + PROC_FRAME_REG (proc_desc) = SP_REGNUM; + PROC_REG_MASK (proc_desc) = 0xffff; + PROC_FREG_MASK (proc_desc) = 0xffff; + PROC_PC_REG (proc_desc) = 26; + PROC_LOCALOFF (proc_desc) = 0; + SET_PROC_DESC_IS_DYN_SIGTRAMP (proc_desc); +} + + /* Guaranteed to set frame->saved_regs to some values (it never leaves it NULL). */ @@ -161,14 +265,9 @@ alpha_find_saved_regs (frame) #endif if (frame->signal_handler_caller) { - CORE_ADDR sigcontext_pointer_addr; CORE_ADDR sigcontext_addr; - if (frame->next) - sigcontext_pointer_addr = frame->next->frame; - else - sigcontext_pointer_addr = frame->frame; - sigcontext_addr = read_memory_integer(sigcontext_pointer_addr, 8); + sigcontext_addr = SIGCONTEXT_ADDR (frame); for (ireg = 0; ireg < 32; ireg++) { reg_position = sigcontext_addr + SIGFRAME_REGSAVE_OFF + ireg * 8; @@ -285,7 +384,10 @@ alpha_saved_pc_after_call (frame) proc_desc = find_proc_desc (pc, frame->next); pcreg = proc_desc ? PROC_PC_REG (proc_desc) : RA_REGNUM; - return read_register (pcreg); + if (frame->signal_handler_caller) + return alpha_frame_saved_pc (frame); + else + return read_register (pcreg); } @@ -471,6 +573,9 @@ after_prologue (pc, proc_desc) if (proc_desc) { + if (PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)) + return PROC_LOW_ADDR (proc_desc); /* "prologue" is in kernel */ + /* If function is frameless, then we need to do it the hard way. I strongly suspect that frameless always means prologueless... */ if (PROC_FRAME_REG (proc_desc) == SP_REGNUM @@ -493,7 +598,7 @@ after_prologue (pc, proc_desc) } /* Return non-zero if we *might* be in a function prologue. Return zero if we - are definatly *not* in a function prologue. */ + are definitively *not* in a function prologue. */ static int alpha_in_prologue (pc, proc_desc) @@ -599,6 +704,8 @@ find_proc_desc (pc, next_frame) } else { + long offset; + /* Is linked_proc_desc_table really necessary? It only seems to be used by procedure call dummys. However, the procedures being called ought to have their own proc_descs, and even if they don't, @@ -610,6 +717,12 @@ find_proc_desc (pc, next_frame) && PROC_HIGH_ADDR(&link->info) > pc) return &link->info; + /* If PC is inside a dynamically generated sigtramp handler, + create and push a procedure descriptor for that code: */ + offset = DYNAMIC_SIGTRAMP_OFFSET (pc); + if (offset >= 0) + return push_sigtramp_desc (pc - offset); + if (startaddr == 0) startaddr = heuristic_proc_start (pc); @@ -650,17 +763,7 @@ alpha_frame_chain(frame) /* The previous frame from a sigtramp frame might be frameless and have frame size zero. */ && !frame->signal_handler_caller) - { - /* The alpha __sigtramp routine is frameless and has a frame size - of zero, but we are able to backtrace through it. */ - char *name; - find_pc_partial_function (saved_pc, &name, - (CORE_ADDR *)NULL, (CORE_ADDR *)NULL); - if (IN_SIGTRAMP (saved_pc, name)) - return frame->frame; - else - return 0; - } + return FRAME_PAST_SIGTRAMP_FRAME (frame, saved_pc); else return read_next_frame_reg(frame, PROC_FRAME_REG(proc_desc)) + PROC_FRAME_OFFSET(proc_desc); @@ -696,7 +799,8 @@ init_extra_frame_info (frame) /* This may not be quite right, if proc has a real frame register. Get the value of the frame relative sp, procedure might have been interrupted by a signal at it's very start. */ - else if (frame->pc == PROC_LOW_ADDR (proc_desc) && !PROC_DESC_IS_DUMMY (proc_desc)) + else if (frame->pc == PROC_LOW_ADDR (proc_desc) + && !PROC_DESC_IS_DYN_SIGTRAMP (proc_desc)) frame->frame = read_next_frame_reg (frame->next, SP_REGNUM); else frame->frame = read_next_frame_reg (frame->next, PROC_FRAME_REG (proc_desc)) @@ -984,7 +1088,8 @@ alpha_pop_frame() write_register (SP_REGNUM, new_sp); flush_cached_frames (); - if (proc_desc && PROC_DESC_IS_DUMMY(proc_desc)) + if (proc_desc && (PROC_DESC_IS_DUMMY(proc_desc) + || PROC_DESC_IS_DYN_SIGTRAMP (proc_desc))) { struct linked_proc_info *pi_ptr, *prev_ptr; |