Re: GDB 7.2 gets SIGSEGV when step into a function in a shared library

Yao Qi
2011-09-20T01:07:27Z

On 09/20/2011 06:17 AM, Liang Cheng wrote:
> But it seems to close what I want. But the extension gets the PC
> wrong, it should be 0x800036fd.
> Why we use
> nextpc = (CORE_ADDR)read_memory_integer ((CORE_ADDR) base,
> 4, byte_order);
> instead of
> nextpc = (CORE_ADDR)read_memory_unsigned integer
> ((CORE_ADDR) base,
> 4, byte_order);
> in arm-tdep.c::arm_get_next_pc_raw? Below is the stack in debug session of gdb.
>

Thanks for your analysis. We should use read_memory_unsigned_interger
here, IMO.

> (gdb) c
> Continuing.
>
> Breakpoint 1, arm_get_next_pc (frame=0x40d9720, pc=34352) at arm-tdep.c:4854
> 4854 {
> (gdb) bt
> #0 arm_get_next_pc (frame=0x40d9720, pc=34352) at arm-tdep.c:4854
> #1 0x0000000000431b0c in arm_linux_software_single_step
> (frame=0x40d9720) at arm-linux-tdep.c:751
> #2 0x00000000004d8321 in maybe_software_singlestep
> (gdbarch=0x13cc920, pc=34352) at infrun.c:1577
> #3 0x00000000004dabad in resume (step=1, sig=TARGET_SIGNAL_0) at infrun.c:1689
> #4 0x00000000004dfbf0 in proceed (addr=<value optimized out>,
> siggnal=TARGET_SIGNAL_DEFAULT, step=1) at infrun.c:2128
> #5 0x00000000004d2227 in step_once (skip_subroutines=0,
> single_inst=1, count=1, thread=-1) at infcmd.c:1046
> #6 0x00000000004d40d4 in step_1 (skip_subroutines=0, single_inst=1,
> count_string=0x0) at infcmd.c:894
>
> (gdb) n
> 4857 if (arm_frame_is_thumb (frame))
> (gdb) n
> 4866 if (nextpc == pc)
> (gdb) p pc
> $1 = 34352
> (gdb) p /x pc
> $2 = 0x8630
> (gdb) p /x nextpc
> $3 = 0xffffffff800036fd
>

The value of nextpc here may explain why inferior stops at the point of
returning from xa_fun_in_lib, rather than the entry of it.

On 09/19/2011 11:57 PM, Liang Cheng wrote:
> infrun: stop_pc = 0x8630

0x8630: ldr pc, [r12, #2820]!

inferior will go to 0x800036fc.

> infrun: software single step trap for Thread 1874.1874
> infrun: stepped into dynsym resolve code
> infrun: resume (step=1, signal=0), trap_expected=0
> infrun: prepare_to_wait
> infrun: target_wait (-1, status) =
> infrun: 1874 [Thread 1874.1874],
> infrun: status->kind = stopped, signal = SIGTRAP
> infrun: infwait_normal_state
> infrun: TARGET_WAITKIND_STOPPED
> infrun: stop_pc = 0x8d20

However, inferior stops at 0x8d20,

0x00008d1c <+88>: blx 0x8628
0x00008d20 <+92>: mov r3, r0

The reason for this symptom is gdb will insert software single-step
breakpoint at function return address (value of LR register) if the
next_pc is greater than 0xffff0000, as the following code shows

static int
arm_linux_software_single_step (struct frame_info *frame)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
struct address_space *aspace = get_frame_address_space (frame);
CORE_ADDR next_pc = arm_get_next_pc (frame, get_frame_pc (frame));

/* The Linux kernel offers some user-mode helpers in a high page. We can
not read this page (as of 2.6.23), and even if we could then we
couldn't
set breakpoints in it, and even if we could then the atomic operations
would fail when interrupted. They are all called as functions and
return
to the address in LR, so step to there instead. */
if (next_pc > 0xffff0000)
next_pc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);

arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);

return 1;
}

--
Yao (é½å°§)