* [RFC] i386 PLT stub unwinder
@ 2011-06-13 15:56 Mark Kettenis
2011-06-13 16:14 ` Jan Kratochvil
2011-06-14 11:49 ` Pedro Alves
0 siblings, 2 replies; 7+ messages in thread
From: Mark Kettenis @ 2011-06-13 15:56 UTC (permalink / raw)
To: gdb-patches
Jan's mail about DWARF CFI for PLT stubs prompted me to write an
undinder for the PLT stubs as defined by the i386 ABI. With this
change I can step through the PLT stubs and always have a proper
backtrace.
The reason that this is an RFC, is that I'm a little bit confused
about the TRY_CATCH stuff that was introduced in some of the i386
unwinders by Pedro. It isn't entirely clear to me when that is
needed. Unwinding the PC should always succeed at this point, since
the sniffers already rely on that. And unwinding the stack pointer
needs to be working as well, otherwise unwinding the PC will never
have worked. So I don't think I need to worry about unavailable
registers here.
2011-06-12 Mark Kettenis <kettenis@gnu.org>
* i386-tdep.c (i386_plt0_stub_insns, i386_plt_stub_insns)
(i386_pic_plt0_stub_insns, i386_pic_plt_stub_insns): New
variables.
(i386_plt_stub_frame_cache, i386_plt_stub_frame_this_id)
(i386_plt_stub_frame_prev_register, i386_plt_stub_frame_sniffer):
New functions.
(i386_plt_stub_frame_unwind): New variable.
(i386_elf_init_abi): Append PLT stub unwinder.
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.334
diff -u -p -r1.334 i386-tdep.c
--- i386-tdep.c 12 Jun 2011 20:46:11 -0000 1.334
+++ i386-tdep.c 13 Jun 2011 15:43:26 -0000
@@ -2070,6 +2070,200 @@ static const struct frame_unwind i386_st
};
\f
+/* PLT stubs. */
+
+struct i386_insn i386_plt0_stub_insns[] =
+{
+ /* `pushl imm32' */
+ { 6, { 0xff, 0x35 }, { 0xff, 0xff } },
+
+ /* `jmp *disp32' */
+ { 6, { 0xff, 0x25 }, { 0xff, 0xff } },
+
+ {0}
+};
+
+struct i386_insn i386_plt_stub_insns[] =
+{
+ /* `jmp *disp32' */
+ { 6, { 0xff, 0x25 }, { 0xff, 0xff } },
+
+ /* `pushl imm32' */
+ { 5, { 0x68 }, { 0xff } },
+
+ /* `jmp rel32' */
+ { 5, { 0xe9 }, { 0xff } },
+
+ {0}
+};
+
+struct i386_insn i386_pic_plt0_stub_insns[] =
+{
+ /* `pushl imm32' */
+ { 6, { 0xff, 0xb3, 4, 0, 0, 0 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } },
+
+ /* `jmp *imm32' */
+ { 6, { 0xff, 0xa3, 8, 0, 0, 0 }, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } },
+
+ {0}
+};
+
+struct i386_insn i386_pic_plt_stub_insns[] =
+{
+ /* `jmp *disp32(%ebx)' */
+ { 6, { 0xff, 0xa3 }, { 0xff, 0xff } },
+
+ /* `pushl imm32' */
+ { 5, { 0x68 }, { 0xff } },
+
+ /* `jmp rel32' */
+ { 5, { 0xe9 }, { 0xff } },
+
+ {0}
+};
+
+static struct i386_frame_cache *
+i386_plt_stub_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+ struct i386_frame_cache *cache;
+ struct i386_insn *insn;
+ LONGEST sp_offset = -4;
+ CORE_ADDR pc, sp;
+ int i;
+
+ if (*this_cache)
+ return *this_cache;
+
+ cache = i386_alloc_frame_cache ();
+ *this_cache = cache;
+
+ pc = get_frame_pc (this_frame);
+ if (i386_match_insn_block (pc, i386_plt_stub_insns))
+ {
+ insn = i386_match_insn (pc, i386_plt_stub_insns);
+
+ for (i = 0; i < ARRAY_SIZE(i386_plt_stub_insns); i++)
+ {
+ if (insn == &i386_plt_stub_insns[i])
+ break;
+
+ pc -= i386_plt_stub_insns[i].len;
+ }
+
+ if (insn == &i386_plt_stub_insns[2])
+ cache->sp_offset = 0;
+ }
+ else if (i386_match_insn_block (pc, i386_plt0_stub_insns))
+ {
+ insn = i386_match_insn (pc, i386_plt0_stub_insns);
+
+ for (i = 0; i < ARRAY_SIZE(i386_plt0_stub_insns); i++)
+ {
+ if (insn == &i386_plt0_stub_insns[i])
+ break;
+
+ pc -= i386_plt0_stub_insns[i].len;
+ }
+
+ if (insn == &i386_plt0_stub_insns[0])
+ cache->sp_offset = 0;
+ else
+ cache->sp_offset = 4;
+ }
+ else if (i386_match_insn_block (pc, i386_pic_plt_stub_insns))
+ {
+ insn = i386_match_insn (pc, i386_pic_plt_stub_insns);
+
+ for (i = 0; i < ARRAY_SIZE(i386_pic_plt_stub_insns); i++)
+ {
+ if (insn == &i386_pic_plt_stub_insns[i])
+ break;
+
+ pc -= i386_pic_plt_stub_insns[i].len;
+ }
+
+ if (insn == &i386_pic_plt_stub_insns[2])
+ cache->sp_offset = 0;
+ }
+ else if (i386_match_insn_block (pc, i386_pic_plt0_stub_insns))
+ {
+ insn = i386_match_insn (pc, i386_pic_plt0_stub_insns);
+
+ for (i = 0; i < ARRAY_SIZE(i386_pic_plt0_stub_insns); i++)
+ {
+ if (insn == &i386_pic_plt0_stub_insns[i])
+ break;
+
+ pc -= i386_pic_plt0_stub_insns[i].len;
+ }
+
+ if (insn == &i386_pic_plt0_stub_insns[0])
+ cache->sp_offset = 0;
+ else
+ cache->sp_offset = 4;
+ }
+
+ cache->pc = pc;
+
+ sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+ cache->base = sp + cache->sp_offset;
+ cache->saved_sp = cache->base + 8;
+ cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+
+ cache->base_p = 1;
+ return cache;
+}
+
+static void
+i386_plt_stub_frame_this_id (struct frame_info *this_frame, void **this_cache,
+ struct frame_id *this_id)
+{
+ struct i386_frame_cache *cache =
+ i386_plt_stub_frame_cache (this_frame, this_cache);
+
+ /* See the end of i386_push_dummy_call. */
+ (*this_id) = frame_id_build (cache->base + 8, cache->pc);
+}
+
+static struct value *
+i386_plt_stub_frame_prev_register (struct frame_info *this_frame,
+ void **this_cache, int regnum)
+{
+ /* Make sure we've initialized the cache. */
+ i386_plt_stub_frame_cache (this_frame, this_cache);
+
+ return i386_frame_prev_register (this_frame, this_cache, regnum);
+}
+
+static int
+i386_plt_stub_frame_sniffer (const struct frame_unwind *self,
+ struct frame_info *this_frame, void **this_cache)
+{
+ CORE_ADDR pc = get_frame_pc (this_frame);
+
+ if (!in_plt_section(pc, NULL))
+ return 0;
+
+ if (!i386_match_insn_block (pc, i386_plt_stub_insns)
+ && !i386_match_insn_block (pc, i386_plt0_stub_insns)
+ && !i386_match_insn_block (pc, i386_pic_plt_stub_insns)
+ && !i386_match_insn_block (pc, i386_pic_plt0_stub_insns))
+ return 0;
+
+ return 1;
+}
+
+static const struct frame_unwind i386_plt_stub_frame_unwind =
+{
+ NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
+ i386_plt_stub_frame_this_id,
+ i386_plt_stub_frame_prev_register,
+ NULL,
+ i386_plt_stub_frame_sniffer
+};
+\f
+
/* Signal trampolines. */
static struct i386_frame_cache *
@@ -3305,6 +3499,8 @@ i386_elf_init_abi (struct gdbarch_info i
{
/* We typically use stabs-in-ELF with the SVR4 register numbering. */
set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum);
+
+ frame_unwind_append_unwinder (gdbarch, &i386_plt_stub_frame_unwind);
}
/* System V Release 4 (SVR4). */
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-13 15:56 [RFC] i386 PLT stub unwinder Mark Kettenis
@ 2011-06-13 16:14 ` Jan Kratochvil
2011-06-13 16:32 ` Joel Brobecker
2011-06-13 16:43 ` Tom Tromey
2011-06-14 11:49 ` Pedro Alves
1 sibling, 2 replies; 7+ messages in thread
From: Jan Kratochvil @ 2011-06-13 16:14 UTC (permalink / raw)
To: Mark Kettenis; +Cc: gdb-patches
On Mon, 13 Jun 2011 17:55:56 +0200, Mark Kettenis wrote:
> Jan's mail about DWARF CFI for PLT stubs prompted me to write an
> undinder for the PLT stubs as defined by the i386 ABI. With this
> change I can step through the PLT stubs and always have a proper
> backtrace.
I do not think GDB is the right place to fix it, it should be fixed by proper
.eh_Frame as this problem affects all the tools trying to unwind such as also
oprofile, systemtap etc.
Thanks,
Jan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-13 16:14 ` Jan Kratochvil
@ 2011-06-13 16:32 ` Joel Brobecker
2011-06-13 16:43 ` Tom Tromey
1 sibling, 0 replies; 7+ messages in thread
From: Joel Brobecker @ 2011-06-13 16:32 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Mark Kettenis, gdb-patches
> I do not think GDB is the right place to fix it, it should be fixed by proper
> .eh_Frame as this problem affects all the tools trying to unwind such as also
> oprofile, systemtap etc.
But at the same time, isn't it a good thing to have a fallback mechanism
in case the debug info is not there?
--
Joel
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-13 16:14 ` Jan Kratochvil
2011-06-13 16:32 ` Joel Brobecker
@ 2011-06-13 16:43 ` Tom Tromey
2011-06-13 19:15 ` Mark Kettenis
1 sibling, 1 reply; 7+ messages in thread
From: Tom Tromey @ 2011-06-13 16:43 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: Mark Kettenis, gdb-patches
>>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
Jan> On Mon, 13 Jun 2011 17:55:56 +0200, Mark Kettenis wrote:
>> Jan's mail about DWARF CFI for PLT stubs prompted me to write an
>> undinder for the PLT stubs as defined by the i386 ABI. With this
>> change I can step through the PLT stubs and always have a proper
>> backtrace.
Jan> I do not think GDB is the right place to fix it, it should be fixed
Jan> by proper .eh_Frame as this problem affects all the tools trying to
Jan> unwind such as also oprofile, systemtap etc.
I agree, but I think also doing it in GDB is harmless, at least provided
that the new unwinder is only applied when the PLT stubs are missing the
needed info. That way, when ld is fixed, GDB will automatically start
doing the right thing.
Tom
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-13 16:43 ` Tom Tromey
@ 2011-06-13 19:15 ` Mark Kettenis
0 siblings, 0 replies; 7+ messages in thread
From: Mark Kettenis @ 2011-06-13 19:15 UTC (permalink / raw)
To: tromey; +Cc: jan.kratochvil, gdb-patches
> From: Tom Tromey <tromey@redhat.com>
> Date: Mon, 13 Jun 2011 10:43:20 -0600
>
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
>
> Jan> On Mon, 13 Jun 2011 17:55:56 +0200, Mark Kettenis wrote:
> >> Jan's mail about DWARF CFI for PLT stubs prompted me to write an
> >> undinder for the PLT stubs as defined by the i386 ABI. With this
> >> change I can step through the PLT stubs and always have a proper
> >> backtrace.
>
> Jan> I do not think GDB is the right place to fix it, it should be fixed
> Jan> by proper .eh_Frame as this problem affects all the tools trying to
> Jan> unwind such as also oprofile, systemtap etc.
Sure, fixing this in ld is better. But that will only work if people
use a full GNU toolchain.
> I agree, but I think also doing it in GDB is harmless, at least provided
> that the new unwinder is only applied when the PLT stubs are missing the
> needed info. That way, when ld is fixed, GDB will automatically start
> doing the right thing.
Yes. The DWARF CFI unwinder comes before the PLT stub unwinder in the
list, so if there is CFI for the PLT stubs, it will be used instead.
So there is no harm in adding this functionality to GDB.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-13 15:56 [RFC] i386 PLT stub unwinder Mark Kettenis
2011-06-13 16:14 ` Jan Kratochvil
@ 2011-06-14 11:49 ` Pedro Alves
2011-06-14 11:53 ` Pedro Alves
1 sibling, 1 reply; 7+ messages in thread
From: Pedro Alves @ 2011-06-14 11:49 UTC (permalink / raw)
To: gdb-patches; +Cc: Mark Kettenis
On Monday 13 June 2011 16:55:56, Mark Kettenis wrote:
> Jan's mail about DWARF CFI for PLT stubs prompted me to write an
> undinder for the PLT stubs as defined by the i386 ABI. With this
> change I can step through the PLT stubs and always have a proper
> backtrace.
>
> The reason that this is an RFC, is that I'm a little bit confused
> about the TRY_CATCH stuff that was introduced in some of the i386
> unwinders by Pedro. It isn't entirely clear to me when that is
> needed. Unwinding the PC should always succeed at this point, since
> the sniffers already rely on that. And unwinding the stack pointer
> needs to be working as well, otherwise unwinding the PC will never
> have worked. So I don't think I need to worry about unavailable
> registers here.
Not correct. If the PC was not available, the sniffer wouldn't be
able to detect the program is sitting in a plt, so in that case
you indeed don't have to worry. But, all the sniffer needs to
be able to decide the plt unwinder is the best unwinder is to have the
PC available and being able to read some instructions off of that address.
If the SP is unavailable, and so you can't compute the frame
base, the frame needs to be marked un-unwindable.
E.g., with your patch as is:
$ gdb ~/gdb/tests/loop32
...
(gdb) tar remote :9999
Remote debugging using :9999
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
0xf7fe0850 in ?? () from /lib/ld-linux.so.2
(gdb) b main
Breakpoint 1 at 0x804850e: file loop.c, line 84.
(gdb) c
Continuing.
Breakpoint 1, main () at loop.c:84
84 long i = 0;
(gdb) si
...
(gdb)
0x080483c0 in pthread_create@plt ()
(gdb) disassemble
Dump of assembler code for function pthread_create@plt:
=> 0x080483c0 <+0>: jmp *0x804a00c
0x080483c6 <+6>: push $0x18
0x080483cb <+11>: jmp 0x8048380
End of assembler dump.
(gdb) trace *0x080483c6
Tracepoint 2 at 0x80483c6
(gdb) tstart
(gdb) n
Single stepping until exit from function pthread_create@plt,
which has no line number information.
0x08048380 in ?? ()
(gdb) tstatus
Trace is running on the target.
Collected 1 trace frames.
Trace buffer has 5242874 bytes of 5242880 bytes free (0% full).
Trace will stop if GDB disconnects.
Not looking at any trace frame.
(gdb) tstop
(gdb) tfind
Found trace frame 0, tracepoint 2
Register 4 is not available
^^^^^^^^^^^^^^^^^^^^^^^^^^^
That is an error being thrown thrown from:
(top-gdb) bt
#0 throw_error (error=..., fmt=0x7fffffffee15 "") at ../../src/gdb/exceptions.c:420
#1 0x0000000000466705 in frame_unwind_register (frame=0xf20b30, regnum=4, buf=0x7fffffffd600 "") at ../../src/gdb/frame.c:919
#2 0x0000000000466b4d in frame_unwind_register_unsigned (frame=0xf20b30, regnum=4) at ../../src/gdb/frame.c:1025
#3 0x0000000000466b9e in get_frame_register_unsigned (frame=0xf20bf0, regnum=4) at ../../src/gdb/frame.c:1032
#4 0x000000000048325a in i386_plt_stub_frame_cache (this_frame=0xf20bf0, this_cache=0xf20c08) at ../../src/gdb/i386-tdep.c:2208
#5 0x00000000004832d6 in i386_plt_stub_frame_this_id (this_frame=0xf20bf0, this_cache=0xf20c08, this_id=0xf20c50) at ../../src/gdb/i386-tdep.c:2221
#6 0x00000000004653c4 in get_frame_id (fi=0xf20bf0) at ../../src/gdb/frame.c:339
#7 0x0000000000467ed1 in get_prev_frame_1 (this_frame=0xf20bf0) at ../../src/gdb/frame.c:1628
#8 0x00000000004687b7 in get_prev_frame (this_frame=0xf20bf0) at ../../src/gdb/frame.c:1950
#9 0x000000000059c991 in backtrace_command_1 (count_exp=0x0, show_locals=0, from_tty=1) at ../../src/gdb/stack.c:1374
#10 0x000000000059ca57 in backtrace_command_stub (data=0x7fffffffd9d0) at ../../src/gdb/stack.c:1421
#11 0x00000000005a2057 in catch_errors (func=0x59ca24 <backtrace_command_stub>, func_args=0x7fffffffd9d0, errstring=0x809fc8 "", mask=2)
at ../../src/gdb/exceptions.c:506
#12 0x000000000059cc93 in backtrace_command (arg=0x0, from_tty=1) at ../../src/gdb/stack.c:1479
That is:
> +static struct i386_frame_cache *
> +i386_plt_stub_frame_cache (struct frame_info *this_frame, void **this_cache)
> +{
...
> +
> + sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
> + cache->base = sp + cache->sp_offset;
You should wrap that in a TRY_CATCH for NOT_AVAILABLE_ERROR
like the other i386 unwinders, and
> + cache->base_p = 1;
leave that false if the base wasn't computable,
> +static const struct frame_unwind i386_plt_stub_frame_unwind =
> +{
> + NORMAL_FRAME,
> + default_frame_unwind_stop_reason,
and here install a i386_plt_stub_frame_unwind_stop_reason
function that returns UNWIND_UNAVAILABLE if cache->base_p
is false, just like e.g., i386_epilogue_frame_unwind_stop_reason.
Might as well write that in patch form. See below. You
can merge it into yours, or have me apply it when yours goes
in, as you prefer.
Here's what it looks like with the patch applied.
Again, inspecting a tracepoint where only PC is available:
(gdb) tstatus
Trace is running on the target.
Collected 1 trace frames.
Trace buffer has 5242874 bytes of 5242880 bytes free (0% full).
Trace will stop if GDB disconnects.
Not looking at any trace frame.
(gdb) tstop
(gdb) tfind
Found trace frame 0, tracepoint 2
#0 0x080483cb in pthread_create@plt ()
(gdb) bt
#0 0x080483cb in pthread_create@plt ()
Backtrace stopped: Not enough registers or memory available to unwind further
(gdb) info registers
eax *value not available*
ecx *value not available*
edx *value not available*
ebx *value not available*
esp *value not available*
ebp *value not available*
esi *value not available*
edi *value not available*
eip 0x80483cb 0x80483cb <pthread_create@plt+11>
eflags *value not available*
cs *value not available*
ss *value not available*
ds *value not available*
es *value not available*
fs *value not available*
gs *value not available*
(gdb) info frame
Stack level 0, frame at 0x8:
eip = 0x80483cb in pthread_create@plt; saved eip 0x80483cb
Outermost frame: Not enough registers or memory available to unwind further
Arglist at unknown address.
Locals at unknown address,Register 9 is not available
(gdb) up
Initial frame selected; you cannot go up.
(that "Register 9 is not available" in info frame's output is a
common code bug I had missed before)
--
Pedro Alves
---
gdb/i386-tdep.c | 31 +++++++++++++++++++++++++------
1 file changed, 25 insertions(+), 6 deletions(-)
Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c 2011-06-14 12:05:30.000000000 +0100
+++ src/gdb/i386-tdep.c 2011-06-14 12:34:55.466490000 +0100
@@ -2125,6 +2125,7 @@ struct i386_insn i386_pic_plt_stub_insns
static struct i386_frame_cache *
i386_plt_stub_frame_cache (struct frame_info *this_frame, void **this_cache)
{
+ volatile struct gdb_exception ex;
struct i386_frame_cache *cache;
struct i386_insn *insn;
LONGEST sp_offset = -4;
@@ -2205,15 +2206,33 @@ i386_plt_stub_frame_cache (struct frame_
cache->pc = pc;
- sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
- cache->base = sp + cache->sp_offset;
- cache->saved_sp = cache->base + 8;
- cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+ cache->base = sp + cache->sp_offset;
+ cache->saved_sp = cache->base + 8;
+ cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+ cache->base_p = 1;
+ }
+ if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
- cache->base_p = 1;
return cache;
}
+static enum unwind_stop_reason
+i386_plt_stub_frame_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct i386_frame_cache *cache =
+ i386_plt_stub_frame_cache (this_frame, this_cache);
+
+ if (!cache->base_p)
+ return UNWIND_UNAVAILABLE;
+
+ return UNWIND_NO_REASON;
+}
+
static void
i386_plt_stub_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
@@ -2256,7 +2275,7 @@ i386_plt_stub_frame_sniffer (const struc
static const struct frame_unwind i386_plt_stub_frame_unwind =
{
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ i386_plt_stub_frame_unwind_stop_reason,
i386_plt_stub_frame_this_id,
i386_plt_stub_frame_prev_register,
NULL,
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] i386 PLT stub unwinder
2011-06-14 11:49 ` Pedro Alves
@ 2011-06-14 11:53 ` Pedro Alves
0 siblings, 0 replies; 7+ messages in thread
From: Pedro Alves @ 2011-06-14 11:53 UTC (permalink / raw)
To: gdb-patches; +Cc: Mark Kettenis
On Tuesday 14 June 2011 12:49:27, Pedro Alves wrote:
> Might as well write that in patch form. See below. You
> can merge it into yours, or have me apply it when yours goes
> in, as you prefer.
Sorry, forgot to quilt refresh. This is right patch.
--
Pedro Alves
---
gdb/i386-tdep.c | 34 ++++++++++++++++++++++++++++------
1 file changed, 28 insertions(+), 6 deletions(-)
Index: src/gdb/i386-tdep.c
===================================================================
--- src.orig/gdb/i386-tdep.c 2011-06-14 12:05:30.000000000 +0100
+++ src/gdb/i386-tdep.c 2011-06-14 12:42:41.286489839 +0100
@@ -2125,6 +2125,7 @@ struct i386_insn i386_pic_plt_stub_insns
static struct i386_frame_cache *
i386_plt_stub_frame_cache (struct frame_info *this_frame, void **this_cache)
{
+ volatile struct gdb_exception ex;
struct i386_frame_cache *cache;
struct i386_insn *insn;
LONGEST sp_offset = -4;
@@ -2205,15 +2206,33 @@ i386_plt_stub_frame_cache (struct frame_
cache->pc = pc;
- sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
- cache->base = sp + cache->sp_offset;
- cache->saved_sp = cache->base + 8;
- cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
+ cache->base = sp + cache->sp_offset;
+ cache->saved_sp = cache->base + 8;
+ cache->saved_regs[I386_EIP_REGNUM] = cache->base + 4;
+ cache->base_p = 1;
+ }
+ if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR)
+ throw_exception (ex);
- cache->base_p = 1;
return cache;
}
+static enum unwind_stop_reason
+i386_plt_stub_frame_unwind_stop_reason (struct frame_info *this_frame,
+ void **this_cache)
+{
+ struct i386_frame_cache *cache =
+ i386_plt_stub_frame_cache (this_frame, this_cache);
+
+ if (!cache->base_p)
+ return UNWIND_UNAVAILABLE;
+
+ return UNWIND_NO_REASON;
+}
+
static void
i386_plt_stub_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
@@ -2221,6 +2240,9 @@ i386_plt_stub_frame_this_id (struct fram
struct i386_frame_cache *cache =
i386_plt_stub_frame_cache (this_frame, this_cache);
+ if (!cache->base_p)
+ return;
+
/* See the end of i386_push_dummy_call. */
(*this_id) = frame_id_build (cache->base + 8, cache->pc);
}
@@ -2256,7 +2278,7 @@ i386_plt_stub_frame_sniffer (const struc
static const struct frame_unwind i386_plt_stub_frame_unwind =
{
NORMAL_FRAME,
- default_frame_unwind_stop_reason,
+ i386_plt_stub_frame_unwind_stop_reason,
i386_plt_stub_frame_this_id,
i386_plt_stub_frame_prev_register,
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-06-14 11:53 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-13 15:56 [RFC] i386 PLT stub unwinder Mark Kettenis
2011-06-13 16:14 ` Jan Kratochvil
2011-06-13 16:32 ` Joel Brobecker
2011-06-13 16:43 ` Tom Tromey
2011-06-13 19:15 ` Mark Kettenis
2011-06-14 11:49 ` Pedro Alves
2011-06-14 11:53 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox