Article View: gnu.gdb.bug
Article #1049Re: Problem of GDB interaction with interrupted system calls
From: Alexandre Rusev
Date: Fri, 13 Nov 2009 14:42
Date: Fri, 13 Nov 2009 14:42
609 lines
22869 bytes
22869 bytes
This is a multi-part message in MIME format.
--------------080506000804080607030402
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
teawater wrote:
> I think this is a hehavior of kernel. I think change pc always a
> danger thing. :)
>
Yes, extremely dangeorous! ;)
But GDB supports feature such as "call <func_name>", when using it the
Joe user does not even cares the PC,
he just thinks that he makes call to some function...
Moreover the intent of changing stack by kernel is to make system call
to restart.
The kernel (in theory) could choose to not return to userland at this
point (because of no signal handlers are set by the process)
and restart syscall internally.
If it where so, all the process could have been transparent for GDB.
And this usecase is enounted quite often by users....:(
Because the nature of the problem is quite clear, it could be (once "in
theory") worked around both in kernel and in GDB.
Because the GDB does a lot of tricks and serves to thecnical puroses may
be it it the best place to implement workaround there?
Yet from point of view of kernel that's the place where either nobody
(even GDB) is supposed to intervien the kernel internal
housekeeping, at least till the next machine instruction is executed.
So the kernel could either:
[1] not enable the GDB/ptrace to stop process and change user registers
at that point
[2] remember the state of essential registers (PC, may be others likes
FP) and revert all changes before executing the next instruction
[3] remember the state of essential registers (PC, may be others likes
FP) and if the process was stopped
and somebody (GDB/ptrace) changed PC before execution of the next
instruction then kernel can avoid it's own changes of PC
Anyway the problem exists and I'm trying at least to find out where
needs to be fixed
>
> infrun: clear_proceed_status_thread (process 4542)
> infrun: proceed (addr=0xffffffff, signal=144, step=0)
> infrun: resume (step=0, signal=0), trap_expected=0
> infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
> infrun: target_wait (-1, status) =
> infrun: 4542 [process 4542],
> infrun: status->kind = stopped, signal = SIGINT
> infrun: infwait_normal_state
> infrun: TARGET_WAITKIND_STOPPED
> infrun: stop_pc = 0xb7fe3410
> infrun: random signal 2
>
> Program received signal SIGINT, Interrupt.
> infrun: stop_stepping
> 0xb7fe3410 in __kernel_vsyscall ()
> (gdb) disas
> Dump of assembler code for function __kernel_vsyscall:
> 0xb7fe3400 <+0>: push %ecx
> 0xb7fe3401 <+1>: push %edx
> 0xb7fe3402 <+2>: push %ebp
> 0xb7fe3403 <+3>: mov %esp,%ebp
> 0xb7fe3405 <+5>: sysenter
> 0xb7fe3407 <+7>: nop
> 0xb7fe3408 <+8>: nop
> 0xb7fe3409 <+9>: nop
> 0xb7fe340a <+10>: nop
> 0xb7fe340b <+11>: nop
> 0xb7fe340c <+12>: nop
> 0xb7fe340d <+13>: nop
> 0xb7fe340e <+14>: jmp 0xb7fe3403 <__kernel_vsyscall+3>
> => 0xb7fe3410 <+16>: pop %ebp
> 0xb7fe3411 <+17>: pop %edx
> 0xb7fe3412 <+18>: pop %ecx
> 0xb7fe3413 <+19>: ret
> End of assembler dump.
> (gdb) p $pc
> $1 = (void (*)()) 0xb7fe3410 <__kernel_vsyscall+16>
> (gdb) p $pc=0xb7fe3413
> $2 = (void (*)()) 0xb7fe3413 <__kernel_vsyscall+19>
> (gdb) si
> infrun: clear_proceed_status_thread (process 4542)
> infrun: proceed (addr=0xffffffff, signal=144, step=1)
> infrun: resume (step=1, signal=0), trap_expected=0
> infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
> infrun: target_wait (-1, status) =
> infrun: 4542 [process 4542],
> infrun: status->kind = stopped, signal = SIGTRAP
> infrun: infwait_normal_state
> infrun: TARGET_WAITKIND_STOPPED
> infrun: stop_pc = 0xb7fe3412
> infrun: stepi/nexti
> infrun: stop_stepping
> 0xb7fe3412 in __kernel_vsyscall ()
>
> Thanks,
> Hui
>
>
>
> On Nov 2, 7:27 pm, Alexandre Rusev <aru...@ru.mvista.com> wrote:
>
>> teawater wrote:
>>
>>> This signal ctrl-c will not really send to inferior.
>>>
>> But the result is interrupted system call which is restarted then by kernel.
>> And is user changes program counter in GDB at this point,
>> then it takes place before the modification of PC is done by kernel.
>> The result is that execution jumps neither to the point the user said in
>> GDB nor
>> to the point the kernel wishes it be due to restart the syscall.
>>
>> Is it incorrect behavior of GDB or incorrect behavior of kernel or
>> something else???
>>
>>
>>> (gdb) help info handle
>>>
>>> On Oct 31, 12:10 am, Alexandre Rusev <aru...@ru.mvista.com> wrote:
>>>
>>>> Hi.
>>>>
>>>> When the program at ht end of message debugged under GDB is stopped with
>>>> Ctrl+C
>>>> it's usually found in interrupted system call. (The same result is
>>>> observed for x86 and PPC with kernels 2.6.18 and 2.6.28)
>>>>
>>>> (gdb) where
>>>> #0 0xb7fe2424 in __kernel_vsyscall ()
>>>> #1 0xb7f36ad0 in nanosleep () from /lib/libc.so.6
>>>> #2 0xb7f3690e in sleep () from /lib/libc.so.6
>>>> #3 0x08048600 in qqq () at testBT2.c:45
>>>> #4 0x080487a5 in eee () at testBT2.c:73
>>>> #5 0x0804846a in main () at testBT2.c:17
>>>>
>>>> The PC is pointing at the next instruction, accordingly to GDB.
>>>> But the kernel tries to restart syscall by means of changing PC to PC-4
>>>> (in case of PowerPC and to some other value for x86)
>>>> and it does it's change to PC after the user continues execution of
>>>> program in GDB with "cont" or "si" command.
>>>>
>>>> The issue is that if user changed PC at this point or uses "call
>>>> <func_name>" GDB command, the both changes to PC
>>>> are added (as kernel uses PC relative change i.e. PC - 4), and the
>>>> program continues execution at absolutely wrong place.
>>>>
>>>> The issue may be gracefully observed if breakpoint is set just before
>>>> <func_name> and then PC is changed to the <func_name> address.
>>>> In such case the breakpoint is hit while it must not be.
>>>>
>>>> #include <stdio.h>
>>>> #include <stdlib.h>
>>>>
>>>> void qqq();
>>>> void www();
>>>> void eee();
>>>>
>>>> void * xrealloc(void*, int);
>>>>
>>>> int main(void)
>>>> {
>>>> eee();
>>>> return EXIT_SUCCESS;
>>>>
>>>> }
>>>>
>>>> void qqq() {
>>>> void *a[256];
>>>> size_t i, n;
>>>>
>>>> for (i = 0; i < 256; i++)
>>>> {
>>>> n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
>>>> a[i] = malloc(n);
>>>> }
>>>> for (i = 256; i > 0; i--)
>>>> {
>>>> n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
>>>> a[i - 1] = xrealloc(a[i - 1], n);
>>>> }
>>>> sleep(1);
>>>> for (i = 0; i < 256; i += 2)
>>>> free(a[i]);
>>>> for (i = 256; i > 0; i -= 2)
>>>> free(a[i - 1]);
>>>> sleep(1);
>>>>
>>>> }
>>>>
>>>> void www() {
>>>> void *a[256];
>>>> size_t i, n;
>>>>
>>>> for (i = 0; i < 256; i++)
>>>> {
>>>> n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
>>>> a[i] = malloc(n);
>>>> }
>>>> for (i = 256; i > 0; i--)
>>>> {
>>>> n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
>>>> a[i - 1] = realloc(a[i - 1], n);
>>>> }
>>>> sleep(1);
>>>> for (i = 0; i < 256; i += 2)
>>>> free(a[i]);
>>>> for (i = 256; i > 0; i -= 2)
>>>> free(a[i - 1]);
>>>> sleep(1);
>>>>
>>>> }
>>>>
>>>> void eee() {
>>>>
>>>> while (1) {
>>>> qqq();
>>>>
>>>> www();
>>>>
>>>> }
>>>>
>>>> }
>>>>
>>>> void * xrealloc(void* addr, int n) {
>>>> return realloc(addr, n);
>>>>
>>>> }
>>>>
>>> _______________________________________________
>>> bug-gdb mailing list
>>> bug-...@gnu.org
>>> http://lists.gnu.org/mailman/listinfo/bug-gdb
>>>
>
>
--------------080506000804080607030402
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
</head>
<body bgcolor="#ffffff" text="#000000">
teawater wrote:
<blockquote
cite="mid796f72e5-4d84-4282-9dfb-46af789014c9@a31g2000yqn.googlegroups.com"
type="cite">
<pre wrap="">I think this is a hehavior of kernel. I think change pc always a
danger thing. :)
</pre>
</blockquote>
Yes, extremely dangeorous! ;)<br>
But GDB supports feature such as "call <func_name>", when using
it the Joe user does not even cares the PC,<br>
he just thinks that he makes call to some function...<br>
<br>
Moreover the intent of changing stack by kernel is to make system call
to restart.<br>
The kernel (in theory) could choose to not return to userland at this
point (because of no signal handlers are set by the process)<br>
and restart syscall internally.<br>
If it where so, all the process could have been transparent for GDB.<br>
<br>
And this usecase is enounted quite often by users....:(<br>
<br>
Because the nature of the problem is quite clear, it could be (once "in
theory") worked around both in kernel and in GDB.<br>
<br>
Because the GDB does a lot of tricks and serves to thecnical puroses
may be it it the best place to implement workaround there?<br>
<br>
Yet from point of view of kernel that's the place where either nobody
(even GDB) is supposed to intervien the kernel internal<br>
housekeeping, at least till the next machine instruction is executed.<br>
So the kernel could either:<br>
[1] not enable the GDB/ptrace to stop process and change user registers
at that point<br>
[2] remember the state of essential registers (PC, may be others likes
FP) and revert all changes before executing the next instruction<br>
[3] remember the state of essential registers (PC, may be others likes
FP) and if the process was stopped<br>
and somebody (GDB/ptrace) changed PC before execution of the next
instruction then kernel can avoid it's own changes of PC<br>
<br>
<br>
Anyway the problem exists and I'm trying at least to find out where
needs to be fixed<br>
<blockquote
cite="mid796f72e5-4d84-4282-9dfb-46af789014c9@a31g2000yqn.googlegroups.com"
type="cite">
<pre wrap="">
infrun: clear_proceed_status_thread (process 4542)
infrun: proceed (addr=0xffffffff, signal=144, step=0)
infrun: resume (step=0, signal=0), trap_expected=0
infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
infrun: target_wait (-1, status) =
infrun: 4542 [process 4542],
infrun: status->kind = stopped, signal = SIGINT
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0xb7fe3410
infrun: random signal 2
Program received signal SIGINT, Interrupt.
infrun: stop_stepping
0xb7fe3410 in __kernel_vsyscall ()
(gdb) disas
Dump of assembler code for function __kernel_vsyscall:
0xb7fe3400 <+0>: push %ecx
0xb7fe3401 <+1>: push %edx
0xb7fe3402 <+2>: push %ebp
0xb7fe3403 <+3>: mov %esp,%ebp
0xb7fe3405 <+5>: sysenter
0xb7fe3407 <+7>: nop
0xb7fe3408 <+8>: nop
0xb7fe3409 <+9>: nop
0xb7fe340a <+10>: nop
0xb7fe340b <+11>: nop
0xb7fe340c <+12>: nop
0xb7fe340d <+13>: nop
0xb7fe340e <+14>: jmp 0xb7fe3403 <__kernel_vsyscall+3>
=> 0xb7fe3410 <+16>: pop %ebp
0xb7fe3411 <+17>: pop %edx
0xb7fe3412 <+18>: pop %ecx
0xb7fe3413 <+19>: ret
End of assembler dump.
(gdb) p $pc
$1 = (void (*)()) 0xb7fe3410 <__kernel_vsyscall+16>
(gdb) p $pc=0xb7fe3413
$2 = (void (*)()) 0xb7fe3413 <__kernel_vsyscall+19>
(gdb) si
infrun: clear_proceed_status_thread (process 4542)
infrun: proceed (addr=0xffffffff, signal=144, step=1)
infrun: resume (step=1, signal=0), trap_expected=0
infrun: wait_for_inferior (treat_exec_as_sigtrap=0)
infrun: target_wait (-1, status) =
infrun: 4542 [process 4542],
infrun: status->kind = stopped, signal = SIGTRAP
infrun: infwait_normal_state
infrun: TARGET_WAITKIND_STOPPED
infrun: stop_pc = 0xb7fe3412
infrun: stepi/nexti
infrun: stop_stepping
0xb7fe3412 in __kernel_vsyscall ()
Thanks,
Hui
On Nov 2, 7:27 pm, Alexandre Rusev <a class="moz-txt-link-rfc2396E" href="mailto:aru...@ru.mvista.com"><aru...@ru.mvista.com></a> wrote:
</pre>
<blockquote type="cite">
<pre wrap="">teawater wrote:
</pre>
<blockquote type="cite">
<pre wrap="">This signal ctrl-c will not really send to inferior.
</pre>
</blockquote>
<pre wrap="">But the result is interrupted system call which is restarted then by kernel.
And is user changes program counter in GDB at this point,
then it takes place before the modification of PC is done by kernel.
The result is that execution jumps neither to the point the user said in
GDB nor
to the point the kernel wishes it be due to restart the syscall.
Is it incorrect behavior of GDB or incorrect behavior of kernel or
something else???
</pre>
<blockquote type="cite">
<pre wrap="">(gdb) help info handle
</pre>
</blockquote>
<blockquote type="cite">
<pre wrap="">On Oct 31, 12:10 am, Alexandre Rusev <a class="moz-txt-link-rfc2396E" href="mailto:aru...@ru.mvista.com"><aru...@ru.mvista.com></a> wrote:
</pre>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">Hi.
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">When the program at ht end of message debugged under GDB is stopped with
Ctrl+C
it's usually found in interrupted system call. (The same result is
observed for x86 and PPC with kernels 2.6.18 and 2.6.28)
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">(gdb) where
#0 0xb7fe2424 in __kernel_vsyscall ()
#1 0xb7f36ad0 in nanosleep () from /lib/libc.so.6
#2 0xb7f3690e in sleep () from /lib/libc.so.6
#3 0x08048600 in qqq () at testBT2.c:45
#4 0x080487a5 in eee () at testBT2.c:73
#5 0x0804846a in main () at testBT2.c:17
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">The PC is pointing at the next instruction, accordingly to GDB.
But the kernel tries to restart syscall by means of changing PC to PC-4
(in case of PowerPC and to some other value for x86)
and it does it's change to PC after the user continues execution of
program in GDB with "cont" or "si" command.
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">The issue is that if user changed PC at this point or uses "call
<func_name>" GDB command, the both changes to PC
are added (as kernel uses PC relative change i.e. PC - 4), and the
program continues execution at absolutely wrong place.
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">The issue may be gracefully observed if breakpoint is set just before
<func_name> and then PC is changed to the <func_name> address.
In such case the breakpoint is hit while it must not be.
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">#include <stdio.h>
#include <stdlib.h>
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void qqq();
void www();
void eee();
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void * xrealloc(void*, int);
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">int main(void)
{
eee();
return EXIT_SUCCESS;
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">}
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void qqq() {
void *a[256];
size_t i, n;
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap=""> for (i = 0; i < 256; i++)
{
n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
a[i] = malloc(n);
}
for (i = 256; i > 0; i--)
{
n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
a[i - 1] = xrealloc(a[i - 1], n);
}
sleep(1);
for (i = 0; i < 256; i += 2)
free(a[i]);
for (i = 256; i > 0; i -= 2)
free(a[i - 1]);
sleep(1);
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">}
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void www() {
void *a[256];
size_t i, n;
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap=""> for (i = 0; i < 256; i++)
{
n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
a[i] = malloc(n);
}
for (i = 256; i > 0; i--)
{
n = (size_t) ((rand() * 256.0) / (RAND_MAX + 1.0)) + 1;
a[i - 1] = realloc(a[i - 1], n);
}
sleep(1);
for (i = 0; i < 256; i += 2)
free(a[i]);
for (i = 256; i > 0; i -= 2)
free(a[i - 1]);
sleep(1);
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">}
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void eee() {
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap=""> while (1) {
qqq();
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap=""> www();
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap=""> }
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">}
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">void * xrealloc(void* addr, int n) {
return realloc(addr, n);
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<blockquote type="cite">
<pre wrap="">}
</pre>
</blockquote>
</blockquote>
<blockquote type="cite">
<pre wrap="">_______________________________________________
bug-gdb mailing list
<a class="moz-txt-link-abbreviated" href="mailto:bug-...@gnu.org">bug-...@gnu.org</a>
<a class="moz-txt-link-freetext" href="http://lists.gnu.org/mailman/listinfo/bug-gdb">http://lists.gnu.org/mailman/listinfo/bug-gdb</a>
</pre>
</blockquote>
</blockquote>
<pre wrap=""><!---->
</pre>
</blockquote>
<br>
</body>
</html>
--------------080506000804080607030402--
Technical Details
Message-ID:
<mailman.10642.1258123380.2239.bug-gdb@gnu.org>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!news2.google.com!news.glorb.com!usenet.stanford.edu!news.stanford.edu!not-for-mailReferences:
<mailman.9741.1256919066.2239.bug-gdb@gnu.org> <19ff1afc-b27e-4715-a113-dde9929294bf@x25g2000prf.googlegroups.com> <mailman.9901.1257161299.2239.bug-gdb@gnu.org> <796f72e5-4d84-4282-9dfb-46af789014c9@a31g2000yqn.googlegroups.com>Show Full Headers
Complete Article Headers
X-Google-Thread: f0ead4270c,ce66b84e91cebdde X-Google-Attributes: gidf0ead4270c,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!news2.google.com!news.glorb.com!usenet.stanford.edu!news.stanford.edu!not-for-mail From: Alexandre Rusev <arusev@ru.mvista.com> Newsgroups: gnu.gdb.bug Subject: Re: Problem of GDB interaction with interrupted system calls Date: Fri, 13 Nov 2009 17:42:48 +0300 Lines: 611 Approved: bug-gdb@gnu.org Message-ID: <mailman.10642.1258123380.2239.bug-gdb@gnu.org> References: <mailman.9741.1256919066.2239.bug-gdb@gnu.org> <19ff1afc-b27e-4715-a113-dde9929294bf@x25g2000prf.googlegroups.com> <mailman.9901.1257161299.2239.bug-gdb@gnu.org> <796f72e5-4d84-4282-9dfb-46af789014c9@a31g2000yqn.googlegroups.com> NNTP-Posting-Host: lists.gnu.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="------------080506000804080607030402" X-Trace: news.stanford.edu 1258123381 24959 199.232.76.165 (13 Nov 2009 14:43:01 GMT) X-Complaints-To: news@news.stanford.edu To: teawater <teawater@gmail.com>, bug-gdb@gnu.org Envelope-to: bug-gdb@gnu.org User-Agent: Thunderbird 1.5.0.8 (X11/20060911) In-Reply-To: <796f72e5-4d84-4282-9dfb-46af789014c9@a31g2000yqn.googlegroups.com> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) X-BeenThere: bug-gdb@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Bug reports for GDB, the GNU debugger" <bug-gdb.gnu.org> List-Unsubscribe: <http://lists.gnu.org/mailman/listinfo/bug-gdb>, <mailto:bug-gdb-request@gnu.org?subject=unsubscribe> List-Archive: <http://lists.gnu.org/pipermail/bug-gdb> List-Post: <mailto:bug-gdb@gnu.org> List-Help: <mailto:bug-gdb-request@gnu.org?subject=help> List-Subscribe: <http://lists.gnu.org/mailman/listinfo/bug-gdb>, <mailto:bug-gdb-request@gnu.org?subject=subscribe>