import gdb-1999-12-21 snapshot
This commit is contained in:
parent
d3a0947552
commit
ed9a39ebf9
69 changed files with 6196 additions and 1946 deletions
275
gdb/ChangeLog
275
gdb/ChangeLog
|
@ -1,3 +1,276 @@
|
|||
1999-12-21 Stan Shebs <shebs@andros.cygnus.com>
|
||||
|
||||
* blockframe.c (generic_pop_current_frame): Cosmetic changes to
|
||||
clarify.
|
||||
|
||||
|
||||
1999-12-21 Jim Blandy <jimb@cygnus.com>
|
||||
|
||||
* Makefile.in (elf_bfd_h): Look for elf-bfd.h in BFD_SRC, not
|
||||
BFD_DIR. Unlike bfd.h, it is not a generated file.
|
||||
|
||||
Fri Dec 17 18:24:58 1999 David Taylor <taylor@texas.cygnus.com>
|
||||
|
||||
* language.c (_initialize_language): move settings of language,
|
||||
range, and type and corresponding function calls
|
||||
set_language_command, set_type_command, and set_range_command
|
||||
closer together to match the model of having the user set the
|
||||
variable via the 'set {language | range | type}' commands.
|
||||
This eliminates startup noise introduced by Jimmy Guo's change
|
||||
of Dec 13th.
|
||||
|
||||
1999-12-17 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* configure.in: test for <stdint.h>, which is not available
|
||||
on earlier versions of Linux.
|
||||
* config.in: define HAVE_STDINT_H if it's present.
|
||||
* configure: autoconfiscate.
|
||||
* lin-thread.c: if not HAVE_STDINT_H, stub out the entire module.
|
||||
|
||||
Fri Dec 17 20:45:21 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* target.c (find_target_beneath): Change ``='' in if to ``==''.
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* defs.h (TIDGET): add default definition.
|
||||
* lin-thread.c (check_for_thread_event): for now, just provide
|
||||
an empty definition (to be filled in later).
|
||||
|
||||
1999-12-16 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* varobj.c (varobj_list): Improve the test and the text of the
|
||||
assertion that guards against wrong tally of root varobjs.
|
||||
(uninstall_variable): Fix for a bug in which the number of root
|
||||
varobjs was not decremented if the first one in the list was deleted.
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* linux-thread.c: Remove printf-debugging code.
|
||||
* lin-thread.c: ditto.
|
||||
* config/alpha/nm-linux.h: protect with NM_LINUX_H.
|
||||
* testsuite/gdb.threads/linux-dp.exp: Make test for "New Thread"
|
||||
message more forgiving. Ditto test for "info threads".
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* lin-thread.c: new file. Implements multi-thread debugging on
|
||||
Linux using the thread_db API first implemented on Solaris. This
|
||||
frees GDB from any dependency on the internal implementation of
|
||||
the thread library. Future versions of the thread library will
|
||||
implement a libthread_db API for debuggers, which GDB will use.
|
||||
* config/i386/linux.mh: add lin-thread.o to the link, and add
|
||||
-ldl and -rdynamic since libthread_db is a dynamic library.
|
||||
* config/alpha/alpha-linux.mh: ditto.
|
||||
* configure.in: test for thread_db.h, proc_service.h
|
||||
* configure: autoconf.
|
||||
* config.in: conditionally define HAVE_THREAD_DB_H
|
||||
and HAVE_PROC_SERVICE_H
|
||||
* gdb_thread_db.h: new file, used when the system doesn't have it.
|
||||
* gdb_proc_service.h: ditto.
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* linux-thread.c: changes to accomodate the new lin-thread.c
|
||||
module based on the thread_db API. These changes make parts of
|
||||
linux-thread.c shareable with lin-thread.c.
|
||||
(linuxthreads_wait_mask): replace with linuxthreads_block_mask.
|
||||
(using_thread_db): new variable. Allows linux-thread module to
|
||||
detect when lin-thread (thread_db API) module is in use.
|
||||
(save_inferior_pid, restore_inferior_pid): make 32/64 bit safe.
|
||||
(check_all_signal_numbers) make extern, shared with lin-thead.c.
|
||||
(linuxthreads_new_objfile): use target_new_objfile_chain to share
|
||||
this hook with the lin-thread module. Call the other module FIRST.
|
||||
If using_thread_db is turned on by the other thread module, do not
|
||||
set linuxthreads_debug and do not call update_stop_threads. Do call
|
||||
check_all_signal_numbers, to be sure it gets set before target_wait.
|
||||
(linux_child_wait): new function. Abstracts out the "child_wait"
|
||||
functionality, so that it can be shared with the lin-thread module.
|
||||
(linuxthreads_wait): call linux_child_wait, instead of doing the
|
||||
waiting inline. If using_thread_db, do not call update_stop_threads
|
||||
and do not turn on linuxthreads_debug.
|
||||
(linuxthreads_mourn_inferior): abstract out the clearing of global
|
||||
state, so that it can be shared with the lin-thread.c module.
|
||||
(_initialize_linuxthreads): use linuxthreads_wait_mask to block
|
||||
SIGCHLD exactly ONCE, and leave it blocked! Then linux_child_wait
|
||||
will call sigsuspend when it wants to wait for this signal.
|
||||
(thread_attach): abstract out ptrace attach to share with lin-thread.c
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
Make target_pid_to_str a target_ops vector.
|
||||
* target.h (target_pid_to_str): redefine to use a target_ops vector.
|
||||
(target_tid_to_str): default to using target_pid_to_str.
|
||||
(target_pid_or_tid_to_str): ditto.
|
||||
* target.c (update_current_target): inherit to_pid_to_str method.
|
||||
(find_target_beneath): new function. Find target stratum below
|
||||
the given one.
|
||||
* config/nm-gnu.h: don't define target_pid_to_str.
|
||||
* config/i386/tm-i386sol2.h: ditto.
|
||||
* config/sparc/tm-sun4sol2.h: ditto.
|
||||
* gnu-nat.c (init_gnu_ops): initialize to_pid_to_str vector.
|
||||
* linux-thread.c (init_linuxthreads_ops): ditto.
|
||||
* sol-thread.c (init_sol_thread_ops: ditto.
|
||||
* procfs.c (init_procfs_ops): ditto.
|
||||
* win32-nat.c (init_child_ops): ditto.
|
||||
* config/i386/tm-cygwin.h: don't define target_pid_to_str.
|
||||
* inftarg.c (child_pid_to_str): new function, used to initialize
|
||||
to_pid_to_str vector. May be suppressed by defining CHILD_PID_TO_STR.
|
||||
(init_child_ops): initialize to_pid_to_str using child_pid_to_str.
|
||||
Derivative modules may substitute their own child_pid_to_str func
|
||||
by defining CHILD_PID_TO_STR.
|
||||
* lynx-nat.c (lynx_pid_to_str): rename to child_pid_to_str.
|
||||
* config/nm-lynx.h: define CHILD_PID_TO_STR.
|
||||
Don't define target_pid_to_str.
|
||||
* hppah-nat.c (hppa_pid_to_str): rename to child_pid_to_str.
|
||||
* infttrace.c (hppa_pid_or_tid_to_str): call child_pid_to str
|
||||
instead of hppa_pid_to_str.
|
||||
* config/pa/nm-hppah.h: define CHILD_PID_TO_STR.
|
||||
Don't define target_pid_to_str.
|
||||
|
||||
1999-12-16 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* i386-linux-nat.c: introduce PIDGET/TIDGET macros as on Solaris,
|
||||
preparatory to using the thread_db debugging API for Linux.
|
||||
(fill_gregset): guard against invalid input.
|
||||
(fetch_regs): add a pid/thread_id argument, so we can fetch regs
|
||||
from multiple processes/clones/threads. (store_regs): ditto.
|
||||
(fetch_fpregs): ditto. (store_fpregs): ditto.
|
||||
(fetch_xfpregs): ditto. (store_xfpregs): ditto.
|
||||
(fetch_inferior_registers): use TIDGET to extract an appropriate
|
||||
thread/clone/process id from inferior_pid, if there's one there,
|
||||
and pass it to fetch_regs etc. (store_inferior_registers): ditto.
|
||||
|
||||
* infptrace.c: include every available version of wait.h.
|
||||
introduce PIDGET/TIDGET macros for use with thread_db API on Linux.
|
||||
(call_ptrace): rearrange lines that were split by an ifdef.
|
||||
(fetch_register): use TIDGET to extract an appropriate process ID
|
||||
from inferior_pid, in case we are debugging more than one process.
|
||||
(store_register): ditto. This is for Linux.
|
||||
(child_xfer_memory): use PIDGET to extract the main process id from
|
||||
inferior_pid, in case we are debugging multiple processes that share
|
||||
the same address space (as on Linux).
|
||||
|
||||
1999-12-16 Christopher Faylor <cgf@cygnus.com>
|
||||
|
||||
* win32-nat.c: Add a missing register to mappings array.
|
||||
(child_fetch_inferior_registers): Use precalculated index into mappings
|
||||
array as supply_registers argument.
|
||||
(handle_output_debug_string): Avoid considering every debug string as a
|
||||
cygwin signal.
|
||||
(handle_exception): Trap first chance exceptions.
|
||||
(child_create_inferior): Initialize Microsoft thread walking API.
|
||||
(sgmb): New function. Used by Microsoft API for stack walking.
|
||||
(child_frame_chain): New function. Uses Microsoft API for stack
|
||||
walking.
|
||||
(child_frame_chain_saved_pc): Ditto.
|
||||
* config/i386/tm-cygwin.h: Define frame handling stuff.
|
||||
|
||||
1999-12-15 Stan Shebs <shebs@andros.cygnus.com>
|
||||
|
||||
ARM GNU/Linux support and general ARM target fixes/cleanup from
|
||||
Scott Bambrough <scottb@netwinder.org>, plus obsoletion of the old
|
||||
RISCix support.
|
||||
* NEWS: Mention addition and obsoletion.
|
||||
* configure.host: Recognize arm* instead of just arm.
|
||||
(arm*-*-linux*): Recognize.
|
||||
* configure.tgt: Ditto, plus assume arm*-*-* is embedded.
|
||||
* config/arm/arm.mh, config/arm/arm.mt, config/arm/nm-arm.h,
|
||||
config/arm/xm-arm.h: Mark as OBSOLETE.
|
||||
* config/arm/embed.mt, config/arm/tm-embed.h: New files.
|
||||
* config/arm/linux.mh, config/arm/linux.mt, config/arm/nm-linux.h,
|
||||
config/arm/tm-linux.h, config/arm/xm-linux.h: Ditto.
|
||||
* config/arm/tm-arm.h: Add more comments, eliminate PARAMS.
|
||||
(STACK_END_ADDR): Remove.
|
||||
(ARM_LE_BREAKPOINT, ARM_BE_BREAKPOINT, THUMB_LE_BREAKPOINT,
|
||||
THUMB_BE_BREAKPOINT): Move to here from arm-tdep.c.
|
||||
(NUM_REGS): Define as sum.
|
||||
(NUM_FREGS, NUM_SREGS, NUM_GREGS): New definitions.
|
||||
(FP_REGISTER_RAW_SIZE, FP_REGISTER_VIRTUAL_SIZE,
|
||||
STATUS_REGISTER_SIZE): Define.
|
||||
(REGISTER_BYTES, REGISTER_BYTE, REGISTER_RAW_SIZE,
|
||||
REGISTER_VIRTUAL_SIZE): Rewrite to use symbolic values.
|
||||
(REGISTER_CONVERTIBLE, REGISTER_CONVERT_TO_VIRTUAL,
|
||||
REGISTER_CONVERT_TO_RAW, USE_STRUCT_CONVENTION,
|
||||
EXTRACT_RETURN_VALUE): Rewrite to use new functions.
|
||||
(IN_SIGTRAMP): Remove definition.
|
||||
* arm-convert.s: Mark as OBSOLETE.
|
||||
* arm-linux-nat.c: New file.
|
||||
* Makefile.in: Add build rule for it.
|
||||
* arm-tdep.c (struct frame_extra_info): New struct.
|
||||
(arm_use_struct_convention): Rewrite.
|
||||
(arm_push_arguments): Rewrite to handle more cases.
|
||||
(arm_register_convertible, arm_register_convert_to_virtual,
|
||||
arm_register_convert_to_raw, arm_extract_return_value): New
|
||||
functions.
|
||||
(LITTLE_BREAKPOINT, BIG_BREAKPOINT): Remove.
|
||||
* arm-xdep.c: Mark as OBSOLETE.
|
||||
|
||||
1999-12-15 Elena Zannoni <ezannoni@kwikemart.cygnus.com>
|
||||
|
||||
* infcmd.c (run_stack_dummy): Temporarily lie about the target
|
||||
ability to support asynchronous execution.
|
||||
|
||||
* remote.c (remote_can_async_p, remote_is_async_p): Return true
|
||||
iff to_async_mask_value is true too.
|
||||
(remote_async): Error out if called when to_async_mask_value is 0.
|
||||
(init_remote_async_ops): Initialize to_async_mask_value to 1.
|
||||
(remote_async_detach, remote_async_resume, remote_async_wait,
|
||||
remote_async_kill): Change SERIAL_IS_ASYNC_P call to
|
||||
target_is_async_p call.
|
||||
(remote_async_resume): Change SERIAL_CAN_ASYNC_P call to
|
||||
target_can_async_p call.
|
||||
|
||||
* target.c (update_current_target): Inherit to_async_mask_value.
|
||||
(target_async_mask): New function. To temporarily turn the target
|
||||
into a synchronous one for inferior function calls, and back to
|
||||
asynchronous.
|
||||
|
||||
* target.h (to_async_mask_value): New entry in the target
|
||||
vector.
|
||||
(target_async_mask): Export.
|
||||
(target_async_mask_value): Define.
|
||||
|
||||
Wed Dec 15 11:24:32 1999 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* hp-psymtab-read.c (trans_lang): Use HP_LANGUAGE_FORTRAN instead
|
||||
of HP_LANGUAGE_F77.
|
||||
|
||||
Wed Dec 15 13:37:55 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* gdb-events.h, gdb-events.c (set_gdb_event_hooks): Return the old
|
||||
event hooks vector.
|
||||
|
||||
1999-08-13 Jim Kingdon <http://developer.redhat.com/>
|
||||
|
||||
* breakpoint.c (bpstat_stop_status): Revert 1998-09-08 change
|
||||
to ->frame matching. The change did not match the ChangeLog
|
||||
entry, looked fishy, and caused infinite stepping when running
|
||||
"next" from main on sparc w/ RH Linux. Thanks to Jakub for the
|
||||
report.
|
||||
|
||||
1999-12-14 Stan Shebs <shebs@andros.cygnus.com>
|
||||
|
||||
* arm-tdep.c (arm_get_next_pc): Add argument to shifted_reg_val
|
||||
call.
|
||||
|
||||
1999-12-14 Mark Salter <msalter@cygnus.com>
|
||||
|
||||
* mips-tdep.c (mips_print_register): Fix printing of individual
|
||||
registers when REGISTER_VIRTUAL_SIZE != REGISTER_RAW_SIZE.
|
||||
|
||||
Tue Dec 14 23:29:19 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* defs.h (mcalloc): Delcare.
|
||||
* utils.c (xcalloc, mcalloc): New functions.
|
||||
|
||||
1999-12-13 Stan Shebs <shebs@andros.cygnus.com>
|
||||
|
||||
* config/arm/tm-arm.h: Reformat comments, in preparation for
|
||||
real changes.
|
||||
* arm-tdep.c: Similarly, plus change function definitions to
|
||||
modern form.
|
||||
|
||||
1999-12-13 Michael Snyder <msnyder@cleaver.cygnus.com>
|
||||
|
||||
* breakpoint.h (enum bptype): add new BP type bp_thread_event.
|
||||
|
@ -396,7 +669,7 @@ Thu Dec 2 17:14:53 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
|||
signal that we are ignoring, and GDB silently resumes the child,
|
||||
resume ALL threads (not just the one that got the signal). All
|
||||
threads are stopped, so all must be resumed.
|
||||
(handle_inferior_pid): on detecting a thread context switch,
|
||||
(handle_inferior_event): on detecting a thread context switch,
|
||||
swap infrun_state ONLY if both the old thread and the new one
|
||||
are in the thread list. Otherwise state information will be lost!
|
||||
Problem may arise with flaky back-ends.
|
||||
|
|
|
@ -229,7 +229,7 @@ CDEPS = $(XM_CDEPS) $(TM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE) \
|
|||
ADD_FILES = $(REGEX) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
|
||||
ADD_DEPS = $(REGEX1) $(XM_ADD_FILES) $(TM_ADD_FILES) $(NAT_ADD_FILES)
|
||||
|
||||
VERSION = 19991213
|
||||
VERSION = 19991221
|
||||
DIST=gdb
|
||||
|
||||
LINT=/usr/5bin/lint
|
||||
|
@ -414,7 +414,7 @@ LINTFILES = $(SFILES) $(YYFILES) @CONFIG_SRCS@ init.c
|
|||
getopt_h = $(INCLUDE_DIR)/getopt.h
|
||||
floatformat_h = $(INCLUDE_DIR)/floatformat.h
|
||||
bfd_h = $(BFD_DIR)/bfd.h
|
||||
elf_bfd_h = $(BFD_DIR)/elf-bfd.h
|
||||
elf_bfd_h = $(BFD_SRC)/elf-bfd.h
|
||||
wait_h = $(INCLUDE_DIR)/wait.h
|
||||
dis-asm_h = $(INCLUDE_DIR)/dis-asm.h
|
||||
remote-sim_h = $(INCLUDE_DIR)/remote-sim.h
|
||||
|
@ -956,7 +956,7 @@ ALLDEPFILES = 29k-share/udi/udip2soc.c 29k-share/udi/udr.c \
|
|||
29k-share/udi/udi2go32.c \
|
||||
a29k-tdep.c a68v-nat.c alpha-nat.c alpha-tdep.c \
|
||||
altos-xdep.c arm-convert.s \
|
||||
arm-tdep.c arm-xdep.c coff-solib.c \
|
||||
arm-linux-nat.c arm-tdep.c arm-xdep.c coff-solib.c \
|
||||
convex-tdep.c convex-xdep.c \
|
||||
core-sol2.c core-regset.c core-aout.c corelow.c \
|
||||
dcache.c delta68-nat.c dpx2-nat.c dstread.c exec.c fork-child.c \
|
||||
|
@ -1017,6 +1017,9 @@ alpha-tdep.o: alpha-tdep.c $(defs_h) $(gdbcmd_h) $(gdbcore_h) \
|
|||
|
||||
annotate.o: annotate.c $(defs_h) annotate.h $(value_h) target.h $(gdbtypes_h)
|
||||
|
||||
arm-linux-nat.o: arm-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
|
||||
gdb_string.h
|
||||
|
||||
arm-tdep.o: arm-tdep.c $(gdbcmd_h) $(gdbcore_h) $(inferior_h) $(defs_h) \
|
||||
$(gdbcore_h)
|
||||
|
||||
|
|
5
gdb/NEWS
5
gdb/NEWS
|
@ -9,6 +9,10 @@ On SVR4 native platforms (such as Solaris), if you attach to a process
|
|||
without first loading a symbol file, GDB will now attempt to locate and
|
||||
load symbols from the running process's executable file.
|
||||
|
||||
* New native configurations
|
||||
|
||||
ARM GNU/Linux arm*-*-linux*
|
||||
|
||||
* New targets
|
||||
|
||||
Motorola MCore mcore-*-*
|
||||
|
@ -21,6 +25,7 @@ TI TMS320C80 tic80-*-*
|
|||
Altos 3068 m68*-altos-*
|
||||
Convex c1-*-*, c2-*-*
|
||||
Pyramid pyramid-*-*
|
||||
ARM RISCix arm-*-* (as host)
|
||||
Tahoe tahoe-*-*
|
||||
|
||||
* Remote targets can connect to a sub-program
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
.text
|
||||
.global _convert_from_extended
|
||||
|
||||
_convert_from_extended:
|
||||
|
||||
ldfe f0,[a1]
|
||||
stfd f0,[a2]
|
||||
movs pc,lr
|
||||
|
||||
.global _convert_to_extended
|
||||
|
||||
_convert_to_extended:
|
||||
|
||||
ldfd f0,[a1]
|
||||
stfe f0,[a2]
|
||||
movs pc,lr
|
||||
/* OBSOLETE .text */
|
||||
/* OBSOLETE .global _convert_from_extended */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE _convert_from_extended: */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE ldfe f0,[a1] */
|
||||
/* OBSOLETE stfd f0,[a2] */
|
||||
/* OBSOLETE movs pc,lr */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE .global _convert_to_extended */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE _convert_to_extended: */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE ldfd f0,[a1] */
|
||||
/* OBSOLETE stfe f0,[a2] */
|
||||
/* OBSOLETE movs pc,lr */
|
||||
|
|
547
gdb/arm-linux-nat.c
Normal file
547
gdb/arm-linux-nat.c
Normal file
|
@ -0,0 +1,547 @@
|
|||
/* GNU/Linux on ARM native support.
|
||||
Copyright 1999 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 "inferior.h"
|
||||
#include "gdbcore.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#include <sys/user.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
extern int arm_apcs_32;
|
||||
|
||||
#define typeNone 0x00
|
||||
#define typeSingle 0x01
|
||||
#define typeDouble 0x02
|
||||
#define typeExtended 0x03
|
||||
#define FPWORDS 28
|
||||
#define CPSR_REGNUM 16
|
||||
|
||||
typedef union tagFPREG
|
||||
{
|
||||
unsigned int fSingle;
|
||||
unsigned int fDouble[2];
|
||||
unsigned int fExtended[3];
|
||||
}
|
||||
FPREG;
|
||||
|
||||
typedef struct tagFPA11
|
||||
{
|
||||
FPREG fpreg[8]; /* 8 floating point registers */
|
||||
unsigned int fpsr; /* floating point status register */
|
||||
unsigned int fpcr; /* floating point control register */
|
||||
unsigned char fType[8]; /* type of floating point value held in
|
||||
floating point registers. */
|
||||
int initflag; /* NWFPE initialization flag. */
|
||||
}
|
||||
FPA11;
|
||||
|
||||
/* The following variables are used to determine the version of the
|
||||
underlying Linux operating system. Examples:
|
||||
|
||||
Linux 2.0.35 Linux 2.2.12
|
||||
os_version = 0x00020023 os_version = 0x0002020c
|
||||
os_major = 2 os_major = 2
|
||||
os_minor = 0 os_minor = 2
|
||||
os_release = 35 os_release = 12
|
||||
|
||||
Note: os_version = (os_major << 16) | (os_minor << 8) | os_release
|
||||
|
||||
These are initialized using get_linux_version() from
|
||||
_initialize_arm_linux_nat(). */
|
||||
|
||||
static unsigned int os_version, os_major, os_minor, os_release;
|
||||
|
||||
static void
|
||||
fetch_nw_fpe_single (unsigned int fn, FPA11 * fpa11, unsigned int *pmem)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fSingle;
|
||||
mem[1] = 0;
|
||||
mem[2] = 0;
|
||||
supply_register (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nw_fpe_double (unsigned int fn, FPA11 * fpa11, unsigned int *pmem)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fDouble[1];
|
||||
mem[1] = fpa11->fpreg[fn].fDouble[0];
|
||||
mem[2] = 0;
|
||||
supply_register (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nw_fpe_none (unsigned int fn, FPA11 * fpa11, unsigned int *pmem)
|
||||
{
|
||||
unsigned int mem[3] =
|
||||
{0, 0, 0};
|
||||
|
||||
supply_register (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
fetch_nw_fpe_extended (unsigned int fn, FPA11 * fpa11, unsigned int *pmem)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
mem[0] = fpa11->fpreg[fn].fExtended[0]; /* sign & exponent */
|
||||
mem[1] = fpa11->fpreg[fn].fExtended[2]; /* ls bits */
|
||||
mem[2] = fpa11->fpreg[fn].fExtended[1]; /* ms bits */
|
||||
supply_register (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
}
|
||||
|
||||
static void
|
||||
store_nw_fpe_single (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fSingle = mem[0];
|
||||
fpa11->fType[fn] = typeSingle;
|
||||
}
|
||||
|
||||
static void
|
||||
store_nw_fpe_double (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fDouble[1] = mem[0];
|
||||
fpa11->fpreg[fn].fDouble[0] = mem[1];
|
||||
fpa11->fType[fn] = typeDouble;
|
||||
}
|
||||
|
||||
void
|
||||
store_nw_fpe_extended (unsigned int fn, FPA11 * fpa11)
|
||||
{
|
||||
unsigned int mem[3];
|
||||
|
||||
read_register_gen (F0_REGNUM + fn, (char *) &mem[0]);
|
||||
fpa11->fpreg[fn].fExtended[0] = mem[0]; /* sign & exponent */
|
||||
fpa11->fpreg[fn].fExtended[2] = mem[1]; /* ls bits */
|
||||
fpa11->fpreg[fn].fExtended[1] = mem[2]; /* ms bits */
|
||||
fpa11->fType[fn] = typeDouble;
|
||||
}
|
||||
|
||||
/* Get the whole floating point state of the process and store the
|
||||
floating point stack into registers[]. */
|
||||
|
||||
static void
|
||||
fetch_fpregs (void)
|
||||
{
|
||||
int ret, regno;
|
||||
FPA11 fp;
|
||||
|
||||
/* Read the floating point state. */
|
||||
ret = ptrace (PT_GETFPREGS, inferior_pid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Unable to fetch the floating point state.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fetch fpsr. */
|
||||
supply_register (FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Fetch the floating point registers. */
|
||||
for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
|
||||
{
|
||||
int fn = regno - F0_REGNUM;
|
||||
unsigned int *p = (unsigned int *) ®isters[REGISTER_BYTE (regno)];
|
||||
|
||||
switch (fp.fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
fetch_nw_fpe_single (fn, &fp, p);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
fetch_nw_fpe_double (fn, &fp, p);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
fetch_nw_fpe_extended (fn, &fp, p);
|
||||
break;
|
||||
|
||||
default:
|
||||
fetch_nw_fpe_none (fn, &fp, p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Save the whole floating point state of the process using
|
||||
the contents from registers[]. */
|
||||
|
||||
static void
|
||||
store_fpregs (void)
|
||||
{
|
||||
int ret, regno;
|
||||
unsigned int mem[3];
|
||||
FPA11 fp;
|
||||
|
||||
/* Store fpsr. */
|
||||
if (register_valid[FPS_REGNUM])
|
||||
read_register_gen (FPS_REGNUM, (char *) &fp.fpsr);
|
||||
|
||||
/* Store the floating point registers. */
|
||||
for (regno = F0_REGNUM; regno <= F7_REGNUM; regno++)
|
||||
{
|
||||
if (register_valid[regno])
|
||||
{
|
||||
unsigned int fn = regno - F0_REGNUM;
|
||||
switch (fp.fType[fn])
|
||||
{
|
||||
case typeSingle:
|
||||
store_nw_fpe_single (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeDouble:
|
||||
store_nw_fpe_double (fn, &fp);
|
||||
break;
|
||||
|
||||
case typeExtended:
|
||||
store_nw_fpe_extended (fn, &fp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, &fp);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Unable to store floating point state.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch all general registers of the process and store into
|
||||
registers[]. */
|
||||
|
||||
static void
|
||||
fetch_regs (void)
|
||||
{
|
||||
int ret, regno;
|
||||
struct pt_regs regs;
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Unable to fetch general registers.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = A1_REGNUM; regno < PC_REGNUM; regno++)
|
||||
supply_register (regno, (char *) ®s.uregs[regno]);
|
||||
|
||||
if (arm_apcs_32)
|
||||
supply_register (PS_REGNUM, (char *) ®s.uregs[CPSR_REGNUM]);
|
||||
else
|
||||
supply_register (PS_REGNUM, (char *) ®s.uregs[PC_REGNUM]);
|
||||
|
||||
regs.uregs[PC_REGNUM] = ADDR_BITS_REMOVE (regs.uregs[PC_REGNUM]);
|
||||
supply_register (PC_REGNUM, (char *) ®s.uregs[PC_REGNUM]);
|
||||
}
|
||||
|
||||
/* Store all general registers of the process from the values in
|
||||
registers[]. */
|
||||
|
||||
static void
|
||||
store_regs (void)
|
||||
{
|
||||
int ret, regno;
|
||||
struct pt_regs regs;
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, ®s);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Unable to fetch general registers.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (regno = A1_REGNUM; regno <= PC_REGNUM; regno++)
|
||||
{
|
||||
if (register_valid[regno])
|
||||
read_register_gen (regno, (char *) ®s.uregs[regno]);
|
||||
}
|
||||
|
||||
ret = ptrace (PTRACE_SETREGS, inferior_pid, 0, ®s);
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Unable to store general registers.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fetch registers from the child process. Fetch all registers if
|
||||
regno == -1, otherwise fetch all general registers or all floating
|
||||
point registers depending upon the value of regno. */
|
||||
|
||||
void
|
||||
fetch_inferior_registers (int regno)
|
||||
{
|
||||
if ((regno < F0_REGNUM) || (regno > FPS_REGNUM))
|
||||
fetch_regs ();
|
||||
|
||||
if (((regno >= F0_REGNUM) && (regno <= FPS_REGNUM)) || (regno == -1))
|
||||
fetch_fpregs ();
|
||||
}
|
||||
|
||||
/* Store registers back into the inferior. Store all registers if
|
||||
regno == -1, otherwise store all general registers or all floating
|
||||
point registers depending upon the value of regno. */
|
||||
|
||||
void
|
||||
store_inferior_registers (int regno)
|
||||
{
|
||||
if ((regno < F0_REGNUM) || (regno > FPS_REGNUM))
|
||||
store_regs ();
|
||||
|
||||
if (((regno >= F0_REGNUM) && (regno <= FPS_REGNUM)) || (regno == -1))
|
||||
store_fpregs ();
|
||||
}
|
||||
|
||||
#ifdef GET_LONGJMP_TARGET
|
||||
|
||||
/* Figure out where the longjmp will land. We expect that we have
|
||||
just entered longjmp and haven't yet altered r0, r1, so the
|
||||
arguments are still in the registers. (A1_REGNUM) points at the
|
||||
jmp_buf structure from which we extract the pc (JB_PC) that we will
|
||||
land at. The pc is copied into ADDR. This routine returns true on
|
||||
success. */
|
||||
|
||||
#define LONGJMP_TARGET_SIZE sizeof(int)
|
||||
#define JB_ELEMENT_SIZE sizeof(int)
|
||||
#define JB_SL 18
|
||||
#define JB_FP 19
|
||||
#define JB_SP 20
|
||||
#define JB_PC 21
|
||||
|
||||
int
|
||||
arm_get_longjmp_target (CORE_ADDR * pc)
|
||||
{
|
||||
CORE_ADDR jb_addr;
|
||||
char buf[LONGJMP_TARGET_SIZE];
|
||||
|
||||
jb_addr = read_register (A1_REGNUM);
|
||||
|
||||
if (target_read_memory (jb_addr + JB_PC * JB_ELEMENT_SIZE, buf,
|
||||
LONGJMP_TARGET_SIZE))
|
||||
return 0;
|
||||
|
||||
*pc = extract_address (buf, LONGJMP_TARGET_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* GET_LONGJMP_TARGET */
|
||||
|
||||
/*
|
||||
Dynamic Linking on ARM Linux
|
||||
----------------------------
|
||||
|
||||
Note: PLT = procedure linkage table
|
||||
GOT = global offset table
|
||||
|
||||
As much as possible, ELF dynamic linking defers the resolution of
|
||||
jump/call addresses until the last minute. The technique used is
|
||||
inspired by the i386 ELF design, and is based on the following
|
||||
constraints.
|
||||
|
||||
1) The calling technique should not force a change in the assembly
|
||||
code produced for apps; it MAY cause changes in the way assembly
|
||||
code is produced for position independent code (i.e. shared
|
||||
libraries).
|
||||
|
||||
2) The technique must be such that all executable areas must not be
|
||||
modified; and any modified areas must not be executed.
|
||||
|
||||
To do this, there are three steps involved in a typical jump:
|
||||
|
||||
1) in the code
|
||||
2) through the PLT
|
||||
3) using a pointer from the GOT
|
||||
|
||||
When the executable or library is first loaded, each GOT entry is
|
||||
initialized to point to the code which implements dynamic name
|
||||
resolution and code finding. This is normally a function in the
|
||||
program interpreter (on ARM Linux this is usually ld-linux.so.2,
|
||||
but it does not have to be). On the first invocation, the function
|
||||
is located and the GOT entry is replaced with the real function
|
||||
address. Subsequent calls go through steps 1, 2 and 3 and end up
|
||||
calling the real code.
|
||||
|
||||
1) In the code:
|
||||
|
||||
b function_call
|
||||
bl function_call
|
||||
|
||||
This is typical ARM code using the 26 bit relative branch or branch
|
||||
and link instructions. The target of the instruction
|
||||
(function_call is usually the address of the function to be called.
|
||||
In position independent code, the target of the instruction is
|
||||
actually an entry in the PLT when calling functions in a shared
|
||||
library. Note that this call is identical to a normal function
|
||||
call, only the target differs.
|
||||
|
||||
2) In the PLT:
|
||||
|
||||
The PLT is a synthetic area, created by the linker. It exists in
|
||||
both executables and libraries. It is an array of stubs, one per
|
||||
imported function call. It looks like this:
|
||||
|
||||
PLT[0]:
|
||||
str lr, [sp, #-4]! @push the return address (lr)
|
||||
ldr lr, [pc, #16] @load from 6 words ahead
|
||||
add lr, pc, lr @form an address for GOT[0]
|
||||
ldr pc, [lr, #8]! @jump to the contents of that addr
|
||||
|
||||
The return address (lr) is pushed on the stack and used for
|
||||
calculations. The load on the second line loads the lr with
|
||||
&GOT[3] - . - 20. The addition on the third leaves:
|
||||
|
||||
lr = (&GOT[3] - . - 20) + (. + 8)
|
||||
lr = (&GOT[3] - 12)
|
||||
lr = &GOT[0]
|
||||
|
||||
On the fourth line, the pc and lr are both updated, so that:
|
||||
|
||||
pc = GOT[2]
|
||||
lr = &GOT[0] + 8
|
||||
= &GOT[2]
|
||||
|
||||
NOTE: PLT[0] borrows an offset .word from PLT[1]. This is a little
|
||||
"tight", but allows us to keep all the PLT entries the same size.
|
||||
|
||||
PLT[n+1]:
|
||||
ldr ip, [pc, #4] @load offset from gotoff
|
||||
add ip, pc, ip @add the offset to the pc
|
||||
ldr pc, [ip] @jump to that address
|
||||
gotoff: .word GOT[n+3] - .
|
||||
|
||||
The load on the first line, gets an offset from the fourth word of
|
||||
the PLT entry. The add on the second line makes ip = &GOT[n+3],
|
||||
which contains either a pointer to PLT[0] (the fixup trampoline) or
|
||||
a pointer to the actual code.
|
||||
|
||||
3) In the GOT:
|
||||
|
||||
The GOT contains helper pointers for both code (PLT) fixups and
|
||||
data fixups. The first 3 entries of the GOT are special. The next
|
||||
M entries (where M is the number of entries in the PLT) belong to
|
||||
the PLT fixups. The next D (all remaining) entries belong to
|
||||
various data fixups. The actual size of the GOT is 3 + M + D.
|
||||
|
||||
The GOT is also a synthetic area, created by the linker. It exists
|
||||
in both executables and libraries. When the GOT is first
|
||||
initialized , all the GOT entries relating to PLT fixups are
|
||||
pointing to code back at PLT[0].
|
||||
|
||||
The special entries in the GOT are:
|
||||
|
||||
GOT[0] = linked list pointer used by the dynamic loader
|
||||
GOT[1] = pointer to the reloc table for this module
|
||||
GOT[2] = pointer to the fixup/resolver code
|
||||
|
||||
The first invocation of function call comes through and uses the
|
||||
fixup/resolver code. On the entry to the fixup/resolver code:
|
||||
|
||||
ip = &GOT[n+3]
|
||||
lr = &GOT[2]
|
||||
stack[0] = return address (lr) of the function call
|
||||
[r0, r1, r2, r3] are still the arguments to the function call
|
||||
|
||||
This is enough information for the fixup/resolver code to work
|
||||
with. Before the fixup/resolver code returns, it actually calls
|
||||
the requested function and repairs &GOT[n+3]. */
|
||||
|
||||
CORE_ADDR
|
||||
arm_skip_solib_resolver (CORE_ADDR pc)
|
||||
{
|
||||
/* FIXME */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
arm_linux_register_u_addr (int blockend, int regnum)
|
||||
{
|
||||
return blockend + REGISTER_BYTE (regnum);
|
||||
}
|
||||
|
||||
int
|
||||
arm_linux_kernel_u_size (void)
|
||||
{
|
||||
return (sizeof (struct user));
|
||||
}
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
|
||||
void
|
||||
arm_linux_extract_return_value (struct type *type,
|
||||
char regbuf[REGISTER_BYTES],
|
||||
char *valbuf)
|
||||
{
|
||||
/* ScottB: This needs to be looked at to handle the different
|
||||
floating point emulators on ARM Linux. Right now the code
|
||||
assumes that fetch inferior registers does the right thing for
|
||||
GDB. I suspect this won't handle NWFPE registers correctly, nor
|
||||
will the default ARM version (arm_extract_return_value()). */
|
||||
|
||||
int regnum = (TYPE_CODE_FLT == TYPE_CODE (type)) ? F0_REGNUM : A1_REGNUM;
|
||||
memcpy (valbuf, ®buf[REGISTER_BYTE (regnum)], TYPE_LENGTH (type));
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_linux_version (unsigned int *vmajor,
|
||||
unsigned int *vminor,
|
||||
unsigned int *vrelease)
|
||||
{
|
||||
struct utsname info;
|
||||
char *pmajor, *pminor, *prelease, *tail;
|
||||
|
||||
if (-1 == uname (&info))
|
||||
{
|
||||
warning ("Unable to determine Linux version.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pmajor = strtok (info.release, ".");
|
||||
pminor = strtok (NULL, ".");
|
||||
prelease = strtok (NULL, ".");
|
||||
|
||||
*vmajor = (unsigned int) strtoul (pmajor, &tail, 0);
|
||||
*vminor = (unsigned int) strtoul (pminor, &tail, 0);
|
||||
*vrelease = (unsigned int) strtoul (prelease, &tail, 0);
|
||||
|
||||
return ((*vmajor << 16) | (*vminor << 8) | *vrelease);
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_arm_linux_nat (void)
|
||||
{
|
||||
os_version = get_linux_version (&os_major, &os_minor, &os_release);
|
||||
}
|
952
gdb/arm-tdep.c
952
gdb/arm-tdep.c
File diff suppressed because it is too large
Load diff
1150
gdb/arm-xdep.c
1150
gdb/arm-xdep.c
File diff suppressed because it is too large
Load diff
|
@ -1229,19 +1229,18 @@ generic_save_dummy_frame_tos (sp)
|
|||
dummy_frame_stack->top = sp;
|
||||
}
|
||||
|
||||
/* Function: pop_frame
|
||||
Restore the machine state from either the saved dummy stack or a
|
||||
/* Restore the machine state from either the saved dummy stack or a
|
||||
real stack frame. */
|
||||
|
||||
void
|
||||
generic_pop_current_frame (pop)
|
||||
void (*pop) (struct frame_info * frame);
|
||||
generic_pop_current_frame (void (*popper) (struct frame_info * frame))
|
||||
{
|
||||
struct frame_info *frame = get_current_frame ();
|
||||
|
||||
if (PC_IN_CALL_DUMMY (frame->pc, frame->frame, frame->frame))
|
||||
generic_pop_dummy_frame ();
|
||||
else
|
||||
pop (frame);
|
||||
(*popper) (frame);
|
||||
}
|
||||
|
||||
/* Function: pop_dummy_frame
|
||||
|
|
|
@ -2528,9 +2528,8 @@ bpstat_stop_status (pc, not_a_breakpoint)
|
|||
real_breakpoint = 1;
|
||||
}
|
||||
|
||||
if (b->frame && b->frame != (get_current_frame ())->frame &&
|
||||
(b->type == bp_step_resume &&
|
||||
(INNER_THAN (get_current_frame ()->frame, b->frame))))
|
||||
if (b->frame &&
|
||||
b->frame != (get_current_frame ())->frame)
|
||||
bs->stop = 0;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -285,6 +285,15 @@
|
|||
/* Define if you have the <wait.h> header file. */
|
||||
#undef HAVE_WAIT_H
|
||||
|
||||
/* Define if you have the <thread_db.h> header file. */
|
||||
#undef HAVE_THREAD_DB_H
|
||||
|
||||
/* Define if you have the <proc_service.h> header file. */
|
||||
#undef HAVE_PROC_SERVICE_H
|
||||
|
||||
/* Define if you have the <stdint.h> header file. */
|
||||
#undef HAVE_STDINT_H
|
||||
|
||||
/* Define if you have the <wchar.h> header file. */
|
||||
#undef HAVE_WCHAR_H
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@ XDEPFILES= ser-tcp.o
|
|||
XM_FILE= xm-alphalinux.h
|
||||
NAT_FILE= nm-linux.h
|
||||
NATDEPFILES= infptrace.o inftarg.o corelow.o core-regset.o alpha-nat.o \
|
||||
fork-child.o solib.o linux-thread.o
|
||||
fork-child.o solib.o linux-thread.o lin-thread.o
|
||||
|
||||
LOADLIBES = -ldl -rdynamic
|
||||
|
||||
MMALLOC =
|
||||
MMALLOC_CFLAGS = -DNO_MMALLOC
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef NM_LINUX_H
|
||||
#define NM_LINUX_H
|
||||
|
||||
#include "nm-linux.h"
|
||||
|
||||
/* Figure out where the longjmp will land. We expect that we have just entered
|
||||
|
@ -64,3 +67,4 @@ get_longjmp_target PARAMS ((CORE_ADDR *));
|
|||
pointer to the first register. */
|
||||
#define ALPHA_REGSET_BASE(regsetp) ((long *) (regsetp))
|
||||
|
||||
#endif /* NM_LINUX_H */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# Host: Acorn RISC machine running RISCiX (4.3bsd)
|
||||
XDEPFILES= infptrace.o inftarg.o fork-child.o arm-xdep.o arm-convert.o
|
||||
XM_FILE= xm-arm.h
|
||||
|
||||
NAT_FILE= nm-arm.h
|
||||
# OBSOLETE # Host: Acorn RISC machine running RISCiX (4.3bsd)
|
||||
# OBSOLETE XDEPFILES= infptrace.o inftarg.o fork-child.o arm-xdep.o arm-convert.o
|
||||
# OBSOLETE
|
||||
# OBSOLETE XM_FILE= xm-arm.h
|
||||
# OBSOLETE
|
||||
# OBSOLETE NAT_FILE= nm-arm.h
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Target: Acorn RISC machine (ARM) with simulator
|
||||
TDEPFILES= arm-tdep.o remote-rdp.o remote-rdi.o
|
||||
TDEPLIBS= rdi-share/libangsd.a
|
||||
TM_FILE= tm-arm.h
|
||||
|
||||
SIM_OBS = remote-sim.o
|
||||
SIM = ../sim/arm/libsim.a
|
||||
# OBSOLETE # Target: Acorn RISC machine (ARM) with simulator
|
||||
# OBSOLETE TDEPFILES= arm-tdep.o remote-rdp.o remote-rdi.oT
|
||||
# OBSOLETE DEPLIBS= rdi-share/libangsd.a
|
||||
# OBSOLETE TM_FILE= tm-arm.h
|
||||
# OBSOLETE
|
||||
# OBSOLETE SIM_OBS = remote-sim.o
|
||||
# OBSOLETE SIM = ../sim/arm/libsim.a
|
||||
|
|
7
gdb/config/arm/embed.mt
Normal file
7
gdb/config/arm/embed.mt
Normal file
|
@ -0,0 +1,7 @@
|
|||
# Target: ARM embedded system
|
||||
TDEPFILES= arm-tdep.o remote-rdp.o remote-rdi.o
|
||||
TDEPLIBS= rdi-share/libangsd.a
|
||||
TM_FILE= tm-embed.h
|
||||
|
||||
SIM_OBS = remote-sim.o
|
||||
SIM = ../sim/arm/libsim.a
|
8
gdb/config/arm/linux.mh
Normal file
8
gdb/config/arm/linux.mh
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Host: ARM based machine running GNU/Linux
|
||||
|
||||
XM_FILE= xm-linux.h
|
||||
XDEPFILES= ser-tcp.o
|
||||
|
||||
NAT_FILE= nm-linux.h
|
||||
NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \
|
||||
core-aout.o core-regset.o arm-linux-nat.o
|
5
gdb/config/arm/linux.mt
Normal file
5
gdb/config/arm/linux.mt
Normal file
|
@ -0,0 +1,5 @@
|
|||
# Target: ARM based machine running GNU/Linux
|
||||
TM_FILE= tm-linux.h
|
||||
TDEPFILES= arm-tdep.o
|
||||
|
||||
GDBSERVER_DEPFILES= low-linux.o
|
|
@ -1,28 +1,28 @@
|
|||
/* Definitions to make GDB run on an ARM under RISCiX (4.3bsd).
|
||||
Copyright (C) 1986, 1987, 1989 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. */
|
||||
|
||||
/* 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 (0x01000000 - (UPAGES * NBPG))
|
||||
|
||||
/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
#define HOST_BYTE_ORDER LITTLE_ENDIAN
|
||||
/* OBSOLETE /* Definitions to make GDB run on an ARM under RISCiX (4.3bsd). */
|
||||
/* OBSOLETE Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This file is part of GDB. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This program is free software; you can redistribute it and/or modify */
|
||||
/* OBSOLETE it under the terms of the GNU General Public License as published by */
|
||||
/* OBSOLETE the Free Software Foundation; either version 2 of the License, or */
|
||||
/* OBSOLETE (at your option) any later version. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This program is distributed in the hope that it will be useful, */
|
||||
/* OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* OBSOLETE GNU General Public License for more details. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE You should have received a copy of the GNU General Public License */
|
||||
/* OBSOLETE along with this program; if not, write to the Free Software */
|
||||
/* OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330, */
|
||||
/* OBSOLETE Boston, MA 02111-1307, USA. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* This is the amount to subtract from u.u_ar0 */
|
||||
/* OBSOLETE to get the offset in the core file of the register values. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define KERNEL_U_ADDR (0x01000000 - (UPAGES * NBPG)) */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Override copies of {fetch,store}_inferior_registers in infptrace.c. *x/ */
|
||||
/* OBSOLETE #define FETCH_INFERIOR_REGISTERS */
|
||||
/* OBSOLETE #define HOST_BYTE_ORDER LITTLE_ENDIAN */
|
||||
|
|
46
gdb/config/arm/nm-linux.h
Normal file
46
gdb/config/arm/nm-linux.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* Definitions to make GDB run on an ARM based machine under GNU/Linux.
|
||||
Copyright 1999 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 NM_ARMLINUX_H
|
||||
#define NM_ARMLINUX_H
|
||||
|
||||
/* Return sizeof user struct to callers in less machine dependent routines */
|
||||
extern int kernel_u_size (void);
|
||||
#define KERNEL_U_SIZE arm_linux_kernel_u_size()
|
||||
|
||||
/* Override copies of {fetch,store}_inferior_registers in infptrace.c. */
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
|
||||
/* Tell gdb that we can attach and detach other processes. */
|
||||
#define ATTACH_DETACH
|
||||
|
||||
extern int arm_register_u_addr (int, int);
|
||||
#define REGISTER_U_ADDR(addr, blockend, regno) \
|
||||
{ (addr) = arm_linux_register_u_addr((blockend), (regno)); }
|
||||
|
||||
/* We define this if link.h is available, because with ELF we use SVR4 style
|
||||
shared libraries. */
|
||||
|
||||
#ifdef HAVE_LINK_H
|
||||
#define SVR4_SHARED_LIBS
|
||||
#include "solib.h" /* Support for shared libraries. */
|
||||
#endif
|
||||
|
||||
#endif /* NM_ARMLINUX_H */
|
|
@ -1,4 +1,4 @@
|
|||
/* Definitions to make GDB target for an ARM
|
||||
/* Definitions to target GDB to ARM targets.
|
||||
Copyright 1986-1989, 1991, 1993-1999 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GDB.
|
||||
|
@ -18,120 +18,168 @@
|
|||
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Forward decls for prototypes */
|
||||
#ifndef TM_ARM_H
|
||||
#define TM_ARM_H
|
||||
|
||||
/* Forward declarations for prototypes. */
|
||||
struct type;
|
||||
struct value;
|
||||
|
||||
#define TARGET_BYTE_ORDER_SELECTABLE
|
||||
|
||||
/* IEEE format floating point */
|
||||
/* Target byte order on ARM defaults to selectable, and defaults to
|
||||
little endian. */
|
||||
#define TARGET_BYTE_ORDER_SELECTABLE_P 1
|
||||
#define TARGET_BYTE_ORDER_DEFAULT LITTLE_ENDIAN
|
||||
|
||||
/* IEEE format floating point. */
|
||||
#define IEEE_FLOAT
|
||||
#define TARGET_DOUBLE_FORMAT (target_byte_order == BIG_ENDIAN \
|
||||
? &floatformat_ieee_double_big \
|
||||
: &floatformat_ieee_double_littlebyte_bigword)
|
||||
|
||||
/* FIXME: may need a floatformat_ieee_double_bigbyte_littleword format for
|
||||
BIG_ENDIAN use. -fnf */
|
||||
|
||||
#define TARGET_DOUBLE_FORMAT (target_byte_order == BIG_ENDIAN \
|
||||
? &floatformat_ieee_double_big \
|
||||
: &floatformat_ieee_double_littlebyte_bigword)
|
||||
|
||||
/* When reading symbols, we need to zap the low bit of the address, which
|
||||
may be set to 1 for Thumb functions. */
|
||||
/* When reading symbols, we need to zap the low bit of the address,
|
||||
which may be set to 1 for Thumb functions. */
|
||||
|
||||
#define SMASH_TEXT_ADDRESS(addr) ((addr) &= ~0x1)
|
||||
|
||||
/* Remove useless bits from addresses in a running program. */
|
||||
|
||||
CORE_ADDR arm_addr_bits_remove PARAMS ((CORE_ADDR));
|
||||
CORE_ADDR arm_addr_bits_remove (CORE_ADDR);
|
||||
|
||||
#define ADDR_BITS_REMOVE(val) (arm_addr_bits_remove (val))
|
||||
#define ADDR_BITS_REMOVE(val) (arm_addr_bits_remove (val))
|
||||
|
||||
/* Offset from address of function to start of its code.
|
||||
Zero on most machines. */
|
||||
/* Offset from address of function to start of its code. Zero on most
|
||||
machines. */
|
||||
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
#define FUNCTION_START_OFFSET 0
|
||||
|
||||
/* Advance PC across any function entry prologue instructions
|
||||
to reach some "real" code. */
|
||||
/* Advance PC across any function entry prologue instructions to reach
|
||||
some "real" code. */
|
||||
|
||||
extern CORE_ADDR arm_skip_prologue PARAMS ((CORE_ADDR pc));
|
||||
extern CORE_ADDR arm_skip_prologue (CORE_ADDR pc);
|
||||
|
||||
#define SKIP_PROLOGUE(pc) (arm_skip_prologue (pc))
|
||||
#define SKIP_PROLOGUE(pc) (arm_skip_prologue (pc))
|
||||
|
||||
/* Immediately after a function call, return the saved pc.
|
||||
Can't always go through the frames for this because on some machines
|
||||
the new frame is not set up until the new function executes
|
||||
some instructions. */
|
||||
/* Immediately after a function call, return the saved pc. Can't
|
||||
always go through the frames for this because on some machines the
|
||||
new frame is not set up until the new function executes some
|
||||
instructions. */
|
||||
|
||||
#define SAVED_PC_AFTER_CALL(frame) arm_saved_pc_after_call (frame)
|
||||
#define SAVED_PC_AFTER_CALL(frame) arm_saved_pc_after_call (frame)
|
||||
struct frame_info;
|
||||
extern CORE_ADDR arm_saved_pc_after_call PARAMS ((struct frame_info *));
|
||||
extern CORE_ADDR arm_saved_pc_after_call (struct frame_info *);
|
||||
|
||||
/* I don't know the real values for these. */
|
||||
#define TARGET_UPAGES UPAGES
|
||||
#define TARGET_NBPG NBPG
|
||||
/* The following define instruction sequences that will cause ARM
|
||||
cpu's to take an undefined instruction trap. These are used to
|
||||
signal a breakpoint to GDB.
|
||||
|
||||
/* Address of end of stack space. */
|
||||
The newer ARMv4T cpu's are capable of operating in ARM or Thumb
|
||||
modes. A different instruction is required for each mode. The ARM
|
||||
cpu's can also be big or little endian. Thus four different
|
||||
instructions are needed to support all cases.
|
||||
|
||||
#define STACK_END_ADDR (0x01000000 - (TARGET_UPAGES * TARGET_NBPG))
|
||||
Note: ARMv4 defines several new instructions that will take the
|
||||
undefined instruction trap. ARM7TDMI is nominally ARMv4T, but does
|
||||
not in fact add the new instructions. The new undefined
|
||||
instructions in ARMv4 are all instructions that had no defined
|
||||
behaviour in earlier chips. There is no guarantee that they will
|
||||
raise an exception, but may be treated as NOP's. In practice, it
|
||||
may only safe to rely on instructions matching:
|
||||
|
||||
3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
|
||||
1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
C C C C 0 1 1 x x x x x x x x x x x x x x x x x x x x 1 x x x x
|
||||
|
||||
Even this may only true if the condition predicate is true. The
|
||||
following use a condition predicate of ALWAYS so it is always TRUE.
|
||||
|
||||
There are other ways of forcing a breakpoint. ARM Linux, RisciX,
|
||||
and I suspect NetBSD will all use a software interrupt rather than
|
||||
an undefined instruction to force a trap. This can be handled by
|
||||
redefining some or all of the following in a target dependent
|
||||
fashion. */
|
||||
|
||||
#define ARM_LE_BREAKPOINT {0xFE,0xDE,0xFF,0xE7}
|
||||
#define ARM_BE_BREAKPOINT {0xE7,0xFF,0xDE,0xFE}
|
||||
#define THUMB_LE_BREAKPOINT {0xfe,0xdf}
|
||||
#define THUMB_BE_BREAKPOINT {0xdf,0xfe}
|
||||
|
||||
/* Stack grows downward. */
|
||||
|
||||
#define INNER_THAN(lhs,rhs) ((lhs) < (rhs))
|
||||
|
||||
/* !!!! if we're using RDP, then we're inserting breakpoints and storing
|
||||
their handles instread of what was in memory. It is nice that
|
||||
this is the same size as a handle - otherwise remote-rdp will
|
||||
/* !!!! if we're using RDP, then we're inserting breakpoints and
|
||||
storing their handles instread of what was in memory. It is nice
|
||||
that this is the same size as a handle - otherwise remote-rdp will
|
||||
have to change. */
|
||||
|
||||
/* BREAKPOINT_FROM_PC uses the program counter value to determine whether a
|
||||
16- or 32-bit breakpoint should be used. It returns a pointer
|
||||
to a string of bytes that encode a breakpoint instruction, stores
|
||||
the length of the string to *lenptr, and adjusts the pc (if necessary) to
|
||||
point to the actual memory location where the breakpoint should be
|
||||
inserted. */
|
||||
/* BREAKPOINT_FROM_PC uses the program counter value to determine
|
||||
whether a 16- or 32-bit breakpoint should be used. It returns a
|
||||
pointer to a string of bytes that encode a breakpoint instruction,
|
||||
stores the length of the string to *lenptr, and adjusts the pc (if
|
||||
necessary) to point to the actual memory location where the
|
||||
breakpoint should be inserted. */
|
||||
|
||||
extern breakpoint_from_pc_fn arm_breakpoint_from_pc;
|
||||
#define BREAKPOINT_FROM_PC(pcptr, lenptr) arm_breakpoint_from_pc (pcptr, lenptr)
|
||||
|
||||
/* Amount PC must be decremented by after a breakpoint.
|
||||
This is often the number of bytes in BREAKPOINT
|
||||
but not always. */
|
||||
/* Amount PC must be decremented by after a breakpoint. This is often
|
||||
the number of bytes in BREAKPOINT but not always. */
|
||||
|
||||
#define DECR_PC_AFTER_BREAK 0
|
||||
|
||||
/* code to execute to print interesting information about the
|
||||
* floating point processor (if any)
|
||||
* No need to define if there is nothing to do.
|
||||
*/
|
||||
/* Code to execute to print interesting information about the floating
|
||||
point processor (if any) or emulator. No need to define if there
|
||||
is nothing to do. */
|
||||
extern void arm_float_info (void);
|
||||
|
||||
#define FLOAT_INFO { arm_float_info (); }
|
||||
#define FLOAT_INFO { arm_float_info (); }
|
||||
|
||||
/* Say how long (ordinary) registers are. This is a piece of bogosity
|
||||
used in push_word and a few other places; REGISTER_RAW_SIZE is the
|
||||
real way to know how big a register is. */
|
||||
|
||||
#define REGISTER_SIZE 4
|
||||
#define REGISTER_SIZE 4
|
||||
|
||||
/* Number of machine registers */
|
||||
/* Say how long FP registers are. Used for documentation purposes and
|
||||
code readability in this header. IEEE extended doubles are 80
|
||||
bits. DWORD aligned they use 96 bits. */
|
||||
#define FP_REGISTER_RAW_SIZE 12
|
||||
|
||||
/* Note: I make a fake copy of the pc in register 25 (calling it ps) so
|
||||
that I can clear the status bits from pc (register 15) */
|
||||
/* GCC doesn't support long doubles (extended IEEE values). The FP
|
||||
register virtual size is therefore 64 bits. Used for documentation
|
||||
purposes and code readability in this header. */
|
||||
#define FP_REGISTER_VIRTUAL_SIZE 8
|
||||
|
||||
#define NUM_REGS 26
|
||||
/* Status registers are the same size as general purpose registers.
|
||||
Used for documentation purposes and code readability in this
|
||||
header. */
|
||||
#define STATUS_REGISTER_SIZE REGISTER_SIZE
|
||||
|
||||
/* Number of machine registers. The only define actually required
|
||||
is NUM_REGS. The other definitions are used for documentation
|
||||
purposes and code readability. */
|
||||
/* For 26 bit ARM code, a fake copy of the PC is placed in register 25 (PS)
|
||||
(and called PS for processor status) so the status bits can be cleared
|
||||
from the PC (register 15). For 32 bit ARM code, a copy of CPSR is placed
|
||||
in PS. */
|
||||
#define NUM_FREGS 8 /* Number of floating point registers. */
|
||||
#define NUM_SREGS 2 /* Number of status registers. */
|
||||
#define NUM_GREGS 16 /* Number of general purpose registers. */
|
||||
#define NUM_REGS (NUM_GREGS + NUM_FREGS + NUM_SREGS)
|
||||
|
||||
/* An array of names of registers. */
|
||||
|
||||
extern char **arm_register_names;
|
||||
|
||||
#define REGISTER_NAME(i) arm_register_names[i]
|
||||
|
||||
/* Register numbers of various important registers.
|
||||
Note that some of these values are "real" register numbers,
|
||||
and correspond to the general registers of the machine,
|
||||
and some are "phony" register numbers which are too large
|
||||
to be actual register numbers as far as the user is concerned
|
||||
but do serve to get the desired values when passed to read_register. */
|
||||
/* Register numbers of various important registers. Note that some of
|
||||
these values are "real" register numbers, and correspond to the
|
||||
general registers of the machine, and some are "phony" register
|
||||
numbers which are too large to be actual register numbers as far as
|
||||
the user is concerned but do serve to get the desired values when
|
||||
passed to read_register. */
|
||||
|
||||
#define A1_REGNUM 0 /* first integer-like argument */
|
||||
#define A4_REGNUM 3 /* last integer-like argument */
|
||||
|
@ -180,88 +228,97 @@ extern char **arm_register_names;
|
|||
|
||||
/* Total amount of space needed to store our copies of the machine's
|
||||
register state, the array `registers'. */
|
||||
#define REGISTER_BYTES (16*4 + 12*8 + 4 + 4)
|
||||
|
||||
#define REGISTER_BYTES ((NUM_GREGS * REGISTER_SIZE) + \
|
||||
(NUM_FREGS * FP_REGISTER_RAW_SIZE) + \
|
||||
(NUM_SREGS * STATUS_REGISTER_SIZE))
|
||||
|
||||
/* Index within `registers' of the first byte of the space for
|
||||
register N. */
|
||||
|
||||
#define REGISTER_BYTE(N) (((N) < F0_REGNUM) ? (N)*4 : \
|
||||
(((N) < PS_REGNUM) ? 16*4 + ((N) - 16)*12 : \
|
||||
16*4 + 8*12 + ((N) - FPS_REGNUM) * 4))
|
||||
#define REGISTER_BYTE(N) \
|
||||
((N) < F0_REGNUM \
|
||||
? (N) * REGISTER_SIZE \
|
||||
: ((N) < PS_REGNUM \
|
||||
? (NUM_GREGS * REGISTER_SIZE + \
|
||||
((N) - F0_REGNUM) * FP_REGISTER_RAW_SIZE) \
|
||||
: (NUM_GREGS * REGISTER_SIZE + \
|
||||
NUM_FREGS * FP_REGISTER_RAW_SIZE + \
|
||||
((N) - FPS_REGNUM) * STATUS_REGISTER_SIZE)))
|
||||
|
||||
/* Number of bytes of storage in the actual machine representation
|
||||
for register N. On the vax, all regs are 4 bytes. */
|
||||
/* Number of bytes of storage in the actual machine representation for
|
||||
register N. All registers are 4 bytes, except fp0 - fp7, which are
|
||||
12 bytes in length. */
|
||||
#define REGISTER_RAW_SIZE(N) \
|
||||
((N) < F0_REGNUM ? REGISTER_SIZE : \
|
||||
(N) < FPS_REGNUM ? FP_REGISTER_RAW_SIZE : STATUS_REGISTER_SIZE)
|
||||
|
||||
#define REGISTER_RAW_SIZE(N) (((N) < F0_REGNUM || (N) >= FPS_REGNUM) ? 4 : 12)
|
||||
|
||||
/* Number of bytes of storage in the program's representation
|
||||
for register N. On the vax, all regs are 4 bytes. */
|
||||
|
||||
#define REGISTER_VIRTUAL_SIZE(N) (((N) < F0_REGNUM || (N) >= FPS_REGNUM) ? 4 : 8)
|
||||
/* Number of bytes of storage in a program's representation
|
||||
for register N. */
|
||||
#define REGISTER_VIRTUAL_SIZE(N) \
|
||||
((N) < F0_REGNUM ? REGISTER_SIZE : \
|
||||
(N) < FPS_REGNUM ? FP_REGISTER_VIRTUAL_SIZE : STATUS_REGISTER_SIZE)
|
||||
|
||||
/* Largest value REGISTER_RAW_SIZE can have. */
|
||||
|
||||
#define MAX_REGISTER_RAW_SIZE 12
|
||||
#define MAX_REGISTER_RAW_SIZE FP_REGISTER_RAW_SIZE
|
||||
|
||||
/* Largest value REGISTER_VIRTUAL_SIZE can have. */
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE FP_REGISTER_VIRTUAL_SIZE
|
||||
|
||||
#define MAX_REGISTER_VIRTUAL_SIZE 8
|
||||
/* Nonzero if register N requires conversion from raw format to
|
||||
virtual format. */
|
||||
extern int arm_register_convertible (unsigned int);
|
||||
#define REGISTER_CONVERTIBLE(REGNUM) (arm_register_convertible (REGNUM))
|
||||
|
||||
/* Nonzero if register N requires conversion
|
||||
from raw format to virtual format. */
|
||||
#define REGISTER_CONVERTIBLE(N) ((unsigned)(N) - F0_REGNUM < 8)
|
||||
|
||||
/* Convert data from raw format for register REGNUM in buffer FROM
|
||||
to virtual format with type TYPE in buffer TO. */
|
||||
|
||||
void convert_from_extended (void *ptr, /*double*/void *dbl);
|
||||
/* Convert data from raw format for register REGNUM in buffer FROM to
|
||||
virtual format with type TYPE in buffer TO. */
|
||||
|
||||
extern void arm_register_convert_to_virtual (unsigned int regnum,
|
||||
struct type *type,
|
||||
void *from, void *to);
|
||||
#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,TYPE,FROM,TO) \
|
||||
{ \
|
||||
double val; \
|
||||
convert_from_extended ((FROM), & val); \
|
||||
store_floating ((TO), TYPE_LENGTH (TYPE), val); \
|
||||
}
|
||||
arm_register_convert_to_virtual (REGNUM, TYPE, FROM, TO)
|
||||
|
||||
/* Convert data from virtual format with type TYPE in buffer FROM
|
||||
to raw format for register REGNUM in buffer TO. */
|
||||
/* Convert data from virtual format with type TYPE in buffer FROM to
|
||||
raw format for register REGNUM in buffer TO. */
|
||||
|
||||
extern void convert_to_extended (void *ptr, /*double*/void *dbl);
|
||||
extern void arm_register_convert_to_raw (unsigned int regnum,
|
||||
struct type *type,
|
||||
void *from, void *to);
|
||||
#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \
|
||||
arm_register_convert_to_raw (REGNUM, TYPE, FROM, TO)
|
||||
|
||||
#define REGISTER_CONVERT_TO_RAW(TYPE,REGNUM,FROM,TO) \
|
||||
{ \
|
||||
double val = extract_floating ((FROM), TYPE_LENGTH (TYPE)); \
|
||||
convert_to_extended (&val, (TO)); \
|
||||
}
|
||||
/* Return the GDB type object for the "standard" data type
|
||||
of data in register N. */
|
||||
/* Return the GDB type object for the "standard" data type of data in
|
||||
register N. */
|
||||
|
||||
#define REGISTER_VIRTUAL_TYPE(N) \
|
||||
(((unsigned)(N) - F0_REGNUM) < 8 ? builtin_type_double : builtin_type_int)
|
||||
|
||||
(((unsigned)(N) - F0_REGNUM) < NUM_FREGS \
|
||||
? builtin_type_double : builtin_type_int)
|
||||
|
||||
/* The system C compiler uses a similar structure return convention to gcc */
|
||||
extern use_struct_convention_fn arm_use_struct_convention;
|
||||
#define USE_STRUCT_CONVENTION(gcc_p, type) arm_use_struct_convention (gcc_p, type)
|
||||
#define USE_STRUCT_CONVENTION(gcc_p, type) \
|
||||
arm_use_struct_convention (gcc_p, type)
|
||||
|
||||
/* Store the address of the place in which to copy the structure the
|
||||
subroutine will return. This is called from call_function. */
|
||||
|
||||
#define STORE_STRUCT_RETURN(ADDR, SP) \
|
||||
{ write_register (0, (ADDR)); }
|
||||
write_register (A1_REGNUM, (ADDR))
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
/* Extract from an array REGBUF containing the (raw) register state a
|
||||
function return value of type TYPE, and copy that, in virtual
|
||||
format, into VALBUF. */
|
||||
|
||||
extern void arm_extract_return_value (struct type *, char[], char *);
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) \
|
||||
convert_from_extended (REGBUF + REGISTER_BYTE (F0_REGNUM), VALBUF); \
|
||||
else \
|
||||
memcpy (VALBUF, REGBUF, TYPE_LENGTH (TYPE))
|
||||
arm_extract_return_value ((TYPE), (REGBUF), (VALBUF))
|
||||
|
||||
/* Write into appropriate registers a function return value
|
||||
of type TYPE, given in virtual format. */
|
||||
/* Write into appropriate registers a function return value of type
|
||||
TYPE, given in virtual format. */
|
||||
|
||||
extern void convert_to_extended (void *dbl, void *ptr);
|
||||
#define STORE_RETURN_VALUE(TYPE,VALBUF) \
|
||||
if (TYPE_CODE (TYPE) == TYPE_CODE_FLT) { \
|
||||
char _buf[MAX_REGISTER_RAW_SIZE]; \
|
||||
|
@ -275,7 +332,7 @@ extern use_struct_convention_fn arm_use_struct_convention;
|
|||
as a CORE_ADDR (or an expression that can be used as one). */
|
||||
|
||||
#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) \
|
||||
(extract_address ((PTR) (REGBUF), REGISTER_RAW_SIZE(0)))
|
||||
(extract_address ((PTR)(REGBUF), REGISTER_RAW_SIZE(0)))
|
||||
|
||||
/* Specify that for the native compiler variables for a particular
|
||||
lexical context are listed after the beginning LBRAC instead of
|
||||
|
@ -283,11 +340,11 @@ extern use_struct_convention_fn arm_use_struct_convention;
|
|||
#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) (!(gcc_p))
|
||||
|
||||
|
||||
/* Define other aspects of the stack frame.
|
||||
We keep the offsets of all saved registers, 'cause we need 'em a lot!
|
||||
We also keep the current size of the stack frame, and the offset of
|
||||
the frame pointer from the stack pointer (for frameless functions, and
|
||||
when we're still in the prologue of a function with a frame) */
|
||||
/* Define other aspects of the stack frame. We keep the offsets of
|
||||
all saved registers, 'cause we need 'em a lot! We also keep the
|
||||
current size of the stack frame, and the offset of the frame
|
||||
pointer from the stack pointer (for frameless functions, and when
|
||||
we're still in the prologue of a function with a frame) */
|
||||
|
||||
#define EXTRA_FRAME_INFO \
|
||||
struct frame_saved_regs fsr; \
|
||||
|
@ -295,29 +352,29 @@ extern use_struct_convention_fn arm_use_struct_convention;
|
|||
int frameoffset; \
|
||||
int framereg;
|
||||
|
||||
extern void arm_init_extra_frame_info PARAMS ((int fromleaf,
|
||||
struct frame_info *fi));
|
||||
extern void arm_init_extra_frame_info (int fromleaf, struct frame_info * fi);
|
||||
#define INIT_EXTRA_FRAME_INFO(fromleaf, fi) \
|
||||
arm_init_extra_frame_info (fromleaf, fi)
|
||||
arm_init_extra_frame_info ((fromleaf), (fi))
|
||||
|
||||
/* Return the frame address. On ARM, it is R11; on Thumb it is R7. */
|
||||
CORE_ADDR arm_target_read_fp PARAMS ((void));
|
||||
CORE_ADDR arm_target_read_fp (void);
|
||||
#define TARGET_READ_FP() arm_target_read_fp ()
|
||||
|
||||
/* Describe the pointer in each stack frame to the previous stack frame
|
||||
(its caller). */
|
||||
/* Describe the pointer in each stack frame to the previous stack
|
||||
frame (its caller). */
|
||||
|
||||
/* FRAME_CHAIN takes a frame's nominal address
|
||||
and produces the frame's chain-pointer.
|
||||
/* FRAME_CHAIN takes a frame's nominal address and produces the
|
||||
frame's chain-pointer.
|
||||
|
||||
However, if FRAME_CHAIN_VALID returns zero,
|
||||
it means the given frame is the outermost one and has no caller. */
|
||||
|
||||
#define FRAME_CHAIN(thisframe) (CORE_ADDR) arm_frame_chain (thisframe)
|
||||
extern CORE_ADDR arm_frame_chain PARAMS ((struct frame_info *));
|
||||
#define FRAME_CHAIN(thisframe) arm_frame_chain (thisframe)
|
||||
extern CORE_ADDR arm_frame_chain (struct frame_info *);
|
||||
|
||||
extern int arm_frame_chain_valid PARAMS ((CORE_ADDR, struct frame_info *));
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) arm_frame_chain_valid (chain, thisframe)
|
||||
extern int arm_frame_chain_valid (CORE_ADDR, struct frame_info *);
|
||||
#define FRAME_CHAIN_VALID(chain, thisframe) \
|
||||
arm_frame_chain_valid (chain, thisframe)
|
||||
|
||||
/* Define other aspects of the stack frame. */
|
||||
|
||||
|
@ -325,14 +382,14 @@ extern int arm_frame_chain_valid PARAMS ((CORE_ADDR, 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.
|
||||
|
||||
Sometimes we have functions that do a little setup (like saving the vN
|
||||
registers with the stmdb instruction, but DO NOT set up a frame.
|
||||
Sometimes we have functions that do a little setup (like saving the
|
||||
vN registers with the stmdb instruction, but DO NOT set up a frame.
|
||||
The symbol table will report this as a prologue. However, it is
|
||||
important not to try to parse these partial frames as frames, or we
|
||||
will get really confused.
|
||||
|
||||
So I will demand 3 instructions between the start & end of the prologue
|
||||
before I call it a real prologue, i.e. at least
|
||||
So I will demand 3 instructions between the start & end of the
|
||||
prologue before I call it a real prologue, i.e. at least
|
||||
mov ip, sp,
|
||||
stmdb sp!, {}
|
||||
sub sp, ip, #4. */
|
||||
|
@ -344,7 +401,7 @@ extern int arm_frameless_function_invocation (struct frame_info *fi);
|
|||
/* Saved Pc. */
|
||||
|
||||
#define FRAME_SAVED_PC(FRAME) arm_frame_saved_pc (FRAME)
|
||||
extern CORE_ADDR arm_frame_saved_pc PARAMS ((struct frame_info *));
|
||||
extern CORE_ADDR arm_frame_saved_pc (struct frame_info *);
|
||||
|
||||
#define FRAME_ARGS_ADDRESS(fi) (fi->frame)
|
||||
|
||||
|
@ -355,15 +412,15 @@ extern CORE_ADDR arm_frame_saved_pc PARAMS ((struct frame_info *));
|
|||
|
||||
#define FRAME_NUM_ARGS(fi) (-1)
|
||||
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
/* Return number of bytes at start of arglist that are not really args. */
|
||||
|
||||
#define FRAME_ARGS_SKIP 0
|
||||
|
||||
/* Put here the code to store, into a struct frame_saved_regs,
|
||||
the addresses of the saved registers of frame described by FRAME_INFO.
|
||||
/* Put here the code to store, into a struct frame_saved_regs, the
|
||||
addresses of the saved registers of frame described by FRAME_INFO.
|
||||
This includes special registers such as pc and fp saved in special
|
||||
ways in the stack frame. sp is even more special:
|
||||
the address we return for it IS the sp for the next frame. */
|
||||
ways in the stack frame. sp is even more special: the address we
|
||||
return for it IS the sp for the next frame. */
|
||||
|
||||
struct frame_saved_regs;
|
||||
struct frame_info;
|
||||
|
@ -371,24 +428,24 @@ void arm_frame_find_saved_regs (struct frame_info * fi,
|
|||
struct frame_saved_regs * fsr);
|
||||
|
||||
#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
|
||||
arm_frame_find_saved_regs (frame_info, &(frame_saved_regs));
|
||||
|
||||
arm_frame_find_saved_regs (frame_info, &(frame_saved_regs));
|
||||
|
||||
/* Things needed for making the inferior call functions. */
|
||||
|
||||
#define PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \
|
||||
(arm_push_arguments ((nargs), (args), (sp), (struct_return), (struct_addr)))
|
||||
extern CORE_ADDR arm_push_arguments PARAMS ((int, struct value **, CORE_ADDR, int, CORE_ADDR));
|
||||
sp = arm_push_arguments ((nargs), (args), (sp), (struct_return), (struct_addr))
|
||||
extern CORE_ADDR arm_push_arguments (int, struct value **, CORE_ADDR, int,
|
||||
CORE_ADDR);
|
||||
|
||||
/* Push an empty stack frame, to record the current PC, etc. */
|
||||
|
||||
void arm_push_dummy_frame PARAMS ((void));
|
||||
void arm_push_dummy_frame (void);
|
||||
|
||||
#define PUSH_DUMMY_FRAME arm_push_dummy_frame ()
|
||||
|
||||
/* Discard from the stack the innermost frame, restoring all registers. */
|
||||
|
||||
void arm_pop_frame PARAMS ((void));
|
||||
void arm_pop_frame (void);
|
||||
|
||||
#define POP_FRAME arm_pop_frame ()
|
||||
|
||||
|
@ -400,69 +457,59 @@ void arm_pop_frame PARAMS ((void));
|
|||
|
||||
Note this is 12 bytes. */
|
||||
|
||||
#define CALL_DUMMY {0xe1a0e00f, 0xe1a0f004, 0xE7FFDEFE}
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */
|
||||
#define CALL_DUMMY {0xe1a0e00f, 0xe1a0f004, 0xe7ffdefe}
|
||||
#define CALL_DUMMY_START_OFFSET 0 /* Start execution at beginning of dummy */
|
||||
|
||||
#define CALL_DUMMY_BREAKPOINT_OFFSET arm_call_dummy_breakpoint_offset()
|
||||
extern int arm_call_dummy_breakpoint_offset PARAMS ((void));
|
||||
extern int arm_call_dummy_breakpoint_offset (void);
|
||||
|
||||
/* Insert the specified number of args and function address
|
||||
into a call sequence of the above form stored at DUMMYNAME. */
|
||||
/* Insert the specified number of args and function address into a
|
||||
call sequence of the above form stored at DUMMYNAME. */
|
||||
|
||||
#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \
|
||||
arm_fix_call_dummy (dummyname, pc, fun, nargs, args, type, gcc_p)
|
||||
arm_fix_call_dummy ((dummyname), (pc), (fun), (nargs), (args), (type), (gcc_p))
|
||||
|
||||
void arm_fix_call_dummy PARAMS ((char *dummy, CORE_ADDR pc, CORE_ADDR fun,
|
||||
int nargs, struct value ** args,
|
||||
struct type * type, int gcc_p));
|
||||
void arm_fix_call_dummy (char *dummy, CORE_ADDR pc, CORE_ADDR fun,
|
||||
int nargs, struct value ** args,
|
||||
struct type * type, int gcc_p);
|
||||
|
||||
CORE_ADDR arm_get_next_pc PARAMS ((CORE_ADDR));
|
||||
CORE_ADDR arm_get_next_pc (CORE_ADDR pc);
|
||||
|
||||
/* Functions for dealing with Thumb call thunks. */
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) arm_in_call_stub (pc, name)
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) arm_skip_stub (pc)
|
||||
extern int arm_in_call_stub PARAMS ((CORE_ADDR pc, char *name));
|
||||
extern CORE_ADDR arm_skip_stub PARAMS ((CORE_ADDR pc));
|
||||
|
||||
/* Function to determine whether MEMADDR is in a Thumb function. */
|
||||
extern int arm_pc_is_thumb PARAMS ((bfd_vma memaddr));
|
||||
|
||||
/* Function to determine whether MEMADDR is in a call dummy called from
|
||||
a Thumb function. */
|
||||
extern int arm_pc_is_thumb_dummy PARAMS ((bfd_vma memaddr));
|
||||
|
||||
/* Macros for setting and testing a bit in a minimal symbol that
|
||||
marks it as Thumb function. The MSB of the minimal symbol's
|
||||
"info" field is used for this purpose. This field is already
|
||||
being used to store the symbol size, so the assumption is
|
||||
that the symbol size cannot exceed 2^31.
|
||||
/* Macros for setting and testing a bit in a minimal symbol that marks
|
||||
it as Thumb function. The MSB of the minimal symbol's "info" field
|
||||
is used for this purpose. This field is already being used to store
|
||||
the symbol size, so the assumption is that the symbol size cannot
|
||||
exceed 2^31.
|
||||
|
||||
COFF_MAKE_MSYMBOL_SPECIAL
|
||||
ELF_MAKE_MSYMBOL_SPECIAL tests whether the COFF or ELF symbol corresponds
|
||||
to a thumb function, and sets a "special" bit in a
|
||||
minimal symbol to indicate that it does
|
||||
MSYMBOL_SET_SPECIAL actually sets the "special" bit
|
||||
MSYMBOL_IS_SPECIAL tests the "special" bit in a minimal symbol
|
||||
MSYMBOL_SIZE returns the size of the minimal symbol, i.e.
|
||||
the "info" field with the "special" bit masked out
|
||||
*/
|
||||
ELF_MAKE_MSYMBOL_SPECIAL
|
||||
|
||||
These macros test whether the COFF or ELF symbol corresponds to a
|
||||
thumb function, and set a "special" bit in a minimal symbol to
|
||||
indicate that it does.
|
||||
|
||||
MSYMBOL_SET_SPECIAL Actually sets the "special" bit.
|
||||
MSYMBOL_IS_SPECIAL Tests the "special" bit in a minimal symbol.
|
||||
MSYMBOL_SIZE Returns the size of the minimal symbol,
|
||||
i.e. the "info" field with the "special" bit
|
||||
masked out
|
||||
*/
|
||||
|
||||
extern int coff_sym_is_thumb (int val);
|
||||
|
||||
#define MSYMBOL_SET_SPECIAL(msym) \
|
||||
MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) | 0x80000000)
|
||||
MSYMBOL_INFO (msym) = (char *) (((long) MSYMBOL_INFO (msym)) | 0x80000000)
|
||||
#define MSYMBOL_IS_SPECIAL(msym) \
|
||||
(((long) MSYMBOL_INFO (msym) & 0x80000000) != 0)
|
||||
#define MSYMBOL_SIZE(msym) \
|
||||
((long) MSYMBOL_INFO (msym) & 0x7fffffff)
|
||||
|
||||
/* Thumb symbol are of type STT_LOPROC, (synonymous with STT_ARM_TFUNC) */
|
||||
/* Thumb symbols are of type STT_LOPROC, (synonymous with STT_ARM_TFUNC) */
|
||||
#define ELF_MAKE_MSYMBOL_SPECIAL(sym,msym) \
|
||||
{ if(ELF_ST_TYPE(((elf_symbol_type *)(sym))->internal_elf_sym.st_info) == STT_LOPROC) \
|
||||
MSYMBOL_SET_SPECIAL(msym); }
|
||||
{ if(ELF_ST_TYPE(((elf_symbol_type *)(sym))->internal_elf_sym.st_info) == STT_LOPROC) \
|
||||
MSYMBOL_SET_SPECIAL(msym); }
|
||||
|
||||
#define COFF_MAKE_MSYMBOL_SPECIAL(val,msym) \
|
||||
{ if(coff_sym_is_thumb(val)) MSYMBOL_SET_SPECIAL(msym); }
|
||||
|
||||
#undef IN_SIGTRAMP
|
||||
#define IN_SIGTRAMP(pc, name) 0
|
||||
#endif /* TM_ARM_H */
|
||||
|
|
66
gdb/config/arm/tm-embed.h
Normal file
66
gdb/config/arm/tm-embed.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/* Definitions to target GDB to ARM embedded systems.
|
||||
Copyright 1986-1989, 1991, 1993-1999 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_ARMEMBED_H
|
||||
#define TM_ARMEMBED_H
|
||||
|
||||
/* Include the common ARM definitions. */
|
||||
#include "arm/tm-arm.h"
|
||||
|
||||
/* I don't know the real values for these. */
|
||||
#define TARGET_UPAGES UPAGES
|
||||
#define TARGET_NBPG NBPG
|
||||
|
||||
/* Address of end of stack space. */
|
||||
#define STACK_END_ADDR (0x01000000 - (TARGET_UPAGES * TARGET_NBPG))
|
||||
|
||||
/* The first 0x20 bytes are the trap vectors. */
|
||||
#define LOWEST_PC 0x20
|
||||
|
||||
/* Override defaults. */
|
||||
|
||||
#undef THUMB_LE_BREAKPOINT
|
||||
#define THUMB_LE_BREAKPOINT {0xbe,0xbe}
|
||||
#undef THUMB_BE_BREAKPOINT
|
||||
#define THUMB_BE_BREAKPOINT {0xbe,0xbe}
|
||||
|
||||
/* Specify that for the native compiler variables for a particular
|
||||
lexical context are listed after the beginning LBRAC instead of
|
||||
before in the executables list of symbols. */
|
||||
#define VARIABLES_INSIDE_BLOCK(desc, gcc_p) (!(gcc_p))
|
||||
|
||||
/* Functions for dealing with Thumb call thunks. */
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) arm_in_call_stub (pc, name)
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) arm_skip_stub (pc)
|
||||
extern int arm_in_call_stub PARAMS ((CORE_ADDR pc, char *name));
|
||||
extern CORE_ADDR arm_skip_stub PARAMS ((CORE_ADDR pc));
|
||||
|
||||
/* Function to determine whether MEMADDR is in a Thumb function. */
|
||||
extern int arm_pc_is_thumb PARAMS ((bfd_vma memaddr));
|
||||
|
||||
/* Function to determine whether MEMADDR is in a call dummy called from
|
||||
a Thumb function. */
|
||||
extern int arm_pc_is_thumb_dummy PARAMS ((bfd_vma memaddr));
|
||||
|
||||
|
||||
#undef IN_SIGTRAMP
|
||||
#define IN_SIGTRAMP(pc, name) 0
|
||||
|
||||
#endif /* TM_ARMEMBED_H */
|
122
gdb/config/arm/tm-linux.h
Normal file
122
gdb/config/arm/tm-linux.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/* Target definitions for GNU/Linux on ARM, for GDB.
|
||||
Copyright 1999 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_ARMLINUX_H
|
||||
#define TM_ARMLINUX_H
|
||||
|
||||
/* Include the common ARM target definitions. */
|
||||
#include "arm/tm-arm.h"
|
||||
|
||||
#include "tm-linux.h"
|
||||
|
||||
/* Target byte order on ARM Linux is not selectable. */
|
||||
#undef TARGET_BYTE_ORDER_SELECTABLE_P
|
||||
#define TARGET_BYTE_ORDER_SELECTABLE_P 0
|
||||
|
||||
/* Under ARM Linux the traditional way of performing a breakpoint is to
|
||||
execute a particular software interrupt, rather than use a particular
|
||||
undefined instruction to provoke a trap. Upon exection of the software
|
||||
interrupt the kernel stops the inferior with a SIGTRAP, and wakes the
|
||||
debugger. Since ARM Linux is little endian, and doesn't support Thumb
|
||||
at the moment we redefined ARM_LE_BREAKPOINT to use the correct software
|
||||
interrupt. */
|
||||
#undef ARM_LE_BREAKPOINT
|
||||
#define ARM_LE_BREAKPOINT {0x01,0x00,0x9f,0xef}
|
||||
|
||||
/* This sequence of words used in the CALL_DUMMY are the following
|
||||
instructions:
|
||||
|
||||
mov lr, pc
|
||||
mov pc, r4
|
||||
swi bkpt_swi
|
||||
|
||||
Note this is 12 bytes. */
|
||||
|
||||
#undef CALL_DUMMY
|
||||
#define CALL_DUMMY {0xe1a0e00f, 0xe1a0f004, 0xef9f001}
|
||||
|
||||
/* Extract from an array REGBUF containing the (raw) register state
|
||||
a function return value of type TYPE, and copy that, in virtual format,
|
||||
into VALBUF. */
|
||||
extern void arm_linux_extract_return_value (struct type *, char[], char *);
|
||||
#undef EXTRACT_RETURN_VALUE
|
||||
#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \
|
||||
arm_linux_extract_return_value ((TYPE), (REGBUF), (VALBUF))
|
||||
|
||||
/* The first page is not writeable in ARM Linux. */
|
||||
#define LOWEST_PC 0x8000
|
||||
|
||||
/* Define NO_SINGLE_STEP if ptrace(PT_STEP,...) fails to function correctly
|
||||
on ARM Linux. This is the case on 2.0.x kernels, 2.1.x kernels and some
|
||||
2.2.x kernels. This will include the implementation of single_step()
|
||||
in armlinux-tdep.c. See armlinux-ss.c for more details. */
|
||||
/* #define NO_SINGLE_STEP 1 */
|
||||
|
||||
/* Offset to saved PC in sigcontext structure, from <asm/sigcontext.h> */
|
||||
#define SIGCONTEXT_PC_OFFSET (sizeof(unsigned long) * 18)
|
||||
|
||||
/* Figure out where the longjmp will land. The code expects that longjmp
|
||||
has just been entered and the code had not altered the registers, so
|
||||
the arguments are are still in r0-r1. r0 points at the jmp_buf structure
|
||||
from which the target pc (JB_PC) is extracted. This pc value is copied
|
||||
into ADDR. This routine returns true on success */
|
||||
extern int arm_get_longjmp_target (CORE_ADDR *);
|
||||
#define GET_LONGJMP_TARGET(addr) arm_get_longjmp_target (addr)
|
||||
|
||||
/* On ARM Linux, each call to a library routine goes through a small piece
|
||||
of trampoline code in the ".plt" section. The wait_for_inferior()
|
||||
routine uses this macro to detect when we have stepped into one of
|
||||
these fragments. We do not use lookup_solib_trampoline_symbol_by_pc,
|
||||
because we cannot always find the shared library trampoline symbols. */
|
||||
extern int in_plt_section (CORE_ADDR, char *);
|
||||
#define IN_SOLIB_CALL_TRAMPOLINE(pc, name) in_plt_section((pc), (name))
|
||||
|
||||
/* On ARM Linux, a call to a library routine does not have to go through
|
||||
any trampoline code. */
|
||||
#define IN_SOLIB_RETURN_TRAMPOLINE(pc, name) 0
|
||||
|
||||
/* If PC is in a shared library trampoline code, return the PC
|
||||
where the function itself actually starts. If not, return 0. */
|
||||
extern CORE_ADDR find_solib_trampoline_target (CORE_ADDR pc);
|
||||
#define SKIP_TRAMPOLINE_CODE(pc) find_solib_trampoline_target (pc)
|
||||
|
||||
/* When we call a function in a shared library, and the PLT sends us
|
||||
into the dynamic linker to find the function's real address, we
|
||||
need to skip over the dynamic linker call. This function decides
|
||||
when to skip, and where to skip to. See the comments for
|
||||
SKIP_SOLIB_RESOLVER at the top of infrun.c. */
|
||||
extern CORE_ADDR arm_skip_solib_resolver (CORE_ADDR pc);
|
||||
#define SKIP_SOLIB_RESOLVER arm_skip_solib_resolver
|
||||
|
||||
/* When we call a function in a shared library, and the PLT sends us
|
||||
into the dynamic linker to find the function's real address, we
|
||||
need to skip over the dynamic linker call. This function decides
|
||||
when to skip, and where to skip to. See the comments for
|
||||
SKIP_SOLIB_RESOLVER at the top of infrun.c. */
|
||||
#if 0
|
||||
#undef IN_SOLIB_DYNSYM_RESOLVE_CODE
|
||||
extern CORE_ADDR arm_in_solib_dynsym_resolve_code (CORE_ADDR pc, char *name);
|
||||
#define IN_SOLIB_DYNSYM_RESOLVE_CODE arm_in_solib_dynsym_resolve_code
|
||||
/* ScottB: Current definition is
|
||||
extern CORE_ADDR in_svr4_dynsym_resolve_code (CORE_ADDR pc, char *name);
|
||||
#define IN_SOLIB_DYNSYM_RESOLVE_CODE in_svr4_dynsym_resolve_code */
|
||||
#endif
|
||||
|
||||
#endif /* TM_ARMLINUX_H */
|
|
@ -1,77 +1,77 @@
|
|||
/* Definitions to make GDB run on an ARM under RISCiX (4.3bsd).
|
||||
Copyright (C) 1986, 1987, 1989 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. */
|
||||
|
||||
#define HOST_BYTE_ORDER LITTLE_ENDIAN
|
||||
|
||||
|
||||
#if 0
|
||||
/* Interface definitions for kernel debugger KDB. */
|
||||
|
||||
/* Map machine fault codes into signal numbers.
|
||||
First subtract 0, divide by 4, then index in a table.
|
||||
Faults for which the entry in this table is 0
|
||||
are not handled by KDB; the program's own trap handler
|
||||
gets to handle then. */
|
||||
|
||||
#define FAULT_CODE_ORIGIN 0
|
||||
#define FAULT_CODE_UNITS 4
|
||||
#define FAULT_TABLE \
|
||||
{ 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \
|
||||
0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \
|
||||
0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Start running with a stack stretching from BEG to END.
|
||||
BEG and END should be symbols meaningful to the assembler.
|
||||
This is used only for kdb. */
|
||||
|
||||
#define INIT_STACK(beg, end) \
|
||||
{ asm (".globl end"); \
|
||||
asm ("movl $ end, sp"); \
|
||||
asm ("clrl fp"); }
|
||||
|
||||
/* Push the frame pointer register on the stack. */
|
||||
#define PUSH_FRAME_PTR \
|
||||
asm ("pushl fp");
|
||||
|
||||
/* Copy the top-of-stack to the frame pointer register. */
|
||||
#define POP_FRAME_PTR \
|
||||
asm ("movl (sp), fp");
|
||||
|
||||
/* After KDB is entered by a fault, push all registers
|
||||
that GDB thinks about (all NUM_REGS of them),
|
||||
so that they appear in order of ascending GDB register number.
|
||||
The fault code will be on the stack beyond the last register. */
|
||||
|
||||
#define PUSH_REGISTERS \
|
||||
{ asm ("pushl 8(sp)"); \
|
||||
asm ("pushl 8(sp)"); \
|
||||
asm ("pushal 0x14(sp)"); \
|
||||
asm ("pushr $037777"); }
|
||||
|
||||
/* Assuming the registers (including processor status) have been
|
||||
pushed on the stack in order of ascending GDB register number,
|
||||
restore them and return to the address in the saved PC register. */
|
||||
|
||||
#define POP_REGISTERS \
|
||||
{ asm ("popr $037777"); \
|
||||
asm ("subl2 $8,(sp)"); \
|
||||
asm ("movl (sp),sp"); \
|
||||
asm ("rei"); }
|
||||
#endif /* 0 */
|
||||
/* OBSOLETE /* Definitions to make GDB run on an ARM under RISCiX (4.3bsd). */
|
||||
/* OBSOLETE Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This file is part of GDB. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This program is free software; you can redistribute it and/or modify */
|
||||
/* OBSOLETE it under the terms of the GNU General Public License as published by */
|
||||
/* OBSOLETE the Free Software Foundation; either version 2 of the License, or */
|
||||
/* OBSOLETE (at your option) any later version. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE This program is distributed in the hope that it will be useful, */
|
||||
/* OBSOLETE but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
||||
/* OBSOLETE MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
||||
/* OBSOLETE GNU General Public License for more details. */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE You should have received a copy of the GNU General Public License */
|
||||
/* OBSOLETE along with this program; if not, write to the Free Software */
|
||||
/* OBSOLETE Foundation, Inc., 59 Temple Place - Suite 330, */
|
||||
/* OBSOLETE Boston, MA 02111-1307, USA. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define HOST_BYTE_ORDER LITTLE_ENDIAN */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #if 0 */
|
||||
/* OBSOLETE /* Interface definitions for kernel debugger KDB. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Map machine fault codes into signal numbers. */
|
||||
/* OBSOLETE First subtract 0, divide by 4, then index in a table. */
|
||||
/* OBSOLETE Faults for which the entry in this table is 0 */
|
||||
/* OBSOLETE are not handled by KDB; the program's own trap handler */
|
||||
/* OBSOLETE gets to handle then. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define FAULT_CODE_ORIGIN 0 */
|
||||
/* OBSOLETE #define FAULT_CODE_UNITS 4 */
|
||||
/* OBSOLETE #define FAULT_TABLE \ */
|
||||
/* OBSOLETE { 0, SIGKILL, SIGSEGV, 0, 0, 0, 0, 0, \ */
|
||||
/* OBSOLETE 0, 0, SIGTRAP, SIGTRAP, 0, 0, 0, 0, \ */
|
||||
/* OBSOLETE 0, 0, 0, 0, 0, 0, 0, 0} */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Start running with a stack stretching from BEG to END. */
|
||||
/* OBSOLETE BEG and END should be symbols meaningful to the assembler. */
|
||||
/* OBSOLETE This is used only for kdb. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define INIT_STACK(beg, end) \ */
|
||||
/* OBSOLETE { asm (".globl end"); \ */
|
||||
/* OBSOLETE asm ("movl $ end, sp"); \ */
|
||||
/* OBSOLETE asm ("clrl fp"); } */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Push the frame pointer register on the stack. *x/ */
|
||||
/* OBSOLETE #define PUSH_FRAME_PTR \ */
|
||||
/* OBSOLETE asm ("pushl fp"); */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Copy the top-of-stack to the frame pointer register. *x/ */
|
||||
/* OBSOLETE #define POP_FRAME_PTR \ */
|
||||
/* OBSOLETE asm ("movl (sp), fp"); */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* After KDB is entered by a fault, push all registers */
|
||||
/* OBSOLETE that GDB thinks about (all NUM_REGS of them), */
|
||||
/* OBSOLETE so that they appear in order of ascending GDB register number. */
|
||||
/* OBSOLETE The fault code will be on the stack beyond the last register. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define PUSH_REGISTERS \ */
|
||||
/* OBSOLETE { asm ("pushl 8(sp)"); \ */
|
||||
/* OBSOLETE asm ("pushl 8(sp)"); \ */
|
||||
/* OBSOLETE asm ("pushal 0x14(sp)"); \ */
|
||||
/* OBSOLETE asm ("pushr $037777"); } */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE /* Assuming the registers (including processor status) have been */
|
||||
/* OBSOLETE pushed on the stack in order of ascending GDB register number, */
|
||||
/* OBSOLETE restore them and return to the address in the saved PC register. *x/ */
|
||||
/* OBSOLETE */
|
||||
/* OBSOLETE #define POP_REGISTERS \ */
|
||||
/* OBSOLETE { asm ("popr $037777"); \ */
|
||||
/* OBSOLETE asm ("subl2 $8,(sp)"); \ */
|
||||
/* OBSOLETE asm ("movl (sp),sp"); \ */
|
||||
/* OBSOLETE asm ("rei"); } */
|
||||
/* OBSOLETE #endif /* 0 *x/ */
|
||||
|
|
37
gdb/config/arm/xm-linux.h
Normal file
37
gdb/config/arm/xm-linux.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Host definitions for ARM GNU/Linux, for GDB, the GNU debugger.
|
||||
Copyright 1999 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_ARMLINUX_H
|
||||
#define XM_ARMLINUX_H
|
||||
|
||||
#define HOST_BYTE_ORDER LITTLE_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>
|
||||
|
||||
#endif /* XM_ARMLINUX_H */
|
|
@ -5,4 +5,6 @@ XDEPFILES= ser-tcp.o
|
|||
|
||||
NAT_FILE= nm-linux.h
|
||||
NATDEPFILES= infptrace.o solib.o inftarg.o fork-child.o corelow.o \
|
||||
core-aout.o i386v-nat.o i386-linux-nat.o linux-thread.o
|
||||
core-aout.o i386v-nat.o i386-linux-nat.o linux-thread.o lin-thread.o
|
||||
|
||||
LOADLIBES = -ldl -rdynamic
|
||||
|
|
|
@ -29,4 +29,20 @@
|
|||
extern CORE_ADDR skip_trampoline_code PARAMS ((CORE_ADDR pc, char *name));
|
||||
|
||||
extern char *cygwin_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) cygwin_pid_to_str (PID)
|
||||
|
||||
struct frame_info;
|
||||
void child_init_frame(int x, struct frame_info *);
|
||||
CORE_ADDR child_frame_saved_pc(struct frame_info *);
|
||||
CORE_ADDR child_frame_chain(struct frame_info *);
|
||||
|
||||
#undef FRAME_CHAIN_VALID_ALTERNATE
|
||||
#define FRAME_CHAIN_VALID_ALTERNATE 1
|
||||
|
||||
#undef INIT_EXTRA_FRAME_INFO
|
||||
#define INIT_EXTRA_FRAME_INFO(x, f) child_init_frame(x, f)
|
||||
|
||||
#undef FRAME_CHAIN
|
||||
#define FRAME_CHAIN child_frame_chain
|
||||
|
||||
#undef FRAME_SAVED_PC
|
||||
#define FRAME_SAVED_PC child_frame_saved_pc
|
||||
|
|
|
@ -53,12 +53,10 @@ extern char *sunpro_static_transform_name PARAMS ((char *));
|
|||
#ifdef HAVE_THREAD_DB_LIB
|
||||
|
||||
extern char *solaris_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) solaris_pid_to_str (PID)
|
||||
|
||||
#else
|
||||
|
||||
extern char *procfs_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) procfs_pid_to_str (PID)
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -422,7 +422,9 @@ extern void mips_push_dummy_frame PARAMS ((void));
|
|||
#define POP_FRAME mips_pop_frame()
|
||||
extern void mips_pop_frame PARAMS ((void));
|
||||
|
||||
#if !GDB_MULTI_ARCH
|
||||
#define CALL_DUMMY { 0 }
|
||||
#endif
|
||||
|
||||
#define CALL_DUMMY_START_OFFSET (0)
|
||||
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#include <mach.h>
|
||||
#include <mach/exception.h>
|
||||
|
||||
#undef target_pid_to_str
|
||||
#define target_pid_to_str(pid) gnu_target_pid_to_str(pid)
|
||||
extern char *gnu_target_pid_to_str (int pid);
|
||||
|
||||
/* Before storing, we need to read all the registers. */
|
||||
|
|
|
@ -37,14 +37,25 @@
|
|||
|
||||
struct objfile;
|
||||
|
||||
/* Hook to look at new objfiles (shared libraries) */
|
||||
extern void
|
||||
linuxthreads_new_objfile PARAMS ((struct objfile *objfile));
|
||||
#define target_new_objfile(OBJFILE) linuxthreads_new_objfile (OBJFILE)
|
||||
|
||||
/* Method to print a human-readable thread description */
|
||||
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)
|
||||
|
||||
/* Defined to make stepping-over-breakpoints be thread-atomic. */
|
||||
#define USE_THREAD_STEP_NEEDED 1
|
||||
|
||||
/* Macros to extract process id and thread id from a composite pid/tid.
|
||||
Allocate lower 19 bits for process id, next 12 bits for thread id, and
|
||||
one bit for a flag to indicate a user thread vs. a kernel thread. */
|
||||
#define PIDGET(PID) (((PID) & 0xffff))
|
||||
#define TIDGET(PID) (((PID) & 0x7fffffff) >> 16)
|
||||
#define MERGEPID(PID, TID) (((PID) & 0xffff) | ((TID) << 16))
|
||||
|
||||
|
|
|
@ -75,10 +75,9 @@ extern int child_wait PARAMS ((int pid, struct target_waitstatus * status));
|
|||
/* Lynx needs a special definition of this so that we can
|
||||
print out the pid and thread number seperatly. */
|
||||
|
||||
#undef target_pid_to_str
|
||||
|
||||
#define target_pid_to_str(PID) lynx_pid_to_str (PID)
|
||||
|
||||
/* override child_pid_to_str in inftarg.c */
|
||||
#define CHILD_PID_TO_STR
|
||||
extern char *lynx_pid_to_str PARAMS ((int pid));
|
||||
|
||||
#endif /* NM_LYNX_H */
|
||||
|
|
|
@ -90,6 +90,7 @@ extern int hppa_prepare_to_proceed PARAMS ((void));
|
|||
#define CHILD_HAS_SYSCALL_EVENT
|
||||
#define CHILD_POST_ATTACH
|
||||
#define CHILD_THREAD_ALIVE
|
||||
#define CHILD_PID_TO_STR
|
||||
|
||||
#define REQUIRE_ATTACH(pid) hppa_require_attach(pid)
|
||||
extern int hppa_require_attach PARAMS ((int));
|
||||
|
@ -226,9 +227,8 @@ extern void hppa_disable_page_protection_events PARAMS ((int));
|
|||
* than processes. So we need a new way to print
|
||||
* the string. Code is in hppah-nat.c.
|
||||
*/
|
||||
#define target_pid_to_str( pid ) \
|
||||
hppa_pid_to_str( pid )
|
||||
extern char *hppa_pid_to_str PARAMS ((pid_t));
|
||||
|
||||
extern char *child_pid_to_str PARAMS ((pid_t));
|
||||
|
||||
#define target_tid_to_str( pid ) \
|
||||
hppa_tid_to_str( pid )
|
||||
|
@ -277,13 +277,6 @@ extern void hppa_ensure_vforking_parent_remains_stopped PARAMS ((int));
|
|||
hppa_resume_execd_vforking_child_to_get_parent_vfork ()
|
||||
extern int hppa_resume_execd_vforking_child_to_get_parent_vfork PARAMS ((void));
|
||||
|
||||
#ifdef HAVE_HPUX_THREAD_SUPPORT
|
||||
|
||||
extern char *hpux_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) hpux_pid_to_str (PID)
|
||||
|
||||
#endif /* HAVE_HPUX_THREAD_SUPPORT */
|
||||
|
||||
#define HPUXHPPA
|
||||
|
||||
#define MAY_SWITCH_FROM_INFERIOR_PID (1)
|
||||
|
|
|
@ -85,11 +85,9 @@ extern char *sunpro_static_transform_name PARAMS ((char *));
|
|||
#ifdef HAVE_THREAD_DB_LIB
|
||||
|
||||
extern char *solaris_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) solaris_pid_to_str (PID)
|
||||
|
||||
#else
|
||||
|
||||
extern char *procfs_pid_to_str PARAMS ((int pid));
|
||||
#define target_pid_to_str(PID) procfs_pid_to_str (PID)
|
||||
|
||||
#endif
|
||||
|
|
575
gdb/configure
vendored
575
gdb/configure
vendored
File diff suppressed because it is too large
Load diff
|
@ -11,6 +11,7 @@
|
|||
case "${host_cpu}" in
|
||||
|
||||
alpha*) gdb_host_cpu=alpha ;;
|
||||
arm*) gdb_host_cpu=arm ;;
|
||||
# OBSOLETE c[12]) gdb_host_cpu=convex ;;
|
||||
hppa*) gdb_host_cpu=pa ;;
|
||||
i[3456]86*) gdb_host_cpu=i386 ;;
|
||||
|
@ -35,7 +36,8 @@ alpha*-*-osf2*) gdb_host=alpha-osf2 ;;
|
|||
alpha*-*-osf[3456789]*) gdb_host=alpha-osf3 ;;
|
||||
alpha*-*-linux*) gdb_host=alpha-linux ;;
|
||||
|
||||
arm-*-*) gdb_host=arm ;;
|
||||
arm*-*-linux*) gdb_host=linux ;;
|
||||
arm*-*-*) gdb_host=arm ;;
|
||||
|
||||
# OBSOLETE c[12]-*-*) gdb_host=convex ;;
|
||||
|
||||
|
|
|
@ -79,9 +79,9 @@ AC_TYPE_SIGNAL
|
|||
|
||||
AC_HEADER_STDC
|
||||
|
||||
AC_CHECK_HEADERS(ctype.h curses.h endian.h link.h \
|
||||
AC_CHECK_HEADERS(ctype.h curses.h endian.h link.h thread_db.h proc_service.h \
|
||||
memory.h objlist.h ptrace.h sgtty.h stddef.h stdlib.h \
|
||||
string.h sys/procfs.h sys/ptrace.h sys/reg.h \
|
||||
string.h sys/procfs.h sys/ptrace.h sys/reg.h stdint.h \
|
||||
term.h termio.h termios.h unistd.h wait.h sys/wait.h \
|
||||
wchar.h wctype.h asm/debugreg.h sys/debugreg.h sys/select.h \
|
||||
time.h sys/ioctl.h)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
case "${target_cpu}" in
|
||||
|
||||
alpha*) gdb_target_cpu=alpha ;;
|
||||
arm*) gdb_target_cpu=arm ;;
|
||||
# OBSOLETE c[12]) gdb_target_cpu=convex ;;
|
||||
hppa*) gdb_target_cpu=pa ;;
|
||||
i[3456]86*) gdb_target_cpu=i386 ;;
|
||||
|
@ -50,8 +51,9 @@ alpha*-*-linux*) gdb_target=alpha-linux ;;
|
|||
|
||||
arc-*-*) gdb_target=arc ;;
|
||||
|
||||
arm-*-* | thumb-*-* | strongarm-*-*)
|
||||
gdb_target=arm
|
||||
arm*-*-linux*) gdb_target=linux ;;
|
||||
arm*-*-* | thumb*-*-* | strongarm*-*-*)
|
||||
gdb_target=embed
|
||||
configdirs="$configdirs rdi-share"
|
||||
;;
|
||||
# OBSOLETE c1-*-*) gdb_target=convex ;;
|
||||
|
|
|
@ -329,6 +329,7 @@ extern int myread (int, char *, int);
|
|||
extern int query (char *, ...) ATTR_FORMAT (printf, 1, 2);
|
||||
|
||||
#if !defined (USE_MMALLOC)
|
||||
extern PTR mcalloc (void *, size_t, size_t);
|
||||
extern PTR mmalloc (PTR, size_t);
|
||||
extern PTR mrealloc (PTR, PTR, size_t);
|
||||
extern void mfree (PTR, PTR);
|
||||
|
@ -1283,7 +1284,8 @@ extern int use_windows;
|
|||
the actual pid. */
|
||||
|
||||
#ifndef PIDGET
|
||||
#define PIDGET(pid) (pid)
|
||||
#define PIDGET(PID) (PID)
|
||||
#define TIDGET(PID) 0
|
||||
#endif
|
||||
|
||||
/* If under Cygwin, provide backwards compatibility with older
|
||||
|
|
|
@ -84,13 +84,15 @@ breakpoint_modify_event (int b)
|
|||
#endif
|
||||
|
||||
#if WITH_GDB_EVENTS
|
||||
void
|
||||
struct gdb_events *
|
||||
set_gdb_event_hooks (struct gdb_events *vector)
|
||||
{
|
||||
struct gdb_events *old_events = current_event_hooks;
|
||||
if (vector == NULL)
|
||||
current_event_hooks = &queue_event_hooks;
|
||||
else
|
||||
current_event_hooks = vector;
|
||||
return old_events;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ extern void breakpoint_modify_event (int b);
|
|||
#endif
|
||||
|
||||
/* Install custom gdb-events hooks. */
|
||||
extern void set_gdb_event_hooks (struct gdb_events *vector);
|
||||
extern struct gdb_events *set_gdb_event_hooks (struct gdb_events *vector);
|
||||
|
||||
/* Deliver any pending events. */
|
||||
extern void gdb_events_deliver (struct gdb_events *vector);
|
||||
|
|
|
@ -257,7 +257,7 @@ echo "#endif"
|
|||
cat <<EOF
|
||||
|
||||
/* Install custom gdb-events hooks. */
|
||||
extern void set_gdb_event_hooks (struct gdb_events *vector);
|
||||
extern struct gdb_events *set_gdb_event_hooks (struct gdb_events *vector);
|
||||
|
||||
/* Deliver any pending events. */
|
||||
extern void gdb_events_deliver (struct gdb_events *vector);
|
||||
|
@ -361,13 +361,15 @@ echo "#endif"
|
|||
echo ""
|
||||
cat <<EOF
|
||||
#if WITH_GDB_EVENTS
|
||||
void
|
||||
struct gdb_events *
|
||||
set_gdb_event_hooks (struct gdb_events *vector)
|
||||
{
|
||||
struct gdb_events *old_events = current_event_hooks;
|
||||
if (vector == NULL)
|
||||
current_event_hooks = &queue_event_hooks;
|
||||
else
|
||||
current_event_hooks = vector;
|
||||
return old_events;
|
||||
EOF
|
||||
function_list | while eval read $read
|
||||
do
|
||||
|
|
24
gdb/gdb_proc_service.h
Normal file
24
gdb/gdb_proc_service.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
typedef enum {
|
||||
PS_OK, /* generic "call succeeded" */
|
||||
PS_ERR, /* generic. */
|
||||
PS_BADPID, /* bad process handle */
|
||||
PS_BADLID, /* bad lwp identifier */
|
||||
PS_BADADDR, /* bad address */
|
||||
PS_NOSYM, /* p_lookup() could not find given symbol */
|
||||
PS_NOFREGS
|
||||
/*
|
||||
* FPU register set not available for given
|
||||
* lwp
|
||||
*/
|
||||
} ps_err_e;
|
||||
|
||||
typedef unsigned int lwpid_t;
|
||||
typedef unsigned long paddr_t;
|
||||
typedef unsigned long psaddr_t;
|
||||
|
||||
|
||||
typedef gregset_t prgregset_t; /* BOGUS BOGUS BOGUS */
|
||||
typedef fpregset_t prfpregset_t; /* BOGUS BOGUS BOGUS */
|
||||
|
||||
|
||||
struct ps_prochandle; /* user defined. */
|
427
gdb/gdb_thread_db.h
Normal file
427
gdb/gdb_thread_db.h
Normal file
|
@ -0,0 +1,427 @@
|
|||
/* Copyright (C) 1999 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _THREAD_DB_H
|
||||
#define _THREAD_DB_H 1
|
||||
|
||||
/* This is the debugger interface for the LinuxThreads library. It is
|
||||
modelled closely after the interface with same names in Solaris with
|
||||
the goal to share the same code in the debugger. */
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
/*#include <sys/ucontext.h>*/
|
||||
|
||||
|
||||
/* Error codes of the library. */
|
||||
typedef enum
|
||||
{
|
||||
TD_OK, /* No error. */
|
||||
TD_ERR, /* No further specified error. */
|
||||
TD_NOTHR, /* No matching thread found. */
|
||||
TD_NOSV, /* No matching synchronization handle found. */
|
||||
TD_NOLWP, /* No matching light-weighted process found. */
|
||||
TD_BADPH, /* Invalid process handle. */
|
||||
TD_BADTH, /* Invalid thread handle. */
|
||||
TD_BADSH, /* Invalid synchronization handle. */
|
||||
TD_BADTA, /* Invalid thread agent. */
|
||||
TD_BADKEY, /* Invalid key. */
|
||||
TD_NOMSG, /* No event available. */
|
||||
TD_NOFPREGS, /* No floating-point register content available. */
|
||||
TD_NOLIBTHREAD, /* Application not linked with thread library. */
|
||||
TD_NOEVENT, /* Requested event is not supported. */
|
||||
TD_NOCAPAB, /* Capability not available. */
|
||||
TD_DBERR, /* Internal debug library error. */
|
||||
TD_NOAPLIC, /* Operation is not applicable. */
|
||||
TD_NOTSD, /* No thread-specific data available. */
|
||||
TD_MALLOC, /* Out of memory. */
|
||||
TD_PARTIALREG,/* Not entire register set was read or written. */
|
||||
TD_NOXREGS /* X register set not available for given thread. */
|
||||
} td_err_e;
|
||||
|
||||
|
||||
/* Possible thread states. TD_THR_ANY_STATE is a pseudo-state used to
|
||||
select threads regardless of state in td_ta_thr_iter(). */
|
||||
typedef enum
|
||||
{
|
||||
TD_THR_ANY_STATE,
|
||||
TD_THR_UNKNOWN,
|
||||
TD_THR_STOPPED,
|
||||
TD_THR_RUN,
|
||||
TD_THR_ACTIVE,
|
||||
TD_THR_ZOMBIE,
|
||||
TD_THR_SLEEP,
|
||||
TD_THR_STOPPED_ASLEEP
|
||||
} td_thr_state_e;
|
||||
|
||||
/* Thread type: user or system. TD_THR_ANY_TYPE is a pseudo-type used
|
||||
to select threads regardless of type in td_ta_thr_iter(). */
|
||||
typedef enum
|
||||
{
|
||||
TD_THR_ANY_TYPE,
|
||||
TD_THR_USER,
|
||||
TD_THR_SYSTEM
|
||||
} td_thr_type_e;
|
||||
|
||||
|
||||
/* Types of the debugging library. */
|
||||
|
||||
/* Addresses. */
|
||||
/*typedef void *psaddr_t;*/
|
||||
|
||||
/* Handle for a process. This type is opaque. */
|
||||
typedef struct td_thragent td_thragent_t;
|
||||
|
||||
/* The actual thread handle type. This is also opaque. */
|
||||
typedef struct td_thrhandle
|
||||
{
|
||||
td_thragent_t *th_ta_p;
|
||||
psaddr_t th_unique;
|
||||
} td_thrhandle_t;
|
||||
|
||||
|
||||
/* Flags for `td_ta_thr_iter'. */
|
||||
#define TD_THR_ANY_USER_FLAGS 0xffffffff
|
||||
#define TD_THR_LOWEST_PRIORITY -20
|
||||
#define TD_SIGNO_MASK NULL
|
||||
|
||||
|
||||
#define TD_EVENTSIZE 2
|
||||
#define BT_UISHIFT 5 /* log base 2 of BT_NBIPUI, to extract word index */
|
||||
#define BT_NBIPUI (1 << BT_UISHIFT) /* n bits per uint */
|
||||
#define BT_UIMASK (BT_NBIPUI - 1) /* to extract bit index */
|
||||
|
||||
/* Bitmask of enabled events. */
|
||||
typedef struct td_thr_events
|
||||
{
|
||||
uint32_t event_bits[TD_EVENTSIZE];
|
||||
} td_thr_events_t;
|
||||
|
||||
/* Event set manipulation macros. */
|
||||
#define __td_eventmask(n) \
|
||||
(UINT32_C (1) << (((n) - 1) & BT_UIMASK))
|
||||
#define __td_eventword(n) \
|
||||
((UINT32_C ((n) - 1)) >> BT_UISHIFT)
|
||||
|
||||
#define td_event_emptyset(setp) \
|
||||
do { \
|
||||
int __i; \
|
||||
for (__i = TD_EVENTSIZE; __i > 0; --__i) \
|
||||
(setp)->event_bits[__i - 1] = 0; \
|
||||
} while (0)
|
||||
|
||||
#define td_event_fillset(setp) \
|
||||
do { \
|
||||
int __i; \
|
||||
for (__i = TD_EVENTSIZE; __i > 0; --__i) \
|
||||
(setp)->event_bits[__i - 1] = UINT32_C (0xffffffff); \
|
||||
} while (0)
|
||||
|
||||
#define td_event_addset(setp, n) \
|
||||
(((setp)->event_bits[__td_eventword (n)]) |= __td_eventmask (n))
|
||||
#define td_event_delset(setp, n) \
|
||||
(((setp)->event_bits[__td_eventword (n)]) &= ~__td_eventmask (n))
|
||||
#define td_eventismember(setp, n) \
|
||||
(__td_eventmask (n) & ((setp)->event_bits[__td_eventword (n)]))
|
||||
#if TD_EVENTSIZE == 2
|
||||
# define td_eventisempty(setp) \
|
||||
(!((setp)->event_bits[0]) && !((setp)->event_bits[1]))
|
||||
#else
|
||||
# error "td_eventisempty must be changed to match TD_EVENTSIZE"
|
||||
#endif
|
||||
|
||||
/* Events reportable by the thread implementation. */
|
||||
typedef enum
|
||||
{
|
||||
TD_ALL_EVENTS, /* Pseudo-event number. */
|
||||
TD_EVENT_NONE = TD_ALL_EVENTS, /* Depends on context. */
|
||||
TD_READY, /* Is executable now. */
|
||||
TD_SLEEP, /* Blocked in a synchronization obj. */
|
||||
TD_SWITCHTO, /* Now assigned to a process. */
|
||||
TD_SWITCHFROM, /* Not anymore assigned to a process. */
|
||||
TD_LOCK_TRY, /* Trying to get an unavailable lock. */
|
||||
TD_CATCHSIG, /* Signal posted to the thread. */
|
||||
TD_IDLE, /* Process getting idle. */
|
||||
TD_CREATE, /* New thread created. */
|
||||
TD_DEATH, /* Thread terminated. */
|
||||
TD_PREEMPT, /* Preempted. */
|
||||
TD_PRI_INHERIT, /* Inherited elevated priority. */
|
||||
TD_REAP, /* Reaped. */
|
||||
TD_CONCURRENCY, /* Number of processes changing. */
|
||||
TD_TIMEOUT, /* Conditional variable wait timed out. */
|
||||
TD_MIN_EVENT_NUM = TD_READY,
|
||||
TD_MAX_EVENT_NUM = TD_TIMEOUT,
|
||||
TD_EVENTS_ENABLE = 31 /* Event reporting enabled. */
|
||||
} td_event_e;
|
||||
|
||||
/* Values representing the different ways events are reported. */
|
||||
typedef enum
|
||||
{
|
||||
NOTIFY_BPT, /* User must insert breakpoint at u.bptaddr. */
|
||||
NOTIFY_AUTOBPT, /* Breakpoint at u.bptaddr is automatically
|
||||
inserted. */
|
||||
NOTIFY_SYSCALL /* System call u.syscallno will be invoked. */
|
||||
} td_notify_e;
|
||||
|
||||
/* Description how event type is reported. */
|
||||
typedef struct td_notify
|
||||
{
|
||||
td_notify_e type; /* Way the event is reported. */
|
||||
union
|
||||
{
|
||||
psaddr_t bptaddr; /* Address of breakpoint. */
|
||||
int syscallno; /* Number of system call used. */
|
||||
} u;
|
||||
} td_notify_t;
|
||||
|
||||
/* Structure used to report event. */
|
||||
typedef struct td_event_msg
|
||||
{
|
||||
td_event_e event; /* Event type being reported. */
|
||||
const td_thrhandle_t *th_p; /* Thread reporting the event. */
|
||||
union
|
||||
{
|
||||
# if 0
|
||||
td_synchandle_t *sh; /* Handle of synchronization object. */
|
||||
#endif
|
||||
uintptr_t data; /* Event specific data. */
|
||||
} msg;
|
||||
} td_event_msg_t;
|
||||
|
||||
|
||||
/* Gathered statistics about the process. */
|
||||
typedef struct td_ta_stats
|
||||
{
|
||||
int nthreads; /* Total number of threads in use. */
|
||||
int r_concurrency; /* Concurrency level requested by user. */
|
||||
int nrunnable_num; /* Average runnable threads, numerator. */
|
||||
int nrunnable_den; /* Average runnable threads, denominator. */
|
||||
int a_concurrency_num; /* Achieved concurrency level, numerator. */
|
||||
int a_concurrency_den; /* Achieved concurrency level, denominator. */
|
||||
int nlwps_num; /* Average number of processes in use,
|
||||
numerator. */
|
||||
int nlwps_den; /* Average number of processes in use,
|
||||
denominator. */
|
||||
int nidle_num; /* Average number of idling processes,
|
||||
numerator. */
|
||||
int nidle_den; /* Average number of idling processes,
|
||||
denominator. */
|
||||
} td_ta_stats_t;
|
||||
|
||||
|
||||
/* Since Sun's library is based on Solaris threads we have to define a few
|
||||
types to map them to POSIX threads. */
|
||||
typedef pthread_t thread_t;
|
||||
typedef pthread_key_t thread_key_t;
|
||||
|
||||
/* Linux has different names for the register set types. */
|
||||
/*typedef gregset_t prgregset_t;*/
|
||||
/*typedef fpregset_t prfpregset_t;*/
|
||||
|
||||
|
||||
/* Callback for iteration over threads. */
|
||||
typedef int td_thr_iter_f __P ((const td_thrhandle_t *, void *));
|
||||
|
||||
/* Callback for iteration over thread local data. */
|
||||
typedef int td_key_iter_f __P ((thread_key_t, void (*) (void *), void *));
|
||||
|
||||
|
||||
|
||||
/* Forward declaration. This has to be defined by the user. */
|
||||
struct ps_prochandle;
|
||||
|
||||
/* We don't have any differences between processes and threads, therefore
|
||||
have only one PID type. */
|
||||
/*typedef pid_t lwpid_t;*/
|
||||
|
||||
|
||||
/* Information about the thread. */
|
||||
typedef struct td_thrinfo
|
||||
{
|
||||
td_thragent_t *ti_ta_p; /* Process handle. */
|
||||
unsigned int ti_user_flags; /* Unused. */
|
||||
thread_t ti_tid; /* Thread ID returned by
|
||||
pthread_create(). */
|
||||
char *ti_tls; /* Pointer to thread-local data. */
|
||||
psaddr_t ti_startfunc; /* Start function passed to
|
||||
pthread_create(). */
|
||||
psaddr_t ti_stkbase; /* Base of thread's stack. */
|
||||
long int ti_stksize; /* Size of thread's stack. */
|
||||
psaddr_t ti_ro_area; /* Unused. */
|
||||
int ti_ro_size; /* Unused. */
|
||||
td_thr_state_e ti_state; /* Thread state. */
|
||||
unsigned char ti_db_suspended; /* Nonzero if suspended by debugger. */
|
||||
td_thr_type_e ti_type; /* Type of the thread (system vs
|
||||
user thread). */
|
||||
intptr_t ti_pc; /* Unused. */
|
||||
intptr_t ti_sp; /* Unused. */
|
||||
short int ti_flags; /* Unused. */
|
||||
int ti_pri; /* Thread priority. */
|
||||
lwpid_t ti_lid; /* Unused. */
|
||||
sigset_t ti_sigmask; /* Signal mask. */
|
||||
unsigned char ti_traceme; /* Nonzero if event reporting
|
||||
enabled. */
|
||||
unsigned char ti_preemptflag; /* Unused. */
|
||||
unsigned char ti_pirecflag; /* Unused. */
|
||||
sigset_t ti_pending; /* Set of pending signals. */
|
||||
td_thr_events_t ti_events; /* Set of enabled events. */
|
||||
} td_thrinfo_t;
|
||||
|
||||
|
||||
|
||||
/* Prototypes for exported library functions. */
|
||||
|
||||
/* Initialize the thread debug support library. */
|
||||
extern td_err_e td_init (void);
|
||||
|
||||
/* Historical relict. Should not be used anymore. */
|
||||
extern td_err_e td_log (void);
|
||||
|
||||
/* Generate new thread debug library handle for process PS. */
|
||||
extern td_err_e td_ta_new (struct ps_prochandle *__ps, td_thragent_t **__ta);
|
||||
|
||||
/* Free resources allocated for TA. */
|
||||
extern td_err_e td_ta_delete (td_thragent_t *__ta);
|
||||
|
||||
/* Get number of currently running threads in process associated with TA. */
|
||||
extern td_err_e td_ta_get_nthreads (const td_thragent_t *__ta, int *__np);
|
||||
|
||||
/* Return process handle passed in `td_ta_new' for process associated with
|
||||
TA. */
|
||||
extern td_err_e td_ta_get_ph (const td_thragent_t *__ta,
|
||||
struct ps_prochandle **__ph);
|
||||
|
||||
/* Map thread library handle PT to thread debug library handle for process
|
||||
associated with TA and store result in *TH. */
|
||||
extern td_err_e td_ta_map_id2thr (const td_thragent_t *__ta, pthread_t __pt,
|
||||
td_thrhandle_t *__th);
|
||||
|
||||
/* Map process ID LWPID to thread debug library handle for process
|
||||
associated with TA and store result in *TH. */
|
||||
extern td_err_e td_ta_map_lwp2thr (const td_thragent_t *__ta, lwpid_t __lwpid,
|
||||
td_thrhandle_t *__th);
|
||||
|
||||
|
||||
/* Call for each thread in a process associated with TA the callback function
|
||||
CALLBACK. */
|
||||
extern td_err_e td_ta_thr_iter (const td_thragent_t *__ta,
|
||||
td_thr_iter_f *__callback, void *__cbdata_p,
|
||||
td_thr_state_e __state, int __ti_pri,
|
||||
sigset_t *__ti_sigmask_p,
|
||||
unsigned int __ti_user_flags);
|
||||
|
||||
/* Call for each defined thread local data entry the callback function KI. */
|
||||
extern td_err_e td_ta_tsd_iter (const td_thragent_t *__ta, td_key_iter_f *__ki,
|
||||
void *__p);
|
||||
|
||||
|
||||
/* Get event address for EVENT. */
|
||||
extern td_err_e td_ta_event_addr (const td_thragent_t *__ta,
|
||||
td_event_e __event, td_notify_t *__ptr);
|
||||
|
||||
|
||||
/* Set suggested concurrency level for process associated with TA. */
|
||||
extern td_err_e td_ta_setconcurrency (const td_thragent_t *__ta, int __level);
|
||||
|
||||
|
||||
/* Enable collecting statistics for process associated with TA. */
|
||||
extern td_err_e td_ta_enable_stats (const td_thragent_t *__ta, int __enable);
|
||||
|
||||
/* Reset statistics. */
|
||||
extern td_err_e td_ta_reset_stats (const td_thragent_t *__ta);
|
||||
|
||||
/* Retrieve statistics from process associated with TA. */
|
||||
extern td_err_e td_ta_get_stats (const td_thragent_t *__ta,
|
||||
td_ta_stats_t *__statsp);
|
||||
|
||||
|
||||
/* Validate that TH is a thread handle. */
|
||||
extern td_err_e td_thr_validate (const td_thrhandle_t *__th);
|
||||
|
||||
/* Return information about thread TH. */
|
||||
extern td_err_e td_thr_get_info (const td_thrhandle_t *__th,
|
||||
td_thrinfo_t *__infop);
|
||||
|
||||
/* Retrieve floating-point register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_getfpregs (const td_thrhandle_t *__th,
|
||||
prfpregset_t *__regset);
|
||||
|
||||
/* Retrieve general register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_getgregs (const td_thrhandle_t *__th,
|
||||
prgregset_t __gregs);
|
||||
|
||||
/* Retrieve extended register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_getxregs (const td_thrhandle_t *__th, void *__xregs);
|
||||
|
||||
/* Get size of extended register set of process running thread TH. */
|
||||
extern td_err_e td_thr_getxregsize (const td_thrhandle_t *__th, int *__sizep);
|
||||
|
||||
/* Set floating-point register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_setfpregs (const td_thrhandle_t *__th,
|
||||
const prfpregset_t *__fpregs);
|
||||
|
||||
/* Set general register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_setgregs (const td_thrhandle_t *__th,
|
||||
prgregset_t __gregs);
|
||||
|
||||
/* Set extended register contents of process running thread TH. */
|
||||
extern td_err_e td_thr_setxregs (const td_thrhandle_t *__th,
|
||||
const void *__addr);
|
||||
|
||||
|
||||
/* Enable reporting for EVENT for thread TH. */
|
||||
extern td_err_e td_thr_event_enable (const td_thrhandle_t *__th, int __event);
|
||||
|
||||
/* Enable EVENT for thread TH. */
|
||||
extern td_err_e td_thr_set_event (const td_thrhandle_t *__th,
|
||||
td_thr_events_t *__event);
|
||||
|
||||
/* Disable EVENT for thread TH. */
|
||||
extern td_err_e td_thr_clear_event (const td_thrhandle_t *__th,
|
||||
td_thr_events_t *__event);
|
||||
|
||||
/* Get event message for thread TH. */
|
||||
extern td_err_e td_thr_event_getmsg (const td_thrhandle_t *__th,
|
||||
td_event_msg_t *__msg);
|
||||
|
||||
|
||||
/* Set priority of thread TH. */
|
||||
extern td_err_e td_thr_setprio (const td_thrhandle_t *__th, int __prio);
|
||||
|
||||
|
||||
/* Set pending signals for thread TH. */
|
||||
extern td_err_e td_thr_setsigpending (const td_thrhandle_t *__th,
|
||||
unsigned char __n, const sigset_t *__ss);
|
||||
|
||||
/* Set signal mask for thread TH. */
|
||||
extern td_err_e td_thr_sigsetmask (const td_thrhandle_t *__th,
|
||||
const sigset_t *__ss);
|
||||
|
||||
|
||||
/* Return thread local data associated with key TK in thread TH. */
|
||||
extern td_err_e td_thr_tsd (const td_thrhandle_t *__th,
|
||||
const thread_key_t __tk, void **__data);
|
||||
|
||||
|
||||
/* Suspend execution of thread TH. */
|
||||
extern td_err_e td_thr_dbsuspend (const td_thrhandle_t *__th);
|
||||
|
||||
/* Resume execution of thread TH. */
|
||||
extern td_err_e td_thr_dbresume (const td_thrhandle_t *__th);
|
||||
|
||||
#endif /* thread_db.h */
|
|
@ -2415,6 +2415,35 @@ gnu_xfer_memory (memaddr, myaddr, len, write, target)
|
|||
}
|
||||
}
|
||||
|
||||
/* Return printable description of proc. */
|
||||
static char *
|
||||
proc_string (struct proc *proc)
|
||||
{
|
||||
static char tid_str[80];
|
||||
if (proc_is_task (proc))
|
||||
sprintf (tid_str, "process %d", proc->inf->pid);
|
||||
else
|
||||
sprintf (tid_str, "thread %d.%d",
|
||||
proc->inf->pid, pid_to_thread_id (proc->tid));
|
||||
return tid_str;
|
||||
}
|
||||
|
||||
static char *
|
||||
gnu_pid_to_str (int tid)
|
||||
{
|
||||
struct inf *inf = current_inferior;
|
||||
struct proc *thread = inf_tid_to_thread (inf, tid);
|
||||
|
||||
if (thread)
|
||||
return proc_string (thread);
|
||||
else
|
||||
{
|
||||
static char tid_str[80];
|
||||
sprintf (tid_str, "bogus thread id %d", tid);
|
||||
return tid_str;
|
||||
}
|
||||
}
|
||||
|
||||
extern void gnu_store_registers (int regno);
|
||||
extern void gnu_fetch_registers (int regno);
|
||||
|
||||
|
@ -2473,6 +2502,7 @@ init_gnu_ops (void)
|
|||
gnu_ops.to_can_run = gnu_can_run; /* to_can_run */
|
||||
gnu_ops.to_notice_signals = 0; /* to_notice_signals */
|
||||
gnu_ops.to_thread_alive = gnu_thread_alive; /* to_thread_alive */
|
||||
gnu_ops.to_pid_to_str = gnu_pid_to_str; /* to_pid_to_str */
|
||||
gnu_ops.to_stop = gnu_stop; /* to_stop */
|
||||
gnu_ops.to_pid_to_exec_file = gnu_pid_to_exec_file; /* to_pid_to_exec_file */
|
||||
gnu_ops.to_core_file_to_sym_file = NULL;
|
||||
|
@ -2488,35 +2518,6 @@ init_gnu_ops (void)
|
|||
gnu_ops.to_magic = OPS_MAGIC; /* to_magic */
|
||||
} /* init_gnu_ops */
|
||||
|
||||
/* Return printable description of proc. */
|
||||
char *
|
||||
proc_string (struct proc *proc)
|
||||
{
|
||||
static char tid_str[80];
|
||||
if (proc_is_task (proc))
|
||||
sprintf (tid_str, "process %d", proc->inf->pid);
|
||||
else
|
||||
sprintf (tid_str, "thread %d.%d",
|
||||
proc->inf->pid, pid_to_thread_id (proc->tid));
|
||||
return tid_str;
|
||||
}
|
||||
|
||||
char *
|
||||
gnu_target_pid_to_str (int tid)
|
||||
{
|
||||
struct inf *inf = current_inferior;
|
||||
struct proc *thread = inf_tid_to_thread (inf, tid);
|
||||
|
||||
if (thread)
|
||||
return proc_string (thread);
|
||||
else
|
||||
{
|
||||
static char tid_str[80];
|
||||
sprintf (tid_str, "bogus thread id %d", tid);
|
||||
return tid_str;
|
||||
}
|
||||
}
|
||||
|
||||
/* User task commands. */
|
||||
|
||||
struct cmd_list_element *set_task_cmd_list = 0;
|
||||
|
|
|
@ -99,7 +99,7 @@ trans_lang (in_lang)
|
|||
else if (in_lang == HP_LANGUAGE_CPLUSPLUS)
|
||||
return language_cplus;
|
||||
|
||||
else if (in_lang == HP_LANGUAGE_F77)
|
||||
else if (in_lang == HP_LANGUAGE_FORTRAN)
|
||||
return language_fortran;
|
||||
|
||||
else
|
||||
|
|
|
@ -438,7 +438,7 @@ child_post_follow_vfork (parent_pid, followed_parent, child_pid, followed_child)
|
|||
/* Format a process id, given PID. Be sure to terminate
|
||||
this with a null--it's going to be printed via a "%s". */
|
||||
char *
|
||||
hppa_pid_to_str (pid)
|
||||
child_pid_to_str (pid)
|
||||
pid_t pid;
|
||||
{
|
||||
/* Static because address returned */
|
||||
|
@ -658,7 +658,7 @@ hppa_pid_or_tid_to_str (id)
|
|||
pid_t id;
|
||||
{
|
||||
/* In the ptrace world, there are only processes. */
|
||||
return hppa_pid_to_str (id);
|
||||
return child_pid_to_str (id);
|
||||
}
|
||||
|
||||
/* This function has no meaning in a non-threaded world. Thus, we
|
||||
|
|
|
@ -34,6 +34,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||
#include <sys/reg.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some systems (Linux) may have threads implemented as pseudo-processes,
|
||||
* in which case we may be tracing more than one process at a time.
|
||||
* In that case, inferior_pid will contain the main process ID and the
|
||||
* individual thread (process) id mashed together. These macros are
|
||||
* used to separate them out. The definitions may be overridden in tm.h
|
||||
*/
|
||||
|
||||
#if !defined (PIDGET) /* Default definition for PIDGET/TIDGET. */
|
||||
#define PIDGET(PID) PID
|
||||
#define TIDGET(PID) 0
|
||||
#endif
|
||||
|
||||
/* This is a duplicate of the table in i386-xdep.c. */
|
||||
|
||||
static int regmap[] =
|
||||
|
@ -141,12 +154,12 @@ fill_gregset (gregset_t *gregsetp,
|
|||
/* Read the general registers from the process, and store them
|
||||
in registers[]. */
|
||||
static void
|
||||
fetch_regs ()
|
||||
fetch_regs (int tid)
|
||||
{
|
||||
int ret, regno;
|
||||
gregset_t buf;
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf);
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, (int) &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't get registers");
|
||||
|
@ -160,12 +173,12 @@ fetch_regs ()
|
|||
/* Set the inferior's general registers to the values in registers[]
|
||||
--- but only those registers marked as valid. */
|
||||
static void
|
||||
store_regs ()
|
||||
store_regs (int tid)
|
||||
{
|
||||
int ret, regno;
|
||||
gregset_t buf;
|
||||
|
||||
ret = ptrace (PTRACE_GETREGS, inferior_pid, 0, (int) &buf);
|
||||
ret = ptrace (PTRACE_GETREGS, tid, 0, (int) &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't get registers");
|
||||
|
@ -174,7 +187,7 @@ store_regs ()
|
|||
|
||||
convert_to_gregset (&buf, registers, register_valid);
|
||||
|
||||
ret = ptrace (PTRACE_SETREGS, inferior_pid, 0, (int)buf);
|
||||
ret = ptrace (PTRACE_SETREGS, tid, 0, (int)buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't write registers");
|
||||
|
@ -285,12 +298,12 @@ fill_fpregset (fpregset_t *fpregsetp,
|
|||
/* Get the whole floating point state of the process and store the
|
||||
floating point stack into registers[]. */
|
||||
static void
|
||||
fetch_fpregs ()
|
||||
fetch_fpregs (int tid)
|
||||
{
|
||||
int ret, regno;
|
||||
fpregset_t buf;
|
||||
|
||||
ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int) &buf);
|
||||
ret = ptrace (PTRACE_GETFPREGS, tid, 0, (int) &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't get floating point status");
|
||||
|
@ -306,12 +319,12 @@ fetch_fpregs ()
|
|||
/* Set the inferior's floating-point registers to the values in
|
||||
registers[] --- but only those registers marked valid. */
|
||||
static void
|
||||
store_fpregs ()
|
||||
store_fpregs (int tid)
|
||||
{
|
||||
int ret;
|
||||
fpregset_t buf;
|
||||
|
||||
ret = ptrace (PTRACE_GETFPREGS, inferior_pid, 0, (int) &buf);
|
||||
ret = ptrace (PTRACE_GETFPREGS, tid, 0, (int) &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't get floating point status");
|
||||
|
@ -320,7 +333,7 @@ store_fpregs ()
|
|||
|
||||
convert_to_fpregset (&buf, registers, register_valid);
|
||||
|
||||
ret = ptrace (PTRACE_SETFPREGS, inferior_pid, 0, (int) &buf);
|
||||
ret = ptrace (PTRACE_SETFPREGS, tid, 0, (int) &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
warning ("Couldn't write floating point status");
|
||||
|
@ -427,7 +440,7 @@ convert_to_xfpregset (struct user_xfpregs_struct *xfpregs,
|
|||
/* Make a PTRACE_GETXFPREGS request, and supply all the register
|
||||
values that yields to GDB. */
|
||||
static int
|
||||
fetch_xfpregs ()
|
||||
fetch_xfpregs (int tid)
|
||||
{
|
||||
int ret;
|
||||
struct user_xfpregs_struct xfpregs;
|
||||
|
@ -435,7 +448,7 @@ fetch_xfpregs ()
|
|||
if (! have_ptrace_getxfpregs)
|
||||
return 0;
|
||||
|
||||
ret = ptrace (PTRACE_GETXFPREGS, inferior_pid, 0, &xfpregs);
|
||||
ret = ptrace (PTRACE_GETXFPREGS, tid, 0, &xfpregs);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno == EIO)
|
||||
|
@ -456,7 +469,7 @@ fetch_xfpregs ()
|
|||
/* Send all the valid register values in GDB's register file covered
|
||||
by the PTRACE_SETXFPREGS request to the inferior. */
|
||||
static int
|
||||
store_xfpregs ()
|
||||
store_xfpregs (int tid)
|
||||
{
|
||||
int ret;
|
||||
struct user_xfpregs_struct xfpregs;
|
||||
|
@ -464,7 +477,7 @@ store_xfpregs ()
|
|||
if (! have_ptrace_getxfpregs)
|
||||
return 0;
|
||||
|
||||
ret = ptrace (PTRACE_GETXFPREGS, inferior_pid, 0, &xfpregs);
|
||||
ret = ptrace (PTRACE_GETXFPREGS, tid, 0, &xfpregs);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno == EIO)
|
||||
|
@ -479,7 +492,7 @@ store_xfpregs ()
|
|||
|
||||
convert_to_xfpregset (&xfpregs, registers, register_valid);
|
||||
|
||||
if (ptrace (PTRACE_SETXFPREGS, inferior_pid, 0, &xfpregs) < 0)
|
||||
if (ptrace (PTRACE_SETXFPREGS, tid, 0, &xfpregs) < 0)
|
||||
{
|
||||
warning ("Couldn't write floating-point and SSE registers.");
|
||||
return 0;
|
||||
|
@ -511,8 +524,8 @@ dummy_sse_values ()
|
|||
|
||||
/* Stub versions of the above routines, for systems that don't have
|
||||
PTRACE_GETXFPREGS. */
|
||||
static int store_xfpregs () { return 0; }
|
||||
static int fetch_xfpregs () { return 0; }
|
||||
static int store_xfpregs (int tid) { return 0; }
|
||||
static int fetch_xfpregs (int tid) { return 0; }
|
||||
static void dummy_sse_values () {}
|
||||
|
||||
#endif
|
||||
|
@ -528,27 +541,33 @@ static void dummy_sse_values () {}
|
|||
void
|
||||
fetch_inferior_registers (int regno)
|
||||
{
|
||||
/* linux lwp id's are process id's */
|
||||
int tid;
|
||||
|
||||
if ((tid = TIDGET (inferior_pid)) == 0)
|
||||
tid = inferior_pid; /* not a threaded program */
|
||||
|
||||
/* Use the xfpregs requests whenever possible, since they transfer
|
||||
more registers in one system call, and we'll cache the results.
|
||||
But remember that fetch_xfpregs can fail, and return zero. */
|
||||
if (regno == -1)
|
||||
{
|
||||
fetch_regs ();
|
||||
if (fetch_xfpregs ())
|
||||
fetch_regs (tid);
|
||||
if (fetch_xfpregs (tid))
|
||||
return;
|
||||
fetch_fpregs ();
|
||||
fetch_fpregs (tid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GETREGS_SUPPLIES (regno))
|
||||
{
|
||||
fetch_regs ();
|
||||
fetch_regs (tid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GETXFPREGS_SUPPLIES (regno))
|
||||
{
|
||||
if (fetch_xfpregs ())
|
||||
if (fetch_xfpregs (tid))
|
||||
return;
|
||||
|
||||
/* Either our processor or our kernel doesn't support the SSE
|
||||
|
@ -557,7 +576,7 @@ fetch_inferior_registers (int regno)
|
|||
more graceful to handle differences in the register set using
|
||||
gdbarch. Until then, this will at least make things work
|
||||
plausibly. */
|
||||
fetch_fpregs ();
|
||||
fetch_fpregs (tid);
|
||||
dummy_sse_values ();
|
||||
return;
|
||||
}
|
||||
|
@ -577,32 +596,38 @@ void
|
|||
store_inferior_registers (regno)
|
||||
int regno;
|
||||
{
|
||||
/* linux lwp id's are process id's */
|
||||
int tid;
|
||||
|
||||
if ((tid = TIDGET (inferior_pid)) == 0)
|
||||
tid = inferior_pid; /* not a threaded program */
|
||||
|
||||
/* Use the xfpregs requests whenever possible, since they transfer
|
||||
more registers in one system call. But remember that
|
||||
fetch_xfpregs can fail, and return zero. */
|
||||
store_xfpregs can fail, and return zero. */
|
||||
if (regno == -1)
|
||||
{
|
||||
store_regs ();
|
||||
if (store_xfpregs ())
|
||||
store_regs (tid);
|
||||
if (store_xfpregs (tid))
|
||||
return;
|
||||
store_fpregs ();
|
||||
store_fpregs (tid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GETREGS_SUPPLIES (regno))
|
||||
{
|
||||
store_regs ();
|
||||
store_regs (tid);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GETXFPREGS_SUPPLIES (regno))
|
||||
{
|
||||
if (store_xfpregs ())
|
||||
if (store_xfpregs (tid))
|
||||
return;
|
||||
|
||||
/* Either our processor or our kernel doesn't support the SSE
|
||||
registers, so just write the FP registers in the traditional way. */
|
||||
store_fpregs ();
|
||||
store_fpregs (tid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -845,6 +845,7 @@ run_stack_dummy (addr, buffer)
|
|||
char *buffer;
|
||||
{
|
||||
struct cleanup *old_cleanups = make_cleanup (null_cleanup, 0);
|
||||
int saved_async = 0;
|
||||
|
||||
/* Now proceed, having reached the desired place. */
|
||||
clear_proceed_status ();
|
||||
|
@ -891,7 +892,15 @@ run_stack_dummy (addr, buffer)
|
|||
|
||||
disable_watchpoints_before_interactive_call_start ();
|
||||
proceed_to_finish = 1; /* We want stop_registers, please... */
|
||||
|
||||
if (target_can_async_p ())
|
||||
saved_async = target_async_mask (0);
|
||||
|
||||
proceed (addr, TARGET_SIGNAL_0, 0);
|
||||
|
||||
if (saved_async)
|
||||
target_async_mask (saved_async);
|
||||
|
||||
enable_watchpoints_after_interactive_call_stop ();
|
||||
|
||||
discard_cleanups (old_cleanups);
|
||||
|
|
|
@ -24,10 +24,18 @@
|
|||
#include "inferior.h"
|
||||
#include "target.h"
|
||||
#include "gdb_string.h"
|
||||
|
||||
#ifdef HAVE_WAIT_H
|
||||
#include <wait.h>
|
||||
#else
|
||||
#ifdef HAVE_SYS_WAIT_H
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
#include "wait.h" /* NOTE: This is ../include/wait.h */
|
||||
#endif
|
||||
|
||||
/* "wait.h" fills in the gaps left by <wait.h> */
|
||||
#include "wait.h" /* NOTE: This is ../include/wait.h */
|
||||
|
||||
#include "command.h"
|
||||
|
||||
#ifdef USG
|
||||
|
@ -109,6 +117,22 @@ static void fetch_register PARAMS ((int));
|
|||
static void store_register PARAMS ((int));
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some systems (Linux) may have threads implemented as pseudo-processes,
|
||||
* in which case we may be tracing more than one process at a time.
|
||||
* In that case, inferior_pid will contain the main process ID and the
|
||||
* individual thread (process) id mashed together. These macros are
|
||||
* used to separate them out. The definitions may be overridden in tm.h
|
||||
*
|
||||
* NOTE: default definitions here are for systems with no threads.
|
||||
* Useful definitions MUST be provided in tm.h
|
||||
*/
|
||||
|
||||
#if !defined (PIDGET) /* Default definition for PIDGET/TIDGET. */
|
||||
#define PIDGET(PID) PID
|
||||
#define TIDGET(PID) 0
|
||||
#endif
|
||||
|
||||
void _initialize_kernel_u_addr PARAMS ((void));
|
||||
void _initialize_infptrace PARAMS ((void));
|
||||
|
||||
|
@ -135,14 +159,13 @@ call_ptrace (request, pid, addr, data)
|
|||
if (request == PT_SETTRC)
|
||||
{
|
||||
errno = 0;
|
||||
pt_status = ptrace (PT_SETTRC, pid, addr, data
|
||||
#if defined (FIVE_ARG_PTRACE)
|
||||
#if !defined (FIVE_ARG_PTRACE)
|
||||
pt_status = ptrace (PT_SETTRC, pid, addr, data);
|
||||
#else
|
||||
/* Deal with HPUX 8.0 braindamage. We never use the
|
||||
calls which require the fifth argument. */
|
||||
,0
|
||||
pt_status = ptrace (PT_SETTRC, pid, addr, data, 0);
|
||||
#endif
|
||||
);
|
||||
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
#if 0
|
||||
|
@ -173,13 +196,14 @@ call_ptrace (request, pid, addr, data)
|
|||
saved_errno = errno;
|
||||
errno = 0;
|
||||
#endif
|
||||
pt_status = ptrace (request, pid, addr, data
|
||||
#if defined (FIVE_ARG_PTRACE)
|
||||
#if !defined (FIVE_ARG_PTRACE)
|
||||
pt_status = ptrace (request, pid, addr, data);
|
||||
#else
|
||||
/* Deal with HPUX 8.0 braindamage. We never use the
|
||||
calls which require the fifth argument. */
|
||||
,0
|
||||
pt_status = ptrace (request, pid, addr, data, 0);
|
||||
#endif
|
||||
);
|
||||
|
||||
#if 0
|
||||
if (errno)
|
||||
printf (" [errno = %d]", errno);
|
||||
|
@ -275,7 +299,9 @@ child_resume (pid, step, signal)
|
|||
target_signal_to_host (signal));
|
||||
|
||||
if (errno)
|
||||
perror_with_name ("ptrace");
|
||||
{
|
||||
perror_with_name ("ptrace");
|
||||
}
|
||||
}
|
||||
#endif /* CHILD_RESUME */
|
||||
|
||||
|
@ -368,6 +394,7 @@ fetch_register (regno)
|
|||
register int i;
|
||||
unsigned int offset; /* Offset of registers within the u area. */
|
||||
char buf[MAX_REGISTER_RAW_SIZE];
|
||||
int tid;
|
||||
|
||||
if (CANNOT_FETCH_REGISTER (regno))
|
||||
{
|
||||
|
@ -376,18 +403,23 @@ fetch_register (regno)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Overload thread id onto process id */
|
||||
if ((tid = TIDGET (inferior_pid)) == 0)
|
||||
tid = inferior_pid; /* no thread id, just use process id */
|
||||
|
||||
offset = U_REGS_OFFSET;
|
||||
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
|
||||
{
|
||||
errno = 0;
|
||||
*(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, inferior_pid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
*(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid,
|
||||
(PTRACE_ARG3_TYPE) regaddr, 0);
|
||||
regaddr += sizeof (PTRACE_XFER_TYPE);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (mess, "reading register %s (#%d)", REGISTER_NAME (regno), regno);
|
||||
sprintf (mess, "reading register %s (#%d)",
|
||||
REGISTER_NAME (regno), regno);
|
||||
perror_with_name (mess);
|
||||
}
|
||||
}
|
||||
|
@ -432,24 +464,30 @@ store_register (regno)
|
|||
char mess[128]; /* For messages */
|
||||
register int i;
|
||||
unsigned int offset; /* Offset of registers within the u area. */
|
||||
int tid;
|
||||
|
||||
if (CANNOT_STORE_REGISTER (regno))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Overload thread id onto process id */
|
||||
if ((tid = TIDGET (inferior_pid)) == 0)
|
||||
tid = inferior_pid; /* no thread id, just use process id */
|
||||
|
||||
offset = U_REGS_OFFSET;
|
||||
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
|
||||
ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr,
|
||||
*(PTRACE_XFER_TYPE *) & registers[REGISTER_BYTE (regno) + i]);
|
||||
regaddr += sizeof (PTRACE_XFER_TYPE);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (mess, "writing register %s (#%d)", REGISTER_NAME (regno), regno);
|
||||
sprintf (mess, "writing register %s (#%d)",
|
||||
REGISTER_NAME (regno), regno);
|
||||
perror_with_name (mess);
|
||||
}
|
||||
}
|
||||
|
@ -520,14 +558,14 @@ child_xfer_memory (memaddr, myaddr, len, write, target)
|
|||
if (addr != memaddr || len < (int) sizeof (PTRACE_XFER_TYPE))
|
||||
{
|
||||
/* Need part of initial word -- fetch it. */
|
||||
buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
|
||||
0);
|
||||
buffer[0] = ptrace (PT_READ_I, PIDGET (inferior_pid),
|
||||
(PTRACE_ARG3_TYPE) addr, 0);
|
||||
}
|
||||
|
||||
if (count > 1) /* FIXME, avoid if even boundary */
|
||||
{
|
||||
buffer[count - 1]
|
||||
= ptrace (PT_READ_I, inferior_pid,
|
||||
= ptrace (PT_READ_I, PIDGET (inferior_pid),
|
||||
((PTRACE_ARG3_TYPE)
|
||||
(addr + (count - 1) * sizeof (PTRACE_XFER_TYPE))),
|
||||
0);
|
||||
|
@ -544,15 +582,15 @@ child_xfer_memory (memaddr, myaddr, len, write, target)
|
|||
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr,
|
||||
buffer[i]);
|
||||
ptrace (PT_WRITE_D, PIDGET (inferior_pid),
|
||||
(PTRACE_ARG3_TYPE) addr, buffer[i]);
|
||||
if (errno)
|
||||
{
|
||||
/* Using the appropriate one (I or D) is necessary for
|
||||
Gould NP1, at least. */
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
|
||||
buffer[i]);
|
||||
ptrace (PT_WRITE_I, PIDGET (inferior_pid),
|
||||
(PTRACE_ARG3_TYPE) addr, buffer[i]);
|
||||
}
|
||||
if (errno)
|
||||
return 0;
|
||||
|
@ -567,7 +605,7 @@ child_xfer_memory (memaddr, myaddr, len, write, target)
|
|||
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
|
||||
{
|
||||
errno = 0;
|
||||
buffer[i] = ptrace (PT_READ_I, inferior_pid,
|
||||
buffer[i] = ptrace (PT_READ_I, PIDGET (inferior_pid),
|
||||
(PTRACE_ARG3_TYPE) addr, 0);
|
||||
if (errno)
|
||||
return 0;
|
||||
|
|
|
@ -814,6 +814,14 @@ child_core_file_to_sym_file (core)
|
|||
}
|
||||
|
||||
|
||||
#if !defined(CHILD_PID_TO_STR)
|
||||
char *
|
||||
child_pid_to_str (pid)
|
||||
int pid;
|
||||
{
|
||||
return normal_pid_to_str (pid);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
init_child_ops ()
|
||||
|
@ -865,6 +873,7 @@ init_child_ops ()
|
|||
child_ops.to_mourn_inferior = child_mourn_inferior;
|
||||
child_ops.to_can_run = child_can_run;
|
||||
child_ops.to_thread_alive = child_thread_alive;
|
||||
child_ops.to_pid_to_str = child_pid_to_str;
|
||||
child_ops.to_stop = child_stop;
|
||||
child_ops.to_enable_exception_callback = child_enable_exception_callback;
|
||||
child_ops.to_get_current_exception_event = child_get_current_exception_event;
|
||||
|
|
|
@ -5773,7 +5773,7 @@ hppa_pid_or_tid_to_str (id)
|
|||
|
||||
/* Does this appear to be a process? If so, print it that way. */
|
||||
if (is_process_id (id))
|
||||
return hppa_pid_to_str (id);
|
||||
return child_pid_to_str (id);
|
||||
|
||||
/* Else, print both the GDB thread number and the system thread id. */
|
||||
sprintf (buf, "thread %d (", pid_to_thread_id (id));
|
||||
|
|
|
@ -1578,12 +1578,11 @@ _initialize_language ()
|
|||
add_language (&auto_language_defn);
|
||||
|
||||
language = savestring ("auto", strlen ("auto"));
|
||||
range = savestring ("auto", strlen ("auto"));
|
||||
type = savestring ("auto", strlen ("auto"));
|
||||
|
||||
/* Have the above take effect */
|
||||
|
||||
set_language_command (language, 0);
|
||||
|
||||
type = savestring ("auto", strlen ("auto"));
|
||||
set_type_command (NULL, 0);
|
||||
|
||||
range = savestring ("auto", strlen ("auto"));
|
||||
set_range_command (NULL, 0);
|
||||
}
|
||||
|
|
2140
gdb/lin-thread.c
Normal file
2140
gdb/lin-thread.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -115,7 +115,7 @@ static int *linuxthreads_wait_status; /* wait array of status */
|
|||
static int linuxthreads_wait_last; /* index of last valid elt in
|
||||
linuxthreads_wait_{pid,status} */
|
||||
|
||||
static sigset_t linuxthreads_wait_mask; /* sigset with SIGCHLD */
|
||||
static sigset_t linuxthreads_block_mask; /* sigset without SIGCHLD */
|
||||
|
||||
static int linuxthreads_step_pid; /* current stepped pid */
|
||||
static int linuxthreads_step_signo; /* current stepped target signal */
|
||||
|
@ -170,6 +170,13 @@ struct linuxthreads_signal linuxthreads_sig_debug = {
|
|||
"__pthread_sig_debug", 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* Set by thread_db module when it takes over the thread_stratum.
|
||||
In that case we must:
|
||||
a) refrain from turning on the debug signal, and
|
||||
b) refrain from calling add_thread. */
|
||||
|
||||
int using_thread_db = 0;
|
||||
|
||||
/* A table of breakpoint locations, one per PID. */
|
||||
static struct linuxthreads_breakpoint {
|
||||
CORE_ADDR pc; /* PC of breakpoint */
|
||||
|
@ -292,23 +299,37 @@ linuxthreads_find_trap (pid, stop)
|
|||
{
|
||||
/* Make sure that we'll find what we're looking for. */
|
||||
if (!found_trap)
|
||||
kill (pid, SIGTRAP);
|
||||
{
|
||||
kill (pid, SIGTRAP);
|
||||
}
|
||||
if (!found_stop)
|
||||
kill (pid, SIGSTOP);
|
||||
{
|
||||
kill (pid, SIGSTOP);
|
||||
}
|
||||
}
|
||||
|
||||
/* Catch all status until SIGTRAP and optionally SIGSTOP show up. */
|
||||
for (;;)
|
||||
{
|
||||
/* resume the child every time... */
|
||||
child_resume (pid, 1, TARGET_SIGNAL_0);
|
||||
|
||||
/* loop as long as errno == EINTR:
|
||||
waitpid syscall may be aborted due to GDB receiving a signal.
|
||||
FIXME: EINTR handling should no longer be necessary here, since
|
||||
we now block SIGCHLD except in an explicit sigsuspend call. */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
rpid = waitpid (pid, &status, __WCLONE);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* There are a few reasons the wait call above may have
|
||||
failed. If the thread manager dies, its children get
|
||||
|
@ -320,9 +341,11 @@ linuxthreads_find_trap (pid, stop)
|
|||
2.0.36. */
|
||||
rpid = waitpid (pid, &status, 0);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (errno != EINTR)
|
||||
perror_with_name ("waitpid");
|
||||
perror_with_name ("find_trap/waitpid");
|
||||
}
|
||||
|
||||
if (!WIFSTOPPED(status)) /* Thread has died */
|
||||
|
@ -347,7 +370,9 @@ linuxthreads_find_trap (pid, stop)
|
|||
/* Resend any other signals we noticed to the thread, to be received
|
||||
when we continue it. */
|
||||
while (--last >= 0)
|
||||
kill (pid, WSTOPSIG(wstatus[last]));
|
||||
{
|
||||
kill (pid, WSTOPSIG(wstatus[last]));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -357,15 +382,22 @@ static void
|
|||
restore_inferior_pid (arg)
|
||||
void *arg;
|
||||
{
|
||||
int pid = (int) arg;
|
||||
inferior_pid = pid;
|
||||
#if TARGET_PTR_BIT > TARGET_INT_BIT
|
||||
inferior_pid = (int) ((long) arg);
|
||||
#else
|
||||
inferior_pid = (int) arg;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Register a cleanup to restore the value of inferior_pid. */
|
||||
static struct cleanup *
|
||||
save_inferior_pid ()
|
||||
{
|
||||
#if TARGET_PTR_BIT > TARGET_INT_BIT
|
||||
return make_cleanup (restore_inferior_pid, (void *) ((long) inferior_pid));
|
||||
#else
|
||||
return make_cleanup (restore_inferior_pid, (void *) inferior_pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -476,8 +508,7 @@ check_signal_number (sig)
|
|||
sig->print = signal_print_update (target_signal_from_host (num), 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
void
|
||||
check_all_signal_numbers ()
|
||||
{
|
||||
/* If this isn't a LinuxThreads program, quit early. */
|
||||
|
@ -497,6 +528,7 @@ check_all_signal_numbers ()
|
|||
sact.sa_handler = sigchld_handler;
|
||||
sigemptyset(&sact.sa_mask);
|
||||
sact.sa_flags = 0;
|
||||
|
||||
if (linuxthreads_sig_debug.signal > 0)
|
||||
sigaction(linuxthreads_sig_cancel.signal, &sact, NULL);
|
||||
else
|
||||
|
@ -576,7 +608,6 @@ iterate_active_threads (func, all)
|
|||
(*func)(pid);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Insert a thread breakpoint at linuxthreads_breakpoint_addr.
|
||||
|
@ -640,9 +671,13 @@ kill_thread (pid)
|
|||
int pid;
|
||||
{
|
||||
if (in_thread_list (pid))
|
||||
ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
|
||||
{
|
||||
ptrace (PT_KILL, pid, (PTRACE_ARG3_TYPE) 0, 0);
|
||||
}
|
||||
else
|
||||
kill (pid, SIGKILL);
|
||||
{
|
||||
kill (pid, SIGKILL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Resume a thread */
|
||||
|
@ -655,9 +690,13 @@ resume_thread (pid)
|
|||
&& linuxthreads_thread_alive (pid))
|
||||
{
|
||||
if (pid == linuxthreads_step_pid)
|
||||
child_resume (pid, 1, linuxthreads_step_signo);
|
||||
{
|
||||
child_resume (pid, 1, linuxthreads_step_signo);
|
||||
}
|
||||
else
|
||||
child_resume (pid, 0, TARGET_SIGNAL_0);
|
||||
{
|
||||
child_resume (pid, 0, TARGET_SIGNAL_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -677,6 +716,15 @@ detach_thread (pid)
|
|||
}
|
||||
}
|
||||
|
||||
/* Attach a thread */
|
||||
void
|
||||
attach_thread (pid)
|
||||
int pid;
|
||||
{
|
||||
if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) != 0)
|
||||
perror_with_name ("attach_thread");
|
||||
}
|
||||
|
||||
/* Stop a thread */
|
||||
static void
|
||||
stop_thread (pid)
|
||||
|
@ -685,17 +733,21 @@ stop_thread (pid)
|
|||
if (pid != inferior_pid)
|
||||
{
|
||||
if (in_thread_list (pid))
|
||||
kill (pid, SIGSTOP);
|
||||
{
|
||||
kill (pid, SIGSTOP);
|
||||
}
|
||||
else if (ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0) == 0)
|
||||
{
|
||||
if (!linuxthreads_attach_pending)
|
||||
printf_unfiltered ("[New %s]\n", target_pid_to_str (pid));
|
||||
printf_filtered ("[New %s]\n", target_pid_to_str (pid));
|
||||
add_thread (pid);
|
||||
if (linuxthreads_sig_debug.signal)
|
||||
/* After a new thread in glibc 2.1 signals gdb its existence,
|
||||
it suspends itself and wait for linuxthreads_sig_restart,
|
||||
now we can wake up it. */
|
||||
kill (pid, linuxthreads_sig_restart.signal);
|
||||
{
|
||||
/* After a new thread in glibc 2.1 signals gdb its existence,
|
||||
it suspends itself and wait for linuxthreads_sig_restart,
|
||||
now we can wake it up. */
|
||||
kill (pid, linuxthreads_sig_restart.signal);
|
||||
}
|
||||
}
|
||||
else
|
||||
perror_with_name ("ptrace in stop_thread");
|
||||
|
@ -712,14 +764,22 @@ wait_thread (pid)
|
|||
|
||||
if (pid != inferior_pid && in_thread_list (pid))
|
||||
{
|
||||
/* loop as long as errno == EINTR:
|
||||
waitpid syscall may be aborted if GDB receives a signal.
|
||||
FIXME: EINTR handling should no longer be necessary here, since
|
||||
we now block SIGCHLD except during an explicit sigsuspend call. */
|
||||
for (;;)
|
||||
{
|
||||
/* Get first pid status. */
|
||||
rpid = waitpid(pid, &status, __WCLONE);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* There are two reasons this might have failed:
|
||||
|
||||
|
@ -739,9 +799,11 @@ wait_thread (pid)
|
|||
didn't work. */
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (errno != EINTR && linuxthreads_thread_alive (pid))
|
||||
perror_with_name ("waitpid");
|
||||
perror_with_name ("wait_thread/waitpid");
|
||||
|
||||
/* the thread is dead. */
|
||||
return;
|
||||
|
@ -810,16 +872,17 @@ update_stop_threads (test_pid)
|
|||
if (!in_thread_list (test_pid))
|
||||
{
|
||||
if (!linuxthreads_attach_pending)
|
||||
printf_unfiltered ("[New %s]\n",
|
||||
target_pid_to_str (test_pid));
|
||||
printf_filtered ("[New %s]\n",
|
||||
target_pid_to_str (test_pid));
|
||||
add_thread (test_pid);
|
||||
if (linuxthreads_sig_debug.signal
|
||||
&& inferior_pid == test_pid)
|
||||
/* After a new thread in glibc 2.1 signals gdb its
|
||||
existence, it suspends itself and wait for
|
||||
linuxthreads_sig_restart, now we can wake up
|
||||
it. */
|
||||
kill (test_pid, linuxthreads_sig_restart.signal);
|
||||
{
|
||||
/* After a new thread in glibc 2.1 signals gdb its
|
||||
existence, it suspends itself and wait for
|
||||
linuxthreads_sig_restart, now we can wake it up. */
|
||||
kill (test_pid, linuxthreads_sig_restart.signal);
|
||||
}
|
||||
}
|
||||
}
|
||||
iterate_active_threads (stop_thread, 0);
|
||||
|
@ -851,6 +914,13 @@ linuxthreads_new_objfile (objfile)
|
|||
{
|
||||
struct minimal_symbol *ms;
|
||||
|
||||
/* Call predecessor on chain, if any.
|
||||
Calling the new module first allows it to dominate,
|
||||
if it finds its compatible libraries. */
|
||||
|
||||
if (target_new_objfile_chain)
|
||||
target_new_objfile_chain (objfile);
|
||||
|
||||
if (!objfile)
|
||||
{
|
||||
/* We're starting an entirely new executable, so we can no
|
||||
|
@ -989,19 +1059,21 @@ any thread other than the main thread.");
|
|||
linuxthreads_breakpoint_zombie = (struct linuxthreads_breakpoint *)
|
||||
xmalloc (sizeof (struct linuxthreads_breakpoint) * (linuxthreads_max + 1));
|
||||
|
||||
if (inferior_pid && !linuxthreads_attach_pending)
|
||||
if (inferior_pid &&
|
||||
!linuxthreads_attach_pending &&
|
||||
!using_thread_db) /* suppressed by thread_db module */
|
||||
{
|
||||
int on = 1;
|
||||
|
||||
target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
|
||||
linuxthreads_attach_pending = 1;
|
||||
update_stop_threads (inferior_pid);
|
||||
linuxthreads_attach_pending = 0;
|
||||
}
|
||||
|
||||
check_all_signal_numbers ();
|
||||
|
||||
quit:
|
||||
/* Call predecessor on chain, if any. */
|
||||
if (target_new_objfile_chain)
|
||||
target_new_objfile_chain (objfile);
|
||||
}
|
||||
|
||||
/* If we have switched threads from a one that stopped at breakpoint,
|
||||
|
@ -1147,7 +1219,9 @@ linuxthreads_resume (pid, step, signo)
|
|||
enum target_signal signo;
|
||||
{
|
||||
if (!linuxthreads_max || stop_soon_quietly || linuxthreads_manager_pid == 0)
|
||||
child_ops.to_resume (pid, step, signo);
|
||||
{
|
||||
child_ops.to_resume (pid, step, signo);
|
||||
}
|
||||
else
|
||||
{
|
||||
int rpid;
|
||||
|
@ -1208,11 +1282,69 @@ linuxthreads_resume (pid, step, signo)
|
|||
}
|
||||
|
||||
/* Resume initial thread. */
|
||||
/* [unles it has a wait event pending] */
|
||||
if (!linuxthreads_pending_status (rpid))
|
||||
child_ops.to_resume (rpid, step, signo);
|
||||
{
|
||||
child_ops.to_resume (rpid, step, signo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Abstract out the child_wait functionality. */
|
||||
int
|
||||
linux_child_wait (pid, rpid, status)
|
||||
int pid;
|
||||
int *rpid;
|
||||
int *status;
|
||||
{
|
||||
int save_errno;
|
||||
|
||||
/* Note: inftarg has these inside the loop. */
|
||||
set_sigint_trap (); /* Causes SIGINT to be passed on to the
|
||||
attached process. */
|
||||
set_sigio_trap ();
|
||||
|
||||
errno = save_errno = 0;
|
||||
for (;;)
|
||||
{
|
||||
errno = 0;
|
||||
*rpid = waitpid (pid, status, __WCLONE | WNOHANG);
|
||||
save_errno = errno;
|
||||
|
||||
if (*rpid > 0)
|
||||
{
|
||||
/* Got an event -- break out */
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR) /* interrupted by signal, try again */
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
*rpid = waitpid (pid, status, WNOHANG);
|
||||
if (*rpid > 0)
|
||||
{
|
||||
/* Got an event -- break out */
|
||||
break;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (errno != 0 && save_errno != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
sigsuspend(&linuxthreads_block_mask);
|
||||
}
|
||||
clear_sigio_trap ();
|
||||
clear_sigint_trap ();
|
||||
|
||||
return errno ? errno : save_errno;
|
||||
}
|
||||
|
||||
|
||||
/* Wait for any threads to stop. We may have to convert PID from a thread id
|
||||
to a LWP id, and vice versa on the way out. */
|
||||
|
||||
|
@ -1280,44 +1412,8 @@ linuxthreads_wait (pid, ourstatus)
|
|||
if (rpid == 0)
|
||||
{
|
||||
int save_errno;
|
||||
sigset_t omask;
|
||||
|
||||
set_sigint_trap(); /* Causes SIGINT to be passed on to the
|
||||
attached process. */
|
||||
set_sigio_trap ();
|
||||
|
||||
sigprocmask(SIG_BLOCK, &linuxthreads_wait_mask, &omask);
|
||||
for (;;)
|
||||
{
|
||||
rpid = waitpid (pid, &status, __WCLONE | WNOHANG);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
if (rpid == 0)
|
||||
save_errno = 0;
|
||||
else if (errno != EINTR)
|
||||
save_errno = errno;
|
||||
else
|
||||
continue;
|
||||
|
||||
rpid = waitpid (pid, &status, WNOHANG);
|
||||
if (rpid > 0)
|
||||
break;
|
||||
if (rpid < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else if (save_errno != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
sigsuspend(&omask);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &omask, NULL);
|
||||
|
||||
save_errno = errno;
|
||||
clear_sigio_trap ();
|
||||
|
||||
clear_sigint_trap();
|
||||
save_errno = linux_child_wait (pid, &rpid, &status);
|
||||
|
||||
if (rpid == -1)
|
||||
{
|
||||
|
@ -1338,15 +1434,19 @@ linuxthreads_wait (pid, ourstatus)
|
|||
}
|
||||
}
|
||||
|
||||
/* Signals arrive in any order. So get all signals until SIGTRAP
|
||||
and resend previous ones to be held after. */
|
||||
/* We have now gotten a new event from waitpid above. */
|
||||
|
||||
/* Signals arrive in any order. So get all signals until
|
||||
SIGTRAP and resend previous ones to be held after. */
|
||||
if (linuxthreads_max
|
||||
&& !linuxthreads_breakpoints_inserted
|
||||
&& WIFSTOPPED(status))
|
||||
if (WSTOPSIG(status) == SIGTRAP)
|
||||
{
|
||||
while (--last >= 0)
|
||||
kill (rpid, WSTOPSIG(wstatus[last]));
|
||||
{
|
||||
kill (rpid, WSTOPSIG(wstatus[last]));
|
||||
}
|
||||
|
||||
/* insert negative zombie breakpoint */
|
||||
for (i = 0; i <= linuxthreads_breakpoint_last; i++)
|
||||
|
@ -1368,7 +1468,9 @@ linuxthreads_wait (pid, ourstatus)
|
|||
if (wstatus[i] == status)
|
||||
break;
|
||||
if (i >= last)
|
||||
wstatus[last++] = status;
|
||||
{
|
||||
wstatus[last++] = status;
|
||||
}
|
||||
}
|
||||
child_resume (rpid, 1, TARGET_SIGNAL_0);
|
||||
continue;
|
||||
|
@ -1387,9 +1489,13 @@ linuxthreads_wait (pid, ourstatus)
|
|||
if (!linuxthreads_pending_status (rpid))
|
||||
{
|
||||
if (linuxthreads_step_pid == rpid)
|
||||
child_resume (rpid, 1, linuxthreads_step_signo);
|
||||
{
|
||||
child_resume (rpid, 1, linuxthreads_step_signo);
|
||||
}
|
||||
else
|
||||
child_resume (rpid, 0, TARGET_SIGNAL_0);
|
||||
{
|
||||
child_resume (rpid, 0, TARGET_SIGNAL_0);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -1433,9 +1539,13 @@ linuxthreads_wait (pid, ourstatus)
|
|||
write_pc_pid (linuxthreads_breakpoint_zombie[i].pc
|
||||
- DECR_PC_AFTER_BREAK, rpid);
|
||||
if (linuxthreads_step_pid == rpid)
|
||||
child_resume (rpid, 1, linuxthreads_step_signo);
|
||||
{
|
||||
child_resume (rpid, 1, linuxthreads_step_signo);
|
||||
}
|
||||
else
|
||||
child_resume (rpid, 0, TARGET_SIGNAL_0);
|
||||
{
|
||||
child_resume (rpid, 0, TARGET_SIGNAL_0);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1453,8 +1563,12 @@ linuxthreads_wait (pid, ourstatus)
|
|||
if (linuxthreads_attach_pending && !stop_soon_quietly)
|
||||
{
|
||||
int on = 1;
|
||||
target_write_memory (linuxthreads_debug, (char *)&on, sizeof (on));
|
||||
update_stop_threads (rpid);
|
||||
if (!using_thread_db)
|
||||
{
|
||||
target_write_memory (linuxthreads_debug,
|
||||
(char *) &on, sizeof (on));
|
||||
update_stop_threads (rpid);
|
||||
}
|
||||
linuxthreads_attach_pending = 0;
|
||||
}
|
||||
|
||||
|
@ -1496,6 +1610,19 @@ Use the \"file\" or \"exec-file\" command.");
|
|||
child_ops.to_create_inferior (exec_file, allargs, env);
|
||||
}
|
||||
|
||||
void
|
||||
linuxthreads_discard_global_state ()
|
||||
{
|
||||
linuxthreads_inferior_pid = 0;
|
||||
linuxthreads_breakpoint_pid = 0;
|
||||
linuxthreads_step_pid = 0;
|
||||
linuxthreads_step_signo = TARGET_SIGNAL_0;
|
||||
linuxthreads_manager_pid = 0;
|
||||
linuxthreads_initial_pid = 0;
|
||||
linuxthreads_attach_pending = 0;
|
||||
linuxthreads_max = 0;
|
||||
}
|
||||
|
||||
/* Clean up after the inferior dies. */
|
||||
|
||||
static void
|
||||
|
@ -1506,13 +1633,7 @@ linuxthreads_mourn_inferior ()
|
|||
int off = 0;
|
||||
target_write_memory (linuxthreads_debug, (char *)&off, sizeof (off));
|
||||
|
||||
linuxthreads_inferior_pid = 0;
|
||||
linuxthreads_breakpoint_pid = 0;
|
||||
linuxthreads_step_pid = 0;
|
||||
linuxthreads_step_signo = TARGET_SIGNAL_0;
|
||||
linuxthreads_manager_pid = 0;
|
||||
linuxthreads_initial_pid = 0;
|
||||
linuxthreads_attach_pending = 0;
|
||||
linuxthreads_discard_global_state ();
|
||||
init_thread_list(); /* Destroy thread info */
|
||||
}
|
||||
|
||||
|
@ -1566,12 +1687,18 @@ linuxthreads_kill ()
|
|||
|
||||
/* Wait for all threads. */
|
||||
do
|
||||
rpid = waitpid (-1, &status, __WCLONE | WNOHANG);
|
||||
{
|
||||
rpid = waitpid (-1, &status, __WCLONE | WNOHANG);
|
||||
}
|
||||
while (rpid > 0 || errno == EINTR);
|
||||
/* FIXME: should no longer need to handle EINTR here. */
|
||||
|
||||
do
|
||||
rpid = waitpid (-1, &status, WNOHANG);
|
||||
{
|
||||
rpid = waitpid (-1, &status, WNOHANG);
|
||||
}
|
||||
while (rpid > 0 || errno == EINTR);
|
||||
/* FIXME: should no longer need to handle EINTR here. */
|
||||
|
||||
linuxthreads_mourn_inferior ();
|
||||
}
|
||||
|
@ -1617,6 +1744,7 @@ linuxthreads_can_run ()
|
|||
{
|
||||
return child_suppress_run;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
init_linuxthreads_ops ()
|
||||
|
@ -1636,6 +1764,7 @@ init_linuxthreads_ops ()
|
|||
linuxthreads_ops.to_create_inferior = linuxthreads_create_inferior;
|
||||
linuxthreads_ops.to_mourn_inferior = linuxthreads_mourn_inferior;
|
||||
linuxthreads_ops.to_thread_alive = linuxthreads_thread_alive;
|
||||
linuxthreads_ops.to_pid_to_str = linuxthreads_pid_to_str;
|
||||
linuxthreads_ops.to_magic = OPS_MAGIC;
|
||||
}
|
||||
|
||||
|
@ -1643,6 +1772,7 @@ void
|
|||
_initialize_linuxthreads ()
|
||||
{
|
||||
struct sigaction sact;
|
||||
sigset_t linuxthreads_wait_mask; /* sigset with SIGCHLD */
|
||||
|
||||
init_linuxthreads_ops ();
|
||||
add_target (&linuxthreads_ops);
|
||||
|
@ -1664,4 +1794,10 @@ _initialize_linuxthreads ()
|
|||
/* initialize SIGCHLD mask */
|
||||
sigemptyset (&linuxthreads_wait_mask);
|
||||
sigaddset (&linuxthreads_wait_mask, SIGCHLD);
|
||||
|
||||
/* Use SIG_BLOCK to block receipt of SIGCHLD.
|
||||
The block_mask will allow us to wait for this signal explicitly. */
|
||||
sigprocmask(SIG_BLOCK,
|
||||
&linuxthreads_wait_mask,
|
||||
&linuxthreads_block_mask);
|
||||
}
|
||||
|
|
|
@ -774,7 +774,7 @@ child_resume (pid, step, signal)
|
|||
buffer. */
|
||||
|
||||
char *
|
||||
lynx_pid_to_str (pid)
|
||||
child_pid_to_str (pid)
|
||||
int pid;
|
||||
{
|
||||
static char buf[40];
|
||||
|
|
|
@ -2430,8 +2430,18 @@ mips_print_register (regnum, all)
|
|||
gdb_stdout, 0, 1, 0, Val_pretty_default);
|
||||
/* Else print as integer in hex. */
|
||||
else
|
||||
print_scalar_formatted (raw_buffer, REGISTER_VIRTUAL_TYPE (regnum),
|
||||
'x', 0, gdb_stdout);
|
||||
{
|
||||
int offset;
|
||||
|
||||
if (TARGET_BYTE_ORDER == BIG_ENDIAN)
|
||||
offset = REGISTER_RAW_SIZE (regnum) - REGISTER_VIRTUAL_SIZE (regnum);
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
print_scalar_formatted (raw_buffer + offset,
|
||||
REGISTER_VIRTUAL_TYPE (regnum),
|
||||
'x', 0, gdb_stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/* Replacement for generic do_registers_info.
|
||||
|
@ -3783,6 +3793,7 @@ mips_gdbarch_init (info, arches)
|
|||
switch (info.bfd_arch_info->mach)
|
||||
{
|
||||
case bfd_mach_mips4100:
|
||||
case bfd_mach_mips4111:
|
||||
tdep->mips_fpu_type = MIPS_FPU_NONE;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -5899,6 +5899,9 @@ init_procfs_ops ()
|
|||
procfs_ops.to_can_run = procfs_can_run;
|
||||
procfs_ops.to_notice_signals = procfs_notice_signals;
|
||||
procfs_ops.to_thread_alive = procfs_thread_alive;
|
||||
#ifdef TIDGET
|
||||
procfs_ops.to_pid_to_str = procfs_pid_to_str;
|
||||
#endif
|
||||
procfs_ops.to_stop = procfs_stop;
|
||||
procfs_ops.to_stratum = process_stratum;
|
||||
procfs_ops.to_has_all_memory = 1;
|
||||
|
|
20
gdb/remote.c
20
gdb/remote.c
|
@ -2137,7 +2137,7 @@ remote_async_detach (args, from_tty)
|
|||
remote_send (buf, PBUFSIZ);
|
||||
|
||||
/* Unregister the file descriptor from the event loop. */
|
||||
if (SERIAL_IS_ASYNC_P (remote_desc))
|
||||
if (target_is_async_p ())
|
||||
SERIAL_ASYNC (remote_desc, NULL, 0);
|
||||
|
||||
pop_target ();
|
||||
|
@ -2254,14 +2254,14 @@ remote_async_resume (pid, step, siggnal)
|
|||
/* FIXME: ezannoni 1999-09-28: We may need to move this out of here
|
||||
into infcmd.c in order to allow inferior function calls to work
|
||||
NOT asynchronously. */
|
||||
if (event_loop_p && SERIAL_CAN_ASYNC_P (remote_desc))
|
||||
if (event_loop_p && target_can_async_p ())
|
||||
target_async (inferior_event_handler, 0);
|
||||
/* Tell the world that the target is now executing. */
|
||||
/* FIXME: cagney/1999-09-23: Is it the targets responsibility to set
|
||||
this? Instead, should the client of target just assume (for
|
||||
async targets) that the target is going to start executing? Is
|
||||
this information already found in the continuation block? */
|
||||
if (SERIAL_IS_ASYNC_P (remote_desc))
|
||||
if (target_is_async_p ())
|
||||
target_executing = 1;
|
||||
putpkt (buf);
|
||||
}
|
||||
|
@ -2710,14 +2710,14 @@ remote_async_wait (pid, status)
|
|||
{
|
||||
unsigned char *p;
|
||||
|
||||
if (!SERIAL_IS_ASYNC_P (remote_desc))
|
||||
if (!target_is_async_p ())
|
||||
ofunc = signal (SIGINT, remote_interrupt);
|
||||
/* FIXME: cagney/1999-09-27: If we're in async mode we should
|
||||
_never_ wait for ever -> test on target_is_async_p().
|
||||
However, before we do that we need to ensure that the caller
|
||||
knows how to take the target into/out of async mode. */
|
||||
getpkt (buf, PBUFSIZ, wait_forever_enabled_p);
|
||||
if (!SERIAL_IS_ASYNC_P (remote_desc))
|
||||
if (!target_is_async_p ())
|
||||
signal (SIGINT, ofunc);
|
||||
|
||||
/* This is a hook for when we need to do something (perhaps the
|
||||
|
@ -4009,7 +4009,7 @@ static void
|
|||
remote_async_kill ()
|
||||
{
|
||||
/* Unregister the file descriptor from the event loop. */
|
||||
if (SERIAL_IS_ASYNC_P (remote_desc))
|
||||
if (target_is_async_p ())
|
||||
SERIAL_ASYNC (remote_desc, NULL, 0);
|
||||
|
||||
/* For some mysterious reason, wait_for_inferior calls kill instead of
|
||||
|
@ -5297,14 +5297,14 @@ static int
|
|||
remote_can_async_p (void)
|
||||
{
|
||||
/* We're async whenever the serial device is. */
|
||||
return SERIAL_CAN_ASYNC_P (remote_desc);
|
||||
return (current_target.to_async_mask_value) && SERIAL_CAN_ASYNC_P (remote_desc);
|
||||
}
|
||||
|
||||
static int
|
||||
remote_is_async_p (void)
|
||||
{
|
||||
/* We're async whenever the serial device is. */
|
||||
return SERIAL_IS_ASYNC_P (remote_desc);
|
||||
return (current_target.to_async_mask_value) && SERIAL_IS_ASYNC_P (remote_desc);
|
||||
}
|
||||
|
||||
/* Pass the SERIAL event on and up to the client. One day this code
|
||||
|
@ -5326,6 +5326,9 @@ remote_async_serial_handler (serial_t scb, void *context)
|
|||
static void
|
||||
remote_async (void (*callback) (enum inferior_event_type event_type, void *context), void *context)
|
||||
{
|
||||
if (current_target.to_async_mask_value == 0)
|
||||
internal_error ("Calling remote_async when async is masked");
|
||||
|
||||
if (callback != NULL)
|
||||
{
|
||||
SERIAL_ASYNC (remote_desc, remote_async_serial_handler, NULL);
|
||||
|
@ -5382,6 +5385,7 @@ Specify the serial device it is connected to (e.g. /dev/ttya).";
|
|||
remote_async_ops.to_can_async_p = remote_can_async_p;
|
||||
remote_async_ops.to_is_async_p = remote_is_async_p;
|
||||
remote_async_ops.to_async = remote_async;
|
||||
remote_async_ops.to_async_mask_value = 1;
|
||||
remote_async_ops.to_magic = OPS_MAGIC;
|
||||
}
|
||||
|
||||
|
|
|
@ -1609,6 +1609,7 @@ init_sol_thread_ops ()
|
|||
sol_thread_ops.to_can_run = sol_thread_can_run;
|
||||
sol_thread_ops.to_notice_signals = sol_thread_notice_signals;
|
||||
sol_thread_ops.to_thread_alive = sol_thread_alive;
|
||||
sol_thread_ops.to_pid_to_str = solaris_pid_to_str;
|
||||
sol_thread_ops.to_find_new_threads = sol_find_new_threads;
|
||||
sol_thread_ops.to_stop = sol_thread_stop;
|
||||
sol_thread_ops.to_stratum = process_stratum;
|
||||
|
@ -1659,6 +1660,7 @@ init_sol_core_ops ()
|
|||
sol_core_ops.to_has_registers = 1;
|
||||
sol_core_ops.to_has_execution = 0;
|
||||
sol_core_ops.to_has_thread_control = tc_none;
|
||||
sol_core_ops.to_pid_to_str = solaris_pid_to_str;
|
||||
sol_core_ops.to_sections = 0;
|
||||
sol_core_ops.to_sections_end = 0;
|
||||
sol_core_ops.to_magic = OPS_MAGIC;
|
||||
|
|
37
gdb/target.c
37
gdb/target.c
|
@ -78,7 +78,7 @@ static void
|
|||
target_command PARAMS ((char *, int));
|
||||
|
||||
static struct target_ops *
|
||||
find_default_run_target PARAMS ((char *));
|
||||
find_default_run_target PARAMS ((char *));
|
||||
|
||||
static void
|
||||
update_current_target PARAMS ((void));
|
||||
|
@ -536,6 +536,7 @@ update_current_target ()
|
|||
INHERIT (to_notice_signals, t);
|
||||
INHERIT (to_thread_alive, t);
|
||||
INHERIT (to_find_new_threads, t);
|
||||
INHERIT (to_pid_to_str, t);
|
||||
INHERIT (to_stop, t);
|
||||
INHERIT (to_query, t);
|
||||
INHERIT (to_rcmd, t);
|
||||
|
@ -556,6 +557,7 @@ update_current_target ()
|
|||
INHERIT (to_can_async_p, t);
|
||||
INHERIT (to_is_async_p, t);
|
||||
INHERIT (to_async, t);
|
||||
INHERIT (to_async_mask_value, t);
|
||||
INHERIT (to_magic, t);
|
||||
|
||||
#undef INHERIT
|
||||
|
@ -1046,6 +1048,14 @@ target_link (modname, t_reloc)
|
|||
*t_reloc = (CORE_ADDR) -1;
|
||||
}
|
||||
|
||||
int
|
||||
target_async_mask (int mask)
|
||||
{
|
||||
int saved_async_masked_status = target_async_mask_value;
|
||||
target_async_mask_value = mask;
|
||||
return saved_async_masked_status;
|
||||
}
|
||||
|
||||
/* Look through the list of possible targets for a target that can
|
||||
execute a run or attach command without any other data. This is
|
||||
used to locate the default process stratum.
|
||||
|
@ -1226,6 +1236,9 @@ find_run_target ()
|
|||
return (count == 1 ? runable : NULL);
|
||||
}
|
||||
|
||||
/* Find a single core_stratum target in the list of targets and return it.
|
||||
If for some reason there is more than one, return NULL. */
|
||||
|
||||
struct target_ops *
|
||||
find_core_target ()
|
||||
{
|
||||
|
@ -1247,6 +1260,27 @@ find_core_target ()
|
|||
|
||||
return (count == 1 ? runable : NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the next target down the stack from the specified target.
|
||||
*/
|
||||
|
||||
struct target_ops *
|
||||
find_target_beneath (t)
|
||||
struct target_ops *t;
|
||||
{
|
||||
struct target_stack_item *cur;
|
||||
|
||||
for (cur = target_stack; cur; cur = cur->next)
|
||||
if (cur->target_ops == t)
|
||||
break;
|
||||
|
||||
if (cur == NULL || cur->next == NULL)
|
||||
return NULL;
|
||||
else
|
||||
return cur->next->target_ops;
|
||||
}
|
||||
|
||||
|
||||
/* The inferior process has died. Long live the inferior! */
|
||||
|
||||
|
@ -2053,6 +2087,7 @@ init_dummy_target ()
|
|||
dummy_target.to_require_detach = find_default_require_detach;
|
||||
dummy_target.to_create_inferior = find_default_create_inferior;
|
||||
dummy_target.to_clone_and_follow_inferior = find_default_clone_and_follow_inferior;
|
||||
dummy_target.to_pid_to_str = normal_pid_to_str;
|
||||
dummy_target.to_stratum = dummy_stratum;
|
||||
dummy_target.to_magic = OPS_MAGIC;
|
||||
}
|
||||
|
|
62
gdb/target.h
62
gdb/target.h
|
@ -414,6 +414,7 @@ struct target_ops
|
|||
void (*to_notice_signals) PARAMS ((int pid));
|
||||
int (*to_thread_alive) PARAMS ((int pid));
|
||||
void (*to_find_new_threads) PARAMS ((void));
|
||||
char *(*to_pid_to_str) PARAMS ((int));
|
||||
void (*to_stop) PARAMS ((void));
|
||||
int (*to_query) PARAMS ((int /*char */ , char *, char *, int *));
|
||||
void (*to_rcmd) (char *command, struct gdb_file *output);
|
||||
|
@ -438,6 +439,7 @@ struct target_ops
|
|||
int (*to_can_async_p) (void);
|
||||
int (*to_is_async_p) (void);
|
||||
void (*to_async) (void (*cb) (enum inferior_event_type, void *context), void *context);
|
||||
int to_async_mask_value;
|
||||
int to_magic;
|
||||
/* Need sub-structure for target machine related rather than comm related? */
|
||||
};
|
||||
|
@ -597,7 +599,8 @@ target_detach PARAMS ((char *, int));
|
|||
#define target_prepare_to_store() \
|
||||
(*current_target.to_prepare_to_store) ()
|
||||
|
||||
extern int target_read_string PARAMS ((CORE_ADDR, char **, int, int *));
|
||||
extern int
|
||||
target_read_string PARAMS ((CORE_ADDR, char **, int, int *));
|
||||
|
||||
extern int
|
||||
target_read_memory PARAMS ((CORE_ADDR memaddr, char *myaddr, int len));
|
||||
|
@ -621,15 +624,17 @@ child_xfer_memory PARAMS ((CORE_ADDR, char *, int, int, struct target_ops *));
|
|||
of bytes actually transfered is not defined) and ERR is set to a
|
||||
non-zero error indication. */
|
||||
|
||||
extern int target_read_memory_partial (CORE_ADDR addr, char *buf, int len, int *err);
|
||||
extern int
|
||||
target_read_memory_partial (CORE_ADDR addr, char *buf, int len, int *err);
|
||||
|
||||
extern int target_write_memory_partial (CORE_ADDR addr, char *buf, int len, int *err);
|
||||
extern int
|
||||
target_write_memory_partial (CORE_ADDR addr, char *buf, int len, int *err);
|
||||
|
||||
extern char *
|
||||
child_pid_to_exec_file PARAMS ((int));
|
||||
child_pid_to_exec_file PARAMS ((int));
|
||||
|
||||
extern char *
|
||||
child_core_file_to_sym_file PARAMS ((char *));
|
||||
child_core_file_to_sym_file PARAMS ((char *));
|
||||
|
||||
#if defined(CHILD_POST_ATTACH)
|
||||
extern void
|
||||
|
@ -1060,24 +1065,41 @@ extern void target_load (char *arg, int from_tty);
|
|||
/* Put the target in async mode with the specified callback function. */
|
||||
#define target_async(CALLBACK,CONTEXT) (current_target.to_async((CALLBACK), (CONTEXT)))
|
||||
|
||||
/* This is to be used ONLY within run_stack_dummy(). It
|
||||
provides a workaround, to have inferior function calls done in
|
||||
sychronous mode, even though the target is asynchronous. After
|
||||
target_async_mask(0) is called, calls to target_can_async_p() will
|
||||
return FALSE , so that target_resume() will not try to start the
|
||||
target asynchronously. After the inferior stops, we IMMEDIATELY
|
||||
restore the previous nature of the target, by calling
|
||||
target_async_mask(1). After that, target_can_async_p() will return
|
||||
TRUE. ANY OTHER USE OF THIS FEATURE IS DEPRECATED.
|
||||
|
||||
FIXME ezannoni 1999-12-13: we won't need this once we move
|
||||
the turning async on and off to the single execution commands,
|
||||
from where it is done currently, in remote_resume().*/
|
||||
|
||||
#define target_async_mask_value \
|
||||
(current_target.to_async_mask_value)
|
||||
|
||||
extern int target_async_mask (int mask);
|
||||
|
||||
extern void target_link PARAMS ((char *, CORE_ADDR *));
|
||||
|
||||
/* Converts a process id to a string. Usually, the string just contains
|
||||
`process xyz', but on some systems it may contain
|
||||
`process xyz thread abc'. */
|
||||
|
||||
#ifndef target_pid_to_str
|
||||
#define target_pid_to_str(PID) \
|
||||
normal_pid_to_str (PID)
|
||||
extern char *normal_pid_to_str PARAMS ((int pid));
|
||||
#endif
|
||||
#undef target_pid_to_str
|
||||
#define target_pid_to_str(PID) current_target.to_pid_to_str (PID)
|
||||
|
||||
#ifndef target_tid_to_str
|
||||
#define target_tid_to_str(PID) \
|
||||
normal_pid_to_str (PID)
|
||||
target_pid_to_str (PID)
|
||||
extern char *normal_pid_to_str PARAMS ((int pid));
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* New Objfile Event Hook:
|
||||
*
|
||||
|
@ -1105,7 +1127,7 @@ extern void (*target_new_objfile_hook) PARAMS ((struct objfile *));
|
|||
|
||||
#ifndef target_pid_or_tid_to_str
|
||||
#define target_pid_or_tid_to_str(ID) \
|
||||
normal_pid_to_str (ID)
|
||||
target_pid_to_str (ID)
|
||||
#endif
|
||||
|
||||
/* Attempts to find the pathname of the executable file
|
||||
|
@ -1321,24 +1343,28 @@ noprocess PARAMS ((void));
|
|||
extern void
|
||||
find_default_attach PARAMS ((char *, int));
|
||||
|
||||
void
|
||||
extern void
|
||||
find_default_require_attach PARAMS ((char *, int));
|
||||
|
||||
void
|
||||
extern void
|
||||
find_default_require_detach PARAMS ((int, char *, int));
|
||||
|
||||
extern void
|
||||
find_default_create_inferior PARAMS ((char *, char *, char **));
|
||||
|
||||
void
|
||||
extern void
|
||||
find_default_clone_and_follow_inferior PARAMS ((int, int *));
|
||||
|
||||
extern struct target_ops *find_run_target PARAMS ((void));
|
||||
extern struct target_ops *
|
||||
find_run_target PARAMS ((void));
|
||||
|
||||
extern struct target_ops *
|
||||
find_core_target PARAMS ((void));
|
||||
find_core_target PARAMS ((void));
|
||||
|
||||
int
|
||||
extern struct target_ops *
|
||||
find_target_beneath PARAMS ((struct target_ops *));
|
||||
|
||||
extern int
|
||||
target_resize_to_sections PARAMS ((struct target_ops *target, int num_added));
|
||||
|
||||
/* Stuff that should be shared among the various remote targets. */
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
1999-12-13n Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
1999-12-16 Stan Shebs <shebs@andros.cygnus.com>
|
||||
|
||||
* gdb.base/default.exp: Match arm* etc instead of arm in "info
|
||||
float" test.
|
||||
|
||||
1999-12-13 Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* gdb.base/watchpoint.exp: Add missing "(timeout)" to test message.
|
||||
|
||||
1999-12-13n Fernando Nasser <fnasser@totem.to.cygnus.com>
|
||||
|
||||
* gdb.base/break.exp: Add missing anchor to reg exp on "finish from
|
||||
outermost frame disallowed".
|
||||
|
||||
|
|
|
@ -298,11 +298,11 @@ gdb_test "info frame" "No stack.|No selected frame." "info frame"
|
|||
#test info files
|
||||
gdb_test "info files" "" "info files"
|
||||
#test info float
|
||||
if [istarget "arm-*-*"] then {
|
||||
if [istarget "arm*-*-*"] then {
|
||||
gdb_test "info float" "Software FPU type.*mask:.*flags:.*" "info float"
|
||||
} elseif [istarget "thumb-*-*"] then {
|
||||
} elseif [istarget "thumb*-*-*"] then {
|
||||
gdb_test "info float" "Software FPU type.*mask:.*flags:.*" "info float"
|
||||
} elseif [istarget "strongarm-*-*"] then {
|
||||
} elseif [istarget "strongarm*-*-*"] then {
|
||||
gdb_test "info float" "Software FPU type.*mask:.*flags:.*" "info float"
|
||||
} elseif [istarget "i\[3456\]86-*-*"] then {
|
||||
gdb_test "info float" "R7:.*Status Word:.*Opcode:.*" "info float"
|
||||
|
|
|
@ -68,7 +68,7 @@ for {set i 0} {$i < 5} {incr i} {
|
|||
gdb_continue_to_breakpoint "about to create philosopher: $i"
|
||||
send_gdb "next\n"
|
||||
gdb_expect {
|
||||
-re "\\\[New Thread .*\\\].*$gdb_prompt $" {
|
||||
-re "\\\[New .*\\\].*$gdb_prompt $" {
|
||||
pass "create philosopher: $i"
|
||||
}
|
||||
-re "Program received signal.*(Unknown signal|SIGUSR).*$gdb_prompt $" {
|
||||
|
@ -90,7 +90,7 @@ for {set i 0} {$i < 5} {incr i} {
|
|||
# Run until there are some threads.
|
||||
gdb_breakpoint [gdb_get_line_number "linuxthreads.exp: info threads 2"]
|
||||
gdb_continue_to_breakpoint "main thread's sleep"
|
||||
gdb_test "info threads" "7 Thread .*6 Thread .*5 Thread .*4 Thread .*3 Thread .*2 Thread .* \\(initial thread\\) main \\(argc=1, argv=.*\\) at .*linux-dp.c:.*1 Thread .* \\(manager thread\\).*" "info threads 2"
|
||||
gdb_test "info threads" "7 Thread .*6 Thread .*5 Thread .*4 Thread .*3 Thread .*2 Thread .*1 Thread .*" "info threads 2"
|
||||
|
||||
# Try setting a thread-specific breakpoint.
|
||||
gdb_breakpoint "print_philosopher thread 5"
|
||||
|
|
17
gdb/utils.c
17
gdb/utils.c
|
@ -931,6 +931,12 @@ request_quit (signo)
|
|||
|
||||
#if !defined (USE_MMALLOC)
|
||||
|
||||
void *
|
||||
mcalloc (void *md, size_t number, size_t size)
|
||||
{
|
||||
return calloc (number, size);
|
||||
}
|
||||
|
||||
PTR
|
||||
mmalloc (md, size)
|
||||
PTR md;
|
||||
|
@ -1092,6 +1098,17 @@ xmalloc (size)
|
|||
return (xmmalloc ((PTR) NULL, size));
|
||||
}
|
||||
|
||||
/* Like calloc but get error if no storage available */
|
||||
|
||||
PTR
|
||||
xcalloc (size_t number, size_t size)
|
||||
{
|
||||
void *mem = mcalloc (NULL, number, size);
|
||||
if (mem == NULL)
|
||||
nomem (number * size);
|
||||
return mem;
|
||||
}
|
||||
|
||||
/* Like mrealloc but get error if no storage available. */
|
||||
|
||||
PTR
|
||||
|
|
|
@ -165,8 +165,11 @@ static const int mappings[] =
|
|||
context_offset (FloatSave.ErrorOffset),
|
||||
context_offset (FloatSave.DataSelector),
|
||||
context_offset (FloatSave.DataOffset),
|
||||
context_offset (FloatSave.ErrorSelector)
|
||||
};
|
||||
|
||||
#undef context_offset
|
||||
|
||||
/* This vector maps the target's idea of an exception (extracted
|
||||
from the DEBUG_EVENT structure) to GDB's idea. */
|
||||
|
||||
|
@ -297,7 +300,7 @@ do_child_fetch_inferior_registers (int r)
|
|||
supply_register (r, (char *) &l);
|
||||
}
|
||||
else if (r >= 0)
|
||||
supply_register (r, ((char *) ¤t_thread->context) + mappings[r]);
|
||||
supply_register (r, context_offset);
|
||||
else
|
||||
{
|
||||
for (r = 0; r < NUM_REGS; r++)
|
||||
|
@ -529,11 +532,12 @@ handle_output_debug_string (struct target_waitstatus *ourstatus)
|
|||
|| !s || !*s)
|
||||
return gotasig;
|
||||
|
||||
if (strncmp (s, CYGWIN_SIGNAL_STRING, sizeof (CYGWIN_SIGNAL_STRING) - 1))
|
||||
if (strncmp (s, CYGWIN_SIGNAL_STRING, sizeof (CYGWIN_SIGNAL_STRING) - 1) != 0)
|
||||
{
|
||||
if (strncmp (s, "cYg", 3))
|
||||
if (strncmp (s, "cYg", 3) != 0)
|
||||
warning (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *p;
|
||||
int sig = strtol (s + sizeof (CYGWIN_SIGNAL_STRING) - 1, &p, 0);
|
||||
|
@ -592,9 +596,11 @@ handle_exception (struct target_waitstatus *ourstatus)
|
|||
default:
|
||||
/* This may be a structured exception handling exception. In
|
||||
that case, we want to let the program try to handle it, and
|
||||
only break if we see the exception a second time. */
|
||||
only break if we see the exception a second time.
|
||||
if (current_event.u.Exception.dwFirstChance)
|
||||
|
||||
return 0;
|
||||
*/
|
||||
|
||||
printf_unfiltered ("gdb: unknown target exception 0x%08x at 0x%08x\n",
|
||||
current_event.u.Exception.ExceptionRecord.ExceptionCode,
|
||||
|
@ -1017,6 +1023,9 @@ child_create_inferior (exec_file, allargs, env)
|
|||
get_child_debug_event (inferior_pid, &dummy, &event_code, &ret);
|
||||
while (event_code != EXCEPTION_DEBUG_EVENT);
|
||||
|
||||
SymSetOptions (SYMOPT_DEFERRED_LOADS);
|
||||
SymInitialize (current_process_handle, NULL, TRUE);
|
||||
|
||||
proceed ((CORE_ADDR) - 1, TARGET_SIGNAL_0, 0);
|
||||
}
|
||||
|
||||
|
@ -1170,6 +1179,7 @@ init_child_ops (void)
|
|||
child_ops.to_can_run = child_can_run;
|
||||
child_ops.to_notice_signals = 0;
|
||||
child_ops.to_thread_alive = win32_child_thread_alive;
|
||||
child_ops.to_pid_to_str = cygwin_pid_to_str;
|
||||
child_ops.to_stop = child_stop;
|
||||
child_ops.to_stratum = process_stratum;
|
||||
child_ops.DONT_USE = 0;
|
||||
|
@ -1255,40 +1265,60 @@ cygwin_pid_to_str (int pid)
|
|||
sprintf (buf, "thread %d.0x%x", current_event.dwProcessId, pid);
|
||||
return buf;
|
||||
}
|
||||
#ifdef NOTYET
|
||||
CORE_ADDR
|
||||
win32_read_fp ()
|
||||
{
|
||||
STACKFRAME *sf = current_thread->sf;
|
||||
|
||||
memset (&sf, 0, sizeof(sf));
|
||||
sf->AddrPC.Offset = current_thread->context.Eip;
|
||||
sf->AddrPC.Mode = AddrModeFlat;
|
||||
sf->AddrStack.Offset = current_thread->context.Esp;
|
||||
sf->AddrStack.Mode = AddrModeFlat;
|
||||
sf->AddrFrame.Offset = current_thread->context.Ebp;
|
||||
if (!StackWalk (IMAGE_FILE_MACHINE_I386, current_process_handle,
|
||||
current->thread->h, sf, NULL, NULL,
|
||||
SymFunctionTableAccess, SymGetModuleBase, NULL))
|
||||
return NULL;
|
||||
return (CORE_ADDR) sf.AddrFrame.Offset;
|
||||
static LPVOID __stdcall
|
||||
sfta(HANDLE h, DWORD d)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
child_frame_chain(struct frame_info *thisframe)
|
||||
static DWORD __stdcall
|
||||
sgmb(HANDLE h, DWORD d)
|
||||
{
|
||||
STACKFRAME *sf = current->thread->sf;
|
||||
#if 0
|
||||
sf.AddrPC.Offset = thisframe->pc;
|
||||
sf.AddrPC.Mode = AddrModeFlat;
|
||||
sf.AddrStack.Offset = thisframe->;
|
||||
sf.AddrStack.Mode = AddrModeFlat;
|
||||
sf.AddrFrame.Offset = cx->Ebp;
|
||||
return 4;
|
||||
#else
|
||||
return SymGetModuleBase (h, d) ?: 4;
|
||||
#endif
|
||||
if (!StackWalk (IMAGE_FILE_MACHINE_I386, current_process_handle,
|
||||
current->thread->h, &sf, NULL, NULL,
|
||||
SymFunctionTableAccess, SymGetModuleBase, NULL))
|
||||
return NULL;
|
||||
return (CORE_ADDR) sf->AddrFrame.Offset;
|
||||
}
|
||||
#endif
|
||||
|
||||
CORE_ADDR
|
||||
child_frame_chain(struct frame_info *f)
|
||||
{
|
||||
STACKFRAME *sf = (STACKFRAME *) f->extra_info;
|
||||
if (!StackWalk (IMAGE_FILE_MACHINE_I386, current_process_handle,
|
||||
current_thread->h, sf, NULL, NULL, SymFunctionTableAccess, sgmb, NULL) ||
|
||||
!sf->AddrReturn.Offset)
|
||||
return 0;
|
||||
return sf->AddrFrame.Offset;
|
||||
}
|
||||
|
||||
CORE_ADDR
|
||||
child_frame_saved_pc(struct frame_info *f)
|
||||
{
|
||||
STACKFRAME *sf = (STACKFRAME *) f->extra_info;
|
||||
return sf->AddrReturn.Offset;
|
||||
}
|
||||
|
||||
void
|
||||
child_init_frame(int leaf, struct frame_info *f)
|
||||
{
|
||||
STACKFRAME *sf;
|
||||
|
||||
if (f->next && f->next->extra_info)
|
||||
f->extra_info = f->next->extra_info;
|
||||
else if (f->prev && f->prev->extra_info)
|
||||
f->extra_info = f->prev->extra_info;
|
||||
else
|
||||
{
|
||||
sf = (STACKFRAME *) frame_obstack_alloc (sizeof (*sf));
|
||||
f->extra_info = (struct frame_extra_info *) sf;
|
||||
memset (sf, 0, sizeof(*sf));
|
||||
sf->AddrPC.Offset = f->pc;
|
||||
sf->AddrPC.Mode = AddrModeFlat;
|
||||
sf->AddrStack.Offset = current_thread->context.Esp;
|
||||
sf->AddrStack.Mode = AddrModeFlat;
|
||||
sf->AddrFrame.Offset = f->frame;
|
||||
sf->AddrFrame.Mode = AddrModeFlat;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
1999-12-17 Dave Brolley <brolley@cygnus.com>
|
||||
|
||||
* sim-profile.h: (set_profile_option_mask): Add prototype.
|
||||
* sim-profile.c (set_profile_option_mask): No longer static.
|
||||
|
||||
Wed Dec 8 21:47:13 1999 Andrew Cagney <cagney@b1.cygnus.com>
|
||||
|
||||
* sim-arange.c: Include <string.h>
|
||||
|
|
|
@ -108,7 +108,7 @@ static const OPTION profile_options[] = {
|
|||
|
||||
/* Set/reset the profile options indicated in MASK. */
|
||||
|
||||
static SIM_RC
|
||||
SIM_RC
|
||||
set_profile_option_mask (SIM_DESC sd, const char *name, int mask, const char *arg)
|
||||
{
|
||||
int profile_nr;
|
||||
|
|
|
@ -65,6 +65,10 @@ enum {
|
|||
| (1 << PROFILE_MODEL_IDX) \
|
||||
| (1 << PROFILE_CORE_IDX))
|
||||
|
||||
/* Utility to set profile options. */
|
||||
SIM_RC set_profile_option_mask (SIM_DESC sd_, const char *name_, int mask_,
|
||||
const char *arg_);
|
||||
|
||||
/* Utility to parse a --profile-<foo> option. */
|
||||
/* ??? On the one hand all calls could be confined to sim-profile.c, but
|
||||
on the other hand keeping a module's profiling option with the module's
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue