mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-28 14:30:48 +00:00
Changes for GNU/Linux PPC native port of gdb.
This commit is contained in:
parent
2559291b00
commit
c877c8e605
3
gdb/config/powerpc/linux.mt
Normal file
3
gdb/config/powerpc/linux.mt
Normal file
@ -0,0 +1,3 @@
|
||||
# Target: Motorola PPC on Linux
|
||||
TDEPFILES= rs6000-tdep.o ppc-linux-tdep.o
|
||||
TM_FILE= tm-linux.h
|
64
gdb/config/powerpc/nm-linux.h
Normal file
64
gdb/config/powerpc/nm-linux.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* IBM PowerPC native-dependent macros for GDB, the GNU debugger.
|
||||
Copyright 1995 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef NM_LINUX_H
|
||||
#define NM_LINUX_H
|
||||
|
||||
/* Return sizeof user struct to callers in less machine dependent routines */
|
||||
|
||||
#define KERNEL_U_SIZE kernel_u_size()
|
||||
extern int kernel_u_size PARAMS ((void));
|
||||
|
||||
/* Tell gdb that we can attach and detach other processes */
|
||||
#define ATTACH_DETACH
|
||||
|
||||
#define U_REGS_OFFSET 0
|
||||
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
(addr) = ppc_register_u_addr ((blockend),(regno));
|
||||
|
||||
/* No <sys/reg.h> */
|
||||
|
||||
#define NO_SYS_REG_H
|
||||
|
||||
#ifdef HAVE_LINK_H
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
#define SVR4_SHARED_LIBS
|
||||
#endif
|
||||
|
||||
/* Support for Linuxthreads. */
|
||||
|
||||
#ifdef __STDC__
|
||||
struct objfile;
|
||||
#endif
|
||||
|
||||
extern void
|
||||
linuxthreads_new_objfile PARAMS ((struct objfile *objfile));
|
||||
#define target_new_objfile(OBJFILE) linuxthreads_new_objfile (OBJFILE)
|
||||
|
||||
extern char *
|
||||
linuxthreads_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) linuxthreads_pid_to_str (PID)
|
||||
|
||||
extern int
|
||||
linuxthreads_prepare_to_proceed PARAMS ((int step));
|
||||
#define PREPARE_TO_PROCEED(select_it) linuxthreads_prepare_to_proceed (1)
|
||||
|
||||
|
||||
#endif /* #ifndef NM_LINUX_H */
|
113
gdb/config/powerpc/tm-linux.h
Normal file
113
gdb/config/powerpc/tm-linux.h
Normal file
@ -0,0 +1,113 @@
|
||||
/* Definitions to target GDB to Linux on 386.
|
||||
Copyright 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef TM_LINUX_H
|
||||
#define TM_LINUX_H
|
||||
|
||||
#include "powerpc/tm-ppc-eabi.h"
|
||||
|
||||
#undef PUSH_ARGUMENTS
|
||||
|
||||
/* We can single step on linux */
|
||||
#undef SOFTWARE_SINGLE_STEP
|
||||
#define SOFTWARE_SINGLE_STEP(p,q) abort() /* Will never execute! */
|
||||
#undef SOFTWARE_SINGLE_STEP_P
|
||||
#define SOFTWARE_SINGLE_STEP_P 0
|
||||
|
||||
/* Make sure nexti gets the help it needs for debugging assembly code
|
||||
without symbols */
|
||||
|
||||
#define AT_SUBROUTINE_CALL_INSTRUCTION_TARGET(prevpc,stoppc) \
|
||||
at_subroutine_call_instruction_target(prevpc,stoppc)
|
||||
extern int at_subroutine_call_instruction_target();
|
||||
|
||||
/* We _want_ the SVR4 section offset calculations (see syms_from_objfile()
|
||||
in symfile.c) */
|
||||
#undef IBM6000_TARGET
|
||||
|
||||
/* Offset to saved PC in sigcontext, from <linux/signal.h>. */
|
||||
#define SIGCONTEXT_PC_OFFSET 184
|
||||
|
||||
/* Avoid warning from redefinition in tm-sysv4.h */
|
||||
#undef SKIP_TRAMPOLINE_CODE
|
||||
|
||||
/* We need this file for the SOLIB_TRAMPOLINE stuff. */
|
||||
#include "tm-sysv4.h"
|
||||
|
||||
extern CORE_ADDR ppc_linux_skip_trampoline_code (CORE_ADDR pc);
|
||||
#undef SKIP_TRAMPOLINE_CODE
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) ppc_linux_skip_trampoline_code (pc)
|
||||
|
||||
extern int ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name);
|
||||
#undef IN_SIGTRAMP
|
||||
#define IN_SIGTRAMP(pc,func_name) ppc_linux_in_sigtramp (pc,func_name)
|
||||
|
||||
extern unsigned long ppc_linux_frame_saved_pc (struct frame_info *);
|
||||
#undef FRAME_SAVED_PC
|
||||
#define FRAME_SAVED_PC(FRAME) ppc_linux_frame_saved_pc (FRAME)
|
||||
|
||||
extern void ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *);
|
||||
#undef INIT_EXTRA_FRAME_INFO
|
||||
#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
|
||||
ppc_linux_init_extra_frame_info (fromleaf, fi)
|
||||
|
||||
extern int ppc_linux_frameless_function_invocation (struct frame_info *);
|
||||
#undef FRAMELESS_FUNCTION_INVOCATION
|
||||
#define FRAMELESS_FUNCTION_INVOCATION(FI) \
|
||||
(ppc_linux_frameless_function_invocation (FI))
|
||||
|
||||
extern void ppc_linux_frame_init_saved_regs (struct frame_info *);
|
||||
#undef FRAME_INIT_SAVED_REGS
|
||||
#define FRAME_INIT_SAVED_REGS(FI) ppc_linux_frame_init_saved_regs (FI)
|
||||
|
||||
CORE_ADDR ppc_linux_frame_chain (struct frame_info *);
|
||||
#undef FRAME_CHAIN
|
||||
#define FRAME_CHAIN(thisframe) ppc_linux_frame_chain (thisframe)
|
||||
|
||||
CORE_ADDR ppc_sysv_abi_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR));
|
||||
#undef PUSH_ARGUMENTS
|
||||
#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
|
||||
(ppc_sysv_abi_push_arguments((nargs), (args), (sp), (struct_return), (struct_addr)))
|
||||
|
||||
#define CANNOT_FETCH_REGISTER(regno) ((regno) >= MQ_REGNUM)
|
||||
#define CANNOT_STORE_REGISTER(regno) ((regno) >= MQ_REGNUM)
|
||||
|
||||
/* Linux doesn't use the PowerOpen ABI for function pointer representation */
|
||||
#undef CONVERT_FROM_FUNC_PTR_ADDR
|
||||
|
||||
#if 0 /* If skip_prologue() isn't too greedy, we don't need this */
|
||||
/* There is some problem with the debugging symbols generated by the
|
||||
compiler such that the debugging symbol for the first line of a
|
||||
function overlap with the function prologue. */
|
||||
#define PROLOGUE_FIRSTLINE_OVERLAP
|
||||
#endif
|
||||
|
||||
/* Some versions of Linux have real-time signal support in the C library, and
|
||||
some don't. We have to include this file to find out. */
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef __SIGRTMIN
|
||||
#define REALTIME_LO __SIGRTMIN
|
||||
#define REALTIME_HI (__SIGRTMAX + 1)
|
||||
#else
|
||||
#define REALTIME_LO 32
|
||||
#define REALTIME_HI 64
|
||||
#endif
|
||||
|
||||
#endif /* #ifndef TM_LINUX_H */
|
@ -1,3 +1,49 @@
|
||||
/* Native support for linux, for GDB, the GNU debugger.
|
||||
Copyright (C) 1986, 1987, 1989, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef XM_LINUX_H
|
||||
#define XM_LINUX_H
|
||||
|
||||
#define HOST_BYTE_ORDER BIG_ENDIAN
|
||||
|
||||
#define HAVE_TERMIOS
|
||||
|
||||
/* This is the amount to subtract from u.u_ar0
|
||||
+ to get the offset in the core file of the register values. */
|
||||
#define KERNEL_U_ADDR 0x0
|
||||
|
||||
#define NEED_POSIX_SETPGID
|
||||
|
||||
/* Need R_OK etc, but USG isn't defined. */
|
||||
#include <unistd.h>
|
||||
|
||||
/* If you expect to use the mmalloc package to obtain mapped symbol files,
|
||||
for now you have to specify some parameters that determine how gdb places
|
||||
the mappings in it's address space. See the comments in map_to_address()
|
||||
for details. This is expected to only be a short term solution. Yes it
|
||||
is a kludge.
|
||||
FIXME: Make this more automatic. */
|
||||
|
||||
#define MMAP_BASE_ADDRESS 0x20000000 /* First mapping here */
|
||||
#define MMAP_INCREMENT 0x01000000 /* Increment to next mapping */
|
||||
|
||||
#endif /* #ifndef XM_LINUX_H */
|
||||
/* Host definitions for a Sun 4, for GDB, the GNU debugger.
|
||||
Copyright 1996
|
||||
Free Software Foundation, Inc.
|
||||
|
@ -380,10 +380,9 @@ CORE_ADDR rs6000_frame_chain PARAMS ((struct frame_info *));
|
||||
by FI does not have a frame on the stack associated with it. If it
|
||||
does not, FRAMELESS is set to 1, else 0. */
|
||||
|
||||
extern int rs6000_frameless_function_invocation (struct frame_info *);
|
||||
#define FRAMELESS_FUNCTION_INVOCATION(FI) \
|
||||
(frameless_function_invocation (FI))
|
||||
|
||||
extern int frameless_function_invocation PARAMS ((struct frame_info *));
|
||||
(rs6000_frameless_function_invocation (FI))
|
||||
|
||||
#define INIT_FRAME_PC_FIRST(fromleaf, prev) \
|
||||
prev->pc = (fromleaf ? SAVED_PC_AFTER_CALL (prev->next) : \
|
||||
@ -407,9 +406,9 @@ extern void rs6000_init_extra_frame_info (int fromleaf, struct frame_info *);
|
||||
#define DEFAULT_LR_SAVE 8
|
||||
|
||||
/* Return saved PC from a frame */
|
||||
#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME)
|
||||
#define FRAME_SAVED_PC(FRAME) rs6000_frame_saved_pc (FRAME)
|
||||
|
||||
extern unsigned long frame_saved_pc PARAMS ((struct frame_info *));
|
||||
extern unsigned long rs6000_frame_saved_pc (struct frame_info *);
|
||||
|
||||
extern CORE_ADDR rs6000_frame_args_address PARAMS ((struct frame_info *));
|
||||
#define FRAME_ARGS_ADDRESS(FI) rs6000_frame_args_address (FI)
|
||||
|
76
gdb/ppc-linux-nat.c
Normal file
76
gdb/ppc-linux-nat.c
Normal file
@ -0,0 +1,76 @@
|
||||
/* PPC linux native support.
|
||||
Copyright (C) 1988, 1989, 1991, 1992, 1994, 1996 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <signal.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/procfs.h>
|
||||
|
||||
int
|
||||
kernel_u_size ()
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
static int regmap[] =
|
||||
{PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7,
|
||||
PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15,
|
||||
PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23,
|
||||
PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31,
|
||||
PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6, PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14,
|
||||
PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22, PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30,
|
||||
PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38, PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46,
|
||||
PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62,
|
||||
PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ};
|
||||
|
||||
int
|
||||
ppc_register_u_addr (int ustart, int regnum)
|
||||
{
|
||||
return (ustart + 4 * regmap[regnum]);
|
||||
}
|
||||
|
||||
supply_gregset (gregset_t * gregsetp)
|
||||
{
|
||||
int regi;
|
||||
register greg_t *regp = (greg_t *) gregsetp;
|
||||
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
supply_register (regi, (char *) (regp + regi));
|
||||
|
||||
for (regi = FIRST_UISA_SP_REGNUM; regi <= LAST_UISA_SP_REGNUM; regi++)
|
||||
supply_register (regi, (char *) (regp + regmap[regi]));
|
||||
}
|
||||
|
||||
supply_fpregset (fpregset_t * fpregsetp)
|
||||
{
|
||||
int regi;
|
||||
for (regi = 0; regi < 32; regi++)
|
||||
{
|
||||
supply_register (FP0_REGNUM + regi, (char *) (*fpregsetp + regi));
|
||||
}
|
||||
}
|
599
gdb/ppc-linux-tdep.c
Normal file
599
gdb/ppc-linux-tdep.c
Normal file
@ -0,0 +1,599 @@
|
||||
/* Target-dependent code for GDB, the GNU debugger.
|
||||
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include "defs.h"
|
||||
#include "frame.h"
|
||||
#include "inferior.h"
|
||||
#include "symtab.h"
|
||||
#include "target.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdbcmd.h"
|
||||
#include "symfile.h"
|
||||
#include "objfiles.h"
|
||||
|
||||
/* The following two instructions are used in the signal trampoline
|
||||
code on linux/ppc */
|
||||
#define INSTR_LI_R0_0x7777 0x38007777
|
||||
#define INSTR_SC 0x44000002
|
||||
|
||||
/* Since the *-tdep.c files are platform independent (i.e, they may be
|
||||
used to build cross platform debuggers), we can't include system
|
||||
headers. Therefore, details concerning the sigcontext structure
|
||||
must be painstakingly rerecorded. What's worse, if these details
|
||||
ever change in the header files, they'll have to be changed here
|
||||
as well. */
|
||||
|
||||
/* __SIGNAL_FRAMESIZE from <asm/ptrace.h> */
|
||||
#define PPC_LINUX_SIGNAL_FRAMESIZE 64
|
||||
|
||||
/* From <asm/sigcontext.h>, offsetof(struct sigcontext_struct, regs) == 0x1c */
|
||||
#define PPC_LINUX_REGS_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x1c)
|
||||
|
||||
/* From <asm/sigcontext.h>,
|
||||
offsetof(struct sigcontext_struct, handler) == 0x14 */
|
||||
#define PPC_LINUX_HANDLER_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x14)
|
||||
|
||||
/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
|
||||
#define PPC_LINUX_PT_R0 0
|
||||
#define PPC_LINUX_PT_R1 1
|
||||
#define PPC_LINUX_PT_R2 2
|
||||
#define PPC_LINUX_PT_R3 3
|
||||
#define PPC_LINUX_PT_R4 4
|
||||
#define PPC_LINUX_PT_R5 5
|
||||
#define PPC_LINUX_PT_R6 6
|
||||
#define PPC_LINUX_PT_R7 7
|
||||
#define PPC_LINUX_PT_R8 8
|
||||
#define PPC_LINUX_PT_R9 9
|
||||
#define PPC_LINUX_PT_R10 10
|
||||
#define PPC_LINUX_PT_R11 11
|
||||
#define PPC_LINUX_PT_R12 12
|
||||
#define PPC_LINUX_PT_R13 13
|
||||
#define PPC_LINUX_PT_R14 14
|
||||
#define PPC_LINUX_PT_R15 15
|
||||
#define PPC_LINUX_PT_R16 16
|
||||
#define PPC_LINUX_PT_R17 17
|
||||
#define PPC_LINUX_PT_R18 18
|
||||
#define PPC_LINUX_PT_R19 19
|
||||
#define PPC_LINUX_PT_R20 20
|
||||
#define PPC_LINUX_PT_R21 21
|
||||
#define PPC_LINUX_PT_R22 22
|
||||
#define PPC_LINUX_PT_R23 23
|
||||
#define PPC_LINUX_PT_R24 24
|
||||
#define PPC_LINUX_PT_R25 25
|
||||
#define PPC_LINUX_PT_R26 26
|
||||
#define PPC_LINUX_PT_R27 27
|
||||
#define PPC_LINUX_PT_R28 28
|
||||
#define PPC_LINUX_PT_R29 29
|
||||
#define PPC_LINUX_PT_R30 30
|
||||
#define PPC_LINUX_PT_R31 31
|
||||
#define PPC_LINUX_PT_NIP 32
|
||||
#define PPC_LINUX_PT_MSR 33
|
||||
#define PPC_LINUX_PT_CTR 35
|
||||
#define PPC_LINUX_PT_LNK 36
|
||||
#define PPC_LINUX_PT_XER 37
|
||||
#define PPC_LINUX_PT_CCR 38
|
||||
#define PPC_LINUX_PT_MQ 39
|
||||
#define PPC_LINUX_PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
|
||||
#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
|
||||
#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
|
||||
|
||||
/* Determine if pc is in a signal trampoline...
|
||||
|
||||
Ha! That's not what this does at all. wait_for_inferior in infrun.c
|
||||
calls IN_SIGTRAMP in order to detect entry into a signal trampoline
|
||||
just after delivery of a signal. But on linux, signal trampolines
|
||||
are used for the return path only. The kernel sets things up so that
|
||||
the signal handler is called directly.
|
||||
|
||||
If we use in_sigtramp2() in place of in_sigtramp() (see below)
|
||||
we'll (often) end up with stop_pc in the trampoline and prev_pc in
|
||||
the (now exited) handler. The code there will cause a temporary
|
||||
breakpoint to be set on prev_pc which is not very likely to get hit
|
||||
again.
|
||||
|
||||
If this is confusing, think of it this way... the code in
|
||||
wait_for_inferior() needs to be able to detect entry into a signal
|
||||
trampoline just after a signal is delivered, not after the handler
|
||||
has been run.
|
||||
|
||||
So, we define in_sigtramp() below to return 1 if the following is
|
||||
true:
|
||||
|
||||
1) The previous frame is a real signal trampoline.
|
||||
|
||||
- and -
|
||||
|
||||
2) pc is at the first or second instruction of the corresponding
|
||||
handler.
|
||||
|
||||
Why the second instruction? It seems that wait_for_inferior()
|
||||
never sees the first instruction when single stepping. When a
|
||||
signal is delivered while stepping, the next instruction that
|
||||
would've been stepped over isn't, instead a signal is delivered and
|
||||
the first instruction of the handler is stepped over instead. That
|
||||
puts us on the second instruction. (I added the test for the
|
||||
first instruction long after the fact, just in case the observed
|
||||
behavior is ever fixed.)
|
||||
|
||||
IN_SIGTRAMP is called from blockframe.c as well in order to set
|
||||
the signal_handler_caller flag. Because of our strange definition
|
||||
of in_sigtramp below, we can't rely on signal_handler_caller getting
|
||||
set correctly from within blockframe.c. This is why we take pains
|
||||
to set it in init_extra_frame_info(). */
|
||||
|
||||
int
|
||||
ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
|
||||
{
|
||||
CORE_ADDR lr;
|
||||
CORE_ADDR sp;
|
||||
CORE_ADDR tramp_sp;
|
||||
char buf[4];
|
||||
CORE_ADDR handler;
|
||||
|
||||
lr = read_register (LR_REGNUM);
|
||||
if (!ppc_linux_at_sigtramp_return_path (lr))
|
||||
return 0;
|
||||
|
||||
sp = read_register (SP_REGNUM);
|
||||
|
||||
if (target_read_memory (sp, buf, sizeof (buf)) != 0)
|
||||
return 0;
|
||||
|
||||
tramp_sp = extract_unsigned_integer (buf, 4);
|
||||
|
||||
if (target_read_memory (tramp_sp + PPC_LINUX_HANDLER_PTR_OFFSET, buf,
|
||||
sizeof (buf)) != 0)
|
||||
return 0;
|
||||
|
||||
handler = extract_unsigned_integer (buf, 4);
|
||||
|
||||
return (pc == handler || pc == handler + 4);
|
||||
}
|
||||
|
||||
/*
|
||||
* The signal handler trampoline is on the stack and consists of exactly
|
||||
* two instructions. The easiest and most accurate way of determining
|
||||
* whether the pc is in one of these trampolines is by inspecting the
|
||||
* instructions. It'd be faster though if we could find a way to do this
|
||||
* via some simple address comparisons.
|
||||
*/
|
||||
int
|
||||
ppc_linux_at_sigtramp_return_path (CORE_ADDR pc)
|
||||
{
|
||||
char buf[12];
|
||||
unsigned long pcinsn;
|
||||
if (target_read_memory (pc - 4, buf, sizeof (buf)) != 0)
|
||||
return 0;
|
||||
|
||||
/* extract the instruction at the pc */
|
||||
pcinsn = extract_unsigned_integer (buf + 4, 4);
|
||||
|
||||
return (
|
||||
(pcinsn == INSTR_LI_R0_0x7777
|
||||
&& extract_unsigned_integer (buf + 8, 4) == INSTR_SC)
|
||||
||
|
||||
(pcinsn == INSTR_SC
|
||||
&& extract_unsigned_integer (buf, 4) == INSTR_LI_R0_0x7777));
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
ppc_linux_skip_trampoline_code (CORE_ADDR pc)
|
||||
{
|
||||
char buf[4];
|
||||
struct obj_section *sect;
|
||||
struct objfile *objfile;
|
||||
unsigned long insn;
|
||||
CORE_ADDR plt_start = 0;
|
||||
CORE_ADDR symtab = 0;
|
||||
CORE_ADDR strtab = 0;
|
||||
int num_slots = -1;
|
||||
int reloc_index = -1;
|
||||
CORE_ADDR plt_table;
|
||||
CORE_ADDR reloc;
|
||||
CORE_ADDR sym;
|
||||
long symidx;
|
||||
char symname[1024];
|
||||
struct minimal_symbol *msymbol;
|
||||
|
||||
/* Find the section pc is in; return if not in .plt */
|
||||
sect = find_pc_section (pc);
|
||||
if (!sect || strcmp (sect->the_bfd_section->name, ".plt") != 0)
|
||||
return 0;
|
||||
|
||||
objfile = sect->objfile;
|
||||
|
||||
/* Pick up the instruction at pc. It had better be of the
|
||||
form
|
||||
li r11, IDX
|
||||
|
||||
where IDX is an index into the plt_table. */
|
||||
|
||||
if (target_read_memory (pc, buf, 4) != 0)
|
||||
return 0;
|
||||
insn = extract_unsigned_integer (buf, 4);
|
||||
|
||||
if ((insn & 0xffff0000) != 0x39600000 /* li r11, VAL */ )
|
||||
return 0;
|
||||
|
||||
reloc_index = (insn << 16) >> 16;
|
||||
|
||||
/* Find the objfile that pc is in and obtain the information
|
||||
necessary for finding the symbol name. */
|
||||
for (sect = objfile->sections; sect < objfile->sections_end; ++sect)
|
||||
{
|
||||
const char *secname = sect->the_bfd_section->name;
|
||||
if (strcmp (secname, ".plt") == 0)
|
||||
plt_start = sect->addr;
|
||||
else if (strcmp (secname, ".rela.plt") == 0)
|
||||
num_slots = ((int) sect->endaddr - (int) sect->addr) / 12;
|
||||
else if (strcmp (secname, ".dynsym") == 0)
|
||||
symtab = sect->addr;
|
||||
else if (strcmp (secname, ".dynstr") == 0)
|
||||
strtab = sect->addr;
|
||||
}
|
||||
|
||||
/* Make sure we have all the information we need. */
|
||||
if (plt_start == 0 || num_slots == -1 || symtab == 0 || strtab == 0)
|
||||
return 0;
|
||||
|
||||
/* Compute the value of the plt table */
|
||||
plt_table = plt_start + 72 + 8 * num_slots;
|
||||
|
||||
/* Get address of the relocation entry (Elf32_Rela) */
|
||||
if (target_read_memory (plt_table + reloc_index, buf, 4) != 0)
|
||||
return 0;
|
||||
reloc = extract_address (buf, 4);
|
||||
|
||||
sect = find_pc_section (reloc);
|
||||
if (!sect)
|
||||
return 0;
|
||||
|
||||
if (strcmp (sect->the_bfd_section->name, ".text") == 0)
|
||||
return reloc;
|
||||
|
||||
/* Now get the r_info field which is the relocation type and symbol
|
||||
index. */
|
||||
if (target_read_memory (reloc + 4, buf, 4) != 0)
|
||||
return 0;
|
||||
symidx = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* Shift out the relocation type leaving just the symbol index */
|
||||
/* symidx = ELF32_R_SYM(symidx); */
|
||||
symidx = symidx >> 8;
|
||||
|
||||
/* compute the address of the symbol */
|
||||
sym = symtab + symidx * 4;
|
||||
|
||||
/* Fetch the string table index */
|
||||
if (target_read_memory (sym, buf, 4) != 0)
|
||||
return 0;
|
||||
symidx = extract_unsigned_integer (buf, 4);
|
||||
|
||||
/* Fetch the string; we don't know how long it is. Is it possible
|
||||
that the following will fail because we're trying to fetch too
|
||||
much? */
|
||||
if (target_read_memory (strtab + symidx, symname, sizeof (symname)) != 0)
|
||||
return 0;
|
||||
|
||||
/* This might not work right if we have multiple symbols with the
|
||||
same name; the only way to really get it right is to perform
|
||||
the same sort of lookup as the dynamic linker. */
|
||||
msymbol = lookup_minimal_symbol_text (symname, NULL, NULL);
|
||||
if (!msymbol)
|
||||
return 0;
|
||||
|
||||
return SYMBOL_VALUE_ADDRESS (msymbol);
|
||||
}
|
||||
|
||||
/* The rs6000 version of FRAME_SAVED_PC will almost work for us. The
|
||||
signal handler details are different, so we'll handle those here
|
||||
and call the rs6000 version to do the rest. */
|
||||
unsigned long
|
||||
ppc_linux_frame_saved_pc (struct frame_info *fi)
|
||||
{
|
||||
if (fi->signal_handler_caller)
|
||||
{
|
||||
CORE_ADDR regs_addr =
|
||||
read_memory_integer (fi->frame + PPC_LINUX_REGS_PTR_OFFSET, 4);
|
||||
/* return the NIP in the regs array */
|
||||
return read_memory_integer (regs_addr + 4 * PPC_LINUX_PT_NIP, 4);
|
||||
}
|
||||
|
||||
return rs6000_frame_saved_pc (fi);
|
||||
}
|
||||
|
||||
void
|
||||
ppc_linux_init_extra_frame_info (int fromleaf, struct frame_info *fi)
|
||||
{
|
||||
rs6000_init_extra_frame_info (fromleaf, fi);
|
||||
|
||||
if (fi->next != 0)
|
||||
{
|
||||
/* We're called from get_prev_frame_info; check to see if
|
||||
this is a signal frame by looking to see if the pc points
|
||||
at trampoline code */
|
||||
if (ppc_linux_at_sigtramp_return_path (fi->pc))
|
||||
fi->signal_handler_caller = 1;
|
||||
else
|
||||
fi->signal_handler_caller = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ppc_linux_frameless_function_invocation (struct frame_info *fi)
|
||||
{
|
||||
/* We'll find the wrong thing if we let
|
||||
rs6000_frameless_function_invocation () search for a signal trampoline */
|
||||
if (ppc_linux_at_sigtramp_return_path (fi->pc))
|
||||
return 0;
|
||||
else
|
||||
return rs6000_frameless_function_invocation (fi);
|
||||
}
|
||||
|
||||
void
|
||||
ppc_linux_frame_init_saved_regs (struct frame_info *fi)
|
||||
{
|
||||
if (fi->signal_handler_caller)
|
||||
{
|
||||
CORE_ADDR regs_addr;
|
||||
int i;
|
||||
if (fi->saved_regs)
|
||||
return;
|
||||
|
||||
frame_saved_regs_zalloc (fi);
|
||||
|
||||
regs_addr =
|
||||
read_memory_integer (fi->frame + PPC_LINUX_REGS_PTR_OFFSET, 4);
|
||||
fi->saved_regs[PC_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_NIP;
|
||||
fi->saved_regs[PS_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MSR;
|
||||
fi->saved_regs[CR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CCR;
|
||||
fi->saved_regs[LR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_LNK;
|
||||
fi->saved_regs[CTR_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_CTR;
|
||||
fi->saved_regs[XER_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_XER;
|
||||
fi->saved_regs[MQ_REGNUM] = regs_addr + 4 * PPC_LINUX_PT_MQ;
|
||||
for (i = 0; i < 32; i++)
|
||||
fi->saved_regs[GP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_R0 + 4 * i;
|
||||
for (i = 0; i < 32; i++)
|
||||
fi->saved_regs[FP0_REGNUM + i] = regs_addr + 4 * PPC_LINUX_PT_FPR0 + 8 * i;
|
||||
}
|
||||
else
|
||||
rs6000_frame_init_saved_regs (fi);
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
ppc_linux_frame_chain (struct frame_info *thisframe)
|
||||
{
|
||||
/* Kernel properly constructs the frame chain for the handler */
|
||||
if (thisframe->signal_handler_caller)
|
||||
return read_memory_integer ((thisframe)->frame, 4);
|
||||
else
|
||||
return rs6000_frame_chain (thisframe);
|
||||
}
|
||||
|
||||
/* FIXME: Move the following to rs6000-tdep.c (or some other file where
|
||||
it may be used generically by ports which use either the SysV ABI or
|
||||
the EABI */
|
||||
|
||||
/* round2 rounds x up to the nearest multiple of s assuming that s is a
|
||||
power of 2 */
|
||||
|
||||
#undef round2
|
||||
#define round2(x,s) ((((long) (x) - 1) & ~(long)((s)-1)) + (s))
|
||||
|
||||
/* Pass the arguments in either registers, or in the stack. Using the
|
||||
ppc sysv ABI, the first eight words of the argument list (that might
|
||||
be less than eight parameters if some parameters occupy more than one
|
||||
word) are passed in r3..r10 registers. float and double parameters are
|
||||
passed in fpr's, in addition to that. Rest of the parameters if any
|
||||
are passed in user stack.
|
||||
|
||||
If the function is returning a structure, then the return address is passed
|
||||
in r3, then the first 7 words of the parametes can be passed in registers,
|
||||
starting from r4. */
|
||||
|
||||
CORE_ADDR
|
||||
ppc_sysv_abi_push_arguments (nargs, args, sp, struct_return, struct_addr)
|
||||
int nargs;
|
||||
value_ptr *args;
|
||||
CORE_ADDR sp;
|
||||
int struct_return;
|
||||
CORE_ADDR struct_addr;
|
||||
{
|
||||
int argno;
|
||||
int greg, freg;
|
||||
int argstkspace;
|
||||
int structstkspace;
|
||||
int argoffset;
|
||||
int structoffset;
|
||||
value_ptr arg;
|
||||
struct type *type;
|
||||
int len;
|
||||
char old_sp_buf[4];
|
||||
CORE_ADDR saved_sp;
|
||||
|
||||
greg = struct_return ? 4 : 3;
|
||||
freg = 1;
|
||||
argstkspace = 0;
|
||||
structstkspace = 0;
|
||||
|
||||
/* Figure out how much new stack space is required for arguments
|
||||
which don't fit in registers. Unlike the PowerOpen ABI, the
|
||||
SysV ABI doesn't reserve any extra space for parameters which
|
||||
are put in registers. */
|
||||
for (argno = 0; argno < nargs; argno++)
|
||||
{
|
||||
arg = args[argno];
|
||||
type = check_typedef (VALUE_TYPE (arg));
|
||||
len = TYPE_LENGTH (type);
|
||||
|
||||
if (TYPE_CODE (type) == TYPE_CODE_FLT)
|
||||
{
|
||||
if (freg <= 8)
|
||||
freg++;
|
||||
else
|
||||
{
|
||||
/* SysV ABI converts floats to doubles when placed in
|
||||
memory and requires 8 byte alignment */
|
||||
if (argstkspace & 0x4)
|
||||
argstkspace += 4;
|
||||
argstkspace += 8;
|
||||
}
|
||||
}
|
||||
else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8) /* long long */
|
||||
{
|
||||
if (greg > 9)
|
||||
{
|
||||
greg = 11;
|
||||
if (argstkspace & 0x4)
|
||||
argstkspace += 4;
|
||||
argstkspace += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((greg & 1) == 0)
|
||||
greg++;
|
||||
greg += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len > 4
|
||||
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|
||||
|| TYPE_CODE (type) == TYPE_CODE_UNION)
|
||||
{
|
||||
/* Rounding to the nearest multiple of 8 may not be necessary,
|
||||
but it is safe. Particularly since we don't know the
|
||||
field types of the structure */
|
||||
structstkspace += round2 (len, 8);
|
||||
}
|
||||
if (greg <= 10)
|
||||
greg++;
|
||||
else
|
||||
argstkspace += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get current SP location */
|
||||
saved_sp = read_sp ();
|
||||
|
||||
sp -= argstkspace + structstkspace;
|
||||
|
||||
/* Allocate space for backchain and callee's saved lr */
|
||||
sp -= 8;
|
||||
|
||||
/* Make sure that we maintain 16 byte alignment */
|
||||
sp &= ~0x0f;
|
||||
|
||||
/* Update %sp before proceeding any further */
|
||||
write_register (SP_REGNUM, sp);
|
||||
|
||||
/* write the backchain */
|
||||
store_address (old_sp_buf, 4, saved_sp);
|
||||
write_memory (sp, old_sp_buf, 4);
|
||||
|
||||
argoffset = 8;
|
||||
structoffset = argoffset + argstkspace;
|
||||
freg = 1;
|
||||
greg = 3;
|
||||
/* Now fill in the registers and stack... */
|
||||
for (argno = 0; argno < nargs; argno++)
|
||||
{
|
||||
arg = args[argno];
|
||||
type = check_typedef (VALUE_TYPE (arg));
|
||||
len = TYPE_LENGTH (type);
|
||||
|
||||
if (TYPE_CODE (type) == TYPE_CODE_FLT)
|
||||
{
|
||||
if (freg <= 8)
|
||||
{
|
||||
if (len > 8)
|
||||
printf_unfiltered (
|
||||
"Fatal Error: a floating point parameter #%d with a size > 8 is found!\n", argno);
|
||||
memcpy (®isters[REGISTER_BYTE (FP0_REGNUM + freg)],
|
||||
VALUE_CONTENTS (arg), len);
|
||||
freg++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* SysV ABI converts floats to doubles when placed in
|
||||
memory and requires 8 byte alignment */
|
||||
/* FIXME: Convert floats to doubles */
|
||||
if (argoffset & 0x4)
|
||||
argoffset += 4;
|
||||
write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
|
||||
argoffset += 8;
|
||||
}
|
||||
}
|
||||
else if (TYPE_CODE (type) == TYPE_CODE_INT && len == 8) /* long long */
|
||||
{
|
||||
if (greg > 9)
|
||||
{
|
||||
greg = 11;
|
||||
if (argoffset & 0x4)
|
||||
argoffset += 4;
|
||||
write_memory (sp + argoffset, (char *) VALUE_CONTENTS (arg), len);
|
||||
argoffset += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((greg & 1) == 0)
|
||||
greg++;
|
||||
|
||||
memcpy (®isters[REGISTER_BYTE (greg)],
|
||||
VALUE_CONTENTS (arg), 4);
|
||||
memcpy (®isters[REGISTER_BYTE (greg + 1)],
|
||||
VALUE_CONTENTS (arg) + 4, 4);
|
||||
greg += 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char val_buf[4];
|
||||
if (len > 4
|
||||
|| TYPE_CODE (type) == TYPE_CODE_STRUCT
|
||||
|| TYPE_CODE (type) == TYPE_CODE_UNION)
|
||||
{
|
||||
write_memory (sp + structoffset, VALUE_CONTENTS (arg), len);
|
||||
store_address (val_buf, 4, sp + structoffset);
|
||||
structoffset += round2 (len, 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (val_buf, 0, 4);
|
||||
memcpy (val_buf, VALUE_CONTENTS (arg), len);
|
||||
}
|
||||
if (greg <= 10)
|
||||
{
|
||||
*(int *) ®isters[REGISTER_BYTE (greg)] = 0;
|
||||
memcpy (®isters[REGISTER_BYTE (greg)], val_buf, 4);
|
||||
greg++;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_memory (sp + argoffset, val_buf, 4);
|
||||
argoffset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
target_store_registers (-1);
|
||||
return sp;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/* Target-dependent code for GDB, the GNU debugger.
|
||||
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997
|
||||
Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
@ -1238,8 +1238,7 @@ skip_trampoline_code (pc)
|
||||
/* Determines whether the function FI has a frame on the stack or not. */
|
||||
|
||||
int
|
||||
frameless_function_invocation (fi)
|
||||
struct frame_info *fi;
|
||||
rs6000_frameless_function_invocation (struct frame_info *fi)
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
struct rs6000_framedata fdata;
|
||||
@ -1273,8 +1272,7 @@ frameless_function_invocation (fi)
|
||||
/* Return the PC saved in a frame */
|
||||
|
||||
unsigned long
|
||||
frame_saved_pc (fi)
|
||||
struct frame_info *fi;
|
||||
rs6000_frame_saved_pc (struct frame_info *fi)
|
||||
{
|
||||
CORE_ADDR func_start;
|
||||
struct rs6000_framedata fdata;
|
||||
@ -1302,14 +1300,13 @@ frame_saved_pc (fi)
|
||||
if (fi->next->signal_handler_caller)
|
||||
return read_memory_integer (fi->next->frame + SIG_FRAME_LR_OFFSET, 4);
|
||||
else
|
||||
return read_memory_integer (rs6000_frame_chain (fi) + DEFAULT_LR_SAVE,
|
||||
4);
|
||||
return read_memory_integer (FRAME_CHAIN (fi) + DEFAULT_LR_SAVE, 4);
|
||||
}
|
||||
|
||||
if (fdata.lr_offset == 0)
|
||||
return read_register (LR_REGNUM);
|
||||
|
||||
return read_memory_integer (rs6000_frame_chain (fi) + fdata.lr_offset, 4);
|
||||
return read_memory_integer (FRAME_CHAIN (fi) + fdata.lr_offset, 4);
|
||||
}
|
||||
|
||||
/* If saved registers of frame FI are not known yet, read and cache them.
|
||||
@ -1480,7 +1477,7 @@ rs6000_frame_chain (thisframe)
|
||||
fp = read_memory_integer (thisframe->frame + SIG_FRAME_FP_OFFSET, 4);
|
||||
else if (thisframe->next != NULL
|
||||
&& thisframe->next->signal_handler_caller
|
||||
&& frameless_function_invocation (thisframe))
|
||||
&& FRAMELESS_FUNCTION_INVOCATION (thisframe))
|
||||
/* A frameless function interrupted by a signal did not change the
|
||||
frame pointer. */
|
||||
fp = FRAME_FP (thisframe);
|
||||
|
Loading…
Reference in New Issue
Block a user