This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH 2/2] Fix gdb.mi/mi-stack.exp when gcc generates a stack protector
- From: Yao Qi <qiyaoltc at gmail dot com>
- To: Simon Marchi <simon dot marchi at polymtl dot ca>
- Cc: GDB Patches <gdb-patches at sourceware dot org>
- Date: Wed, 3 Jan 2018 21:53:09 +0000
- Subject: Re: [PATCH 2/2] Fix gdb.mi/mi-stack.exp when gcc generates a stack protector
- Authentication-results: sourceware.org; auth=none
- References: <20171216145651.13936-1-simon.marchi@polymtl.ca> <20171216145651.13936-2-simon.marchi@polymtl.ca> <CAH=s-POVUgp0Vbh_g6bchswwL8UfPy2XSZmBB2ONKUb4A1Xe7w@mail.gmail.com> <9860ca45c4896a0e42190f4c34c68c4a@polymtl.ca>
On Tue, Jan 2, 2018 at 6:14 PM, Simon Marchi <simon.marchi@polymtl.ca> wrote:
> On 2018-01-02 05:38, Yao Qi wrote:
>> Can't we fix GDB to skip these stack protection code?
>
>
> I think it would be desirable to consider the stack protection code as part
> of the prologue, since it's compiler-generated and of little interest to the
> user. But I don't know how to do it without breaking existing behavior.
>
Yes, we can skip them as part of skipping prologue.
> Our heuristic, when using SaL to skip prologue, is to consider the first
> linetable entry to represent the prologue. If we find a consecutive entry
> with the same line number, we assume it's the prologue -> body transition
> (because otherwise there would be no point in having a separate entry).
> When adding a stack protector, gcc puts it in a separate linetable entry, as
> if it was user code, so GDB thinks it's the beginning of the body.
>
> Let's take this small example:
>
> 1 int main()
> 2 {
> 3 int n = 0;
> 4 n++;
> 5 return n;
> 6 }
>
> Which compiles to this with -fstack-protector-all:
>
> 0x0000000000400546 <+0>: push %rbp
> 0x0000000000400547 <+1>: mov %rsp,%rbp
> 0x000000000040054a <+4>: sub $0x10,%rsp
> 0x000000000040054e <+8>: mov %fs:0x28,%rax
> 0x0000000000400557 <+17>: mov %rax,-0x8(%rbp)
> 0x000000000040055b <+21>: xor %eax,%eax
> 0x000000000040055d <+23>: movl $0x0,-0xc(%rbp)
> 0x0000000000400564 <+30>: addl $0x1,-0xc(%rbp)
> 0x0000000000400568 <+34>: mov -0xc(%rbp),%eax
> 0x000000000040056b <+37>: mov -0x8(%rbp),%rdx
> 0x000000000040056f <+41>: xor %fs:0x28,%rdx
> 0x0000000000400578 <+50>: je 0x40057f <main+57>
> 0x000000000040057a <+52>: callq 0x400420 <__stack_chk_fail@plt>
> 0x000000000040057f <+57>: leaveq
> 0x0000000000400580 <+58>: retq
>
> test.c 2 0x400546
> test.c 2 0x40054e
> test.c 3 0x40055d
> test.c 4 0x400564
> test.c 5 0x400568
> test.c 6 0x40056b
>
> GDB currently assumes that the second entry is the beginning of the body.
> But ideally we would treat the first two entries as the prologue, and put
> our breakpoint on line 3/0x40055d.
>
> And then let's look at this modified example, where the first line of code
> is on the same line as the opening curly bracket, and compiled without stack
> protection (-fno-stack-protector):
>
> 1 int main()
> 2 { int n = 0;
> 3 n++;
> 4 return n;
> 5 }
>
>
> 0x00000000004004d6 <+0>: push %rbp
> 0x00000000004004d7 <+1>: mov %rsp,%rbp
> 0x00000000004004da <+4>: movl $0x0,-0x4(%rbp)
> 0x00000000004004e1 <+11>: addl $0x1,-0x4(%rbp)
> 0x00000000004004e5 <+15>: mov -0x4(%rbp),%eax
> 0x00000000004004e8 <+18>: pop %rbp
> 0x00000000004004e9 <+19>: retq
>
> test.c 2 0x4004d6
> test.c 2 0x4004da
> test.c 3 0x4004e1
> test.c 4 0x4004e5
> test.c 5 0x4004e8
>
> We have a similar line table as the previous example (same source line,
> different address), but in this case the second entry at line 2 is really
> the start of user code. We would want to put our breakpoint at line
> 2/0x4004da. So, how do we differentiate these two cases?
>
When GDB sets breakpoint, it calls gdbarch_skip_prologue_noexcept
to skip prologue, amd64 backend doesn't use SAL to identify the end
of prologue unless compiler is clang (see amd64_skip_prologue).
Instead, GDB scans prologue to find the end of prologue, so we can
extend amd64 prologue analyzer to understand these instructions
for stack protection.
(gdb) b callee4
Thread 1 "gdb" hit Breakpoint 1, amd64_analyze_prologue
(gdbarch=gdbarch@entry=0x154ef60, pc=pc@entry=4195734,
current_pc=current_pc@entry=18446744073709551615,
cache=cache@entry=0x7fffffffd1e0) at
../../binutils-gdb/gdb/amd64-tdep.c:2319
2319 {
(gdb) bt 10
#0 amd64_analyze_prologue (gdbarch=gdbarch@entry=0x154ef60,
pc=pc@entry=4195734, current_pc=current_pc@entry=18446744073709551615,
cache=cache@entry=0x7fffffffd1e0)
at ../../binutils-gdb/gdb/amd64-tdep.c:2319
#1 0x0000000000428b8c in amd64_skip_prologue (gdbarch=0x154ef60,
start_pc=4195734) at ../../binutils-gdb/gdb/amd64-tdep.c:2488
#2 0x0000000000515363 in gdbarch_skip_prologue_noexcept
(gdbarch=gdbarch@entry=0x154ef60, pc=pc@entry=4195734) at
../../binutils-gdb/gdb/arch-utils.c:970
#3 0x0000000000692b03 in skip_prologue_sal
(sal=sal@entry=0x7fffffffd4d0) at ../../binutils-gdb/gdb/symtab.c:3721
#4 0x0000000000692e02 in find_function_start_sal
(sym=sym@entry=0x158e8b0, funfirstline=1) at
../../binutils-gdb/gdb/symtab.c:3594
#5 0x00000000005fe0dd in symbol_to_sal
(result=result@entry=0x7fffffffd6d0, funfirstline=<optimized out>,
sym=sym@entry=0x158e8b0)
at ../../binutils-gdb/gdb/linespec.c:4611
We did something similar in arm-tdep.c, search "__stack_chk_guard".
However, I am not sure we can find a "fingerprint" of these stack projection
instructions on amd64.
--
Yao (齐尧)