From b9610957d255719fea6a9aba038c770e2f71215c Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Tue, 19 Dec 2006 19:26:15 +0000 Subject: [PATCH] - Fix bogus 0x0 unwind of the thread's topmost function clone(3) (BZ 216711). - Testcase for readline segfault on excessively long hand-typed lines. - Related: rhbz#216711 --- gdb-6.5-bz216711-clone-is-outermost.patch | 260 ++++++++++++++++++++ gdb-6.5-readline-long-line-crash-test.patch | 136 ++++++++++ gdb.spec | 12 +- 3 files changed, 407 insertions(+), 1 deletion(-) create mode 100644 gdb-6.5-bz216711-clone-is-outermost.patch create mode 100644 gdb-6.5-readline-long-line-crash-test.patch diff --git a/gdb-6.5-bz216711-clone-is-outermost.patch b/gdb-6.5-bz216711-clone-is-outermost.patch new file mode 100644 index 0000000..6d76e54 --- /dev/null +++ b/gdb-6.5-bz216711-clone-is-outermost.patch @@ -0,0 +1,260 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=216711 + + +2006-12-17 Jan Kratochvil + + * gdb/amd64-linux-tdep.c (linux_clone_code): New variable. + (LINUX_CLONE_LEN): New definition. + (amd64_linux_clone_running, amd64_linux_outermost_frame): New function. + (amd64_linux_init_abi): Initialize `outermost_frame_p'. + * gdb/i386-tdep.c (i386_gdbarch_init): Likewise. + * gdb/i386-tdep.h (gdbarch_tdep): Add `outermost_frame_p' member. + * gdb/amd64-tdep.c (amd64_frame_this_id): Call `outermost_frame_p'. + +2006-12-17 Jan Kratochvil + + * gdb.threads/bt-clone-stop.exp, gdb.threads/bt-clone-stop.c: + New file. + + +--- ./gdb/amd64-linux-tdep.c 19 Aug 2006 15:15:18 -0000 1.12 ++++ ./gdb/amd64-linux-tdep.c 17 Dec 2006 17:59:05 -0000 +@@ -235,6 +235,80 @@ amd64_linux_register_reggroup_p (struct + + /* Set the program counter for process PTID to PC. */ + ++/* Detect the outermost frame; during unwind of ++ #5 0x000000305cec68c3 in clone () from /lib64/tls/libc.so.6 ++ avoid the additional bogus frame ++ #6 0x0000000000000000 in ?? ++ We compare if the `linux_clone_code' block is _before_ unwound PC. */ ++ ++static const unsigned char linux_clone_code[] = ++{ ++/* libc/sysdeps/unix/sysv/linux/x86_64/clone.S */ ++/* #ifdef RESET_PID */ ++/* ... */ ++/* mov $SYS_ify(getpid), %eax */ ++/* 0xb8, 0x27, 0x00, 0x00, 0x00 */ ++/* OR */ ++/* mov $SYS_ify(getpid), %rax */ ++/* 0x48, 0xc7, 0xc0, 0x27, 0x00, 0x00, 0x00 */ ++/* so just: */ ++ 0x27, 0x00, 0x00, 0x00, ++/* syscall */ ++ 0x0f, 0x05, ++/* movl %eax, %fs:PID */ ++ 0x64, 0x89, 0x04, 0x25, 0x94, 0x00, 0x00, 0x00, ++/* movl %eax, %fs:TID */ ++ 0x64, 0x89, 0x04, 0x25, 0x90, 0x00, 0x00, 0x00, ++/* #endif */ ++/* |* Set up arguments for the function call. *| */ ++/* popq %rax |* Function to call. *| */ ++ 0x58, ++/* popq %rdi |* Argument. *| */ ++ 0x5f, ++/* call *%rax$ */ ++ 0xff, 0xd0 ++}; ++ ++#define LINUX_CLONE_LEN (sizeof linux_clone_code) ++ ++static int ++amd64_linux_clone_running (struct frame_info *next_frame) ++{ ++ CORE_ADDR pc = frame_pc_unwind (next_frame); ++ unsigned char buf[LINUX_CLONE_LEN]; ++ ++ if (!safe_frame_unwind_memory (next_frame, pc - LINUX_CLONE_LEN, buf, ++ LINUX_CLONE_LEN)) ++ return 0; ++ ++ if (memcmp (buf, linux_clone_code, LINUX_CLONE_LEN) != 0) ++ return 0; ++ ++ return 1; ++} ++ ++static int ++amd64_linux_outermost_frame (struct frame_info *next_frame) ++{ ++ CORE_ADDR pc = frame_pc_unwind (next_frame); ++ char *name; ++ ++ find_pc_partial_function (pc, &name, NULL, NULL); ++ ++ /* If we have NAME, we can optimize the search. ++ `clone' NAME still needs to have the code checked as its name may be ++ present in the user code. ++ `__clone' NAME should not be present in the user code but in the initial ++ parts of the `__clone' implementation the unwind still makes sense. ++ More detailed unwinding decision would be too much sensitive to possible ++ subtle changes in specific glibc revisions. */ ++ if (name == NULL || strcmp (name, "clone") == 0 ++ || strcmp ("__clone", name) == 0) ++ return (amd64_linux_clone_running (next_frame) != 0); ++ ++ return 0; ++} ++ + static void + amd64_linux_write_pc (CORE_ADDR pc, ptid_t ptid) + { +@@ -273,6 +342,8 @@ amd64_linux_init_abi (struct gdbarch_inf + tdep->sc_reg_offset = amd64_linux_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (amd64_linux_sc_reg_offset); + ++ tdep->outermost_frame_p = amd64_linux_outermost_frame; ++ + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); +--- ./gdb/amd64-tdep.c 19 Aug 2006 15:15:18 -0000 1.32 ++++ ./gdb/amd64-tdep.c 17 Dec 2006 17:59:05 -0000 +@@ -879,11 +879,16 @@ amd64_frame_this_id (struct frame_info * + { + struct amd64_frame_cache *cache = + amd64_frame_cache (next_frame, this_cache); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); + + /* This marks the outermost frame. */ + if (cache->base == 0) + return; + ++ /* Detect OS dependent outermost frames; such as `clone'. */ ++ if (tdep->outermost_frame_p && tdep->outermost_frame_p (next_frame)) ++ return; ++ + (*this_id) = frame_id_build (cache->base + 16, cache->pc); + } + +--- ./gdb/i386-tdep.c 8 Aug 2006 21:36:46 -0000 1.225 ++++ ./gdb/i386-tdep.c 17 Dec 2006 17:59:10 -0000 +@@ -2313,6 +2313,9 @@ i386_gdbarch_init (struct gdbarch_info i + tdep->sc_pc_offset = -1; + tdep->sc_sp_offset = -1; + ++ /* Unwinding stops on i386 automatically. */ ++ tdep->outermost_frame_p = NULL; ++ + /* The format used for `long double' on almost all i386 targets is + the i387 extended floating-point format. In fact, of all targets + in the GCC 2.95 tree, only OSF/1 does it different, and insists +--- ./gdb/i386-tdep.h 21 Jan 2006 20:59:50 -0000 1.46 ++++ ./gdb/i386-tdep.h 17 Dec 2006 17:59:10 -0000 +@@ -104,6 +104,9 @@ struct gdbarch_tdep + is deprecated, please use `sc_reg_offset' instead. */ + int sc_pc_offset; + int sc_sp_offset; ++ ++ /* Detect OS dependent outermost frames; such as `clone'. */ ++ int (*outermost_frame_p) (struct frame_info *next_frame); + }; + + /* Floating-point registers. */ +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/bt-clone-stop.c 17 Dec 2006 17:59:19 -0000 +@@ -0,0 +1,39 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2006 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ MA 02110-1301, USA. */ ++ ++ ++#include ++#include ++#include ++ ++ ++void *threader (void *arg) ++{ ++ assert (0); ++ return NULL; ++} ++ ++int main (void) ++{ ++ pthread_t t1; ++ ++ pthread_create (&t1, NULL, threader, (void *) NULL); ++ for (;;) ++ pause(); ++} +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.threads/bt-clone-stop.exp 17 Dec 2006 17:59:19 -0000 +@@ -0,0 +1,61 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Backtraced `clone' must not have `PC == 0' as its previous frame. ++ ++if $tracelevel then { ++ strace $tracelevel ++} ++ ++set testfile bt-clone-stop ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested "Couldn't compile test program" ++ return -1 ++} ++ ++# Get things started. ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++# threader: threader.c:8: threader: Assertion `0' failed. ++# Program received signal SIGABRT, Aborted. ++ ++gdb_test "run" \ ++ "Program received signal SIGABRT.*" \ ++ "run" ++ ++# Former gdb unwind (the first function is `clone'): ++# #5 0x0000003421ecd62d in ?? () from /lib64/libc.so.6 ++# #6 0x0000000000000000 in ?? () ++# (gdb) ++# Tested `amd64_linux_outermost_frame' functionality should omit the line `#6'. ++# ++# Two `-re' cases below must be in this order (1st is a subset of the 2nd one). ++# Unhandled case below should not happen and it is fortunately handled by ++# `amd64_linux_outermost_frame' as FAIL (and result `0x0 entry output invalid'). ++gdb_test_multiple "bt" "0x0 entry output invalid" { ++ -re "in threader \\(.*\n#\[0-9\]* *0x0* in .*$gdb_prompt $" { ++ fail "0x0 entry found" ++ } ++ -re "in threader \\(.*$gdb_prompt $" { ++ pass "0x0 entry not found" ++ } ++} diff --git a/gdb-6.5-readline-long-line-crash-test.patch b/gdb-6.5-readline-long-line-crash-test.patch new file mode 100644 index 0000000..86a82a4 --- /dev/null +++ b/gdb-6.5-readline-long-line-crash-test.patch @@ -0,0 +1,136 @@ +https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214196 + + +Index: ./gdb/testsuite/gdb.base/readline-overflow.exp +=================================================================== +RCS file: ./gdb/testsuite/gdb.base/readline-overflow.exp +diff -N ./gdb/testsuite/gdb.base/readline-overflow.exp +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ ./gdb/testsuite/gdb.base/readline-overflow.exp 13 Nov 2006 23:42:50 -0000 +@@ -0,0 +1,125 @@ ++# Copyright 2006 Free Software Foundation, Inc. ++ ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@prep.ai.mit.edu ++ ++# This file was written by Jan Kratochvil ++ ++# This file is part of the gdb testsuite. ++ ++# ++# Tests for readline buffer overflow. ++# ++ ++if $tracelevel { ++ strace $tracelevel ++} ++ ++# Don't let a .inputrc file or an existing setting of INPUTRC mess up ++# the test results. Even if /dev/null doesn't exist on the particular ++# platform, the readline library will use the default setting just by ++# failing to open the file. OTOH, opening /dev/null successfully will ++# also result in the default settings being used since nothing will be ++# read from this file. ++global env ++if [info exists env(INPUTRC)] { ++ set old_inputrc $env(INPUTRC) ++} ++set env(INPUTRC) "/dev/null" ++ ++set oldtimeout1 $timeout ++set timeout 600 ++ ++if [info exists env(GDBHISTFILE)] { ++ set old_gdbhistfile $env(GDBHISTFILE) ++} ++if [info exists env(HISTSIZE)] { ++ set old_histsize $env(HISTSIZE) ++} ++set env(GDBHISTFILE) "${srcdir}/${subdir}/gdb_history" ++set env(HISTSIZE) "10" ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++ ++set width 11 ++gdb_test "set width $width" \ ++ "" \ ++ "Setting width to $width." ++#gdb_test "set height 1" \ ++# "" \ ++# "Setting height to 1." ++send_gdb "run X" ++set i 0 ++# It crashes using `set width 7' on `set total 3560'. ++# Sometimes it corrupts screen on `set width 7'. ++# Bugreport used `set total 130001': ++# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=214196 ++# Check also `timeout' above. ++set total 4200 ++gdb_expect { ++ -re X { ++ incr i ++ if {$i <= $total} { ++ send_gdb "X" ++ exp_continue ++ } ++ } ++ -re "\[ \b\r\n\]" { ++ exp_continue ++ } ++ eof { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters, reason: EOF" ++ gdb_clear_suppressed ++ } ++ timeout { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters (timeout $timeout), reason: TIMEOUT" ++ gdb_clear_suppressed ++ } ++ default { ++ fail "gdb sending total $total characters" ++ note "Failed after sending $i characters, reason: 0=\[$expect_out(0,string)\] buffer=\[$expect_out(buffer)\]" ++ gdb_clear_suppressed ++ } ++} ++gdb_test "\r" \ ++ "No executable file specified..*" \ ++ "All the characters transferred" ++ ++ ++# Restore globals modified in this test... ++if [info exists old_inputrc] { ++ set env(INPUTRC) $old_inputrc ++} else { ++ unset env(INPUTRC) ++} ++if [info exists old_gdbhistfile] { ++ set env(GDBHISTFILE) $old_gdbhistfile ++} else { ++ unset env(GDBHISTFILE) ++} ++if [info exists old_histsize] { ++ set env(HISTSIZE) $old_histsize ++} else { ++ unset env(HISTSIZE) ++} ++set timeout $oldtimeout1 ++ ++return 0 diff --git a/gdb.spec b/gdb.spec index e1207a1..25e0c76 100644 --- a/gdb.spec +++ b/gdb.spec @@ -11,7 +11,7 @@ Name: gdb Version: 6.5 # The release always contains a leading reserved number, start it at 0. -Release: 19%{?dist} +Release: 20%{?dist} License: GPL Group: Development/Debuggers @@ -304,10 +304,14 @@ Patch208: gdb-6.5-BEA-testsuite.patch # Fix readline segfault on excessively long hand-typed lines. Patch209: gdb-6.5-readline-long-line-crash.patch +Patch213: gdb-6.5-readline-long-line-crash-test.patch # Fix readline history for input mode commands like `command' (BZ 215816). Patch212: gdb-6.5-bz215816-readline-from-callback.patch +# Fix bogus 0x0 unwind of the thread's topmost function clone(3) (BZ 216711). +Patch214: gdb-6.5-bz216711-clone-is-outermost.patch + BuildRequires: ncurses-devel glibc-devel gcc make gzip texinfo dejagnu gettext BuildRequires: flex bison sharutils @@ -428,6 +432,8 @@ and printing their data. %patch209 -p1 %patch211 -p1 %patch212 -p1 +%patch213 -p1 +%patch214 -p1 # Change the version that gets printed at GDB startup, so it is RedHat # specific. @@ -591,6 +597,10 @@ fi # don't include the files in include, they are part of binutils %changelog +* Tue Dec 19 2006 Jan Kratochvil - 6.5-20 +- Fix bogus 0x0 unwind of the thread's topmost function clone(3) (BZ 216711). +- Testcase for readline segfault on excessively long hand-typed lines. + * Tue Dec 12 2006 Jan Kratochvil - 6.5-19 - Fix attachment also to a threaded stopped process (BZ 219118). - Cleanup any leftover testsuite processes as it may stuck mock(1) builds.