Initialization of hpux_threads

John David Anglin
2000-03-16T13:53:00Z

Thu Mar 16 16:49:27 EST 2000 John David Anglin <dave@hiauly1.hia.nrc.ca>

* configure.in: Don't call _initialize_hpux_thread twice.
* configure: Regenerated.

--- configure.in.orig Mon Mar 6 18:30:12 2000
+++ configure.in Thu Mar 16 14:22:26 2000
@@ -330,7 +330,6 @@
AC_DEFINE(HAVE_HPUX_THREAD_SUPPORT)
CONFIG_OBS="${CONFIG_OJS} hpux-thread.o"
CONFIG_SRCS="${CONFIG_SRCS} hpux-thread.c"
- CONFIG_INITS="${CONFIG_INITS} hpux-thread.c"
else
AC_MSG_RESULT(no (suppressed because you are not using GCC))
fi
From jimb@zwingli.cygnus.com Thu Mar 16 14:41:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: gdb-patches@sourceware.cygnus.com
Subject: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 14:41:00 -0000
Message-id: <200003162241.RAA19616@zwingli.cygnus.com>
X-SW-Source: 2000-03/msg00309.html
Content-length: 19632

There's a lot of code in i386-tdep.c devoted to identifying and
unraveling Linux signal trampolines. There's absolutely no reason I
can think of that this should be in i386-tdep.c, intead of
i386-linux-nat.c.

The reason it's there at all is that Ian Taylor provided the patch to
implement that, and I applied it without thinking too carefully.

I've committed this change. If I've misunderstood something and
screwed things up, please holler.

2000-03-16 Jim Blandy <jimb@redhat.com>

* i386-tdep.c (LINUX_SIGTRAMP_INSN0, LINUX_SIGTRAMP_OFFSET0,
LINUX_SIGTRAMP_INSN1, LINUX_SIGTRAMP_OFFSET1,
LINUX_SIGTRAMP_INSN2, LINUX_SIGTRAMP_OFFSET2, linux_sigtramp_code,
LINUX_SIGTRAMP_LEN, i386_linux_sigtramp_start,
LINUX_RT_SIGTRAMP_INSN0, LINUX_RT_SIGTRAMP_OFFSET0,
LINUX_RT_SIGTRAMP_INSN1, LINUX_RT_SIGTRAMP_OFFSET1,
linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN,
i386_linux_rt_sigtramp_start, i386_linux_in_sigtramp,
i386_linux_sigcontext_addr, LINUX_SIGCONTEXT_PC_OFFSET,
i386_linux_sigtramp_saved_pc, LINUX_SIGCONTEXT_SP_OFFSET,
i386_linux_sigtramp_saved_sp): Deleted. These all implement
Linux-specific signal trampoline detection, and should be moved to...
* i386-linux-nat.c: ... here.
* config/i386/tm-linux.h (I386_LINUX_SIGTRAMP): No need to define
this any more, since we're not enabling OS-specific code in a
OS-independent file.

Index: gdb/i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.5
diff -c -r1.5 i386-tdep.c
*** i386-tdep.c 2000/03/04 23:37:33 1.5
--- i386-tdep.c 2000/03/16 22:30:06
***************
*** 779,1031 ****
}
#endif /* I386V4_SIGTRAMP_SAVED_PC */

- #ifdef I386_LINUX_SIGTRAMP
-
- /* Linux has two flavors of signals. Normal signal handlers, and
- "realtime" (RT) signals. The RT signals can provide additional
- information to the signal handler if the SA_SIGINFO flag is set
- when establishing a signal handler using `sigaction'. It is not
- unlikely that future versions of Linux will support SA_SIGINFO for
- normal signals too. */
-
- /* When the i386 Linux kernel calls a signal handler and the
- SA_RESTORER flag isn't set, the return address points to a bit of
- code on the stack. This function returns whether the PC appears to
- be within this bit of code.
-
- The instruction sequence for normal signals is
- pop %eax
- mov $0x77,%eax
- int $0x80
- or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
-
- Checking for the code sequence should be somewhat reliable, because
- the effect is to call the system call sigreturn. This is unlikely
- to occur anywhere other than a signal trampoline.
-
- It kind of sucks that we have to read memory from the process in
- order to identify a signal trampoline, but there doesn't seem to be
- any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
- only call us if no function name could be identified, which should
- be the case since the code is on the stack.
-
- Detection of signal trampolines for handlers that set the
- SA_RESTORER flag is in general not possible. Unfortunately this is
- what the GNU C Library has been doing for quite some time now.
- However, as of version 2.1.2, the GNU C Library uses signal
- trampolines (named __restore and __restore_rt) that are identical
- to the ones used by the kernel. Therefore, these trampolines are
- supported too. */
-
- #define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */
- #define LINUX_SIGTRAMP_OFFSET0 (0)
- #define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */
- #define LINUX_SIGTRAMP_OFFSET1 (1)
- #define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */
- #define LINUX_SIGTRAMP_OFFSET2 (6)
-
- static const unsigned char linux_sigtramp_code[] =
- {
- LINUX_SIGTRAMP_INSN0, /* pop %eax */
- LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */
- LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */
- };
-
- #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
-
- /* If PC is in a sigtramp routine, return the address of the start of
- the routine. Otherwise, return 0. */
-
- static CORE_ADDR
- i386_linux_sigtramp_start (CORE_ADDR pc)
- {
- unsigned char buf[LINUX_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the three instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_SIGTRAMP_INSN0)
- {
- int adjust;
-
- switch (buf[0])
- {
- case LINUX_SIGTRAMP_INSN1:
- adjust = LINUX_SIGTRAMP_OFFSET1;
- break;
- case LINUX_SIGTRAMP_INSN2:
- adjust = LINUX_SIGTRAMP_OFFSET2;
- break;
- default:
- return 0;
- }
-
- pc -= adjust;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
- }
-
- /* This function does the same for RT signals. Here the instruction
- sequence is
- mov $0xad,%eax
- int $0x80
- or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
-
- The effect is to call the system call rt_sigreturn. */
-
- #define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
- #define LINUX_RT_SIGTRAMP_OFFSET0 (0)
- #define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
- #define LINUX_RT_SIGTRAMP_OFFSET1 (5)
-
- static const unsigned char linux_rt_sigtramp_code[] =
- {
- LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad,%eax */
- LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */
- };
-
- #define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
-
- /* If PC is in a RT sigtramp routine, return the address of the start
- of the routine. Otherwise, return 0. */
-
- static CORE_ADDR
- i386_linux_rt_sigtramp_start (CORE_ADDR pc)
- {
- unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the two instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
- {
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
- return 0;
-
- pc -= LINUX_RT_SIGTRAMP_OFFSET1;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
- }
-
- /* Return whether PC is in a Linux sigtramp routine. */
-
- int
- i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
- {
- if (name)
- return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
-
- return (i386_linux_sigtramp_start (pc) != 0
- || i386_linux_rt_sigtramp_start (pc) != 0);
- }
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the address
- of the associated sigcontext structure. */
-
- CORE_ADDR
- i386_linux_sigcontext_addr (struct frame_info *frame)
- {
- CORE_ADDR pc;
-
- pc = i386_linux_sigtramp_start (frame->pc);
- if (pc)
- {
- CORE_ADDR sp;
-
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure lives on
- the stack, right after the signum argument. */
- return frame->next->frame + 12;
-
- /* This is the top frame. We'll have to find the address of the
- sigcontext structure by looking at the stack pointer. Keep
- in mind that the first instruction of the sigtramp code is
- "pop %eax". If the PC is at this instruction, adjust the
- returned value accordingly. */
- sp = read_register (SP_REGNUM);
- if (pc == frame->pc)
- return sp + 4;
- return sp;
- }
-
- pc = i386_linux_rt_sigtramp_start (frame->pc);
- if (pc)
- {
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure is part of
- the user context. A pointer to the user context is passed
- as the third argument to the signal handler. */
- return read_memory_integer (frame->next->frame + 16, 4) + 20;
-
- /* This is the top frame. Again, use the stack pointer to find
- the address of the sigcontext structure. */
- return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
- }
-
- error ("Couldn't recognize signal trampoline.");
- return 0;
- }
-
- /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
- #define LINUX_SIGCONTEXT_PC_OFFSET (56)
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the saved
- program counter. */
-
- CORE_ADDR
- i386_linux_sigtramp_saved_pc (struct frame_info *frame)
- {
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
- }
-
- /* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
- #define LINUX_SIGCONTEXT_SP_OFFSET (28)
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the saved
- stack pointer. */
-
- CORE_ADDR
- i386_linux_sigtramp_saved_sp (struct frame_info *frame)
- {
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
- }
-
- #endif /* I386_LINUX_SIGTRAMP */
-
#ifdef STATIC_TRANSFORM_NAME
/* SunPRO encodes the static variables. This is not related to C++ mangling,
it is done for C too. */
--- 779,784 ----
Index: gdb/i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.4
diff -c -r1.4 i386-linux-nat.c
*** i386-linux-nat.c 2000/03/06 16:08:12 1.4
--- i386-linux-nat.c 2000/03/16 22:30:05
***************
*** 1042,1047 ****
--- 1042,1293 ----
}

\f
+ /* Recognizing signal handler frames. */
+
+ /* Linux has two flavors of signals. Normal signal handlers, and
+ "realtime" (RT) signals. The RT signals can provide additional
+ information to the signal handler if the SA_SIGINFO flag is set
+ when establishing a signal handler using `sigaction'. It is not
+ unlikely that future versions of Linux will support SA_SIGINFO for
+ normal signals too. */
+
+ /* When the i386 Linux kernel calls a signal handler and the
+ SA_RESTORER flag isn't set, the return address points to a bit of
+ code on the stack. This function returns whether the PC appears to
+ be within this bit of code.
+
+ The instruction sequence for normal signals is
+ pop %eax
+ mov $0x77,%eax
+ int $0x80
+ or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
+
+ Checking for the code sequence should be somewhat reliable, because
+ the effect is to call the system call sigreturn. This is unlikely
+ to occur anywhere other than a signal trampoline.
+
+ It kind of sucks that we have to read memory from the process in
+ order to identify a signal trampoline, but there doesn't seem to be
+ any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
+ only call us if no function name could be identified, which should
+ be the case since the code is on the stack.
+
+ Detection of signal trampolines for handlers that set the
+ SA_RESTORER flag is in general not possible. Unfortunately this is
+ what the GNU C Library has been doing for quite some time now.
+ However, as of version 2.1.2, the GNU C Library uses signal
+ trampolines (named __restore and __restore_rt) that are identical
+ to the ones used by the kernel. Therefore, these trampolines are
+ supported too. */
+
+ #define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */
+ #define LINUX_SIGTRAMP_OFFSET0 (0)
+ #define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */
+ #define LINUX_SIGTRAMP_OFFSET1 (1)
+ #define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */
+ #define LINUX_SIGTRAMP_OFFSET2 (6)
+
+ static const unsigned char linux_sigtramp_code[] =
+ {
+ LINUX_SIGTRAMP_INSN0, /* pop %eax */
+ LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */
+ LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */
+ };
+
+ #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+
+ /* If PC is in a sigtramp routine, return the address of the start of
+ the routine. Otherwise, return 0. */
+
+ static CORE_ADDR
+ i386_linux_sigtramp_start (CORE_ADDR pc)
+ {
+ unsigned char buf[LINUX_SIGTRAMP_LEN];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the three instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_SIGTRAMP_INSN0)
+ {
+ int adjust;
+
+ switch (buf[0])
+ {
+ case LINUX_SIGTRAMP_INSN1:
+ adjust = LINUX_SIGTRAMP_OFFSET1;
+ break;
+ case LINUX_SIGTRAMP_INSN2:
+ adjust = LINUX_SIGTRAMP_OFFSET2;
+ break;
+ default:
+ return 0;
+ }
+
+ pc -= adjust;
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ return pc;
+ }
+
+ /* This function does the same for RT signals. Here the instruction
+ sequence is
+ mov $0xad,%eax
+ int $0x80
+ or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
+
+ The effect is to call the system call rt_sigreturn. */
+
+ #define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
+ #define LINUX_RT_SIGTRAMP_OFFSET0 (0)
+ #define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
+ #define LINUX_RT_SIGTRAMP_OFFSET1 (5)
+
+ static const unsigned char linux_rt_sigtramp_code[] =
+ {
+ LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad,%eax */
+ LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */
+ };
+
+ #define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
+
+ /* If PC is in a RT sigtramp routine, return the address of the start
+ of the routine. Otherwise, return 0. */
+
+ static CORE_ADDR
+ i386_linux_rt_sigtramp_start (CORE_ADDR pc)
+ {
+ unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the two instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
+ {
+ if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
+ return 0;
+
+ pc -= LINUX_RT_SIGTRAMP_OFFSET1;
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ return pc;
+ }
+
+ /* Return whether PC is in a Linux sigtramp routine. */
+
+ int
+ i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
+ {
+ if (name)
+ return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
+
+ return (i386_linux_sigtramp_start (pc) != 0
+ || i386_linux_rt_sigtramp_start (pc) != 0);
+ }
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the address
+ of the associated sigcontext structure. */
+
+ CORE_ADDR
+ i386_linux_sigcontext_addr (struct frame_info *frame)
+ {
+ CORE_ADDR pc;
+
+ pc = i386_linux_sigtramp_start (frame->pc);
+ if (pc)
+ {
+ CORE_ADDR sp;
+
+ if (frame->next)
+ /* If this isn't the top frame, the next frame must be for the
+ signal handler itself. The sigcontext structure lives on
+ the stack, right after the signum argument. */
+ return frame->next->frame + 12;
+
+ /* This is the top frame. We'll have to find the address of the
+ sigcontext structure by looking at the stack pointer. Keep
+ in mind that the first instruction of the sigtramp code is
+ "pop %eax". If the PC is at this instruction, adjust the
+ returned value accordingly. */
+ sp = read_register (SP_REGNUM);
+ if (pc == frame->pc)
+ return sp + 4;
+ return sp;
+ }
+
+ pc = i386_linux_rt_sigtramp_start (frame->pc);
+ if (pc)
+ {
+ if (frame->next)
+ /* If this isn't the top frame, the next frame must be for the
+ signal handler itself. The sigcontext structure is part of
+ the user context. A pointer to the user context is passed
+ as the third argument to the signal handler. */
+ return read_memory_integer (frame->next->frame + 16, 4) + 20;
+
+ /* This is the top frame. Again, use the stack pointer to find
+ the address of the sigcontext structure. */
+ return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
+ }
+
+ error ("Couldn't recognize signal trampoline.");
+ return 0;
+ }
+
+ /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
+ #define LINUX_SIGCONTEXT_PC_OFFSET (56)
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the saved
+ program counter. */
+
+ CORE_ADDR
+ i386_linux_sigtramp_saved_pc (struct frame_info *frame)
+ {
+ CORE_ADDR addr;
+ addr = i386_linux_sigcontext_addr (frame);
+ return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
+ }
+
+ /* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
+ #define LINUX_SIGCONTEXT_SP_OFFSET (28)
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the saved
+ stack pointer. */
+
+ CORE_ADDR
+ i386_linux_sigtramp_saved_sp (struct frame_info *frame)
+ {
+ CORE_ADDR addr;
+ addr = i386_linux_sigcontext_addr (frame);
+ return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
+ }
+
+ \f
/* Register that we are able to handle Linux ELF core file formats. */

static struct core_fns linux_elf_core_fns =
Index: gdb/config/i386/tm-linux.h
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/tm-linux.h,v
retrieving revision 1.2
diff -c -r1.2 tm-linux.h
*** tm-linux.h 2000/03/04 23:37:33 1.2
--- tm-linux.h 2000/03/16 22:30:10
***************
*** 98,104 ****
are used to identify this bit of code as a signal trampoline in
order to support backtracing through calls to signal handlers. */

- #define I386_LINUX_SIGTRAMP
#define IN_SIGTRAMP(pc, name) i386_linux_in_sigtramp (pc, name)
extern int i386_linux_in_sigtramp (CORE_ADDR, char *);

--- 98,103 ----
From kevinb@cygnus.com Thu Mar 16 14:55:00 2000
From: Kevin Buettner <kevinb@cygnus.com>
To: Jim Blandy <jimb@cygnus.com>, gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 14:55:00 -0000
Message-id: <1000316225504.ZM3009@ocotillo.lan>
References: <200003162241.RAA19616@zwingli.cygnus.com> <jimb@cygnus.com>
X-SW-Source: 2000-03/msg00310.html
Content-length: 397

On Mar 16, 5:41pm, Jim Blandy wrote:

> There's a lot of code in i386-tdep.c devoted to identifying and
> unraveling Linux signal trampolines. There's absolutely no reason I
> can think of that this should be in i386-tdep.c, intead of
> i386-linux-nat.c.

I think it should go in i386-linux-tdep.c instead. That way you'd be
able to debug a linux/ia32 target from a non-linux/ia32 host.

Kevin
From cgf@cygnus.com Thu Mar 16 15:00:00 2000
From: Chris Faylor <cgf@cygnus.com>
To: Kevin Buettner <kevinb@cygnus.com>
Cc: Jim Blandy <jimb@cygnus.com>, gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 15:00:00 -0000
Message-id: <20000316180048.A30640@cygnus.com>
References: <200003162241.RAA19616@zwingli.cygnus.com> <jimb@cygnus.com> <1000316225504.ZM3009@ocotillo.lan>
X-SW-Source: 2000-03/msg00311.html
Content-length: 575

On Thu, Mar 16, 2000 at 03:55:04PM -0700, Kevin Buettner wrote:
>On Mar 16, 5:41pm, Jim Blandy wrote:
>
>> There's a lot of code in i386-tdep.c devoted to identifying and
>> unraveling Linux signal trampolines. There's absolutely no reason I
>> can think of that this should be in i386-tdep.c, intead of
>> i386-linux-nat.c.
>
>I think it should go in i386-linux-tdep.c instead. That way you'd be
>able to debug a linux/ia32 target from a non-linux/ia32 host.

What about the 14 character limit for filenames?

(Just trying to see if anyone has a deja vu experience)

cgf
From kettenis@wins.uva.nl Thu Mar 16 15:11:00 2000
From: Mark Kettenis <kettenis@wins.uva.nl>
To: cgf@cygnus.com
Cc: kevinb@cygnus.com, jimb@cygnus.com, gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 15:11:00 -0000
Message-id: <200003162311.e2GNBUH00362@delius.kettenis.local>
References: <200003162241.RAA19616@zwingli.cygnus.com> <jimb@cygnus.com> <1000316225504.ZM3009@ocotillo.lan> <20000316180048.A30640@cygnus.com>
X-SW-Source: 2000-03/msg00312.html
Content-length: 794

From: Chris Faylor <cgf@cygnus.com>
Date: Thu, 16 Mar 2000 18:00:48 -0500

On Thu, Mar 16, 2000 at 03:55:04PM -0700, Kevin Buettner wrote:
>On Mar 16, 5:41pm, Jim Blandy wrote:
>
>> There's a lot of code in i386-tdep.c devoted to identifying and
>> unraveling Linux signal trampolines. There's absolutely no reason I
>> can think of that this should be in i386-tdep.c, intead of
>> i386-linux-nat.c.
>
>I think it should go in i386-linux-tdep.c instead. That way you'd be
>able to debug a linux/ia32 target from a non-linux/ia32 host.

I fully agree with Kevin here.

What about the 14 character limit for filenames?

That's why I dumped the issue after raking it up a week ago.
i386-tdep.c is a better place for this code than i386-linux-nat.c.

Mark
From kevinb@cygnus.com Thu Mar 16 15:16:00 2000
From: Kevin Buettner <kevinb@cygnus.com>
To: Chris Faylor <cgf@cygnus.com>
Cc: Jim Blandy <jimb@cygnus.com>, gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 15:16:00 -0000
Message-id: <1000316231630.ZM3057@ocotillo.lan>
References: <200003162241.RAA19616@zwingli.cygnus.com> <jimb@cygnus.com> <1000316225504.ZM3009@ocotillo.lan> <20000316180048.A30640@cygnus.com> <cgf@cygnus.com>
X-SW-Source: 2000-03/msg00313.html
Content-length: 901

On Mar 16, 6:00pm, Chris Faylor wrote:

> On Thu, Mar 16, 2000 at 03:55:04PM -0700, Kevin Buettner wrote:
> >On Mar 16, 5:41pm, Jim Blandy wrote:
> >
> >> There's a lot of code in i386-tdep.c devoted to identifying and
> >> unraveling Linux signal trampolines. There's absolutely no reason I
> >> can think of that this should be in i386-tdep.c, intead of
> >> i386-linux-nat.c.
> >
> >I think it should go in i386-linux-tdep.c instead. That way you'd be
> >able to debug a linux/ia32 target from a non-linux/ia32 host.
>
> What about the 14 character limit for filenames?
>
> (Just trying to see if anyone has a deja vu experience)

Didn't we decide that they just had to be 8.3 unique for files which
have to compile on a DOS system?

In any event, the point is that the sigtramp detection code ought to
go into a *-tdep.c file so we can debug linux/ia32 systems from a
different host.

Kevin
From jimb@zwingli.cygnus.com Thu Mar 16 15:20:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: Kevin Buettner <kevinb@cygnus.com>
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: [PATCH RFA] solib.c
Date: Thu, 16 Mar 2000 15:20:00 -0000
Message-id: <np4sa6a4dn.fsf@zwingli.cygnus.com>
References: <1000316202058.ZM2781@ocotillo.lan>
X-SW-Source: 2000-03/msg00314.html
Content-length: 3422

This looks good.

I have only one request: the code which scans an array of
section_table entries and fills in a struct section_addr_info is
hardly specific to shared libraries. Could you turn it into a
function, put it in symfile.c, and just call it from solib.c? I guess
you'll need a corresponding cleanup function to free the names.

If that works out, go ahead and commit the patch. If turns out not to
be a good idea, let me know.

> The changes below are motivated by the desire to have correct section
> addresses stored in the obj_section structs (for shared objects) found
> via the object_files list.
>
> More information regarding this issue may be found at
>
> http://sourceware.cygnus.com/ml/gdb/2000-q1/msg00681.html .
>
> There was also a patch appended to the above message. I hereby
> withdraw that patch from consideration.
>
> Note that MAX_SECTIONS has been increased to 30 (from 12). The reason
> for this is that 12 was much too small. So how did I arrive at 30? I
> counted the number of special sections documented in my (now rather
> old) System V ABI book and counted 24. I added on six more for good
> measure (to accomodate architecture specific sections.)
>
> * solib.c (symbol_add_stub): Make symbol_file_add() aware of
> all section addresses, not just .text.
> * symtab.h (MAX_SECTIONS): Increase to 30.
>
> Index: solib.c
> ===================================================================
> RCS file: /cvs/src/src/gdb/solib.c,v
> retrieving revision 1.3
> diff -u -p -r1.3 solib.c
> --- solib.c 2000/03/15 16:55:07 1.3
> +++ solib.c 2000/03/16 19:34:40
> @@ -1182,12 +1182,37 @@ symbol_add_stub (arg)
>
> {
> struct section_addr_info section_addrs;
> + struct section_table *stp;
> + struct cleanup *old_chain;
> + int oidx;
>
> memset (&section_addrs, 0, sizeof (section_addrs));
> section_addrs.text_addr = text_addr;
>
> + old_chain = make_cleanup (null_cleanup, 0);
> +
> + for (stp = so->sections, oidx = 0; stp != so->sections_end; stp++)
> + {
> + if (strcmp (stp->the_bfd_section->name, ".data") == 0)
> + section_addrs.data_addr = stp->addr;
> + else if (strcmp (stp->the_bfd_section->name, ".bss") == 0)
> + section_addrs.bss_addr = stp->addr;
> +
> + if (stp->the_bfd_section->flags & (SEC_ALLOC | SEC_LOAD)
> + && oidx < MAX_SECTIONS)
> + {
> + section_addrs.other[oidx].addr = stp->addr;
> + section_addrs.other[oidx].name =
> + xstrdup (stp->the_bfd_section->name);
> + make_cleanup (free, section_addrs.other[oidx].name);
> + section_addrs.other[oidx].sectindex = stp->the_bfd_section->index;
> + oidx++;
> + }
> + }
> +
> so->objfile = symbol_file_add (so->so_name, so->from_tty,
> &section_addrs, 0, OBJF_SHARED);
> + do_cleanups (old_chain);
> }
>
> return (1);
> Index: symtab.h
> ===================================================================
> RCS file: /cvs/src/src/gdb/symtab.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 symtab.h
> --- symtab.h 2000/03/14 19:58:02 1.3
> +++ symtab.h 2000/03/16 19:34:44
> @@ -842,7 +842,7 @@ struct section_offsets
> can keep track of the section names until we read the file and
> can map them to bfd sections. */
>
> -#define MAX_SECTIONS 12
> +#define MAX_SECTIONS 30
> struct section_addr_info
> {
> /* Sections whose names are always known to gdb. */
>
>
From jimb@zwingli.cygnus.com Thu Mar 16 16:01:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: gdb-patches@sourceware.cygnus.com
Subject: solib.c: minor cleanup
Date: Thu, 16 Mar 2000 16:01:00 -0000
Message-id: <200003170001.TAA21483@zwingli.cygnus.com>
X-SW-Source: 2000-03/msg00315.html
Content-length: 1341

2000-03-16 Jim Blandy <jimb@redhat.com>

* solib.c (current_sos): Be more careful about freeing the new
so_list node if an error occurs.

Index: solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.3
retrieving revision 1.4
diff -c -r1.3 -r1.4
*** solib.c 2000/03/15 16:55:07 1.3
--- solib.c 2000/03/16 23:12:42 1.4
***************
*** 1091,1096 ****
--- 1091,1097 ----
{
struct so_list *new
= (struct so_list *) xmalloc (sizeof (struct so_list));
+ struct cleanup *old_chain = make_cleanup (free, new);
memset (new, 0, sizeof (*new));

new->lmaddr = lm;
***************
*** 1104,1112 ****
does have a name, so we can no longer use a missing name to
decide when to ignore it. */
if (IGNORE_FIRST_LINK_MAP_ENTRY (new))
! {
! free_so (new);
! }
else
{
int errcode;
--- 1105,1111 ----
does have a name, so we can no longer use a missing name to
decide when to ignore it. */
if (IGNORE_FIRST_LINK_MAP_ENTRY (new))
! free_so (new);
else
{
int errcode;
***************
*** 1140,1145 ****
--- 1139,1146 ----
link_ptr = &new->next;
}
}
+
+ discard_cleanups (old_chain);
}

return head;
From cgf@cygnus.com Thu Mar 16 16:36:00 2000
From: Chris Faylor <cgf@cygnus.com>
To: Mark Kettenis <kettenis@wins.uva.nl>
Cc: kevinb@cygnus.com, jimb@cygnus.com, gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Thu, 16 Mar 2000 16:36:00 -0000
Message-id: <20000316193609.D30640@cygnus.com>
References: <200003162241.RAA19616@zwingli.cygnus.com> <jimb@cygnus.com> <1000316225504.ZM3009@ocotillo.lan> <20000316180048.A30640@cygnus.com> <200003162311.e2GNBUH00362@delius.kettenis.local>
X-SW-Source: 2000-03/msg00316.html
Content-length: 1191

On Fri, Mar 17, 2000 at 12:11:30AM +0100, Mark Kettenis wrote:
> From: Chris Faylor <cgf@cygnus.com>
> Date: Thu, 16 Mar 2000 18:00:48 -0500
>
> On Thu, Mar 16, 2000 at 03:55:04PM -0700, Kevin Buettner wrote:
> >On Mar 16, 5:41pm, Jim Blandy wrote:
> >
> >> There's a lot of code in i386-tdep.c devoted to identifying and
> >> unraveling Linux signal trampolines. There's absolutely no reason I
> >> can think of that this should be in i386-tdep.c, intead of
> >> i386-linux-nat.c.
> >
> >I think it should go in i386-linux-tdep.c instead. That way you'd be
> >able to debug a linux/ia32 target from a non-linux/ia32 host.
>
>I fully agree with Kevin here.
>
> What about the 14 character limit for filenames?
>
>That's why I dumped the issue after raking it up a week ago.
>i386-tdep.c is a better place for this code than i386-linux-nat.c.

FWIW, so do I. I thought that there was agreement to this when you
brought it up before.

I would be in favor of just creating an i386-linux-tdep.c and working
out the 8.3 issues later. Since there are already 8.3 issues in
the gdb source directory, adding one more is not going to aggravate
the problem unduly.

cgf
From msnyder@cygnus.com Fri Mar 17 11:47:00 2000
From: Michael Snyder <msnyder@cygnus.com>
To: Mark Kettenis <kettenis@wins.uva.nl>
Cc: ac131313@cygnus.com, gdb-patches@sourceware.cygnus.com
Subject: Re: [PATCH] Replace ../include/wait.h with gdb_wait.h.
Date: Fri, 17 Mar 2000 11:47:00 -0000
Message-id: <38D28BC0.4243@cygnus.com>
References: <38A12872.13D194C4@cygnus.com> <200002091429.e19ETk916570@delius.kettenis.local>
X-SW-Source: 2000-03/msg00317.html
Content-length: 1094

Mark Kettenis wrote:

> [snip]

> There is a problem with `linux-thread.c', where `gdb_wait.h' is included
> before config.h. This means that HAVE_SYS_WAIT_H and HAVE_WAIT_H are
> still undefined and the system headers are never used.
>
> Since `linux-thread.c' uses __W_STOPCODE, and `gdb_wait.h' doesn't
> provide a fallback macro I get a linker failure. Moving up the
> include for `defs.h' solves this problem.

As noted earlier, the above part of this patch has already
been checked in...

> The rest of GDB seems to be using WSETSTOP, so it seems appropriate to
> use that macro instead of __W_STOPCODE in `linux-thread.c'. I changed
> the definition of WSETSTOP and WSETEXIT in `gdb_wait.h' to use
> W_STOPCODE and W_EXITCODE if they are available. All BSD-derived
> systems and systems that try to be source-compatible with BSD (like
> Linux and the Hurd) should have those macros. The change is merely
> cosmetic but there might be systems out there that really use a
> different way to store this information.

And I've now checked in this part as well.

Michael Snyder
From jimb@zwingli.cygnus.com Fri Mar 17 12:02:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: Kevin Buettner <kevinb@cygnus.com>
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Fri, 17 Mar 2000 12:02:00 -0000
Message-id: <npsnxp8ix6.fsf@zwingli.cygnus.com>
References: <200003162241.RAA19616@zwingli.cygnus.com> <1000316225504.ZM3009@ocotillo.lan>
X-SW-Source: 2000-03/msg00318.html
Content-length: 22059

I'm sorry --- this is obviously a tdep issue. Does the following
change look better?

2000-03-17 Jim Blandy <jimb@redhat.com>

* i386-linux-nat.c: No need to #include "frame.h" any more.
(LINUX_SIGTRAMP_INSN0, LINUX_SIGTRAMP_OFFSET0,
LINUX_SIGTRAMP_INSN1, LINUX_SIGTRAMP_OFFSET1,
LINUX_SIGTRAMP_INSN2, LINUX_SIGTRAMP_OFFSET2, linux_sigtramp_code,
LINUX_SIGTRAMP_LEN, i386_linux_sigtramp_start,
LINUX_RT_SIGTRAMP_INSN0, LINUX_RT_SIGTRAMP_OFFSET0,
LINUX_RT_SIGTRAMP_INSN1, LINUX_RT_SIGTRAMP_OFFSET1,
linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN,
i386_linux_rt_sigtramp_start, i386_linux_in_sigtramp,
i386_linux_sigcontext_addr, LINUX_SIGCONTEXT_PC_OFFSET,
i386_linux_sigtramp_saved_pc, LINUX_SIGCONTEXT_SP_OFFSET,
i386_linux_sigtramp_saved_sp): Deleted. Folks rightly pointed
out that these are target-dependent, and useful in non-native
configurations. Moved to...
* i386-linux-tdep.c: ... Here, a new file.
* Makefile.in (ALLDEPFILES): Add i386-linux-tdep.c.
(i386-linux-tdep.o): New rule.
(i386-linux-nat.o): We no longer depend on frame.h.
* config/i386/linux.mt (TDEPFILES): Add i386-linux-tdep.o.

Index: gdb/Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.13
diff -c -r1.13 Makefile.in
*** gdb/Makefile.in 2000/03/16 10:23:38 1.13
--- gdb/Makefile.in 2000/03/17 19:59:40
***************
*** 1063,1068 ****
--- 1063,1069 ----
i386-tdep.c i386b-nat.c i386mach-nat.c i386v-nat.c i386-linux-nat.c \
i386aix-nat.c i386m3-nat.c i386v4-nat.c i386ly-tdep.c \
i387-tdep.c \
+ i386-linux-tdep.c \
i960-tdep.c \
infptrace.c inftarg.c irix4-nat.c irix5-nat.c isi-xdep.c \
lynx-nat.c m3-nat.c \
***************
*** 1395,1401 ****
$(inferior_h) language.h target.h

i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
! $(symtab_h) $(frame_h) symfile.h objfiles.h

i386v4-nat.o: i386v4-nat.c $(defs_h)

--- 1396,1405 ----
$(inferior_h) language.h target.h

i386-linux-nat.o: i386-linux-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
! $(symtab_h) symfile.h objfiles.h
!
! i386-linux-tdep.o: i386-linux-tdep.c $(defs_h) $(gdbcore_h) $(frame_h) \
! $(value_h)

i386v4-nat.o: i386v4-nat.c $(defs_h)

Index: gdb/i386-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-nat.c,v
retrieving revision 1.7
diff -c -r1.7 i386-linux-nat.c
*** gdb/i386-linux-nat.c 2000/03/16 23:53:35 1.7
--- gdb/i386-linux-nat.c 2000/03/17 19:59:41
***************
*** 23,29 ****

/* For i386_linux_skip_solib_resolver. */
#include "symtab.h"
- #include "frame.h"
#include "symfile.h"
#include "objfiles.h"

--- 23,28 ----
***************
*** 1041,1303 ****
return result;

return 0;
- }
-
- \f
- /* Recognizing signal handler frames. */
-
- /* Linux has two flavors of signals. Normal signal handlers, and
- "realtime" (RT) signals. The RT signals can provide additional
- information to the signal handler if the SA_SIGINFO flag is set
- when establishing a signal handler using `sigaction'. It is not
- unlikely that future versions of Linux will support SA_SIGINFO for
- normal signals too. */
-
- /* When the i386 Linux kernel calls a signal handler and the
- SA_RESTORER flag isn't set, the return address points to a bit of
- code on the stack. This function returns whether the PC appears to
- be within this bit of code.
-
- The instruction sequence for normal signals is
- pop %eax
- mov $0x77,%eax
- int $0x80
- or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
-
- Checking for the code sequence should be somewhat reliable, because
- the effect is to call the system call sigreturn. This is unlikely
- to occur anywhere other than a signal trampoline.
-
- It kind of sucks that we have to read memory from the process in
- order to identify a signal trampoline, but there doesn't seem to be
- any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
- only call us if no function name could be identified, which should
- be the case since the code is on the stack.
-
- Detection of signal trampolines for handlers that set the
- SA_RESTORER flag is in general not possible. Unfortunately this is
- what the GNU C Library has been doing for quite some time now.
- However, as of version 2.1.2, the GNU C Library uses signal
- trampolines (named __restore and __restore_rt) that are identical
- to the ones used by the kernel. Therefore, these trampolines are
- supported too. */
-
- #define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */
- #define LINUX_SIGTRAMP_OFFSET0 (0)
- #define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */
- #define LINUX_SIGTRAMP_OFFSET1 (1)
- #define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */
- #define LINUX_SIGTRAMP_OFFSET2 (6)
-
- static const unsigned char linux_sigtramp_code[] =
- {
- LINUX_SIGTRAMP_INSN0, /* pop %eax */
- LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */
- LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */
- };
-
- #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
-
- /* If PC is in a sigtramp routine, return the address of the start of
- the routine. Otherwise, return 0. */
-
- static CORE_ADDR
- i386_linux_sigtramp_start (CORE_ADDR pc)
- {
- unsigned char buf[LINUX_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the three instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_SIGTRAMP_INSN0)
- {
- int adjust;
-
- switch (buf[0])
- {
- case LINUX_SIGTRAMP_INSN1:
- adjust = LINUX_SIGTRAMP_OFFSET1;
- break;
- case LINUX_SIGTRAMP_INSN2:
- adjust = LINUX_SIGTRAMP_OFFSET2;
- break;
- default:
- return 0;
- }
-
- pc -= adjust;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
- }
-
- /* This function does the same for RT signals. Here the instruction
- sequence is
- mov $0xad,%eax
- int $0x80
- or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
-
- The effect is to call the system call rt_sigreturn. */
-
- #define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
- #define LINUX_RT_SIGTRAMP_OFFSET0 (0)
- #define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
- #define LINUX_RT_SIGTRAMP_OFFSET1 (5)
-
- static const unsigned char linux_rt_sigtramp_code[] =
- {
- LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad,%eax */
- LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */
- };
-
- #define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
-
- /* If PC is in a RT sigtramp routine, return the address of the start
- of the routine. Otherwise, return 0. */
-
- static CORE_ADDR
- i386_linux_rt_sigtramp_start (CORE_ADDR pc)
- {
- unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
-
- /* We only recognize a signal trampoline if PC is at the start of
- one of the two instructions. We optimize for finding the PC at
- the start, as will be the case when the trampoline is not the
- first frame on the stack. We assume that in the case where the
- PC is not at the start of the instruction sequence, there will be
- a few trailing readable bytes on the stack. */
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
- {
- if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
- return 0;
-
- pc -= LINUX_RT_SIGTRAMP_OFFSET1;
-
- if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
- }
-
- if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
- return 0;
-
- return pc;
- }
-
- /* Return whether PC is in a Linux sigtramp routine. */
-
- int
- i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
- {
- if (name)
- return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
-
- return (i386_linux_sigtramp_start (pc) != 0
- || i386_linux_rt_sigtramp_start (pc) != 0);
- }
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the address
- of the associated sigcontext structure. */
-
- CORE_ADDR
- i386_linux_sigcontext_addr (struct frame_info *frame)
- {
- CORE_ADDR pc;
-
- pc = i386_linux_sigtramp_start (frame->pc);
- if (pc)
- {
- CORE_ADDR sp;
-
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure lives on
- the stack, right after the signum argument. */
- return frame->next->frame + 12;
-
- /* This is the top frame. We'll have to find the address of the
- sigcontext structure by looking at the stack pointer. Keep
- in mind that the first instruction of the sigtramp code is
- "pop %eax". If the PC is at this instruction, adjust the
- returned value accordingly. */
- sp = read_register (SP_REGNUM);
- if (pc == frame->pc)
- return sp + 4;
- return sp;
- }
-
- pc = i386_linux_rt_sigtramp_start (frame->pc);
- if (pc)
- {
- if (frame->next)
- /* If this isn't the top frame, the next frame must be for the
- signal handler itself. The sigcontext structure is part of
- the user context. A pointer to the user context is passed
- as the third argument to the signal handler. */
- return read_memory_integer (frame->next->frame + 16, 4) + 20;
-
- /* This is the top frame. Again, use the stack pointer to find
- the address of the sigcontext structure. */
- return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
- }
-
- error ("Couldn't recognize signal trampoline.");
- return 0;
- }
-
- /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
- #define LINUX_SIGCONTEXT_PC_OFFSET (56)
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the saved
- program counter. */
-
- CORE_ADDR
- i386_linux_sigtramp_saved_pc (struct frame_info *frame)
- {
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
- }
-
- /* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
- #define LINUX_SIGCONTEXT_SP_OFFSET (28)
-
- /* Assuming FRAME is for a Linux sigtramp routine, return the saved
- stack pointer. */
-
- CORE_ADDR
- i386_linux_sigtramp_saved_sp (struct frame_info *frame)
- {
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
- }
-
- /* Immediately after a function call, return the saved pc. */
-
- CORE_ADDR
- i386_linux_saved_pc_after_call (struct frame_info *frame)
- {
- if (frame->signal_handler_caller)
- return i386_linux_sigtramp_saved_pc (frame);
-
- return read_memory_integer (read_register (SP_REGNUM), 4);
}

\f
--- 1040,1045 ----
Index: gdb/i386-linux-tdep.c
===================================================================
RCS file: i386-linux-tdep.c
diff -N i386-linux-tdep.c
*** gdb/i386-linux-tdep.c Tue May 5 13:32:27 1998
--- gdb/i386-linux-tdep.c Fri Mar 17 11:59:41 2000
***************
*** 0 ****
--- 1,281 ----
+ /* Target-dependent code for Linux running on i386's, for GDB.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+ #include "defs.h"
+ #include "gdbcore.h"
+ #include "frame.h"
+ #include "value.h"
+
+ \f
+ /* Recognizing signal handler frames. */
+
+ /* Linux has two flavors of signals. Normal signal handlers, and
+ "realtime" (RT) signals. The RT signals can provide additional
+ information to the signal handler if the SA_SIGINFO flag is set
+ when establishing a signal handler using `sigaction'. It is not
+ unlikely that future versions of Linux will support SA_SIGINFO for
+ normal signals too. */
+
+ /* When the i386 Linux kernel calls a signal handler and the
+ SA_RESTORER flag isn't set, the return address points to a bit of
+ code on the stack. This function returns whether the PC appears to
+ be within this bit of code.
+
+ The instruction sequence for normal signals is
+ pop %eax
+ mov $0x77,%eax
+ int $0x80
+ or 0x58 0xb8 0x77 0x00 0x00 0x00 0xcd 0x80.
+
+ Checking for the code sequence should be somewhat reliable, because
+ the effect is to call the system call sigreturn. This is unlikely
+ to occur anywhere other than a signal trampoline.
+
+ It kind of sucks that we have to read memory from the process in
+ order to identify a signal trampoline, but there doesn't seem to be
+ any other way. The IN_SIGTRAMP macro in tm-linux.h arranges to
+ only call us if no function name could be identified, which should
+ be the case since the code is on the stack.
+
+ Detection of signal trampolines for handlers that set the
+ SA_RESTORER flag is in general not possible. Unfortunately this is
+ what the GNU C Library has been doing for quite some time now.
+ However, as of version 2.1.2, the GNU C Library uses signal
+ trampolines (named __restore and __restore_rt) that are identical
+ to the ones used by the kernel. Therefore, these trampolines are
+ supported too. */
+
+ #define LINUX_SIGTRAMP_INSN0 (0x58) /* pop %eax */
+ #define LINUX_SIGTRAMP_OFFSET0 (0)
+ #define LINUX_SIGTRAMP_INSN1 (0xb8) /* mov $NNNN,%eax */
+ #define LINUX_SIGTRAMP_OFFSET1 (1)
+ #define LINUX_SIGTRAMP_INSN2 (0xcd) /* int */
+ #define LINUX_SIGTRAMP_OFFSET2 (6)
+
+ static const unsigned char linux_sigtramp_code[] =
+ {
+ LINUX_SIGTRAMP_INSN0, /* pop %eax */
+ LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77,%eax */
+ LINUX_SIGTRAMP_INSN2, 0x80 /* int $0x80 */
+ };
+
+ #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code)
+
+ /* If PC is in a sigtramp routine, return the address of the start of
+ the routine. Otherwise, return 0. */
+
+ static CORE_ADDR
+ i386_linux_sigtramp_start (CORE_ADDR pc)
+ {
+ unsigned char buf[LINUX_SIGTRAMP_LEN];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the three instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_SIGTRAMP_INSN0)
+ {
+ int adjust;
+
+ switch (buf[0])
+ {
+ case LINUX_SIGTRAMP_INSN1:
+ adjust = LINUX_SIGTRAMP_OFFSET1;
+ break;
+ case LINUX_SIGTRAMP_INSN2:
+ adjust = LINUX_SIGTRAMP_OFFSET2;
+ break;
+ default:
+ return 0;
+ }
+
+ pc -= adjust;
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ return pc;
+ }
+
+ /* This function does the same for RT signals. Here the instruction
+ sequence is
+ mov $0xad,%eax
+ int $0x80
+ or 0xb8 0xad 0x00 0x00 0x00 0xcd 0x80.
+
+ The effect is to call the system call rt_sigreturn. */
+
+ #define LINUX_RT_SIGTRAMP_INSN0 (0xb8) /* mov $NNNN,%eax */
+ #define LINUX_RT_SIGTRAMP_OFFSET0 (0)
+ #define LINUX_RT_SIGTRAMP_INSN1 (0xcd) /* int */
+ #define LINUX_RT_SIGTRAMP_OFFSET1 (5)
+
+ static const unsigned char linux_rt_sigtramp_code[] =
+ {
+ LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad,%eax */
+ LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */
+ };
+
+ #define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code)
+
+ /* If PC is in a RT sigtramp routine, return the address of the start
+ of the routine. Otherwise, return 0. */
+
+ static CORE_ADDR
+ i386_linux_rt_sigtramp_start (CORE_ADDR pc)
+ {
+ unsigned char buf[LINUX_RT_SIGTRAMP_LEN];
+
+ /* We only recognize a signal trampoline if PC is at the start of
+ one of the two instructions. We optimize for finding the PC at
+ the start, as will be the case when the trampoline is not the
+ first frame on the stack. We assume that in the case where the
+ PC is not at the start of the instruction sequence, there will be
+ a few trailing readable bytes on the stack. */
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ if (buf[0] != LINUX_RT_SIGTRAMP_INSN0)
+ {
+ if (buf[0] != LINUX_RT_SIGTRAMP_INSN1)
+ return 0;
+
+ pc -= LINUX_RT_SIGTRAMP_OFFSET1;
+
+ if (read_memory_nobpt (pc, (char *) buf, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+ }
+
+ if (memcmp (buf, linux_rt_sigtramp_code, LINUX_RT_SIGTRAMP_LEN) != 0)
+ return 0;
+
+ return pc;
+ }
+
+ /* Return whether PC is in a Linux sigtramp routine. */
+
+ int
+ i386_linux_in_sigtramp (CORE_ADDR pc, char *name)
+ {
+ if (name)
+ return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
+
+ return (i386_linux_sigtramp_start (pc) != 0
+ || i386_linux_rt_sigtramp_start (pc) != 0);
+ }
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the address
+ of the associated sigcontext structure. */
+
+ CORE_ADDR
+ i386_linux_sigcontext_addr (struct frame_info *frame)
+ {
+ CORE_ADDR pc;
+
+ pc = i386_linux_sigtramp_start (frame->pc);
+ if (pc)
+ {
+ CORE_ADDR sp;
+
+ if (frame->next)
+ /* If this isn't the top frame, the next frame must be for the
+ signal handler itself. The sigcontext structure lives on
+ the stack, right after the signum argument. */
+ return frame->next->frame + 12;
+
+ /* This is the top frame. We'll have to find the address of the
+ sigcontext structure by looking at the stack pointer. Keep
+ in mind that the first instruction of the sigtramp code is
+ "pop %eax". If the PC is at this instruction, adjust the
+ returned value accordingly. */
+ sp = read_register (SP_REGNUM);
+ if (pc == frame->pc)
+ return sp + 4;
+ return sp;
+ }
+
+ pc = i386_linux_rt_sigtramp_start (frame->pc);
+ if (pc)
+ {
+ if (frame->next)
+ /* If this isn't the top frame, the next frame must be for the
+ signal handler itself. The sigcontext structure is part of
+ the user context. A pointer to the user context is passed
+ as the third argument to the signal handler. */
+ return read_memory_integer (frame->next->frame + 16, 4) + 20;
+
+ /* This is the top frame. Again, use the stack pointer to find
+ the address of the sigcontext structure. */
+ return read_memory_integer (read_register (SP_REGNUM) + 8, 4) + 20;
+ }
+
+ error ("Couldn't recognize signal trampoline.");
+ return 0;
+ }
+
+ /* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
+ #define LINUX_SIGCONTEXT_PC_OFFSET (56)
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the saved
+ program counter. */
+
+ CORE_ADDR
+ i386_linux_sigtramp_saved_pc (struct frame_info *frame)
+ {
+ CORE_ADDR addr;
+ addr = i386_linux_sigcontext_addr (frame);
+ return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
+ }
+
+ /* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
+ #define LINUX_SIGCONTEXT_SP_OFFSET (28)
+
+ /* Assuming FRAME is for a Linux sigtramp routine, return the saved
+ stack pointer. */
+
+ CORE_ADDR
+ i386_linux_sigtramp_saved_sp (struct frame_info *frame)
+ {
+ CORE_ADDR addr;
+ addr = i386_linux_sigcontext_addr (frame);
+ return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
+ }
+
+ /* Immediately after a function call, return the saved pc. */
+
+ CORE_ADDR
+ i386_linux_saved_pc_after_call (struct frame_info *frame)
+ {
+ if (frame->signal_handler_caller)
+ return i386_linux_sigtramp_saved_pc (frame);
+
+ return read_memory_integer (read_register (SP_REGNUM), 4);
+ }
Index: gdb/config/i386/linux.mt
===================================================================
RCS file: /cvs/src/src/gdb/config/i386/linux.mt,v
retrieving revision 1.1.1.1
diff -c -r1.1.1.1 linux.mt
*** gdb/config/i386/linux.mt 1999/04/16 01:34:19 1.1.1.1
--- gdb/config/i386/linux.mt 2000/03/17 19:59:41
***************
*** 1,5 ****
# Target: Intel 386 running GNU/Linux
! TDEPFILES= i386-tdep.o i387-tdep.o
TM_FILE= tm-linux.h

GDBSERVER_DEPFILES= low-linux.o
--- 1,5 ----
# Target: Intel 386 running GNU/Linux
! TDEPFILES= i386-tdep.o i386-linux-tdep.o i387-tdep.o
TM_FILE= tm-linux.h

GDBSERVER_DEPFILES= low-linux.o
From kevinb@cygnus.com Fri Mar 17 13:02:00 2000
From: Kevin Buettner <kevinb@cygnus.com>
To: Jim Blandy <jimb@cygnus.com>
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: Linux sigtramp detection code moved to its proper place
Date: Fri, 17 Mar 2000 13:02:00 -0000
Message-id: <1000317210204.ZM4651@ocotillo.lan>
References: <200003162241.RAA19616@zwingli.cygnus.com> <1000316225504.ZM3009@ocotillo.lan> <npsnxp8ix6.fsf@zwingli.cygnus.com> <jimb@cygnus.com>
X-SW-Source: 2000-03/msg00319.html
Content-length: 663

On Mar 17, 3:01pm, Jim Blandy wrote:

> I'm sorry --- this is obviously a tdep issue. Does the following
> change look better?

Yes. Much better.

i386-linux-tdep.c would also be a good place to put linux/ia32
specific code for handling shared libraries -- I think Mark was
about to do this a few weeks ago.

Note that macros like SKIP_TRAMPOLINE_CODE, SKIP_SOLIB_RESOLVER, etc.
will eventually need to be gdbarch'd.

The ia64 will be a good place to (eventually) test this kind of
thing since it's possible to run both native ia64 programs as well
as legacy ia32 programs. It'd be nice if we could build a gdb which
would handle both simultaneously.

Kevin
From jimb@zwingli.cygnus.com Fri Mar 17 13:43:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: Mark Kettenis <kettenis@wins.uva.nl>
Cc: ac131313@cygnus.com, gdb-patches@sourceware.cygnus.com
Subject: RFA: Fix arguments passed to W_SETSTOP
Date: Fri, 17 Mar 2000 13:43:00 -0000
Message-id: <npog8d8e85.fsf_-_@zwingli.cygnus.com>
References: <38A12872.13D194C4@cygnus.com> <200002091429.e19ETk916570@delius.kettenis.local>
X-SW-Source: 2000-03/msg00320.html
Content-length: 855

Looks like a careless cut and paste. Does this fix look right?

2000-03-17 Jim Blandy <jimb@redhat.com>

* gdb_wait.h (WSETSTOP): Pass the appropriate number of arguments
to W_STOPCODE.

Index: gdb_wait.h
===================================================================
RCS file: /cvs/src/src/gdb/gdb_wait.h,v
retrieving revision 1.2
diff -c -c -b -F'^(' -r1.2 gdb_wait.h
*** gdb_wait.h 2000/03/17 19:50:29 1.2
--- gdb_wait.h 2000/03/17 21:39:24
***************
*** 95,101 ****

#ifndef WSETSTOP
# ifdef W_STOPCODE
! #define WSETSTOP(w,status) ((w) = W_STOPCODE(status,0))
# else
#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
# endif
--- 95,101 ----

#ifndef WSETSTOP
# ifdef W_STOPCODE
! #define WSETSTOP(w,sig) ((w) = W_STOPCODE(sig))
# else
#define WSETSTOP(w,sig) ((w) = (0177 | ((sig) << 8)))
# endif
From jimb@zwingli.cygnus.com Fri Mar 17 13:49:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: gdb-patches@sourceware.cygnus.com
Subject: RFA: Fix typo in linux-threads.c
Date: Fri, 17 Mar 2000 13:49:00 -0000
Message-id: <200003172149.QAA24577@zwingli.cygnus.com>
X-SW-Source: 2000-03/msg00321.html
Content-length: 1876

May I commit this?

2000-03-17 Jim Blandy <jimb@redhat.com>

* linux-thread.c (linuxthreads_attach, linuxthreads_detach,
linuxthreads_create_inferior): Fix typo in variable name: it's
linuxthreads_exit_status, not linux_exit_status.

Index: linux-thread.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-thread.c,v
retrieving revision 1.4
diff -c -c -r1.4 linux-thread.c
*** linux-thread.c 2000/03/17 19:50:29 1.4
--- linux-thread.c 2000/03/17 21:46:23
***************
*** 1129,1135 ****
linuxthreads_breakpoints_inserted = 1;
linuxthreads_breakpoint_last = -1;
linuxthreads_wait_last = -1;
! WSETSTOP (linux_exit_status, 0);

child_ops.to_attach (args, from_tty);

--- 1129,1135 ----
linuxthreads_breakpoints_inserted = 1;
linuxthreads_breakpoint_last = -1;
linuxthreads_wait_last = -1;
! WSETSTOP (linuxthreads_exit_status, 0);

child_ops.to_attach (args, from_tty);

***************
*** 1189,1195 ****
linuxthreads_find_trap (inferior_pid, 1);

linuxthreads_wait_last = -1;
! WSETSTOP (linux_exit_status, 0);
}

linuxthreads_inferior_pid = 0;
--- 1189,1195 ----
linuxthreads_find_trap (inferior_pid, 1);

linuxthreads_wait_last = -1;
! WSETSTOP (linuxthreads_exit_status, 0);
}

linuxthreads_inferior_pid = 0;
***************
*** 1601,1607 ****
linuxthreads_breakpoints_inserted = 1;
linuxthreads_breakpoint_last = -1;
linuxthreads_wait_last = -1;
! WSETSTOP (linux_exit_status, 0);

if (linuxthreads_max)
linuxthreads_attach_pending = 1;
--- 1601,1607 ----
linuxthreads_breakpoints_inserted = 1;
linuxthreads_breakpoint_last = -1;
linuxthreads_wait_last = -1;
! WSETSTOP (linuxthreads_exit_status, 0);

if (linuxthreads_max)
linuxthreads_attach_pending = 1;
From jimb@zwingli.cygnus.com Fri Mar 17 16:07:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: gdb-patches@sourceware.cygnus.com
Subject: RFA: minor watchpoint code cleanup
Date: Fri, 17 Mar 2000 16:07:00 -0000
Message-id: <200003180006.TAA26919@zwingli.cygnus.com>
X-SW-Source: 2000-03/msg00322.html
Content-length: 1675

This is just a cosmetic change. Let me know.

2000-03-17 Jim Blandy <jimb@redhat.com>

* i386v-nat.c (i386_insert_nonaligned_watchpoint): Use a
two-dimensional array, instead of faking it with explicit index
arithmetic.

Index: i386v-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/i386v-nat.c,v
retrieving revision 1.1.1.3
diff -c -c -b -F'^(' -r1.1.1.3 i386v-nat.c
*** i386v-nat.c 1999/12/08 02:50:38 1.1.1.3
--- i386v-nat.c 2000/03/17 23:57:07
***************
*** 229,240 ****
int size;
int rv;

! static int size_try_array[16] =
{
! 1, 1, 1, 1, /* trying size one */
! 2, 1, 2, 1, /* trying size two */
! 2, 1, 2, 1, /* trying size three */
! 4, 1, 2, 1 /* trying size four */
};

rv = 0;
--- 229,240 ----
int size;
int rv;

! static int size_try_array[4][4] =
{
! { 1, 1, 1, 1 }, /* trying size one */
! { 2, 1, 2, 1 }, /* trying size two */
! { 2, 1, 2, 1 }, /* trying size three */
! { 4, 1, 2, 1 } /* trying size four */
};

rv = 0;
***************
*** 242,249 ****
{
align = addr % 4;
/* Four is the maximum length for 386. */
! size = (len > 4) ? 3 : len - 1;
! size = size_try_array[size * 4 + align];

rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
if (rv)
--- 242,249 ----
{
align = addr % 4;
/* Four is the maximum length for 386. */
! size = (len > 4) ? 4 : len;
! size = size_try_array[size - 1][align];

rv = i386_insert_aligned_watchpoint (pid, waddr, addr, size, rw);
if (rv)
From jimb@zwingli.cygnus.com Fri Mar 17 16:10:00 2000
From: Jim Blandy <jimb@zwingli.cygnus.com>
To: John Wehle <john@feith.com>
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: GDB 4.17 Patch for stack aligned i386 code
Date: Fri, 17 Mar 2000 16:10:00 -0000
Message-id: <npk8j187fh.fsf@zwingli.cygnus.com>
References: <200003062256.RAA10752@jwlab.FEITH.COM>
X-SW-Source: 2000-03/msg00323.html
Content-length: 36773

> >> Just curious what the status is of my patch for debugging
> >> frame pointerless i386 code. Last we "spoke" (on March 9)
> >> Jim B was going to look at it. Is it still in the queue?
> >> Are there any issues with it that I need to address?
> >
> > Yes, I'm still on the spot for this. It's definitely on my queue, and
> > towards the top.
> >
> > I won't reject it without letting you know why. :)
>
> Figured since it's been a few months it was safe to ping you
> again regarding the status of this patch. :-)

Sorry --- I still haven't had a chance to look at it. Since we have
more maintainers now, it's more likely the cycles will arise, so I'll
re-post the patch here.

------- Start of forwarded message -------
Date: Thu, 25 Feb 1999 23:47:31 -0500 (EST)
From: John Wehle <john@feith.com>
Message-Id: <199902260447.XAA01101@jwlab.FEITH.COM>
To: shebs@cygnus.com
Cc: gdb-patches@cygnus.com
Subject: Re: GDB 4.17 Patch for stack aligned i386 code
Reply-To: gdb-patches@cygnus.com

> Actually, the last I looked at this, I was unclear about what/which of
> several patches were needed, and in which order. If you had a single
> integrated set and could resend, that would be helpful...

Here's both patches consolidated into one.

This patch adds support for debugging functions where the
frame pointer has been eliminated and the stack pointer
is unchanging. It also adds support for debugging functions
where the stack has been aligned.

There are no regressions evident from running the gdb 4.17
testsuite on Solaris 2.5.1 with gcc 2.7.2.1, egcs (from cvs on
1999-02-25), and egcs -momit-leaf-frame-pointer with this patch
installed. There were no regressions evident from running the
gdb 4.17 testsuite on FreeBSD 3.0 and Solaris 2.5.1 with gcc
2.7.2.1, egcs (from cvs on 1999-01-14), and egcs
-momit-leaf-frame-pointer with the original two separate
patches installed.

Notes:

1) The SVR4 changes to support sigtramp backtraces are untested.

2) Platforms other than those tested may require some work in order
to properly support sigtramp backtraces. Start by looking at
the BSD and Solaris definitions of:

i386_sigcontext_addr
SIGCONTEXT_FP_OFFSET
SIGCONTEXT_SP_OFFSET

ChangeLog:

Wed Jan 20 22:14:03 EST 1999 John Wehle (john@feith.com)

* tm-i386.h (FRAME_CHAIN): Call i386_frame_chain for
signal handler callers.
(EXTRA_FRAME_INFO): Define stack_mask.
(FRAME_ARGS_ADDRESS, FRAME_LOCALS_ADDRESS): Use it.
* i386-tdep.c (i386_get_frame_setup): Set it.
(i386_frame_find_saved_regs): Use it.
(i386_init_extra_frame_info): Initialize it.
(i386_frame_find_saved_regs): Don't accidently zero
fi->fsr.regs[FP_REGNUM].
(i386_sigcontext_addr): New function.
(i386v4_sigtramp_saved_pc): Use it.
(i386_analyze_prologue): Use it.
(i386_analyze_prologue): Handle dummy frames.
(i386_analyze_prologue): If the start of a function can't
be located than assume the frame is in the frame pointer.
(i386_frame_chain): If the caller's prologue can't be
analyze then return the current frame as the frame.
(i386_frame_chain): Check the current frame for FP_REGNUM.
(i386_frame_chain): Handle chaining back from a signal
handler caller to a function which uses the stack pointer
for the frame pointer.
(i386_frame_chain): Include the stack space occupied by
FP_REGNUM when caculating the caller's frame.
(i386_pop_frame): Don't bother explicitly restoring PC_REGNUM,
it is restored by the for loop.
* tm-i386bsd.h (SIGCONTEXT_FP_OFFSET,
SIGCONTEXT_SP_OFFSET): Define.
* tm-i386sol2.h: Likewise.
* tm-i386v4.h: Likewise.

Wed Nov 4 22:29:19 EST 1998 John Wehle (john@feith.com)

* i386-tdep.c (codestream_fill): Use read_memory_nobpt.
(i386_analyze_prologue, i386_frame_chain,
i386_init_extra_frame_info): New functions.
(i386_get_frame_setup, i386_frame_find_saved_regs,
i386_skip_prologue, i386_pop_frame): Support prologues
which don't setup a frame pointer.
* tm-i386.h (EXTRA_FRAME_INFO, INIT_EXTRA_FRAME_INFO,
INIT_FRAME_PC): Define.
(FRAME_CHAIN): Call i386_frame_chain.
(FRAME_FIND_SAVED_REGS, FRAME_SAVED_PC): Use fsr to
locate the saved registers.
(FRAMELESS_FUNCTION_INVOCATION): Don't define.
(i386_init_extra_frame_info, i386_frame_chain): Add
prototypes.

-- John Wehle
------------------8<------------------------8<------------------------
*** gdb/i386-tdep.c.ORIGINAL Sat Apr 11 01:39:37 1998
--- gdb/i386-tdep.c Thu Feb 25 22:24:11 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 28,37 ****
#include "symtab.h"
#include "gdbcmd.h"

- static long i386_get_frame_setup PARAMS ((CORE_ADDR));
-
- static void i386_follow_jump PARAMS ((void));
-
static void codestream_read PARAMS ((unsigned char *, int));

static void codestream_seek PARAMS ((CORE_ADDR));
--- 28,33 ----
*************** static unsigned char
*** 72,82 ****
codestream_fill (peek_flag)
int peek_flag;
{
codestream_addr = codestream_next_addr;
codestream_next_addr += CODESTREAM_BUFSIZ;
codestream_off = 0;
codestream_cnt = CODESTREAM_BUFSIZ;
! read_memory (codestream_addr, (char *) codestream_buf, CODESTREAM_BUFSIZ);

if (peek_flag)
return (codestream_peek());
--- 68,83 ----
codestream_fill (peek_flag)
int peek_flag;
{
+ int status;
+
codestream_addr = codestream_next_addr;
codestream_next_addr += CODESTREAM_BUFSIZ;
codestream_off = 0;
codestream_cnt = CODESTREAM_BUFSIZ;
! status = read_memory_nobpt (codestream_addr,
! (char *) codestream_buf, CODESTREAM_BUFSIZ);
! if (status != 0)
! memory_error (status, codestream_addr);

if (peek_flag)
return (codestream_peek());
*************** i386_follow_jump ()
*** 161,185 ****
}

/*
! * find & return amound a local space allocated, and advance codestream to
! * first register push (if any)
*
! * if entry sequence doesn't make sense, return -1, and leave
! * codestream pointer random
*/

! static long
! i386_get_frame_setup (pc)
! CORE_ADDR pc;
{
unsigned char op;

- codestream_seek (pc);
-
- i386_follow_jump ();
-
op = codestream_get ();
-
if (op == 0x58) /* popl %eax */
{
/*
--- 162,186 ----
}

/*
! * Determine the amount of local space allocated, and advance codestream to
! * first register push (if any).
*
! * If the entry sequence doesn't make sense, then assume it is a frameless
! * function with no local space.
*/

! #define MY_FRAME_IN_SP 0x1
! #define MY_FRAME_IN_FP 0x2
! #define NO_MORE_FRAMES 0x4
! #define INCOMPLETE_FRAME 0x8
!
! static void
! i386_get_frame_setup (fi)
! struct frame_info *fi;
{
unsigned char op;

op = codestream_get ();
if (op == 0x58) /* popl %eax */
{
/*
*************** i386_get_frame_setup (pc)
*** 214,285 ****
if (op == 0x55) /* pushl %ebp */
{
/* check for movl %esp, %ebp - can be written two ways */
! switch (codestream_get ())
! {
! case 0x8b:
! if (codestream_get () != 0xec)
! return (-1);
! break;
! case 0x89:
! if (codestream_get () != 0xe5)
! return (-1);
! break;
! default:
! return (-1);
}
! /* check for stack adjustment
! *
! * subl $XXX, %esp
! *
! * note: you can't subtract a 16 bit immediate
! * from a 32 bit reg, so we don't have to worry
! * about a data16 prefix
! */
! op = codestream_peek ();
! if (op == 0x83)
{
! /* subl with 8 bit immed */
! codestream_get ();
! if (codestream_get () != 0xec)
! /* Some instruction starting with 0x83 other than subl. */
! {
! codestream_seek (codestream_tell () - 2);
! return 0;
! }
! /* subl with signed byte immediate
! * (though it wouldn't make sense to be negative)
! */
! return (codestream_get());
}
! else if (op == 0x81)
{
! char buf[4];
! /* Maybe it is subl with 32 bit immedediate. */
! codestream_get();
! if (codestream_get () != 0xec)
! /* Some instruction starting with 0x81 other than subl. */
! {
! codestream_seek (codestream_tell () - 2);
! return 0;
! }
! /* It is subl with 32 bit immediate. */
! codestream_read ((unsigned char *)buf, 4);
! return extract_signed_integer (buf, 4);
}
! else
{
! return (0);
}
}
! else if (op == 0xc8)
{
! char buf[2];
! /* enter instruction: arg is 16 bit unsigned immed */
! codestream_read ((unsigned char *)buf, 2);
! codestream_get (); /* flush final byte of enter instruction */
! return extract_unsigned_integer (buf, 2);
}
! return (-1);
}

/* Return number of args passed to a frame.
--- 215,328 ----
if (op == 0x55) /* pushl %ebp */
{
/* check for movl %esp, %ebp - can be written two ways */
! unsigned char buf[2];
! static unsigned char proto1[2] = { 0x8b,0xec };
! static unsigned char proto2[2] = { 0x89,0xe5 };
! codestream_read (buf, sizeof(buf));
! if (memcmp (buf, proto1, 2) != 0
! && memcmp (buf, proto2, 2) != 0)
! {
! /* frameless function with no local space */
! codestream_seek (codestream_tell () - 3);
! return;
}
! fi->status = MY_FRAME_IN_FP;
! }
! else if (op == 0xc8)
! {
! char buf[2];
! /* enter instruction: arg is 16 bit unsigned immed */
! codestream_read ((unsigned char *)buf, 2);
! codestream_get (); /* flush final byte of enter instruction */
! fi->status = MY_FRAME_IN_FP;
! fi->stack_size = extract_unsigned_integer (buf, 2);
! return;
! }
! else
! codestream_seek (codestream_tell () - 1);
!
! if ( (fi->status & MY_FRAME_IN_SP) )
! fi->stack_mask = -1;
!
! /* check for stack alignment
! *
! * andl $XXX, %esp
! *
! * note: you can't and a 16 bit immediate
! * with a 32 bit reg, so we don't have to worry
! * about a data16 prefix
! */
! op = codestream_peek ();
! if (op == 0x83)
! {
! /* andl with 8 bit immed */
! codestream_get ();
! if (codestream_get () != 0xe4)
! /* Some instruction starting with 0x83 other than andl. */
! codestream_seek (codestream_tell () - 2);
! else
{
! /* andl with signed byte immediate */
! fi->stack_mask = (char)codestream_get();
}
! }
! else if (op == 0x81)
! {
! char buf[4];
! /* Maybe it is andl with 32 bit immediate. */
! codestream_get();
! if (codestream_get () != 0xe4)
! /* Some instruction starting with 0x81 other than andl. */
! codestream_seek (codestream_tell () - 2);
! else
{
! /* It is andl with 32 bit immediate. */
! codestream_read ((unsigned char *)buf, 4);
! fi->stack_mask = extract_signed_integer (buf, 4);
}
! }
!
! /* check for stack adjustment
! *
! * subl $XXX, %esp
! *
! * note: you can't subtract a 16 bit immediate
! * from a 32 bit reg, so we don't have to worry
! * about a data16 prefix
! */
! op = codestream_peek ();
! if (op == 0x83)
! {
! /* subl with 8 bit immed */
! codestream_get ();
! if (codestream_get () != 0xec)
! /* Some instruction starting with 0x83 other than subl. */
{
! codestream_seek (codestream_tell () - 2);
! return;
}
+ /* subl with signed byte immediate
+ * (though it wouldn't make sense to be negative)
+ */
+ fi->stack_size = codestream_get();
}
! else if (op == 0x81)
{
! char buf[4];
! /* Maybe it is subl with 32 bit immedediate. */
! codestream_get();
! if (codestream_get () != 0xec)
! /* Some instruction starting with 0x81 other than subl. */
! {
! codestream_seek (codestream_tell () - 2);
! return;
! }
! /* It is subl with 32 bit immediate. */
! codestream_read ((unsigned char *)buf, 4);
! fi->stack_size = extract_signed_integer (buf, 4);
}
!
! return;
}

/* Return number of args passed to a frame.
*************** i386_frame_num_args (fi)
*** 358,372 ****
#endif
}

/*
! * parse the first few instructions of the function to see
! * what registers were stored.
*
* We handle these cases:
*
* The startup sequence can be at the start of the function,
* or the function can start with a branch to startup code at the end.
*
* %ebp can be set up with either the 'enter' instruction, or
* 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
* but was once used in the sys5 compiler)
--- 401,562 ----
#endif
}

+ #if defined(I386V4_SIGTRAMP_SAVED_PC)
+ /*
+ * Determine the location of the registers saved in the signal context
+ * for all three variants of SVR4 sigtramps.
+ */
+
+ static CORE_ADDR
+ i386_sigcontext_addr (fi)
+ struct frame_info *fi;
+ {
+ int offset = 0;
+ char *name = NULL;
+
+ find_pc_partial_function (fi->pc, &name, NULL, NULL);
+ if (name)
+ {
+ if (STREQ (name, "_sigreturn"))
+ offset = 132;
+ else if (STREQ (name, "_sigacthandler"))
+ offset = 80;
+ else if (STREQ (name, "sigvechandler"))
+ offset = 120;
+ }
+
+ if (offset == 0)
+ return 0;
+
+ if (fi->next)
+ return fi->next->frame + offset;
+
+ return read_register (SP_REGNUM) + offset;
+ }
+
+ /* Get saved user PC for sigtramp from the pushed ucontext on the stack. */
+
+ CORE_ADDR
+ i386v4_sigtramp_saved_pc (fi)
+ struct frame_info *frame;
+ {
+
+ return read_memory_integer (i386_sigcontext_addr (fi) + 14 * 4, 4);
+ }
+
+ #elif defined(SIGCONTEXT_FP_OFFSET)
+ /*
+ * Determine the location of the signal context.
+ */
+
+ static CORE_ADDR
+ i386_sigcontext_addr (fi)
+ struct frame_info *fi;
+ {
+ CORE_ADDR sigcontext_addr;
+ int ptrbytes = TARGET_PTR_BIT / TARGET_CHAR_BIT;
+ int sigcontext_offs = (2 * TARGET_INT_BIT) / TARGET_CHAR_BIT;
+
+ /* Get sigcontext address, it is the third parameter on the stack. */
+ if (fi->next)
+ sigcontext_addr = read_memory_integer (FRAME_ARGS_ADDRESS (fi->next)
+ + FRAME_ARGS_SKIP
+ + sigcontext_offs,
+ ptrbytes);
+ else
+ sigcontext_addr = read_memory_integer (read_register (SP_REGNUM)
+ + sigcontext_offs,
+ ptrbytes);
+
+ return sigcontext_addr;
+ }
+ #endif
+
/*
! * Determine where the registers were stored.
! */
!
! static void
! i386_frame_find_saved_regs (fi)
! struct frame_info *fi;
! {
! unsigned char op;
! CORE_ADDR adr;
! int i;
! int offset;
!
! /*
! * First determine the offset of each register that has
! * been placed on the stack.
! */
!
! offset = fi->stack_size;
!
! for (i = 0; i < 8; i++)
! {
! op = codestream_peek ();
! if (op < 0x50 || op > 0x57)
! break;
! codestream_get ();
! offset += 4;
! #ifdef I386_REGNO_TO_SYMMETRY
! /* Dynix uses different internal numbering. Ick. */
! fi->fsr.regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = offset;
! #else
! fi->fsr.regs[op - 0x50] = offset;
! #endif
! }
!
! /*
! * Then determine the actual location of each register
! * that has been placed on the stack.
! */
!
! if (fi->status == MY_FRAME_IN_SP)
! {
! /* Fix fi->frame if it's bogus at this point. */
! if (fi->next == NULL)
! fi->frame = read_sp() + offset;
! }
!
! adr = fi->stack_mask ? (fi->frame & fi->stack_mask) : fi->frame;
!
! for (i = 0; i < 8; i++)
! {
! #ifdef I386_REGNO_TO_SYMMETRY
! /* Dynix uses different internal numbering. Ick. */
! if (fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)])
! fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)] =
! adr - fi->fsr.regs[I386_REGNO_TO_SYMMETRY(i)];
! #else
! if (fi->fsr.regs[i])
! fi->fsr.regs[i] = adr - fi->fsr.regs[i];
! #endif
! }
!
! /*
! * Finally determine where some important registers are located
! */
!
! if (fi->status == MY_FRAME_IN_FP)
! {
! fi->fsr.regs[FP_REGNUM] = fi->frame;
! fi->fsr.regs[PC_REGNUM] = fi->frame + 4;
! }
! else if (fi->status == MY_FRAME_IN_SP)
! fi->fsr.regs[PC_REGNUM] = fi->frame;
! }
!
! /*
! * Parse the prologue.
*
* We handle these cases:
*
* The startup sequence can be at the start of the function,
* or the function can start with a branch to startup code at the end.
*
+ * The function can be frameless.
+ *
* %ebp can be set up with either the 'enter' instruction, or
* 'pushl %ebp, movl %esp, %ebp' (enter is too slow to be useful,
* but was once used in the sys5 compiler)
*************** i386_frame_num_args (fi)
*** 374,448 ****
* Local space is allocated just below the saved %ebp by either the
* 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
* a 16 bit unsigned argument for space to allocate, and the
! * 'addl' instruction could have either a signed byte, or
* 32 bit immediate.
*
* Next, the registers used by this function are pushed. In
* the sys5 compiler they will always be in the order: %edi, %esi, %ebx
* (and sometimes a harmless bug causes it to also save but not restore %eax);
! * however, the code below is willing to see the pushes in any order,
* and will handle up to 8 of them.
*
* If the setup sequence is at the end of the function, then the
* next instruction will be a branch back to the start.
*/

! void
! i386_frame_find_saved_regs (fip, fsrp)
! struct frame_info *fip;
! struct frame_saved_regs *fsrp;
{
- long locals = -1;
- unsigned char op;
- CORE_ADDR dummy_bottom;
CORE_ADDR adr;
! CORE_ADDR pc;
int i;
!
! memset (fsrp, 0, sizeof *fsrp);
!
/* if frame is the end of a dummy, compute where the
* beginning would be
*/
! dummy_bottom = fip->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;

/* check if the PC is in the stack, in a dummy frame */
! if (dummy_bottom <= fip->pc && fip->pc <= fip->frame)
{
! /* all regs were saved by push_call_dummy () */
! adr = fip->frame;
for (i = 0; i < NUM_REGS; i++)
{
adr -= REGISTER_RAW_SIZE (i);
! fsrp->regs[i] = adr;
}
return;
}

! pc = get_pc_function_start (fip->pc);
! if (pc != 0)
! locals = i386_get_frame_setup (pc);
!
! if (locals >= 0)
{
! adr = fip->frame - 4 - locals;
! for (i = 0; i < 8; i++)
! {
! op = codestream_get ();
! if (op < 0x50 || op > 0x57)
! break;
#ifdef I386_REGNO_TO_SYMMETRY
! /* Dynix uses different internal numbering. Ick. */
! fsrp->regs[I386_REGNO_TO_SYMMETRY(op - 0x50)] = adr;
#else
! fsrp->regs[op - 0x50] = adr;
#endif
! adr -= 4;
! }
}
-
- fsrp->regs[PC_REGNUM] = fip->frame + 4;
- fsrp->regs[FP_REGNUM] = fip->frame;
}

/* return pc of first real instruction */
--- 564,771 ----
* Local space is allocated just below the saved %ebp by either the
* 'enter' instruction, or by 'subl $<size>, %esp'. 'enter' has
* a 16 bit unsigned argument for space to allocate, and the
! * 'subl' instruction could have either a signed byte, or
* 32 bit immediate.
*
* Next, the registers used by this function are pushed. In
* the sys5 compiler they will always be in the order: %edi, %esi, %ebx
* (and sometimes a harmless bug causes it to also save but not restore %eax);
! * however, the code is willing to see the pushes in any order,
* and will handle up to 8 of them.
*
* If the setup sequence is at the end of the function, then the
* next instruction will be a branch back to the start.
*/

! static void
! i386_analyze_prologue (fi, skip_prologue)
! struct frame_info *fi;
! int skip_prologue;
{
CORE_ADDR adr;
! CORE_ADDR dummy_bottom;
! CORE_ADDR func_addr, func_end;
! char *name;
! unsigned char op;
int i;
! int status;
!
! /* Find the start of this function. */
! status = find_pc_partial_function (fi->pc, &name, &func_addr, &func_end);
!
! /* If we're in a sigtramp which has a sigcontext then record the location
! of the frame and the stack pointer so that i386_frame_chain will work.
! At some point it may be worth while to also record the location of the
! other registers. */
! #if defined(SIGCONTEXT_FP_OFFSET)
! if (IN_SIGTRAMP (fi->pc, name))
! {
! fi->fsr.regs[FP_REGNUM]
! = i386_sigcontext_addr (fi) + SIGCONTEXT_FP_OFFSET;
! fi->fsr.regs[SP_REGNUM]
! = i386_sigcontext_addr (fi) + SIGCONTEXT_SP_OFFSET;
! return;
! }
! #endif
!
/* if frame is the end of a dummy, compute where the
* beginning would be
*/
! dummy_bottom = fi->frame - 4 - REGISTER_BYTES - CALL_DUMMY_LENGTH;

/* check if the PC is in the stack, in a dummy frame */
! if (dummy_bottom <= fi->pc && fi->pc <= fi->frame)
{
! /* all regs were saved by i386_push_dummy_frame */
! fi->status = MY_FRAME_IN_FP;
! adr = fi->frame;
for (i = 0; i < NUM_REGS; i++)
{
adr -= REGISTER_RAW_SIZE (i);
! fi->fsr.regs[i] = adr;
}
+ fi->fsr.regs[FP_REGNUM] = fi->frame;
+ fi->fsr.regs[PC_REGNUM] = fi->frame + 4;
return;
}
+
+ /* If we couldn't find the start of this function then assume that
+ it's frame is in the frame pointer so that we can chain back to
+ a dummy frame. */
+ if (status == 0)
+ {
+ fi->status = MY_FRAME_IN_FP;
+ return;
+ }
+
+ /* If we're in start, then give up. */
+ if (strcmp (name, "start") == 0)
+ {
+ fi->status = NO_MORE_FRAMES;
+ return;
+ }
+
+ /* At the start of a function our frame is in the stack pointer. */
+ fi->status = MY_FRAME_IN_SP;
+
+ /* If we're physically on the first insn of a prologue, then our frame
+ hasn't been allocated yet. And if we're physically on an "return"
+ instruction, then our frame has already been deallocated. */
+ if (!skip_prologue)
+ {
+ codestream_seek (fi->pc);
+ op = codestream_peek();
+ if (fi->pc == func_addr
+ || op == 0xc2 || op == 0xc3 || op == 0xca || op == 0xcb)
+ {
+ /* Fix fi->frame if it's bogus at this point. */
+ if (fi->next == NULL)
+ fi->frame = read_sp();
+ fi->fsr.regs[PC_REGNUM] = fi->frame;
+ fi->status = INCOMPLETE_FRAME;
+ return;
+ }
+ }
+
+ /* Start scanning on the first instruction of this function. */
+ codestream_seek (func_addr);
+
+ i386_follow_jump ();
+
+ i386_get_frame_setup (fi);

! i386_frame_find_saved_regs (fi);
! }
!
! /* Function: frame_chain
! Figure out and return the caller's frame pointer given current
! frame_info struct.
!
! We don't handle dummy frames yet but we would probably just return the
! stack pointer that was in use at the time the function call was made? */
!
! CORE_ADDR
! i386_frame_chain (fi)
! struct frame_info *fi;
! {
! struct frame_info dummy_frame;
!
! /* Walk through the prologue to determine the stack size,
! location of saved registers, end of the prologue, etc. */
! if (fi->status == 0)
! i386_init_extra_frame_info (fi);
!
! /* Quit now if i386_analyze_prologue set NO_MORE_FRAMES. */
! if (fi->status & NO_MORE_FRAMES)
! return 0;
!
! /* Now that we've analyzed our prologue, determine the frame
! pointer for our caller.
!
! If our caller has a frame pointer, then we need to
! find the entry value of %ebp to our function.
!
! If fsr.regs[FP_REGNUM] is nonzero, then it's at the memory
! location pointed to by fsr.regs[FP_REGNUM].
!
! Else it's still in %ebp.
!
! If our caller does not have a frame pointer, then his
! frame base is fi->frame + <pc save space> +
! <caller's register save space> + <caller's stack size>
! assuming that the caller's stack pointer was unchanging.
!
! The easiest way to get that info is to analyze our caller's frame.
! So we set up a dummy frame and call i386_init_extra_frame_info to
! find stuff for us. BTW, the actual value of dummy_frame.frame
! doesn't matter so long as it isn't zero. */
!
! dummy_frame.next = fi;
! dummy_frame.frame = fi->frame;
! i386_init_extra_frame_info (&dummy_frame);
!
! if (! dummy_frame.status)
! return fi->frame;
!
! if (dummy_frame.status & MY_FRAME_IN_FP)
! {
! char buf[MAX_REGISTER_RAW_SIZE];
!
! /* Our caller has a frame pointer. So find the frame in %ebp or
! in the stack. */
! if (fi->fsr.regs[FP_REGNUM])
! return read_memory_integer (fi->fsr.regs[FP_REGNUM], 4);
! get_saved_register(buf, NULL, NULL, fi, FP_REGNUM, NULL);
! return extract_address (buf, REGISTER_RAW_SIZE (FP_REGNUM));
! }
! else
{
! int offset;
! int i;
!
! offset = dummy_frame.stack_size;
!
! for (i = 0; i < 8; i++)
#ifdef I386_REGNO_TO_SYMMETRY
! /* Dynix uses different internal numbering. Ick. */
! if (dummy_frame.fsr.regs[I386_REGNO_TO_SYMMETRY(i)])
! offset += 4;
#else
! if (dummy_frame.fsr.regs[i])
! offset += 4;
#endif
!
! if (fi->signal_handler_caller && fi->fsr.regs[SP_REGNUM])
! return read_memory_integer (fi->fsr.regs[SP_REGNUM], 4) + offset;
!
! offset += (fi->status & MY_FRAME_IN_FP) ? 8 : 4;
!
! /* Our caller does not have a frame pointer. Assume his stack
! pointer was constant which means that his frame starts at
! the base of our frame (fi->frame) + pc save space +
! <his register save space> + <his size>. */
! return fi->frame + offset;
}
}

/* return pc of first real instruction */
*************** i386_skip_prologue (pc)
*** 457,479 ****
0x5b, /* popl %ebx */
};
CORE_ADDR pos;

! if (i386_get_frame_setup (pc) < 0)
! return (pc);
!
! /* found valid frame setup - codestream now points to
! * start of push instructions for saving registers
! */
!
! /* skip over register saves */
! for (i = 0; i < 8; i++)
! {
! op = codestream_peek ();
! /* break if not pushl inst */
! if (op < 0x50 || op > 0x57)
! break;
! codestream_get ();
! }

/* The native cc on SVR4 in -K PIC mode inserts the following code to get
the address of the global offset table (GOT) into register %ebx.
--- 780,791 ----
0x5b, /* popl %ebx */
};
CORE_ADDR pos;
+ struct frame_info fi;

! fi.frame = 0;
! fi.pc = pc;
!
! i386_analyze_prologue (&fi, 1);

/* The native cc on SVR4 in -K PIC mode inserts the following code to get
the address of the global offset table (GOT) into register %ebx.
*************** i386_skip_prologue (pc)
*** 525,531 ****

i386_follow_jump ();

! return (codestream_tell ());
}

void
--- 837,843 ----

i386_follow_jump ();

! return codestream_tell ();
}

void
*************** void
*** 550,562 ****
i386_pop_frame ()
{
struct frame_info *frame = get_current_frame ();
- CORE_ADDR fp;
int regnum;
struct frame_saved_regs fsr;
char regbuf[MAX_REGISTER_RAW_SIZE];

- fp = FRAME_FP (frame);
get_frame_saved_regs (frame, &fsr);
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
CORE_ADDR adr;
--- 862,873 ----
i386_pop_frame ()
{
struct frame_info *frame = get_current_frame ();
int regnum;
struct frame_saved_regs fsr;
char regbuf[MAX_REGISTER_RAW_SIZE];

get_frame_saved_regs (frame, &fsr);
+
for (regnum = 0; regnum < NUM_REGS; regnum++)
{
CORE_ADDR adr;
*************** i386_pop_frame ()
*** 568,576 ****
REGISTER_RAW_SIZE (regnum));
}
}
! write_register (FP_REGNUM, read_memory_integer (fp, 4));
! write_register (PC_REGNUM, read_memory_integer (fp + 4, 4));
! write_register (SP_REGNUM, fp + 8);
flush_cached_frames ();
}

--- 879,887 ----
REGISTER_RAW_SIZE (regnum));
}
}
!
! write_register (SP_REGNUM, fsr.regs[PC_REGNUM] + 4);
!
flush_cached_frames ();
}

*************** i386_extract_return_value(type, regbuf,
*** 632,665 ****
}
}

- #ifdef I386V4_SIGTRAMP_SAVED_PC
- /* Get saved user PC for sigtramp from the pushed ucontext on the stack
- for all three variants of SVR4 sigtramps. */
-
- CORE_ADDR
- i386v4_sigtramp_saved_pc (frame)
- struct frame_info *frame;
- {
- CORE_ADDR saved_pc_offset = 4;
- char *name = NULL;
-
- find_pc_partial_function (frame->pc, &name, NULL, NULL);
- if (name)
- {
- if (STREQ (name, "_sigreturn"))
- saved_pc_offset = 132 + 14 * 4;
- else if (STREQ (name, "_sigacthandler"))
- saved_pc_offset = 80 + 14 * 4;
- else if (STREQ (name, "sigvechandler"))
- saved_pc_offset = 120 + 14 * 4;
- }
-
- if (frame->next)
- return read_memory_integer (frame->next->frame + saved_pc_offset, 4);
- return read_memory_integer (read_register (SP_REGNUM) + saved_pc_offset, 4);
- }
- #endif /* I386V4_SIGTRAMP_SAVED_PC */
-
#ifdef STATIC_TRANSFORM_NAME
/* SunPRO encodes the static variables. This is not related to C++ mangling,
it is done for C too. */
--- 943,948 ----
*************** skip_trampoline_code (pc, name)
*** 712,717 ****
--- 995,1029 ----
return 0; /* not a trampoline */
}

+ /* Function: init_extra_frame_info
+ Setup the frame's frame pointer, pc, and frame addresses for saved
+ registers. Most of the work is done in i386_analyze_prologue().
+
+ Note that when we are called for the last frame (currently active frame),
+ that fi->pc and fi->frame will already be setup. However, fi->frame will
+ be valid only if this routine uses FP. For previous frames, fi->frame will
+ always be correct. i386_analyze_prologue will fix fi->frame if
+ it's not valid.
+
+ We can be called with the PC in the call dummy under two circumstances.
+ First, during normal backtracing, second, while figuring out the frame
+ pointer just prior to calling the target function (see run_stack_dummy). */
+
+ void
+ i386_init_extra_frame_info (fi)
+ struct frame_info *fi;
+ {
+
+ if (fi->next)
+ fi->pc = FRAME_SAVED_PC (fi->next);
+
+ memset (fi->fsr.regs, '\000', sizeof fi->fsr.regs);
+ fi->status = 0;
+ fi->stack_mask = 0;
+ fi->stack_size = 0;
+
+ i386_analyze_prologue (fi, 0);
+ }

void
_initialize_i386_tdep ()
*** gdb/config/i386/tm-i386.h.ORIGINAL Thu Jan 4 02:23:24 1996
--- gdb/config/i386/tm-i386.h Thu Feb 25 22:09:21 1999
*************** extern void i386_extract_return_value PA
*** 188,193 ****
--- 188,204 ----

#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)(REGBUF))

+ #define EXTRA_FRAME_INFO \
+ int status; \
+ int stack_mask; \
+ int stack_size; \
+ struct frame_saved_regs fsr;
+
+ #define INIT_EXTRA_FRAME_INFO(fromleaf, fi) i386_init_extra_frame_info (fi)
+ #define INIT_FRAME_PC /* Not necessary */
+
+ extern void i386_init_extra_frame_info PARAMS ((struct frame_info *));
+
/* The following redefines make backtracing through sigtramp work.
They manufacture a fake sigtramp frame and obtain the saved pc in sigtramp
from the sigcontext structure which is pushed by the kernel on the
*************** extern void i386_extract_return_value PA
*** 200,235 ****

#define FRAME_CHAIN(thisframe) \
((thisframe)->signal_handler_caller \
! ? (thisframe)->frame \
: (!inside_entry_file ((thisframe)->pc) \
! ? read_memory_integer ((thisframe)->frame, 4) \
: 0))

! /* A macro that tells us whether the function invocation represented
! by FI does not have a frame on the stack associated with it. If it
! does not, FRAMELESS is set to 1, else 0. */
!
! #define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \
! do { \
! if ((FI)->signal_handler_caller) \
! (FRAMELESS) = 0; \
! else \
! (FRAMELESS) = frameless_look_for_prologue(FI); \
! } while (0)

/* Saved Pc. Get it from sigcontext if within sigtramp. */

#define FRAME_SAVED_PC(FRAME) \
(((FRAME)->signal_handler_caller \
? sigtramp_saved_pc (FRAME) \
! : read_memory_integer ((FRAME)->frame + 4, 4)) \
)

extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *));

! #define FRAME_ARGS_ADDRESS(fi) ((fi)->frame)

! #define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame)

/* Return number of args passed to a frame. Can return -1, meaning no way
to tell, which is typical now that the C compiler delays popping them. */
--- 211,251 ----

#define FRAME_CHAIN(thisframe) \
((thisframe)->signal_handler_caller \
! ? i386_frame_chain (thisframe) \
: (!inside_entry_file ((thisframe)->pc) \
! ? i386_frame_chain (thisframe) \
: 0))

! extern CORE_ADDR i386_frame_chain PARAMS ((struct frame_info *));

/* Saved Pc. Get it from sigcontext if within sigtramp. */

#define FRAME_SAVED_PC(FRAME) \
(((FRAME)->signal_handler_caller \
? sigtramp_saved_pc (FRAME) \
! : read_memory_integer ((FRAME)->fsr.regs[PC_REGNUM], 4)) \
)

extern CORE_ADDR sigtramp_saved_pc PARAMS ((struct frame_info *));

! /* There are several meanings associated with stack_mask:
!
! stack_mask == 0 Both the args and locals use %ebp.
!
! stack_mask == -1 Both the args and locals use %esp.

! stack_mask != 0 The args use %ebp and the locals use %esp.
! && stack_mask != -1 */
!
! #define FRAME_ARGS_ADDRESS(fi) \
! (((fi)->stack_mask == -1) \
! ? ((fi)->frame - (fi)->stack_size) \
! : (fi)->frame)
!
! #define FRAME_LOCALS_ADDRESS(fi) \
! ((fi)->stack_mask \
! ? (((fi)->frame & (fi)->stack_mask) - (fi)->stack_size) \
! : (fi)->frame)

/* Return number of args passed to a frame. Can return -1, meaning no way
to tell, which is typical now that the C compiler delays popping them. */
*************** extern int i386_frame_num_args PARAMS ((
*** 248,259 ****
ways in the stack frame. sp is even more special:
the address we return for it IS the sp for the next frame. */

! #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \
! { i386_frame_find_saved_regs ((frame_info), &(frame_saved_regs)); }
!
! extern void i386_frame_find_saved_regs PARAMS ((struct frame_info *,
! struct frame_saved_regs *));
!
\f
/* Things needed for making the inferior call functions. */

--- 264,270 ----
ways in the stack frame. sp is even more special:
the address we return for it IS the sp for the next frame. */

! #define FRAME_FIND_SAVED_REGS(fi, regaddr) regaddr = fi->fsr
\f
/* Things needed for making the inferior call functions. */

*** gdb/config/i386/tm-i386bsd.h.ORIGINAL Sun May 26 17:41:33 1996
--- gdb/config/i386/tm-i386bsd.h Thu Feb 25 22:09:21 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 39,43 ****
--- 39,45 ----

/* Offset to saved PC in sigcontext, from <sys/signal.h>. */
#define SIGCONTEXT_PC_OFFSET 20
+ #define SIGCONTEXT_FP_OFFSET 12
+ #define SIGCONTEXT_SP_OFFSET 8

#endif /* ifndef TM_I386BSD_H */
*** gdb/config/i386/tm-i386sol2.h.ORIGINAL Sat Apr 11 01:39:47 1998
--- gdb/config/i386/tm-i386sol2.h Thu Feb 25 22:23:14 1999
*************** Foundation, Inc., 59 Temple Place - Suit
*** 27,33 ****
--- 27,37 ----
a pointer to an ucontext. */
#undef sigtramp_saved_pc
#undef I386V4_SIGTRAMP_SAVED_PC
+ #undef SIGCONTEXT_FP_OFFSET
+ #undef SIGCONTEXT_SP_OFFSET
#define SIGCONTEXT_PC_OFFSET (36 + 14 * 4)
+ #define SIGCONTEXT_FP_OFFSET (36 + 6 * 4)
+ #define SIGCONTEXT_SP_OFFSET (36 + 17 * 4)
#undef IN_SIGTRAMP
#define IN_SIGTRAMP(pc, name) (pc == 0xFFFFFFFF)

*** gdb/config/i386/tm-i386v4.h.ORIGINAL Thu Nov 2 10:20:44 1995
--- gdb/config/i386/tm-i386v4.h Thu Feb 25 22:09:21 1999
*************** get_longjmp_target PARAMS ((CORE_ADDR *)
*** 65,70 ****
--- 65,72 ----
user stack. Unfortunately there are three variants of sigtramp handlers. */

#define I386V4_SIGTRAMP_SAVED_PC
+ #define SIGCONTEXT_FP_OFFSET (6 * 4)
+ #define SIGCONTEXT_SP_OFFSET (17 * 4)
#define IN_SIGTRAMP(pc, name) ((name) \
&& (STREQ ("_sigreturn", name) \
|| STREQ ("_sigacthandler", name) \
-------------------------------------------------------------------------
| Feith Systems | Voice: 1-215-646-8000 | Email: john@feith.com |
| John Wehle | Fax: 1-215-540-5495 | |
-------------------------------------------------------------------------

------- End of forwarded message -------
From msnyder@cygnus.com Fri Mar 17 16:19:00 2000
From: Michael Snyder <msnyder@cygnus.com>
To: John David Anglin <dave@hiauly1.hia.nrc.ca>
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: Initialization of hpux_threads
Date: Fri, 17 Mar 2000 16:19:00 -0000
Message-id: <38D2CB7D.24B6@cygnus.com>
References: <200003162153.QAA08326@hiauly1.hia.nrc.ca>
X-SW-Source: 2000-03/msg00324.html
Content-length: 752

John David Anglin wrote:
>
> Thu Mar 16 16:49:27 EST 2000 John David Anglin <dave@hiauly1.hia.nrc.ca>
>
> * configure.in: Don't call _initialize_hpux_thread twice.
> * configure: Regenerated.
>
> --- configure.in.orig Mon Mar 6 18:30:12 2000
> +++ configure.in Thu Mar 16 14:22:26 2000
> @@ -330,7 +330,6 @@
> AC_DEFINE(HAVE_HPUX_THREAD_SUPPORT)
> CONFIG_OBS="${CONFIG_OJS} hpux-thread.o"
> CONFIG_SRCS="${CONFIG_SRCS} hpux-thread.c"
> - CONFIG_INITS="${CONFIG_INITS} hpux-thread.c"
> else
> AC_MSG_RESULT(no (suppressed because you are not using GCC))
> fi

If someone from HP will approve this, I will check it in...

Michael Snyder
From shebs@shebs.cnchost.com Fri Mar 17 16:46:00 2000
From: Stan Shebs <shebs@shebs.cnchost.com>
To: dima@Chg.RU
Cc: gdb-patches@sourceware.cygnus.com
Subject: Re: [Fwd: Yet another patch to gdb.texinfo]
Date: Fri, 17 Mar 2000 16:46:00 -0000
Message-id: <38D2D35F.19B3E3C6@shebs.cnchost.com>
References: <38CEFA08.FC2D40B@apple.com>
X-SW-Source: 2000-03/msg00325.html
Content-length: 879

> Subject: Yet another patch to gdb.texinfo
> Date: Tue, 14 Mar 2000 22:30:19 +0300 (MSK)
> From: Dmitry Sivachenko <dima@Chg.RU>
> To: gdb-patches@sourceware.cygnus.com
>
> I think this is better way to add new entry into dir-file:
>
> Please apply this patch.

OK, I just committed the last four manual patches en masse, though
with some additional tweaks. In particular, I clarified the bit
about string constants, since they *can* have single quotes; don't
even need an escape char, and double quotes just need a backslash.
In short, GDB follows the usual rules of C.

Also, in reference to a previous discussion, I reviewed the texinfo
manual and indeed @samp{} is recommended when displaying command
arguments, options, etc. Sometimes it does look a little weird,
such as for an example GDB string - it comes out as `"abc"'. But
that's the price of consistency.

Stan
From kevinb@cygnus.com Fri Mar 17 18:28:00 2000
From: Kevin Buettner <kevinb@cygnus.com>
To: gdb-patches@sourceware.cygnus.com
Subject: [PATCH RFA] solib.c, symfile.c, symtab.h, and target.h changes
Date: Fri, 17 Mar 2000 18:28:00 -0000
Message-id: <1000318022821.ZM8341@ocotillo.lan>
X-SW-Source: 2000-03/msg00326.html
Content-length: 6633

Yesterday, I submitted an RFA for changes to solib.c in

http://sourceware.cygnus.com/ml/gdb-patches/2000-q1/msg00746.html

Jim Blandy asked me to restructure the code somewhat. He said,

I have only one request: the code which scans an array of
section_table entries and fills in a struct section_addr_info is
hardly specific to shared libraries. Could you turn it into a
function, put it in symfile.c, and just call it from solib.c? I
guess you'll need a corresponding cleanup function to free the
names.

I have done this and am submitting for approval the patch below. This
patch supersedes the patches contained in

http://sourceware.cygnus.com/ml/gdb/2000-q1/msg00681.html
http://sourceware.cygnus.com/ml/gdb-patches/2000-q1/msg00746.html

The difficult part was choosing names for the new functions and
deciding which header file should be used to declare the new
functions. I ended up putting them next to the declaration of
build_section_table() in target.h. target.h was the best choice
for the following reasons:

1) The prototype for build_section_addr_info_from_section_table()
refers to struct section_table *. This type is declared in
target.h.

2) The return type for build_section_addr_info_from_section_table()
is struct section_addr_info *. This type is declared in symtab.h.
But target.h includes symtab.h. So this type is available to
target.h as well.

3) target.h already has a declaration for a function dealing with
struct section_table *.

Jim B. "pre-approved" me for checking in the changes to solib.c,
symtab.h, and symfile.c. It's not clear to me who the maintainer
for target.h is, so I'm seeking approval for those changes. (My
guess is that Andrew is the maintainer by default.)

* symtab.h (MAX_SECTIONS): Increase to 30.
* solib.c (symbol_add_stub): Make symbol_file_add() aware of
all section addresses, not just .text.
* target.h, symfile.h (free_section_addr_info,
build_section_addr_info_from_section_table): New functions.

Index: solib.c
===================================================================
RCS file: /cvs/src/src/gdb/solib.c,v
retrieving revision 1.5
diff -u -p -r1.5 solib.c
--- solib.c 2000/03/17 20:12:23 1.5
+++ solib.c 2000/03/18 01:49:43
@@ -1155,6 +1155,7 @@ symbol_add_stub (arg)
{
register struct so_list *so = (struct so_list *) arg; /* catch_errs bogon */
CORE_ADDR text_addr = 0;
+ struct section_addr_info *sap;

/* Have we already loaded this shared object? */
ALL_OBJFILES (so->objfile)
@@ -1181,15 +1182,12 @@ symbol_add_stub (arg)
+ LM_ADDR (so);
}

- {
- struct section_addr_info section_addrs;
-
- memset (&section_addrs, 0, sizeof (section_addrs));
- section_addrs.text_addr = text_addr;
-
- so->objfile = symbol_file_add (so->so_name, so->from_tty,
- &section_addrs, 0, OBJF_SHARED);
- }
+ sap = build_section_addr_info_from_section_table (so->sections,
+ so->sections_end);
+ sap->text_addr = text_addr;
+ so->objfile = symbol_file_add (so->so_name, so->from_tty,
+ sap, 0, OBJF_SHARED);
+ free_section_addr_info (sap);

return (1);
}
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.2
diff -u -p -r1.2 symfile.c
--- symfile.c 2000/03/15 19:43:57 1.2
+++ symfile.c 2000/03/18 01:49:47
@@ -461,6 +461,58 @@ find_lowest_section (abfd, sect, obj)
*lowest = sect;
}

+
+/* Build (allocate and populate) a section_addr_info struct from
+ an existing section table. */
+
+extern struct section_addr_info *
+build_section_addr_info_from_section_table (struct section_table *start,
+ struct section_table *end)
+{
+ struct section_addr_info *sap;
+ struct section_table *stp;
+ int oidx;
+
+ sap = xmalloc (sizeof (struct section_addr_info));
+ memset (sap, 0, sizeof (struct section_addr_info));
+
+ for (stp = start, oidx = 0; stp != end; stp++)
+ {
+ if (strcmp (stp->the_bfd_section->name, ".text") == 0)
+ sap->text_addr = stp->addr;
+ else if (strcmp (stp->the_bfd_section->name, ".data") == 0)
+ sap->data_addr = stp->addr;
+ else if (strcmp (stp->the_bfd_section->name, ".bss") == 0)
+ sap->bss_addr = stp->addr;
+
+ if (stp->the_bfd_section->flags & (SEC_ALLOC | SEC_LOAD)
+ && oidx < MAX_SECTIONS)
+ {
+ sap->other[oidx].addr = stp->addr;
+ sap->other[oidx].name = xstrdup (stp->the_bfd_section->name);
+ sap->other[oidx].sectindex = stp->the_bfd_section->index;
+ oidx++;
+ }
+ }
+
+ return sap;
+}
+
+
+/* Free all memory allocated by build_section_addr_info_from_section_table. */
+
+extern void
+free_section_addr_info (struct section_addr_info *sap)
+{
+ int idx;
+
+ for (idx = 0; idx < MAX_SECTIONS; idx++)
+ if (sap->other[idx].name)
+ free (sap->other[idx].name);
+ free (sap);
+}
+
+
/* Parse the user's idea of an offset for dynamic linking, into our idea
of how to represent it for fast symbol reading. This is the default
version of the sym_fns.sym_offsets function for symbol readers that
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.3
diff -u -p -r1.3 symtab.h
--- symtab.h 2000/03/14 19:58:02 1.3
+++ symtab.h 2000/03/18 01:49:48
@@ -842,7 +842,7 @@ struct section_offsets
can keep track of the section names until we read the file and
can map them to bfd sections. */

-#define MAX_SECTIONS 12
+#define MAX_SECTIONS 30
struct section_addr_info
{
/* Sections whose names are always known to gdb. */
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.2
diff -u -p -r1.2 target.h
--- target.h 2000/03/15 16:55:07 1.2
+++ target.h 2000/03/18 01:49:49
@@ -1326,6 +1326,18 @@ extern int
build_section_table PARAMS ((bfd *, struct section_table **,
struct section_table **));

+/* Build (allocate and populate) a section_addr_info struct from
+ an existing section table. */
+
+extern struct section_addr_info *
+build_section_addr_info_from_section_table (struct section_table *start,
+ struct section_table *end);
+
+/* Free all memory allocated by build_section_addr_info_from_section_table. */
+
+extern void
+free_section_addr_info (struct section_addr_info *);
+
/* From mem-break.c */

extern int memory_remove_breakpoint PARAMS ((CORE_ADDR, char *));