Message ID | 53554475.3010201@mentor.com |
---|---|
State | Superseded |
Headers |
Return-Path: <x14314964@homiemail-mx23.g.dreamhost.com> X-Original-To: siddhesh@wilcox.dreamhost.com Delivered-To: siddhesh@wilcox.dreamhost.com Received: from homiemail-mx23.g.dreamhost.com (mx2.sub5.homie.mail.dreamhost.com [208.113.200.128]) by wilcox.dreamhost.com (Postfix) with ESMTP id 5B8D4360068 for <siddhesh@wilcox.dreamhost.com>; Mon, 21 Apr 2014 09:17:02 -0700 (PDT) Received: by homiemail-mx23.g.dreamhost.com (Postfix, from userid 14314964) id 1B03762E0CE24; Mon, 21 Apr 2014 09:17:01 -0700 (PDT) X-Original-To: gdb@patchwork.siddhesh.in Delivered-To: x14314964@homiemail-mx23.g.dreamhost.com Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by homiemail-mx23.g.dreamhost.com (Postfix) with ESMTPS id B5FC662CDC14D for <gdb@patchwork.siddhesh.in>; Mon, 21 Apr 2014 09:17:01 -0700 (PDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:date:from:mime-version:to:subject :content-type:content-transfer-encoding; q=dns; s=default; b=L3T aWj0hE+F0PrDHyseSkZuAzMIVIoMMqltVtkGFJbIgZOZQyQl+zTxdv//PCWl5/ZY PDDgZnQUOrazjPO+LUTYXkWmzlfqn8257oi25DuuBf+8OpMCIIqwW9usMYwX/+9g 9qkitLUrulRhXK86Po7dNdz7jHW2/lo1bks/Dp6o= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:date:from:mime-version:to:subject :content-type:content-transfer-encoding; s=default; bh=8dI355FNz lO/t3dJQlLEM5QuLLI=; b=L757q40sOmXUJkMeEGmamIOxWyD4LERCkzWfUlvSn 6Yb1SI8FkWfn1yHzmzvDNVqDYBTOHqlPEenTF28CSpxc/cJxYGgNnCJ7wREHHm6e AhHY+vokr7MN/X7R74mHm/AA9PfO1r1NzH9k+/f9Ov00z9JjRUGXrE6dkoCpqDRC QU= Received: (qmail 14964 invoked by alias); 21 Apr 2014 16:17:00 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: <gdb-patches.sourceware.org> List-Unsubscribe: <mailto:gdb-patches-unsubscribe-gdb=patchwork.siddhesh.in@sourceware.org> List-Subscribe: <mailto:gdb-patches-subscribe@sourceware.org> List-Archive: <http://sourceware.org/ml/gdb-patches/> List-Post: <mailto:gdb-patches@sourceware.org> List-Help: <mailto:gdb-patches-help@sourceware.org>, <http://sourceware.org/ml/#faqs> Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 14954 invoked by uid 89); 21 Apr 2014 16:17:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00 autolearn=ham version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 21 Apr 2014 16:16:58 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1WcGtq-0006I8-Rx from Hui_Zhu@mentor.com for gdb-patches@sourceware.org; Mon, 21 Apr 2014 09:16:54 -0700 Received: from SVR-ORW-FEM-02.mgc.mentorg.com ([147.34.96.206]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Mon, 21 Apr 2014 09:16:54 -0700 Received: from localhost.localdomain (147.34.91.1) by svr-orw-fem-02.mgc.mentorg.com (147.34.96.168) with Microsoft SMTP Server id 14.2.247.3; Mon, 21 Apr 2014 09:16:54 -0700 Message-ID: <53554475.3010201@mentor.com> Date: Tue, 22 Apr 2014 00:16:53 +0800 From: Hui Zhu <hui_zhu@mentor.com> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.4.0 MIME-Version: 1.0 To: gdb-patches ml <gdb-patches@sourceware.org> Subject: [PATCH] Fix interrupt.exp fails with m32 in x86_64 Content-Type: text/plain; charset="ISO-8859-1"; format=flowed Content-Transfer-Encoding: 7bit X-IsSubscribed: yes X-DH-Original-To: gdb@patchwork.siddhesh.in |
Commit Message
Hui Zhu
April 21, 2014, 4:16 p.m. UTC
make check RUNTESTFLAGS="GDB_TESTCASE_OPTIONS=\"-m32\" interrupt.exp" in x86_64 will got some fails: FAIL: gdb.base/interrupt.exp: signal SIGINT (the program is no longer running) FAIL: gdb.base/interrupt.exp: echo more data (timeout) FAIL: gdb.base/interrupt.exp: send end of file The issue can be reproduced: #uname -p x86_64 #gcc -g -m32 gdb.base/interrupt.c #gdb ./a.out (gdb) r Starting program: /home/teawater/gdb/binutils-gdb/gdb/testsuite/a.out talk to me baby data data ^C Program received signal SIGINT, Interrupt. 0xf7ffd430 in __kernel_vsyscall () (gdb) c Continuing. ^C Program received signal SIGINT, Interrupt. 0xf7ffd430 in __kernel_vsyscall () (gdb) p func1() $1 = 4 (gdb) c Continuing. Unknown error 512 [Inferior 1 (process 7953) exited with code 01] nbytes = read (0, &x, 1); if (nbytes < 0) { #ifdef EINTR if (errno != EINTR) #endif After GDB call a function "func1()" by hands, "read" will get errno 512(ERESTARTSYS) that should handled by Linux kernel. The root cause of this issue is: When user use ctrl-c stop the inferior, the signal will be handled in Linux kernel function "do_signal" in arch/x86/kernel/signal.c. The inferior will be stoped by function "ptrace_stop". The call trace is: #0 freezable_schedule () at include/linux/freezer.h:172 #1 ptrace_stop (exit_code=exit_code@entry=5, why=why@entry=262148, clear_code=clear_code@entry=0, info=info@entry=0xffff88001d833e78) at kernel/signal.c:1920 #2 0xffffffff8107ec33 in ptrace_signal (info=0xffff88001d833e78, signr=5) at kernel/signal.c:2157 #3 get_signal_to_deliver (info=info@entry=0xffff88001d833e78, return_ka=return_ka@entry=0xffff88001d833e58, regs=<optimized out>, cookie=cookie@entry=0x0 <irq_stack_union>) at kernel/signal.c:2269 #4 0xffffffff81013438 in do_signal (regs=regs@entry=0xffff88001d833f58) at arch/x86/kernel/signal.c:696 #5 0xffffffff81013a40 in do_notify_resume (regs=0xffff88001d833f58, unused=<optimized out>, thread_info_flags=4) at arch/x86/kernel/signal.c:747 #6 <signal handler called> #7 0x0000000000000000 in irq_stack_union () When GDB "call func1()", to control inferior execute the function func1() and go back to old ip. GDB need set all the registers by GDB function "amd64_collect_native_gregset" that will zero-extend most of 32 bits registers to 64 bits and set to inferior. And execute from ptrace_stop and got back to do_signal. current_thread_info()->status TS_COMPAT will be clean by function "int_with_check" when it return to user space. When GDB "continue", inferior will execute from ptrace_stop and got back to do_signal again. Because this signal interrupt a syscall, go back to function do_signal will use function "syscall_get_error" check if this is a syscall and got error: static inline long syscall_get_error(struct task_struct *task, struct pt_regs *regs) { unsigned long error = regs->ax; #ifdef CONFIG_IA32_EMULATION /* * TS_COMPAT is set for 32-bit syscall entries and then * remains set until we return to user mode. */ if (task_thread_info(task)->status & TS_COMPAT) /* * Sign-extend the value so (int)-EFOO becomes (long)-EFOO * and will match correctly in comparisons. */ error = (long) (int) error; #endif return IS_ERR_VALUE(error) ? error : 0; } Now ax is in 32 bits now, need sign-extend to 64 bits. But current_thread_info()->status TS_COMPAT is cleared when GDB call "call func1()". Linux kernel don't know this is a 32 bits task and will not extend it. Then -ERESTARTSYS is not be handled and go back to user space. Then the syscall "read" get a errno in ERESTARTSYS. I make a patch that let eax sign-extend in function amd64_collect_native_gregset that can handle this issue. It can handle the issue and pass the regression test. Please help me review it. And I make a another patch for Linux kernel that can handle this issue too. I will post it to LKML later. Thanks, Hui 2014-04-21 Hui Zhu <hui@codesourcery.com> * amd64-nat.c(amd64_collect_native_gregset): Make %eax sign-extended. } @@ -156,7 +158,24 @@ amd64_collect_native_gregset (const stru int offset = amd64_native_gregset_reg_offset (gdbarch, i); if (offset != -1) - regcache_raw_collect (regcache, i, regs + offset); + { + if (i == I386_EAX_REGNUM + && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) + { + /* Make sure %eax get sign-extended to 64 bits. */ + LONGEST val; + + regcache_raw_collect (regcache, I386_EAX_REGNUM, + regs + offset); + val = extract_signed_integer ((gdb_byte *)(regs + offset), + 4, + gdbarch_byte_order (gdbarch)); + store_signed_integer ((gdb_byte *)(regs + offset), 8, + gdbarch_byte_order (gdbarch), val); + } + else + regcache_raw_collect (regcache, i, regs + offset); + } } } }
Comments
> Date: Tue, 22 Apr 2014 00:16:53 +0800 > From: Hui Zhu <hui_zhu@mentor.com> > > I make a patch that let eax sign-extend in function > amd64_collect_native_gregset > that can handle this issue. > It can handle the issue and pass the regression test. > Please help me review it. I don't think the generic amd64 target code is the proper place to work around Linux kernel bugs. If you really want to work around this bug in GDB, it should probably be done in the Linux-specific i386/amd64 native code. Mark > 2014-04-21 Hui Zhu <hui@codesourcery.com> > > * amd64-nat.c(amd64_collect_native_gregset): Make %eax sign-extended. > --- a/gdb/amd64-nat.c > +++ b/gdb/amd64-nat.c > @@ -131,10 +131,12 @@ amd64_collect_native_gregset (const stru > { > num_regs = amd64_native_gregset32_num_regs; > > - /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and > + /* Make sure %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and > %eip get zero-extended to 64 bits. */ > for (i = 0; i <= I386_EIP_REGNUM; i++) > { > + if (i == I386_EAX_REGNUM) > + continue; > if (regnum == -1 || regnum == i) > memset (regs + amd64_native_gregset_reg_offset (gdbarch, i), > 0, 8); > } > @@ -156,7 +158,24 @@ amd64_collect_native_gregset (const stru > int offset = amd64_native_gregset_reg_offset (gdbarch, i); > > if (offset != -1) > - regcache_raw_collect (regcache, i, regs + offset); > + { > + if (i == I386_EAX_REGNUM > + && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) > + { > + /* Make sure %eax get sign-extended to 64 bits. */ > + LONGEST val; > + > + regcache_raw_collect (regcache, I386_EAX_REGNUM, > + regs + offset); > + val = extract_signed_integer ((gdb_byte *)(regs + offset), > + 4, > + gdbarch_byte_order (gdbarch)); > + store_signed_integer ((gdb_byte *)(regs + offset), 8, > + gdbarch_byte_order (gdbarch), val); > + } > + else > + regcache_raw_collect (regcache, i, regs + offset); > + } > } > } > } > >
I am sorry that the root cause of issue has something wrong. The right root cause is: When inferior call 32 bits syscall "read", Linux kernel function "ia32_cstar_target" will set TS_COMPAT to current_thread_info->status. syscall read is interrupt by ctrl-c. Then the $rax will be set to errno -512 in 64 bits. And the inferior will be stopped by Linux kernel function ptrace_stop, the call trace is: #0 freezable_schedule () at include/linux/freezer.h:172 #1 ptrace_stop (exit_code=exit_code@entry=5, why=why@entry=262148, clear_code=clear_code@entry=0, info=info@entry=0xffff88001d833e78) at kernel/signal.c:1920 #2 0xffffffff8107ec33 in ptrace_signal (info=0xffff88001d833e78, signr=5) at kernel/signal.c:2157 #3 get_signal_to_deliver (info=info@entry=0xffff88001d833e78, return_ka=return_ka@entry=0xffff88001d833e58, regs=<optimized out>, cookie=cookie@entry=0x0 <irq_stack_union>) at kernel/signal.c:2269 #4 0xffffffff81013438 in do_signal (regs=regs@entry=0xffff88001d833f58) at arch/x86/kernel/signal.c:696 #5 0xffffffff81013a40 in do_notify_resume (regs=0xffff88001d833f58, unused=<optimized out>, thread_info_flags=4) at arch/x86/kernel/signal.c:747 #6 <signal handler called> #7 0x0000000000000000 in irq_stack_union () After that, GDB can control the stopped inferior. To call function "func1()" of inferior, GDB need: Step 1, save current values of registers ($rax 0xfffffffffffffe00(64 bits -512) is cut to 0xfffffe00(32 bits -512) because inferior is a 32 bits program). Step 2, change the values of registers. Step 3, Push a dummy frame to stack. Step 4, set a breakpint in the return address. When GDB resume the inferior, it will keep execut from ptrace_stop with new values of registers that set by GDB. And TS_COMPAT inside current_thread_info->status will be cleared when inferior switch back to user space. When function "func1()" return, inferior will be stoped by breakpoint inferior will be stopped by Linux kernel function "ptrace_stop" again. current_thread_info->status will not set TS_COMPAT when inferior swith from user space to kernel space because breakpoint handler "int3" doesn't has code for that. GDB begin to set saved values of registers back to inferior that use function "amd64_collect_native_gregset". Because this function just zero-extend each 32 bits value to 64 bits value before put them to inferior. $rax's value is set to 0xfffffe00(32 bits -512) but not 0xfffffffffffffe00(64 bits -512). When GDB continue syscall "read" that is interrupted by "ctrl-c", it will keep execute from ptrace_stop without "TS_COMPAT". Then in Linux kernel function "syscall_get_error", current_thread_info->status doesn't have TS_COMPAT and $rax is 0xfffffe00(32 bits -512). Then in function do_signal will not handle this -ERESTARTSYS. -ERESTARTSYS will be return back to inferior, that is why inferior got a errno -ERESTARTSYS. On Tue, Apr 22, 2014 at 2:27 AM, Mark Kettenis <mark.kettenis@xs4all.nl> wrote: >> Date: Tue, 22 Apr 2014 00:16:53 +0800 >> From: Hui Zhu <hui_zhu@mentor.com> >> >> I make a patch that let eax sign-extend in function >> amd64_collect_native_gregset >> that can handle this issue. >> It can handle the issue and pass the regression test. >> Please help me review it. > > I don't think the generic amd64 target code is the proper place to > work around Linux kernel bugs. If you really want to work around this > bug in GDB, it should probably be done in the Linux-specific > i386/amd64 native code. > > Mark > >> 2014-04-21 Hui Zhu <hui@codesourcery.com> >> >> * amd64-nat.c(amd64_collect_native_gregset): Make %eax sign-extended. >> --- a/gdb/amd64-nat.c >> +++ b/gdb/amd64-nat.c >> @@ -131,10 +131,12 @@ amd64_collect_native_gregset (const stru >> { >> num_regs = amd64_native_gregset32_num_regs; >> >> - /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and >> + /* Make sure %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and >> %eip get zero-extended to 64 bits. */ >> for (i = 0; i <= I386_EIP_REGNUM; i++) >> { >> + if (i == I386_EAX_REGNUM) >> + continue; >> if (regnum == -1 || regnum == i) >> memset (regs + amd64_native_gregset_reg_offset (gdbarch, i), >> 0, 8); >> } >> @@ -156,7 +158,24 @@ amd64_collect_native_gregset (const stru >> int offset = amd64_native_gregset_reg_offset (gdbarch, i); >> >> if (offset != -1) >> - regcache_raw_collect (regcache, i, regs + offset); >> + { >> + if (i == I386_EAX_REGNUM >> + && gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32) >> + { >> + /* Make sure %eax get sign-extended to 64 bits. */ >> + LONGEST val; >> + >> + regcache_raw_collect (regcache, I386_EAX_REGNUM, >> + regs + offset); >> + val = extract_signed_integer ((gdb_byte *)(regs + offset), >> + 4, >> + gdbarch_byte_order (gdbarch)); >> + store_signed_integer ((gdb_byte *)(regs + offset), 8, >> + gdbarch_byte_order (gdbarch), val); >> + } >> + else >> + regcache_raw_collect (regcache, i, regs + offset); >> + } >> } >> } >> } >> >>
On 04/29/2014 04:56 PM, Hui Zhu wrote: > I am sorry that the root cause of issue has something wrong. > The right root cause is: > When inferior call 32 bits syscall "read", Linux kernel function > "ia32_cstar_target" will set TS_COMPAT to current_thread_info->status. Thanks a lot of tracking this stuff down. I appreciate the effort. It'd be great if we got an ack on the kernel side on what's going on before we considered working around it in GDB. Thanks,
--- a/gdb/amd64-nat.c +++ b/gdb/amd64-nat.c @@ -131,10 +131,12 @@ amd64_collect_native_gregset (const stru { num_regs = amd64_native_gregset32_num_regs; - /* Make sure %eax, %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and + /* Make sure %ebx, %ecx, %edx, %esi, %edi, %ebp, %esp and %eip get zero-extended to 64 bits. */ for (i = 0; i <= I386_EIP_REGNUM; i++) { + if (i == I386_EAX_REGNUM) + continue; if (regnum == -1 || regnum == i) memset (regs + amd64_native_gregset_reg_offset (gdbarch, i), 0, 8);