diff --git a/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-1of3.patch b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-1of3.patch new file mode 100644 index 0000000..a163ecd --- /dev/null +++ b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-1of3.patch @@ -0,0 +1,218 @@ +commit 6e22494e5076e4d3c0b2c2785883162f83db499e +Author: Jan Kratochvil +Date: Fri Jun 26 15:11:14 2015 +0200 + + Do not skip prologue for asm (.S) files + + GDB tries to skip prologue for .S files according to .debug_line but it then + places the breakpoint to a location where it is never hit. + + This is because #defines in .S files cause prologue skipping which is + completely inappropriate, for s390x: + + glibc/sysdeps/unix/syscall-template.S + 78:/* This is a "normal" system call stub: if there is an error, + 79: it returns -1 and sets errno. */ + 80: + 81:T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS) + 82: ret + + 00000000000f4210 T __select + Line Number Statements: + Extended opcode 2: set Address to 0xf41c8 + Advance Line by 80 to 81 + Copy + Advance PC by 102 to 0xf422e + Special opcode 6: advance Address by 0 to 0xf422e and Line by 1 to 82 + Special opcode 34: advance Address by 2 to 0xf4230 and Line by 1 to 83 + Advance PC by 38 to 0xf4256 + Extended opcode 1: End of Sequence + Compilation Unit @ offset 0x28b3e0: + <0><28b3eb>: Abbrev Number: 1 (DW_TAG_compile_unit) + <28b3ec> DW_AT_stmt_list : 0x7b439 + <28b3f0> DW_AT_low_pc : 0xf41c8 + <28b3f8> DW_AT_high_pc : 0xf4256 + <28b400> DW_AT_name : ../sysdeps/unix/syscall-template.S + <28b423> DW_AT_comp_dir : /usr/src/debug////////glibc-2.17-c758a686/misc + <28b452> DW_AT_producer : GNU AS 2.23.52.0.1 + <28b465> DW_AT_language : 32769 (MIPS assembler) + + without debuginfo or with debuginfo and the fix - correct address: + (gdb) b select + Breakpoint 1 at 0xf4210 + + It is also where .dynsym+.symtab point to: + 00000000000f4210 T __select + 00000000000f4210 W select + + with debuginfo, without the fix: + (gdb) b select + Breakpoint 1 at 0xf41c8: file ../sysdeps/unix/syscall-template.S, line 81. + + One part is to behave for asm files similar way like for 'locations_valid': + /* Symtab has been compiled with both optimizations and debug info so that + GDB may stop skipping prologues as variables locations are valid already + at function entry points. */ + unsigned int locations_valid : 1; + + The other part is to extend the 'locations_valid'-like functionality more. + + Both minsym_found and find_function_start_sal need to be patched, otherwise + their addresses do not match and GDB regresses on ppc64: + + gdb/ChangeLog + 2015-06-26 Jan Kratochvil + + * linespec.c (minsym_found): Reset sal.PC for COMPUNIT_LOCATIONS_VALID + and language_asm.. + * symtab.c (find_function_start_sal): Likewise. + + gdb/testsuite/ChangeLog + 2015-06-26 Jan Kratochvil + + * gdb.arch/amd64-prologue-skip.S: New file. + * gdb.arch/amd64-prologue-skip.exp: New file. + +Index: gdb-7.6.1/gdb/linespec.c +=================================================================== +--- gdb-7.6.1.orig/gdb/linespec.c ++++ gdb-7.6.1/gdb/linespec.c +@@ -3386,7 +3386,9 @@ collect_symbols (struct symbol *sym, voi + } + + /* We've found a minimal symbol MSYMBOL in OBJFILE to associate with our +- linespec; return the SAL in RESULT. */ ++ linespec; return the SAL in RESULT. This function should return SALs ++ matching those from find_function_start_sal, otherwise false ++ multiple-locations breakpoints could be placed. */ + + static void + minsym_found (struct linespec_state *self, struct objfile *objfile, +@@ -3408,7 +3410,23 @@ minsym_found (struct linespec_state *sel + sal = find_pc_sect_line (pc, NULL, 0); + + if (self->funfirstline) +- skip_prologue_sal (&sal); ++ { ++ if (sal.symtab != NULL ++ && (sal.symtab->locations_valid ++ || sal.symtab->language == language_asm)) ++ { ++ /* If gdbarch_convert_from_func_ptr_addr does not apply then ++ sal.SECTION, sal.LINE&co. will stay correct from above. ++ If gdbarch_convert_from_func_ptr_addr applies then ++ sal.SECTION is cleared from above and sal.LINE&co. will ++ stay correct from the last find_pc_sect_line above. */ ++ sal.pc = SYMBOL_VALUE_ADDRESS (msymbol); ++ sal.pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, ++ ¤t_target); ++ } ++ else ++ skip_prologue_sal (&sal); ++ } + + if (maybe_add_address (self->addr_set, objfile->pspace, sal.pc)) + add_sal_to_sals (self, result, &sal, SYMBOL_NATURAL_NAME (msymbol), 0); +Index: gdb-7.6.1/gdb/symtab.c +=================================================================== +--- gdb-7.6.1.orig/gdb/symtab.c ++++ gdb-7.6.1/gdb/symtab.c +@@ -2762,7 +2762,9 @@ skip_prologue_using_lineinfo (CORE_ADDR + /* Given a function symbol SYM, find the symtab and line for the start + of the function. + If the argument FUNFIRSTLINE is nonzero, we want the first line +- of real code inside the function. */ ++ of real code inside the function. ++ This function should return SALs matching those from minsym_found, ++ otherwise false multiple-locations breakpoints could be placed. */ + + struct symtab_and_line + find_function_start_sal (struct symbol *sym, int funfirstline) +@@ -2773,6 +2775,14 @@ find_function_start_sal (struct symbol * + sal = find_pc_sect_line (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), + SYMBOL_OBJ_SECTION (sym), 0); + ++ if (funfirstline && sal.symtab != NULL ++ && (sal.symtab->locations_valid ++ || sal.symtab->language == language_asm)) ++ { ++ sal.pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); ++ return sal; ++ } ++ + /* We always should have a line for the function start address. + If we don't, something is odd. Create a plain SAL refering + just the PC and hope that skip_prologue_sal (if requested) +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/amd64-prologue-skip.S +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/amd64-prologue-skip.S +@@ -0,0 +1,28 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2015 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 3 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, see . */ ++ ++ .text ++/*0*/ hlt ++pushrbp: .globl pushrbp ++#define PUSHRBP push %rbp; mov %rsp, %rbp; nop ++/*1*/ PUSHRBP ++/*6*/ hlt ++ ++/*7*/ hlt ++#define MINSYM nop; .globl minsym; minsym: nop ++/*8*/ MINSYM ++/*a*/ hlt +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/amd64-prologue-skip.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/amd64-prologue-skip.exp +@@ -0,0 +1,35 @@ ++# Copyright 2010-2015 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 3 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, see . ++ ++standard_testfile .S ++set binfile ${binfile}.o ++ ++if { ![istarget x86_64-*-* ] || ![is_lp64_target] } { ++ verbose "Skipping ${testfile}." ++ return ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" object {debug}] != "" } { ++ untested ${testfile} ++ return ++} ++ ++clean_restart ${binfile} ++ ++gdb_test "break *pushrbp" " at 0x1: file .*" ++gdb_test "break pushrbp" " at 0x1: file .*" ++ ++gdb_test "break *minsym" " at 0x9: file .*" ++gdb_test "break minsym" " at 0x9: file .*" diff --git a/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-2of3.patch b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-2of3.patch new file mode 100644 index 0000000..d87cfa9 --- /dev/null +++ b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-2of3.patch @@ -0,0 +1,98 @@ +From gdb-patches-return-123876-listarch-gdb-patches=sources dot redhat dot com at sourceware dot org Mon Jun 29 16:37:14 2015 +Return-Path: +Delivered-To: listarch-gdb-patches at sources dot redhat dot com +Received: (qmail 98411 invoked by alias); 29 Jun 2015 16:37:14 -0000 +Mailing-List: contact gdb-patches-help at sourceware dot org; run by ezmlm +Precedence: bulk +List-Id: +List-Subscribe: +List-Archive: +List-Post: +List-Help: , +Sender: gdb-patches-owner at sourceware dot org +Delivered-To: mailing list gdb-patches at sourceware dot org +Received: (qmail 98402 invoked by uid 89); 29 Jun 2015 16:37:13 -0000 +Authentication-Results: sourceware.org; auth=none +X-Virus-Found: No +X-Spam-SWARE-Status: No, score=-3.5 required=5.0 tests=AWL,BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=no version=3.3.2 +X-HELO: mx1.redhat.com +Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 29 Jun 2015 16:37:13 +0000 +Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id DF7D48EA29 for ; Mon, 29 Jun 2015 16:37:11 +0000 (UTC) +Received: from host1.jankratochvil.net (ovpn-116-41.ams2.redhat.com [10.36.116.41]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t5TGb8I0022607 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO) for ; Mon, 29 Jun 2015 12:37:11 -0400 +Date: Mon, 29 Jun 2015 18:37:08 +0200 +From: Jan Kratochvil +To: gdb-patches at sourceware dot org +Subject: [testsuite patch] Fix testsuite regression by: Do not skip prologue for asm (.S) files +Message-ID: <20150629163708.GA28795@host1.jankratochvil.net> +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="wac7ysb48OaltWcw" +Content-Disposition: inline +User-Agent: Mutt/1.5.23 (2014-03-12) +X-IsSubscribed: yes + + +--wac7ysb48OaltWcw +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline + +Hi, + +I have somehow missed gdb.asm/asm-source.exp PASS->FAIL even on x86_64. + +It has no longer valid assumption that "break" breaks after the prologue even +in assembler. So I have changed this assumption of the testfile. + +Tested it FAIL->PASSes on x86_64, ppc64 and s390x. + +OK for check-in? + + +Jan + +--wac7ysb48OaltWcw +Content-Type: text/plain; charset=us-ascii +Content-Disposition: inline; filename=2 + +gdb/testsuite/ +2015-06-29 Jan Kratochvil + + * gdb.asm/asm-source.exp (f at main): Stop at gdbasm_enter. + (n at main): New. + * gdb.asm/asmsrc1.s: Add comment "mark: main enter". + +Index: gdb-7.6.1/gdb/testsuite/gdb.asm/asm-source.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.asm/asm-source.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.asm/asm-source.exp +@@ -272,6 +272,7 @@ if { [istarget "m6811-*-*"] || [istarget + } + + # Collect some line numbers. ++set line_enter [expr [gdb_get_line_number "main enter" "asmsrc1.s"] + 1] + set line_main [expr [gdb_get_line_number "main start" "asmsrc1.s"] + 1] + set line_call_foo2 [expr [gdb_get_line_number "call foo2" "asmsrc1.s"] + 1] + set line_search_comment [expr [gdb_get_line_number "search" "asmsrc1.s"] + 1] +@@ -295,7 +296,10 @@ if ![runto_main] then { + } + + # Execute the `f' command and see if the result includes source info. +-gdb_test "f" "asmsrc1\[.\]s:$line_main.*several_nops" "f at main" ++gdb_test "f" "asmsrc1\[.\]s:$line_enter.*gdbasm_enter" "f at main" ++ ++# Execute the `n' command. ++gdb_test "n" "$line_main\[ \]*.*several_nops" "n at main" + + # See if we properly `next' over a macro with several insns. + gdb_test "n" "$line_call_foo2\[ \]*.*foo2" "next over macro" +Index: gdb-7.6.1/gdb/testsuite/gdb.asm/asmsrc1.s +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.asm/asmsrc1.s ++++ gdb-7.6.1/gdb/testsuite/gdb.asm/asmsrc1.s +@@ -34,6 +34,7 @@ + + .global main + gdbasm_declare main ++ comment "mark: main enter" + gdbasm_enter + + comment "Call a macro that consists of several lines of assembler code." diff --git a/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch new file mode 100644 index 0000000..af7271a --- /dev/null +++ b/SOURCES/gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch @@ -0,0 +1,226 @@ +These testcases have been created by compiling glibc-2.17-78 on +RHEL-7.1 s390x/ppc64 boxes, and then taking the "select.o" file +present at $builddir/misc/select.o. + +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/s390x-prologue-skip.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/s390x-prologue-skip.exp +@@ -0,0 +1,34 @@ ++# Copyright 2015 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 3 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, see . ++ ++if { ![istarget s390x-*linux-*] || ![is_lp64_target] } { ++ verbose "Skipping s390x-prologue-skip.exp" ++ return ++} ++ ++set testfile "s390x-prologue-skip" ++set uufile "${srcdir}/${subdir}/${testfile}.o.uu" ++set ofile "${srcdir}/${subdir}/${testfile}.o" ++ ++if { [catch "system \"uudecode -o ${ofile} ${uufile}\"" ] != 0 } { ++ untested "failed uudecode" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_load $ofile ++ ++gdb_test "break select" "Breakpoint $decimal at 0x48: file ../sysdeps/unix/syscall-template.S, line 81." "breakpoint on select" +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/s390x-prologue-skip.o.uu +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/s390x-prologue-skip.o.uu +@@ -0,0 +1,64 @@ ++begin 644 s390x-prologue-skip.o.uu ++M?T5,1@("`0`````````````!`!8````!```````````````````````````` ++M``+```````!```````!``!(`#^LE\!``).O?\&@`)+D$`.^G^_]@X^#P```D ++MP.4`````N00``NLE\+``!`J.N00`TKD$`"#`Y0````"Y!``MZ]_Q"``$I_0` ++M"L`0`````+\/$`"G=/_7"HZG2?`!N2$`),"T``````?^````5@`"````.0$! ++M^PX-``$!`0$````!```!+BXO7-C86QL+71E;7!L ++M871E+E,``0`````)`@```````````]```0)F$P("``$!````CP`"``````@! ++M```````````````````````````N+B]S>7-D97!S+W5N:7@OE(``7@. ++M`1L,#Z`!````````&````!P`````````1`!,CP6.!HT'2`[``@```!`````X ++M`````````"```````"YS>6UT86(`+G-T``````````&````!`````&``````````@````````` ++M&````%<````!``````````````````````````````$"`````````),````` ++M```````````````!``````````````!2````!``````````````````````` ++M```````)^`````````!@````$`````@`````````"``````````8````8P`` ++M``$``````````````````````````````94`````````%``````````````` ++M``````$``````````````'8````!``````````````````````````````&P ++M`````````#`````````````````````0``````````````!Q````!``````` ++M```````````````````````*6``````````P````$`````L`````````"``` ++M```````8````B@````$``````````@```````````````````>`````````` ++M2`````````````````````@``````````````(4````$```````````````` ++M``````````````J(`````````#`````0````#0`````````(`````````!@` ++M```1`````P`````````````````````````````"*`````````"4```````` ++M`````````````0```````````````0````(````````````````````````` ++M````!T`````````!L````!$````*``````````@`````````&`````D````# ++M``````````````````````````````CP`````````(X````````````````` ++M```!`````````````````````````````````````````````````P```0`` ++M`````````````````````````P```P```````````````````````````P`` ++M!````````````````````````````P``"``````````````````````````` ++M`P``"@```````````````````````````P``!@`````````````````````` ++M`````P``"P```````````````````````````P``#0`````````````````` ++M`````````P``!0`````````````````````````!$``````````````````` ++M```````````;$``````````````````````````````V$@```0````````!( ++M`````````"`````_$`````````````````````````````!7$@```0`````` ++M``!6`````````!````!I$`````````````````````````````!Y(@```0`` ++M``````!(`````````"````"'(@```0````````!(`````````"``7U]L:6)C ++M7V5N86)L95]A. ++ ++if { ![istarget powerpc64-*linux-*] || ![is_lp64_target] } { ++ verbose "Skipping ppc64-prologue-skip.exp" ++ return ++} ++ ++set testfile "ppc64-prologue-skip" ++set uufile "${srcdir}/${subdir}/${testfile}.o.uu" ++set ofile "${srcdir}/${subdir}/${testfile}.o" ++ ++if { [catch "system \"uudecode -o ${ofile} ${uufile}\"" ] != 0 } { ++ untested "failed uudecode" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_load $ofile ++ ++gdb_test "break ___newselect_nocancel" "Breakpoint $decimal at 0xc: file ../sysdeps/unix/syscall-template.S, line 81." "breakpoint on ___newselect_nocancel" +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/ppc64-prologue-skip.o.uu +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/ppc64-prologue-skip.o.uu +@@ -0,0 +1,70 @@ ++begin 644 ppc64-skip-prologue.o.uu ++M?T5,1@("`0`````````````!`!4````!```````````````````````````` ++M``-(``````!```````!``!0`$8%-B-`L"@``0,(`-#@``(Y$```"3.,`('P( ++M`J;X`0`0^"'_D4@```%@````Z`$`@#@A`'!\"`.F3H``(/@A_X%]*`*F^2$` ++MD/CA`-#XP0#(^*$`P/B!`+CX80"P2````6````#X80!PZ.$`T.C!`,CHH0#` ++MZ($`N.AA`+`X``".1````GP``";X80!X^`$`B.AA`'!(```!8````.DA`)#H ++M`0"(Z&$`>'TH`Z9\#_$@."$`@$SC`"!+__]@```````,($``````````O``( ++M7U]S96QE8W0```````````````````````````!6``(````Y!`'[#@T``0$! ++M`0````$```$N+B]S>7-D97!S+W5N:7@``'-Y"]S>7-C86QL+71E;7!L871E ++M+E,`+W)O;W0O9VQI8F,O9VQI8F,M,BXQ-RTW."YE;#$$!&PP!```` ++M`#`````8`````````+P`20YP$4%^1`X`009!0@Z``4(107Y2$49_20X`!D$& ++M1@``````+G-Y;71A8@`N`````````!(````$@````$`````````"``````````8```` ++M)@````$``````````P```````````````````1@````````````````````` ++M``````````$``````````````"P````(``````````,````````````````` ++M``$8```````````````````````````````!```````````````V`````0`` ++M```````#```````````````````!&``````````0```````````````````` ++M"```````````````,0````0`````````````````````````````"L`````` ++M````,````!(````%``````````@`````````&````#L````!```````````` ++M``````````````````$H```````````````````````````````!```````` ++M``````!0`````0`````````````````````````````!*`````````!:```` ++M`````````````````0``````````````2P````0````````````````````` ++M````````"O``````````&````!(````(``````````@`````````&````&$` ++M```!``````````````````````````````&"`````````),````````````` ++M```````!``````````````!<````!``````````````````````````````+ ++M"`````````!@````$@````H`````````"``````````8````;0````$````` ++M`````````````````````````A4`````````%`````````````````````$` ++M`````````````(`````!``````````````````````````````(P```````` ++M`#`````````````````````0``````````````![````!``````````````` ++M```````````````+:``````````P````$@````T`````````"``````````8 ++M````E`````$``````````@```````````````````F``````````2``````` ++M``````````````@``````````````(\````$```````````````````````` ++M``````N8`````````!@````2````#P`````````(`````````!@````1```` ++M`P`````````````````````````````"J`````````">```````````````` ++M`````0```````````````0````(`````````````````````````````"$@` ++M```````!L````!,````+``````````@`````````&`````D````#```````` ++M``````````````````````GX`````````'H````````````````````!```` ++M`````````````````````````````````````````````P```0`````````` ++M`````````````````P```P```````````````````````````P``!``````` ++M`````````````````````P``!0```````````````````````````P``"@`` ++M`````````````````````````P``#````````````````````````````P`` ++M"````````````````````````````P``#0`````````````````````````` ++M`P``#P```````````````````````````P``!P`````````````````````` ++M```!$@``!0```````````````````-@````*$@```0`````````,```````` ++M`#`````@$``````````````````````````````P$``````````````````` ++M``````````!*$`````````````````````````````!E(@``!0`````````` ++M`````````-@```!S(@``!0```````````````````-@`7U]S96QE8W0`7U]? ++M;F5W6YC8V%N8V5L`%]?;&EB8U]D:7-A8FQE7V%S>6YC8V%N8V5L`%]? ++M;&EB8U]S96QE8W0` +Date: Fri, 13 Sep 2013 14:11:15 +0000 +Subject: [PATCH 2/3] 2013-09-13 Andreas Arnez + + * s390-tdep.h (S390_IS_GREGSET_REGNUM): New macro. + (S390_IS_FPREGSET_REGNUM): New macro. + * s390-tdep.c (s390_dwarf_regmap): Make const. + (regnum_is_gpr_full): New function for replacing repeated code. + (s390_pseudo_register_name): Use it. + (s390_pseudo_register_type): Likewise. + (s390_pseudo_register_read): Likewise. + (s390_pseudo_register_write): Likewise. + (s390_unwind_pseudo_register): Likewise. + (s390_regmap_gregset): New format for regmap. + (s390x_regmap_gregset): Likewise. + (s390_regmap_fpregset): Likewise. + (s390_regmap_upper): Likewise. + (s390_regmap_last_break): Likewise. + (s390_regmap_system_call): Likewise. + (s390_supply_regset): Adjust to new regmap format. + (s390_collect_regset): Likewise. + * s390-nat.c (s390_native_supply): Adjust to new regmap format. + (s390_native_collect): Likewise. + (supply_gregset): Likewise. + (fill_gregset): Likewise. + (supply_fpregset): Likewise. + (fill_fpregset): Likewise. + (fetch_regset): Likewise. + (store_regset): Likewise. + (s390_linux_fetch_inferior_registers): Likewise. + (s390_linux_fetch_inferior_registers): Likewise. +--- + gdb/ChangeLog | 30 +++++ + gdb/s390-nat.c | 233 +++++++++++++++++------------------ + gdb/s390-tdep.c | 369 +++++++++++++++++++++++++++----------------------------- + gdb/s390-tdep.h | 20 ++- + 4 files changed, 328 insertions(+), 324 deletions(-) + +Index: gdb-7.6.1/gdb/s390-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-nat.c ++++ gdb-7.6.1/gdb/s390-nat.c +@@ -63,139 +63,139 @@ static int have_regset_system_call = 0; + + #define regmap_fpregset s390_regmap_fpregset + +-/* When debugging a 32-bit executable running under a 64-bit kernel, +- we have to fix up the 64-bit registers we get from the kernel +- to make them look like 32-bit registers. */ ++/* Fill the regset described by MAP into REGCACHE, using the values ++ from REGP. The MAP array represents each register as a pair ++ (offset, regno) of short integers and is terminated with -1. */ + + static void +-s390_native_supply (struct regcache *regcache, int regno, +- const gdb_byte *regp, int *regmap) ++s390_native_supply (struct regcache *regcache, const short *map, ++ const gdb_byte *regp) + { +- int offset = regmap[regno]; ++ for (; map[0] >= 0; map += 2) ++ regcache_raw_supply (regcache, map[1], regp + map[0]); ++} ++ ++/* Collect the register REGNO out of the regset described by MAP from ++ REGCACHE into REGP. If REGNO == -1, do this for all registers in ++ this regset. */ + ++static void ++s390_native_collect (const struct regcache *regcache, const short *map, ++ int regno, gdb_byte *regp) ++{ ++ for (; map[0] >= 0; map += 2) ++ if (regno == -1 || regno == map[1]) ++ regcache_raw_collect (regcache, map[1], regp + map[0]); ++} ++ ++/* Fill GDB's register array with the general-purpose register values ++ in *REGP. ++ ++ When debugging a 32-bit executable running under a 64-bit kernel, ++ we have to fix up the 64-bit registers we get from the kernel to ++ make them look like 32-bit registers. */ ++ ++void ++supply_gregset (struct regcache *regcache, const gregset_t *regp) ++{ + #ifdef __s390x__ + struct gdbarch *gdbarch = get_regcache_arch (regcache); +- if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32) ++ if (gdbarch_ptr_bit (gdbarch) == 32) + { + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ ULONGEST pswm = 0, pswa = 0; ++ gdb_byte buf[4]; ++ const short *map; + +- if (regno == S390_PSWM_REGNUM) +- { +- ULONGEST pswm; +- gdb_byte buf[4]; +- +- pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM], +- 8, byte_order); +- +- store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000); +- regcache_raw_supply (regcache, regno, buf); +- return; +- } +- +- if (regno == S390_PSWA_REGNUM) ++ for (map = regmap_gregset; map[0] >= 0; map += 2) + { +- ULONGEST pswm, pswa; +- gdb_byte buf[4]; ++ const gdb_byte *p = (const gdb_byte *) regp + map[0]; ++ int regno = map[1]; + +- pswa = extract_unsigned_integer (regp + regmap[S390_PSWA_REGNUM], +- 8, byte_order); +- pswm = extract_unsigned_integer (regp + regmap[S390_PSWM_REGNUM], +- 8, byte_order); +- +- store_unsigned_integer (buf, 4, byte_order, +- (pswa & 0x7fffffff) | (pswm & 0x80000000)); +- regcache_raw_supply (regcache, regno, buf); +- return; ++ if (regno == S390_PSWM_REGNUM) ++ pswm = extract_unsigned_integer (p, 8, byte_order); ++ else if (regno == S390_PSWA_REGNUM) ++ pswa = extract_unsigned_integer (p, 8, byte_order); ++ else ++ { ++ if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM) ++ || regno == S390_ORIG_R2_REGNUM) ++ p += 4; ++ regcache_raw_supply (regcache, regno, p); ++ } + } + +- if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM) +- || regno == S390_ORIG_R2_REGNUM) +- offset += 4; ++ store_unsigned_integer (buf, 4, byte_order, (pswm >> 32) | 0x80000); ++ regcache_raw_supply (regcache, S390_PSWM_REGNUM, buf); ++ store_unsigned_integer (buf, 4, byte_order, ++ (pswa & 0x7fffffff) | (pswm & 0x80000000)); ++ regcache_raw_supply (regcache, S390_PSWA_REGNUM, buf); ++ return; + } + #endif + +- if (offset != -1) +- regcache_raw_supply (regcache, regno, regp + offset); ++ s390_native_supply (regcache, regmap_gregset, (const gdb_byte *) regp); + } + +-static void +-s390_native_collect (const struct regcache *regcache, int regno, +- gdb_byte *regp, int *regmap) +-{ +- int offset = regmap[regno]; ++/* Fill register REGNO (if it is a general-purpose register) in ++ *REGP with the value in GDB's register array. If REGNO is -1, ++ do this for all registers. */ + ++void ++fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) ++{ + #ifdef __s390x__ + struct gdbarch *gdbarch = get_regcache_arch (regcache); +- if (offset != -1 && gdbarch_ptr_bit (gdbarch) == 32) ++ if (gdbarch_ptr_bit (gdbarch) == 32) + { +- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ gdb_byte *psw_p[2]; ++ const short *map; + +- if (regno == S390_PSWM_REGNUM) ++ for (map = regmap_gregset; map[0] >= 0; map += 2) + { +- ULONGEST pswm; +- gdb_byte buf[4]; ++ gdb_byte *p = (gdb_byte *) regp + map[0]; ++ int reg = map[1]; + +- regcache_raw_collect (regcache, regno, buf); +- pswm = extract_unsigned_integer (buf, 4, byte_order); ++ if (reg >= S390_PSWM_REGNUM && reg <= S390_PSWA_REGNUM) ++ psw_p[reg - S390_PSWM_REGNUM] = p; + +- /* We don't know the final addressing mode until the PSW address +- is known, so leave it as-is. When the PSW address is collected +- (below), the addressing mode will be updated. */ +- store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM], +- 4, byte_order, pswm & 0xfff7ffff); +- return; ++ else if (regno == -1 || regno == reg) ++ { ++ if ((reg >= S390_R0_REGNUM && reg <= S390_R15_REGNUM) ++ || reg == S390_ORIG_R2_REGNUM) ++ { ++ memset (p, 0, 4); ++ p += 4; ++ } ++ regcache_raw_collect (regcache, reg, p + 4); ++ } + } + +- if (regno == S390_PSWA_REGNUM) ++ if (regno == -1 ++ || regno == S390_PSWM_REGNUM || regno == S390_PSWA_REGNUM) + { +- ULONGEST pswa; ++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ ULONGEST pswa, pswm; + gdb_byte buf[4]; + +- regcache_raw_collect (regcache, regno, buf); ++ regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf); ++ pswm = extract_unsigned_integer (buf, 4, byte_order); ++ regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf); + pswa = extract_unsigned_integer (buf, 4, byte_order); + +- store_unsigned_integer (regp + regmap[S390_PSWA_REGNUM], +- 8, byte_order, pswa & 0x7fffffff); +- +- /* Update basic addressing mode bit in PSW mask, see above. */ +- store_unsigned_integer (regp + regmap[S390_PSWM_REGNUM] + 4, +- 4, byte_order, pswa & 0x80000000); +- return; +- } +- +- if ((regno >= S390_R0_REGNUM && regno <= S390_R15_REGNUM) +- || regno == S390_ORIG_R2_REGNUM) +- { +- memset (regp + offset, 0, 4); +- offset += 4; ++ if (regno == -1 || regno == S390_PSWM_REGNUM) ++ store_unsigned_integer (psw_p[0], 8, byte_order, ++ ((pswm & 0xfff7ffff) << 32) | ++ (pswa & 0x80000000)); ++ if (regno == -1 || regno == S390_PSWA_REGNUM) ++ store_unsigned_integer (psw_p[1], 8, byte_order, ++ pswa & 0x7fffffff); + } ++ return; + } + #endif + +- if (offset != -1) +- regcache_raw_collect (regcache, regno, regp + offset); +-} +- +-/* Fill GDB's register array with the general-purpose register values +- in *REGP. */ +-void +-supply_gregset (struct regcache *regcache, const gregset_t *regp) +-{ +- int i; +- for (i = 0; i < S390_NUM_REGS; i++) +- s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_gregset); +-} +- +-/* Fill register REGNO (if it is a general-purpose register) in +- *REGP with the value in GDB's register array. If REGNO is -1, +- do this for all registers. */ +-void +-fill_gregset (const struct regcache *regcache, gregset_t *regp, int regno) +-{ +- int i; +- for (i = 0; i < S390_NUM_REGS; i++) +- if (regno == -1 || regno == i) +- s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_gregset); ++ s390_native_collect (regcache, regmap_gregset, regno, (gdb_byte *) regp); + } + + /* Fill GDB's register array with the floating-point register values +@@ -203,9 +203,7 @@ fill_gregset (const struct regcache *reg + void + supply_fpregset (struct regcache *regcache, const fpregset_t *regp) + { +- int i; +- for (i = 0; i < S390_NUM_REGS; i++) +- s390_native_supply (regcache, i, (const gdb_byte *) regp, regmap_fpregset); ++ s390_native_supply (regcache, regmap_fpregset, (const gdb_byte *) regp); + } + + /* Fill register REGNO (if it is a general-purpose register) in +@@ -214,10 +212,7 @@ supply_fpregset (struct regcache *regcac + void + fill_fpregset (const struct regcache *regcache, fpregset_t *regp, int regno) + { +- int i; +- for (i = 0; i < S390_NUM_REGS; i++) +- if (regno == -1 || regno == i) +- s390_native_collect (regcache, i, (gdb_byte *) regp, regmap_fpregset); ++ s390_native_collect (regcache, regmap_fpregset, regno, (gdb_byte *) regp); + } + + /* Find the TID for the current inferior thread to use with ptrace. */ +@@ -311,12 +306,10 @@ store_fpregs (const struct regcache *reg + process/thread TID and store their values in GDB's register cache. */ + static void + fetch_regset (struct regcache *regcache, int tid, +- int regset, int regsize, int *regmap) ++ int regset, int regsize, const short *regmap) + { +- struct gdbarch *gdbarch = get_regcache_arch (regcache); + gdb_byte *buf = alloca (regsize); + struct iovec iov; +- int i; + + iov.iov_base = buf; + iov.iov_len = regsize; +@@ -324,8 +317,7 @@ fetch_regset (struct regcache *regcache, + if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) + perror_with_name (_("Couldn't get register set")); + +- for (i = 0; i < S390_NUM_REGS; i++) +- s390_native_supply (regcache, i, buf, regmap); ++ s390_native_supply (regcache, regmap, buf); + } + + /* Store all registers in the kernel's register set whose number is REGSET, +@@ -333,12 +325,10 @@ fetch_regset (struct regcache *regcache, + GDB's register cache back to process/thread TID. */ + static void + store_regset (struct regcache *regcache, int tid, +- int regset, int regsize, int *regmap) ++ int regset, int regsize, const short *regmap) + { +- struct gdbarch *gdbarch = get_regcache_arch (regcache); + gdb_byte *buf = alloca (regsize); + struct iovec iov; +- int i; + + iov.iov_base = buf; + iov.iov_len = regsize; +@@ -346,8 +336,7 @@ store_regset (struct regcache *regcache, + if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) + perror_with_name (_("Couldn't get register set")); + +- for (i = 0; i < S390_NUM_REGS; i++) +- s390_native_collect (regcache, i, buf, regmap); ++ s390_native_collect (regcache, regmap, -1, buf); + + if (ptrace (PTRACE_SETREGSET, tid, (long) regset, (long) &iov) < 0) + perror_with_name (_("Couldn't set register set")); +@@ -378,12 +367,10 @@ s390_linux_fetch_inferior_registers (str + { + int tid = s390_inferior_tid (); + +- if (regnum == -1 +- || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) ++ if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum)) + fetch_regs (regcache, tid); + +- if (regnum == -1 +- || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) ++ if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum)) + fetch_fpregs (regcache, tid); + + if (have_regset_last_break) +@@ -406,12 +393,10 @@ s390_linux_store_inferior_registers (str + { + int tid = s390_inferior_tid (); + +- if (regnum == -1 +- || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) ++ if (regnum == -1 || S390_IS_GREGSET_REGNUM (regnum)) + store_regs (regcache, tid, regnum); + +- if (regnum == -1 +- || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) ++ if (regnum == -1 || S390_IS_FPREGSET_REGNUM (regnum)) + store_fpregs (regcache, tid, regnum); + + /* S390_LAST_BREAK_REGNUM is read-only. */ +Index: gdb-7.6.1/gdb/s390-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.c ++++ gdb-7.6.1/gdb/s390-tdep.c +@@ -141,7 +141,7 @@ s390_write_pc (struct regcache *regcache + + /* DWARF Register Mapping. */ + +-static int s390_dwarf_regmap[] = ++static const short s390_dwarf_regmap[] = + { + /* General Purpose Registers. */ + S390_R0_REGNUM, S390_R1_REGNUM, S390_R2_REGNUM, S390_R3_REGNUM, +@@ -212,6 +212,14 @@ s390_adjust_frame_regnum (struct gdbarch + + /* Pseudo registers. */ + ++static int ++regnum_is_gpr_full (struct gdbarch_tdep *tdep, int regnum) ++{ ++ return (tdep->gpr_full_regnum != -1 ++ && regnum >= tdep->gpr_full_regnum ++ && regnum <= tdep->gpr_full_regnum + 15); ++} ++ + static const char * + s390_pseudo_register_name (struct gdbarch *gdbarch, int regnum) + { +@@ -223,9 +231,7 @@ s390_pseudo_register_name (struct gdbarc + if (regnum == tdep->cc_regnum) + return "cc"; + +- if (tdep->gpr_full_regnum != -1 +- && regnum >= tdep->gpr_full_regnum +- && regnum < tdep->gpr_full_regnum + 16) ++ if (regnum_is_gpr_full (tdep, regnum)) + { + static const char *full_name[] = { + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", +@@ -248,9 +254,7 @@ s390_pseudo_register_type (struct gdbarc + if (regnum == tdep->cc_regnum) + return builtin_type (gdbarch)->builtin_int; + +- if (tdep->gpr_full_regnum != -1 +- && regnum >= tdep->gpr_full_regnum +- && regnum < tdep->gpr_full_regnum + 16) ++ if (regnum_is_gpr_full (tdep, regnum)) + return builtin_type (gdbarch)->builtin_uint64; + + internal_error (__FILE__, __LINE__, _("invalid regnum")); +@@ -295,9 +299,7 @@ s390_pseudo_register_read (struct gdbarc + return status; + } + +- if (tdep->gpr_full_regnum != -1 +- && regnum >= tdep->gpr_full_regnum +- && regnum < tdep->gpr_full_regnum + 16) ++ if (regnum_is_gpr_full (tdep, regnum)) + { + enum register_status status; + ULONGEST val_upper; +@@ -352,9 +354,7 @@ s390_pseudo_register_write (struct gdbar + return; + } + +- if (tdep->gpr_full_regnum != -1 +- && regnum >= tdep->gpr_full_regnum +- && regnum < tdep->gpr_full_regnum + 16) ++ if (regnum_is_gpr_full (tdep, regnum)) + { + regnum -= tdep->gpr_full_regnum; + val = extract_unsigned_integer (buf, regsize, byte_order); +@@ -409,175 +409,166 @@ s390_pseudo_register_reggroup_p (struct + } + + +-/* Core file register sets. */ ++/* Maps for register sets. */ + +-int s390_regmap_gregset[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- 0x00, 0x04, +- /* General Purpose Registers. */ +- 0x08, 0x0c, 0x10, 0x14, +- 0x18, 0x1c, 0x20, 0x24, +- 0x28, 0x2c, 0x30, 0x34, +- 0x38, 0x3c, 0x40, 0x44, +- /* Access Registers. */ +- 0x48, 0x4c, 0x50, 0x54, +- 0x58, 0x5c, 0x60, 0x64, +- 0x68, 0x6c, 0x70, 0x74, +- 0x78, 0x7c, 0x80, 0x84, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GNU/Linux-specific optional "registers". */ +- 0x88, -1, -1, +-}; ++const short s390_regmap_gregset[] = ++ { ++ 0x00, S390_PSWM_REGNUM, ++ 0x04, S390_PSWA_REGNUM, ++ 0x08, S390_R0_REGNUM, ++ 0x0c, S390_R1_REGNUM, ++ 0x10, S390_R2_REGNUM, ++ 0x14, S390_R3_REGNUM, ++ 0x18, S390_R4_REGNUM, ++ 0x1c, S390_R5_REGNUM, ++ 0x20, S390_R6_REGNUM, ++ 0x24, S390_R7_REGNUM, ++ 0x28, S390_R8_REGNUM, ++ 0x2c, S390_R9_REGNUM, ++ 0x30, S390_R10_REGNUM, ++ 0x34, S390_R11_REGNUM, ++ 0x38, S390_R12_REGNUM, ++ 0x3c, S390_R13_REGNUM, ++ 0x40, S390_R14_REGNUM, ++ 0x44, S390_R15_REGNUM, ++ 0x48, S390_A0_REGNUM, ++ 0x4c, S390_A1_REGNUM, ++ 0x50, S390_A2_REGNUM, ++ 0x54, S390_A3_REGNUM, ++ 0x58, S390_A4_REGNUM, ++ 0x5c, S390_A5_REGNUM, ++ 0x60, S390_A6_REGNUM, ++ 0x64, S390_A7_REGNUM, ++ 0x68, S390_A8_REGNUM, ++ 0x6c, S390_A9_REGNUM, ++ 0x70, S390_A10_REGNUM, ++ 0x74, S390_A11_REGNUM, ++ 0x78, S390_A12_REGNUM, ++ 0x7c, S390_A13_REGNUM, ++ 0x80, S390_A14_REGNUM, ++ 0x84, S390_A15_REGNUM, ++ 0x88, S390_ORIG_R2_REGNUM, ++ -1, -1 ++ }; + +-int s390x_regmap_gregset[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- 0x00, 0x08, +- /* General Purpose Registers. */ +- 0x10, 0x18, 0x20, 0x28, +- 0x30, 0x38, 0x40, 0x48, +- 0x50, 0x58, 0x60, 0x68, +- 0x70, 0x78, 0x80, 0x88, +- /* Access Registers. */ +- 0x90, 0x94, 0x98, 0x9c, +- 0xa0, 0xa4, 0xa8, 0xac, +- 0xb0, 0xb4, 0xb8, 0xbc, +- 0xc0, 0xc4, 0xc8, 0xcc, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- 0x10, 0x18, 0x20, 0x28, +- 0x30, 0x38, 0x40, 0x48, +- 0x50, 0x58, 0x60, 0x68, +- 0x70, 0x78, 0x80, 0x88, +- /* GNU/Linux-specific optional "registers". */ +- 0xd0, -1, -1, +-}; ++const short s390x_regmap_gregset[] = ++ { ++ 0x00, S390_PSWM_REGNUM, ++ 0x08, S390_PSWA_REGNUM, ++ 0x10, S390_R0_REGNUM, ++ 0x18, S390_R1_REGNUM, ++ 0x20, S390_R2_REGNUM, ++ 0x28, S390_R3_REGNUM, ++ 0x30, S390_R4_REGNUM, ++ 0x38, S390_R5_REGNUM, ++ 0x40, S390_R6_REGNUM, ++ 0x48, S390_R7_REGNUM, ++ 0x50, S390_R8_REGNUM, ++ 0x58, S390_R9_REGNUM, ++ 0x60, S390_R10_REGNUM, ++ 0x68, S390_R11_REGNUM, ++ 0x70, S390_R12_REGNUM, ++ 0x78, S390_R13_REGNUM, ++ 0x80, S390_R14_REGNUM, ++ 0x88, S390_R15_REGNUM, ++ 0x90, S390_A0_REGNUM, ++ 0x94, S390_A1_REGNUM, ++ 0x98, S390_A2_REGNUM, ++ 0x9c, S390_A3_REGNUM, ++ 0xa0, S390_A4_REGNUM, ++ 0xa4, S390_A5_REGNUM, ++ 0xa8, S390_A6_REGNUM, ++ 0xac, S390_A7_REGNUM, ++ 0xb0, S390_A8_REGNUM, ++ 0xb4, S390_A9_REGNUM, ++ 0xb8, S390_A10_REGNUM, ++ 0xbc, S390_A11_REGNUM, ++ 0xc0, S390_A12_REGNUM, ++ 0xc4, S390_A13_REGNUM, ++ 0xc8, S390_A14_REGNUM, ++ 0xcc, S390_A15_REGNUM, ++ 0x10, S390_R0_UPPER_REGNUM, ++ 0x18, S390_R1_UPPER_REGNUM, ++ 0x20, S390_R2_UPPER_REGNUM, ++ 0x28, S390_R3_UPPER_REGNUM, ++ 0x30, S390_R4_UPPER_REGNUM, ++ 0x38, S390_R5_UPPER_REGNUM, ++ 0x40, S390_R6_UPPER_REGNUM, ++ 0x48, S390_R7_UPPER_REGNUM, ++ 0x50, S390_R8_UPPER_REGNUM, ++ 0x58, S390_R9_UPPER_REGNUM, ++ 0x60, S390_R10_UPPER_REGNUM, ++ 0x68, S390_R11_UPPER_REGNUM, ++ 0x70, S390_R12_UPPER_REGNUM, ++ 0x78, S390_R13_UPPER_REGNUM, ++ 0x80, S390_R14_UPPER_REGNUM, ++ 0x88, S390_R15_UPPER_REGNUM, ++ 0xd0, S390_ORIG_R2_REGNUM, ++ -1, -1 ++ }; + +-int s390_regmap_fpregset[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- -1, -1, +- /* General Purpose Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Access Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Floating Point Control Word. */ +- 0x00, +- /* Floating Point Registers. */ +- 0x08, 0x10, 0x18, 0x20, +- 0x28, 0x30, 0x38, 0x40, +- 0x48, 0x50, 0x58, 0x60, +- 0x68, 0x70, 0x78, 0x80, +- /* GPR Uppper Halves. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GNU/Linux-specific optional "registers". */ +- -1, -1, -1, +-}; ++const short s390_regmap_fpregset[] = ++ { ++ 0x00, S390_FPC_REGNUM, ++ 0x08, S390_F0_REGNUM, ++ 0x10, S390_F1_REGNUM, ++ 0x18, S390_F2_REGNUM, ++ 0x20, S390_F3_REGNUM, ++ 0x28, S390_F4_REGNUM, ++ 0x30, S390_F5_REGNUM, ++ 0x38, S390_F6_REGNUM, ++ 0x40, S390_F7_REGNUM, ++ 0x48, S390_F8_REGNUM, ++ 0x50, S390_F9_REGNUM, ++ 0x58, S390_F10_REGNUM, ++ 0x60, S390_F11_REGNUM, ++ 0x68, S390_F12_REGNUM, ++ 0x70, S390_F13_REGNUM, ++ 0x78, S390_F14_REGNUM, ++ 0x80, S390_F15_REGNUM, ++ -1, -1 ++ }; + +-int s390_regmap_upper[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- -1, -1, +- /* General Purpose Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Access Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- 0x00, 0x04, 0x08, 0x0c, +- 0x10, 0x14, 0x18, 0x1c, +- 0x20, 0x24, 0x28, 0x2c, +- 0x30, 0x34, 0x38, 0x3c, +- /* GNU/Linux-specific optional "registers". */ +- -1, -1, -1, +-}; ++const short s390_regmap_upper[] = ++ { ++ 0x00, S390_R0_UPPER_REGNUM, ++ 0x04, S390_R1_UPPER_REGNUM, ++ 0x08, S390_R2_UPPER_REGNUM, ++ 0x0c, S390_R3_UPPER_REGNUM, ++ 0x10, S390_R4_UPPER_REGNUM, ++ 0x14, S390_R5_UPPER_REGNUM, ++ 0x18, S390_R6_UPPER_REGNUM, ++ 0x1c, S390_R7_UPPER_REGNUM, ++ 0x20, S390_R8_UPPER_REGNUM, ++ 0x24, S390_R9_UPPER_REGNUM, ++ 0x28, S390_R10_UPPER_REGNUM, ++ 0x2c, S390_R11_UPPER_REGNUM, ++ 0x30, S390_R12_UPPER_REGNUM, ++ 0x34, S390_R13_UPPER_REGNUM, ++ 0x38, S390_R14_UPPER_REGNUM, ++ 0x3c, S390_R15_UPPER_REGNUM, ++ -1, -1 ++ }; + +-int s390_regmap_last_break[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- -1, -1, +- /* General Purpose Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Access Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GNU/Linux-specific optional "registers". */ +- -1, 4, -1, +-}; ++const short s390_regmap_last_break[] = ++ { ++ 0x04, S390_LAST_BREAK_REGNUM, ++ -1, -1 ++ }; ++ ++const short s390x_regmap_last_break[] = ++ { ++ 0x00, S390_LAST_BREAK_REGNUM, ++ -1, -1 ++ }; ++ ++const short s390_regmap_system_call[] = ++ { ++ 0x00, S390_SYSTEM_CALL_REGNUM, ++ -1, -1 ++ }; + +-int s390x_regmap_last_break[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- -1, -1, +- /* General Purpose Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Access Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GNU/Linux-specific optional "registers". */ +- -1, 0, -1, +-}; + +-int s390_regmap_system_call[S390_NUM_REGS] = +-{ +- /* Program Status Word. */ +- -1, -1, +- /* General Purpose Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Access Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* Floating Point Control Word. */ +- -1, +- /* Floating Point Registers. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GPR Uppper Halves. */ +- -1, -1, -1, -1, -1, -1, -1, -1, +- -1, -1, -1, -1, -1, -1, -1, -1, +- /* GNU/Linux-specific optional "registers". */ +- -1, -1, 0, +-}; + + /* Supply register REGNUM from the register set REGSET to register cache + REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ +@@ -585,14 +576,10 @@ static void + s390_supply_regset (const struct regset *regset, struct regcache *regcache, + int regnum, const void *regs, size_t len) + { +- const int *offset = regset->descr; +- int i; +- +- for (i = 0; i < S390_NUM_REGS; i++) +- { +- if ((regnum == i || regnum == -1) && offset[i] != -1) +- regcache_raw_supply (regcache, i, (const char *)regs + offset[i]); +- } ++ const short *map; ++ for (map = regset->descr; map[0] >= 0; map += 2) ++ if (regnum == -1 || regnum == map[1]) ++ regcache_raw_supply (regcache, map[1], (const char *)regs + map[0]); + } + + /* Collect register REGNUM from the register cache REGCACHE and store +@@ -604,14 +591,10 @@ s390_collect_regset (const struct regset + const struct regcache *regcache, + int regnum, void *regs, size_t len) + { +- const int *offset = regset->descr; +- int i; +- +- for (i = 0; i < S390_NUM_REGS; i++) +- { +- if ((regnum == i || regnum == -1) && offset[i] != -1) +- regcache_raw_collect (regcache, i, (char *)regs + offset[i]); +- } ++ const short *map; ++ for (map = regset->descr; map[0] >= 0; map += 2) ++ if (regnum == -1 || regnum == map[1]) ++ regcache_raw_collect (regcache, map[1], (char *)regs + map[0]); + } + + static const struct regset s390_gregset = { +@@ -1718,9 +1701,7 @@ s390_unwind_pseudo_register (struct fram + + /* Unwind full GPRs to show at least the lower halves (as the + upper halves are undefined). */ +- if (tdep->gpr_full_regnum != -1 +- && regnum >= tdep->gpr_full_regnum +- && regnum < tdep->gpr_full_regnum + 16) ++ if (regnum_is_gpr_full (tdep, regnum)) + { + int reg = regnum - tdep->gpr_full_regnum; + struct value *val; +Index: gdb-7.6.1/gdb/s390-tdep.h +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.h ++++ gdb-7.6.1/gdb/s390-tdep.h +@@ -106,16 +106,24 @@ + #define S390_RETADDR_REGNUM S390_R14_REGNUM + #define S390_FRAME_REGNUM S390_R11_REGNUM + ++#define S390_IS_GREGSET_REGNUM(i) \ ++ (((i) >= S390_PSWM_REGNUM && (i) <= S390_A15_REGNUM) \ ++ || ((i) >= S390_R0_UPPER_REGNUM && (i) <= S390_R15_UPPER_REGNUM) \ ++ || (i) == S390_ORIG_R2_REGNUM) ++ ++#define S390_IS_FPREGSET_REGNUM(i) \ ++ ((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM) ++ + /* Core file register sets, defined in s390-tdep.c. */ + #define s390_sizeof_gregset 0x90 +-extern int s390_regmap_gregset[S390_NUM_REGS]; ++extern const short s390_regmap_gregset[]; + #define s390x_sizeof_gregset 0xd8 +-extern int s390x_regmap_gregset[S390_NUM_REGS]; ++extern const short s390x_regmap_gregset[]; + #define s390_sizeof_fpregset 0x88 +-extern int s390_regmap_fpregset[S390_NUM_REGS]; +-extern int s390_regmap_last_break[S390_NUM_REGS]; +-extern int s390x_regmap_last_break[S390_NUM_REGS]; +-extern int s390_regmap_system_call[S390_NUM_REGS]; ++extern const short s390_regmap_fpregset[]; ++extern const short s390_regmap_last_break[]; ++extern const short s390x_regmap_last_break[]; ++extern const short s390_regmap_system_call[]; + + /* GNU/Linux target descriptions. */ + extern struct target_desc *tdesc_s390_linux32; diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-2of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-2of9.patch new file mode 100644 index 0000000..2087e2b --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-2of9.patch @@ -0,0 +1,22 @@ +commit 9b44a3a57d17ea2d35823780007a38daeeaec6a4 +Author: Andreas Arnez +Date: Tue May 13 14:55:53 2014 +0200 + + S390: Fix erroneous offset in fill_gregset. + + This fixes a bug that leads to various failures when debugging a + 31-bit inferior with a 64-bit gdb on s390x. + +Index: gdb-7.6.1/gdb/s390-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-nat.c ++++ gdb-7.6.1/gdb/s390-nat.c +@@ -167,7 +167,7 @@ fill_gregset (const struct regcache *reg + memset (p, 0, 4); + p += 4; + } +- regcache_raw_collect (regcache, reg, p + 4); ++ regcache_raw_collect (regcache, reg, p); + } + } + diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-3of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-3of9.patch new file mode 100644 index 0000000..ac325db --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-3of9.patch @@ -0,0 +1,1398 @@ +From 4ac33720d6022079e8b038e795e40f0e06a4012c Mon Sep 17 00:00:00 2001 +From: Ulrich Weigand +Date: Fri, 13 Sep 2013 14:17:31 +0000 +Subject: [PATCH 3/3] gdb/ChangeLog: 2013-09-13 Andreas Arnez + + + * NEWS: Mention TDB support. + * features/s390-tdb.xml: New file. + * features/s390-te-linux64.xml: New file. + * features/s390x-te-linux64.xml: New file. + * features/Makefile (WHICH): Add new tdescs above. + (s390-te-linux64-expedite): Set. + (s390x-te-linux64-expedite): Set. + * features/s390-te-linux64.c: New file (generated). + * features/s390x-te-linux64.c: New file (generated). + * regformats/s390-te-linux64.dat: New file (generated). + * regformats/s390x-te-linux64.dat: New file (generated). + * s390-tdep.h (HWCAP_S390_HIGH_GPRS): Define. + (HWCAP_S390_TE): Likewise. + (S390_TDB_DWORD0_REGNUM): Likewise. + (S390_TDB_DWORD0_REGNUM): Likewise. + (S390_TDB_ABORT_CODE_REGNUM): Likewise. + (S390_TDB_CONFLICT_TOKEN_REGNUM): Likewise. + (S390_TDB_ATIA_REGNUM): Likewise. + (S390_TDB_R0_REGNUM): Likewise. + (S390_TDB_R1_REGNUM): Likewise. + (S390_TDB_R2_REGNUM): Likewise. + (S390_TDB_R3_REGNUM): Likewise. + (S390_TDB_R4_REGNUM): Likewise. + (S390_TDB_R5_REGNUM): Likewise. + (S390_TDB_R6_REGNUM): Likewise. + (S390_TDB_R7_REGNUM): Likewise. + (S390_TDB_R8_REGNUM): Likewise. + (S390_TDB_R9_REGNUM): Likewise. + (S390_TDB_R10_REGNUM): Likewise. + (S390_TDB_R11_REGNUM): Likewise. + (S390_TDB_R12_REGNUM): Likewise. + (S390_TDB_R13_REGNUM): Likewise. + (S390_TDB_R14_REGNUM): Likewise. + (S390_TDB_R15_REGNUM): Likewise. + (S390_NUM_REGS): Increase. + (S390_IS_TDBREGSET_REGNUM): New macro. + (s390_regmap_tdb): Declare. + (s390_sizeof_tdbregset): Define. + (tdesc_s390_te_linux64): Declare. + (tdesc_s390x_te_linux64): Likewise. + * s390-tdep.c: Add includes for "auxv.h", , + "features/s390-te-linux64.c", and "features/s390x-te-linux64.c". + (s390_regmap_tdb): New regmap. + (s390_supply_tdb_regset): New function. + (s390_tdb_regset): New regset. + (s390_linux64v2_regset_sections): Add TDB regset to list. + (s390x_linux64v2_regset_sections): Likewise. + (s390_regset_from_core_section): Recognize TDB core note section. + (s390_core_read_description): If HWCAP indicates TE support, + select tdesc_s390_te_linux64 or tdesc_s390_s390x_te_linux64. + (s390_gdbarch_init): Handle TDB regset. + (_initialize_s390_tdep): Initialize new tdescs. + * s390-nat.c (HWCAP_S390_HIGH_GPRS): Remove define. + (have_regset_tdb): New variable. + (s390_native_supply): Support register invalidation. + (fetch_regset): Invalidate registers if ptrace yields ENODATA. + (check_regset): Treat ENODATA as "regset exists". + (s390_linux_fetch_inferior_registers): Add TDB. + (s390_read_description): Check for TDB existence and select + appropriate tdesc. + * gdbserver/Makefile.in (clean): Add removal of new makefile + targets. + (s390-te-linux64.c): New makefile target. + (s390x-te-linux64.c): Likewise. + * gdbserver/configure.srv (srv_regobj): Append new objects + s390-te-linux64.o and s390x-te-linux64.o. + (srv_xmlfiles): Append new files s390-te-linux64.xml, + s390x-te-linux64.xml, and s390-tdb.xml. + * gdbserver/linux-s390-low.c (init_registers_s390_te_linux64): New + declaration. + (tdesc_s390_te_linux64): Likewise. + (init_registers_s390x_te_linux64): Likewise. + (tdesc_s390x_te_linux64): Likewise. + (s390_check_regset): Treat ENODATA as "regset exists". + (s390_arch_setup): Add TDB regset support. + (initialize_low_arch): Initialize registers for new tdescs. + +gdb/doc/ChangeLog: +2013-09-13 Andreas Arnez + + * gdb.texinfo (Decimal Floating Point format): Mention S/390. + (Standard Target Features): Add new node to menu. + (S/390 and System z Features): New node. + +gdb/testsuite/ChangeLog: +2013-09-13 Andreas Arnez + + * gdb.arch/s390-tdbregs.c: New file. + * gdb.arch/s390-tdbregs.exp: New file. +--- + gdb/ChangeLog | 79 +++++++++++++++++++++ + gdb/NEWS | 4 ++ + gdb/doc/ChangeLog | 6 ++ + gdb/doc/gdb.texinfo | 38 +++++++++- + gdb/features/Makefile | 3 + + gdb/features/s390-tdb.xml | 30 ++++++++ + gdb/features/s390-te-linux64.c | 118 ++++++++++++++++++++++++++++++++ + gdb/features/s390-te-linux64.xml | 25 +++++++ + gdb/features/s390x-te-linux64.c | 102 +++++++++++++++++++++++++++ + gdb/features/s390x-te-linux64.xml | 24 +++++++ + gdb/gdbserver/Makefile.in | 7 ++ + gdb/gdbserver/configure.srv | 5 ++ + gdb/gdbserver/linux-s390-low.c | 25 +++++-- + gdb/regformats/s390-te-linux64.dat | 94 +++++++++++++++++++++++++ + gdb/regformats/s390x-te-linux64.dat | 78 +++++++++++++++++++++ + gdb/s390-nat.c | 37 ++++++---- + gdb/s390-tdep.c | 85 ++++++++++++++++++++++- + gdb/s390-tdep.h | 40 ++++++++++- + gdb/testsuite/ChangeLog | 5 ++ + gdb/testsuite/gdb.arch/s390-tdbregs.c | 64 +++++++++++++++++ + gdb/testsuite/gdb.arch/s390-tdbregs.exp | 75 ++++++++++++++++++++ + 21 files changed, 921 insertions(+), 23 deletions(-) + create mode 100644 gdb/features/s390-tdb.xml + create mode 100644 gdb/features/s390-te-linux64.c + create mode 100644 gdb/features/s390-te-linux64.xml + create mode 100644 gdb/features/s390x-te-linux64.c + create mode 100644 gdb/features/s390x-te-linux64.xml + create mode 100644 gdb/regformats/s390-te-linux64.dat + create mode 100644 gdb/regformats/s390x-te-linux64.dat + create mode 100644 gdb/testsuite/gdb.arch/s390-tdbregs.c + create mode 100644 gdb/testsuite/gdb.arch/s390-tdbregs.exp + +Index: gdb-7.6.1/gdb/NEWS +=================================================================== +--- gdb-7.6.1.orig/gdb/NEWS ++++ gdb-7.6.1/gdb/NEWS +@@ -14,6 +14,10 @@ add-auto-load-scripts-directory director + + ** Frame filters and frame decorators have been added. + ++* On S/390 targets that provide the transactional-execution feature, ++ the program interruption transaction diagnostic block (TDB) is now ++ represented as a number of additional "registers" in GDB. ++ + * New remote packets + + qXfer:libraries-svr4:read's annex +Index: gdb-7.6.1/gdb/doc/gdb.texinfo +=================================================================== +--- gdb-7.6.1.orig/gdb/doc/gdb.texinfo ++++ gdb-7.6.1/gdb/doc/gdb.texinfo +@@ -13737,8 +13737,8 @@ specified by the extension to support de + + There are two encodings in use, depending on the architecture: BID (Binary + Integer Decimal) for x86 and x86-64, and DPD (Densely Packed Decimal) for +-PowerPC. @value{GDBN} will use the appropriate encoding for the configured +-target. ++PowerPC and S/390. @value{GDBN} will use the appropriate encoding for the ++configured target. + + Because of a limitation in @file{libdecnumber}, the library used by @value{GDBN} + to manipulate decimal floating point numbers, it is not possible to convert +@@ -42082,6 +42082,7 @@ registers using the capitalization used + * MIPS Features:: + * M68K Features:: + * PowerPC Features:: ++* S/390 and System z Features:: + * TIC6x Features:: + @end menu + +@@ -42261,6 +42262,39 @@ contain registers @samp{ev0h} through @s + these to present registers @samp{ev0} through @samp{ev31} to the + user. + ++@node S/390 and System z Features ++@subsection S/390 and System z Features ++@cindex target descriptions, S/390 features ++@cindex target descriptions, System z features ++ ++The @samp{org.gnu.gdb.s390.core} feature is required for S/390 and ++System z targets. It should contain the PSW and the 16 general ++registers. In particular, System z targets should provide the 64-bit ++registers @samp{pswm}, @samp{pswa}, and @samp{r0} through @samp{r15}. ++S/390 targets should provide the 32-bit versions of these registers. ++A System z target that runs in 31-bit addressing mode should provide ++32-bit versions of @samp{pswm} and @samp{pswa}, as well as the general ++register's upper halves @samp{r0h} through @samp{r15h}, and their ++lower halves @samp{r0l} through @samp{r15l}. ++ ++The @samp{org.gnu.gdb.s390.fpr} feature is required. It should ++contain the 64-bit registers @samp{f0} through @samp{f15}, and ++@samp{fpc}. ++ ++The @samp{org.gnu.gdb.s390.acr} feature is required. It should ++contain the 32-bit registers @samp{acr0} through @samp{acr15}. ++ ++The @samp{org.gnu.gdb.s390.linux} feature is optional. It should ++contain the register @samp{orig_r2}, which is 64-bit wide on System z ++targets and 32-bit otherwise. In addition, the feature may contain ++the @samp{last_break} register, whose width depends on the addressing ++mode, as well as the @samp{system_call} register, which is always ++32-bit wide. ++ ++The @samp{org.gnu.gdb.s390.tdb} feature is optional. It should ++contain the 64-bit registers @samp{tdb0}, @samp{tac}, @samp{tct}, ++@samp{atia}, and @samp{tr0} through @samp{tr15}. ++ + @node TIC6x Features + @subsection TMS320C6x Features + @cindex target descriptions, TIC6x features +Index: gdb-7.6.1/gdb/features/Makefile +=================================================================== +--- gdb-7.6.1.orig/gdb/features/Makefile ++++ gdb-7.6.1/gdb/features/Makefile +@@ -49,6 +49,7 @@ WHICH = aarch64 aarch64-without-fpu \ + s390-linux32 s390-linux64 s390x-linux64 \ + s390-linux32v1 s390-linux64v1 s390x-linux64v1 \ + s390-linux32v2 s390-linux64v2 s390x-linux64v2 \ ++ s390-te-linux64 s390x-te-linux64 \ + tic6x-c64xp tic6x-c64x tic6x-c62x \ + tic6x-c64xp-linux tic6x-c64x-linux tic6x-c62x-linux + +@@ -82,9 +83,11 @@ s390-linux32v2-expedite = r14,r15,pswa + s390-linux64-expedite = r14l,r15l,pswa + s390-linux64v1-expedite = r14l,r15l,pswa + s390-linux64v2-expedite = r14l,r15l,pswa ++s390-te-linux64-expedite = r14,r15,pswa + s390x-linux64-expedite = r14,r15,pswa + s390x-linux64v1-expedite = r14,r15,pswa + s390x-linux64v2-expedite = r14,r15,pswa ++s390x-te-linux64-expedite = r14,r15,pswa + tic6x-c64xp-expedite = A15,PC + tic6x-c64x-expedite = A15,PC + tic6x-c62x-expedite = A15,PC +Index: gdb-7.6.1/gdb/features/s390-tdb.xml +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/features/s390-tdb.xml +@@ -0,0 +1,30 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: gdb-7.6.1/gdb/features/s390-te-linux64.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/features/s390-te-linux64.c +@@ -0,0 +1,118 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: s390-te-linux64.xml */ ++ ++#include "defs.h" ++#include "osabi.h" ++#include "target-descriptions.h" ++ ++struct target_desc *tdesc_s390_te_linux64; ++static void ++initialize_tdesc_s390_te_linux64 (void) ++{ ++ struct target_desc *result = allocate_target_description (); ++ struct tdesc_feature *feature; ++ ++ set_tdesc_architecture (result, bfd_scan_arch ("s390:31-bit")); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core"); ++ tdesc_create_reg (feature, "pswm", 0, 1, "psw", 32, "uint32"); ++ tdesc_create_reg (feature, "pswa", 1, 1, "psw", 32, "uint32"); ++ tdesc_create_reg (feature, "r0h", 2, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r0l", 3, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r1h", 4, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r1l", 5, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r2h", 6, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r2l", 7, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r3h", 8, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r3l", 9, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r4h", 10, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r4l", 11, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r5h", 12, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r5l", 13, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r6h", 14, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r6l", 15, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r7h", 16, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r7l", 17, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r8h", 18, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r8l", 19, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r9h", 20, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r9l", 21, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r10h", 22, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r10l", 23, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r11h", 24, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r11l", 25, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r12h", 26, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r12l", 27, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r13h", 28, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r13l", 29, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r14h", 30, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r14l", 31, 1, "lower", 32, "uint32"); ++ tdesc_create_reg (feature, "r15h", 32, 1, "upper", 32, "uint32"); ++ tdesc_create_reg (feature, "r15l", 33, 1, "lower", 32, "uint32"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.acr"); ++ tdesc_create_reg (feature, "acr0", 34, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr1", 35, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr2", 36, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr3", 37, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr4", 38, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr5", 39, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr6", 40, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr7", 41, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr8", 42, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr9", 43, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr10", 44, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr11", 45, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr12", 46, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr13", 47, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr14", 48, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr15", 49, 1, "access", 32, "uint32"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.fpr"); ++ tdesc_create_reg (feature, "fpc", 50, 1, "float", 32, "uint32"); ++ tdesc_create_reg (feature, "f0", 51, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f1", 52, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f2", 53, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f3", 54, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f4", 55, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f5", 56, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f6", 57, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f7", 58, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f8", 59, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f9", 60, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f10", 61, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f11", 62, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f12", 63, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f13", 64, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f14", 65, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f15", 66, 1, "float", 64, "ieee_double"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.linux"); ++ tdesc_create_reg (feature, "orig_r2", 67, 1, "system", 32, "uint32"); ++ tdesc_create_reg (feature, "last_break", 68, 0, "system", 32, "code_ptr"); ++ tdesc_create_reg (feature, "system_call", 69, 1, "system", 32, "uint32"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.tdb"); ++ tdesc_create_reg (feature, "tdb0", 70, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tac", 71, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tct", 72, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "atia", 73, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr0", 74, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr1", 75, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr2", 76, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr3", 77, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr4", 78, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr5", 79, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr6", 80, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr7", 81, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr8", 82, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr9", 83, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr10", 84, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr11", 85, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr12", 86, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr13", 87, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr14", 88, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr15", 89, 1, "tdb", 64, "uint64"); ++ ++ tdesc_s390_te_linux64 = result; ++} +Index: gdb-7.6.1/gdb/features/s390-te-linux64.xml +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/features/s390-te-linux64.xml +@@ -0,0 +1,25 @@ ++ ++ ++ ++ ++ ++ ++ ++ s390:31-bit ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: gdb-7.6.1/gdb/features/s390x-te-linux64.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/features/s390x-te-linux64.c +@@ -0,0 +1,102 @@ ++/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro: ++ Original: s390x-te-linux64.xml */ ++ ++#include "defs.h" ++#include "osabi.h" ++#include "target-descriptions.h" ++ ++struct target_desc *tdesc_s390x_te_linux64; ++static void ++initialize_tdesc_s390x_te_linux64 (void) ++{ ++ struct target_desc *result = allocate_target_description (); ++ struct tdesc_feature *feature; ++ ++ set_tdesc_architecture (result, bfd_scan_arch ("s390:64-bit")); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.core"); ++ tdesc_create_reg (feature, "pswm", 0, 1, "psw", 64, "uint64"); ++ tdesc_create_reg (feature, "pswa", 1, 1, "psw", 64, "uint64"); ++ tdesc_create_reg (feature, "r0", 2, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r1", 3, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r2", 4, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r3", 5, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r4", 6, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r5", 7, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r6", 8, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r7", 9, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r8", 10, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r9", 11, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r10", 12, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r11", 13, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r12", 14, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r13", 15, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r14", 16, 1, "general", 64, "uint64"); ++ tdesc_create_reg (feature, "r15", 17, 1, "general", 64, "uint64"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.acr"); ++ tdesc_create_reg (feature, "acr0", 18, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr1", 19, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr2", 20, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr3", 21, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr4", 22, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr5", 23, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr6", 24, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr7", 25, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr8", 26, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr9", 27, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr10", 28, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr11", 29, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr12", 30, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr13", 31, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr14", 32, 1, "access", 32, "uint32"); ++ tdesc_create_reg (feature, "acr15", 33, 1, "access", 32, "uint32"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.fpr"); ++ tdesc_create_reg (feature, "fpc", 34, 1, "float", 32, "uint32"); ++ tdesc_create_reg (feature, "f0", 35, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f1", 36, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f2", 37, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f3", 38, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f4", 39, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f5", 40, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f6", 41, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f7", 42, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f8", 43, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f9", 44, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f10", 45, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f11", 46, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f12", 47, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f13", 48, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f14", 49, 1, "float", 64, "ieee_double"); ++ tdesc_create_reg (feature, "f15", 50, 1, "float", 64, "ieee_double"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.linux"); ++ tdesc_create_reg (feature, "orig_r2", 51, 1, "system", 64, "uint64"); ++ tdesc_create_reg (feature, "last_break", 52, 0, "system", 64, "code_ptr"); ++ tdesc_create_reg (feature, "system_call", 53, 1, "system", 32, "uint32"); ++ ++ feature = tdesc_create_feature (result, "org.gnu.gdb.s390.tdb"); ++ tdesc_create_reg (feature, "tdb0", 54, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tac", 55, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tct", 56, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "atia", 57, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr0", 58, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr1", 59, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr2", 60, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr3", 61, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr4", 62, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr5", 63, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr6", 64, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr7", 65, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr8", 66, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr9", 67, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr10", 68, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr11", 69, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr12", 70, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr13", 71, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr14", 72, 1, "tdb", 64, "uint64"); ++ tdesc_create_reg (feature, "tr15", 73, 1, "tdb", 64, "uint64"); ++ ++ tdesc_s390x_te_linux64 = result; ++} +Index: gdb-7.6.1/gdb/features/s390x-te-linux64.xml +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/features/s390x-te-linux64.xml +@@ -0,0 +1,24 @@ ++ ++ ++ ++ ++ ++ ++ ++ s390:64-bit ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +Index: gdb-7.6.1/gdb/gdbserver/Makefile.in +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/Makefile.in ++++ gdb-7.6.1/gdb/gdbserver/Makefile.in +@@ -329,6 +329,9 @@ clean: + rm -f powerpc-isa205-altivec32l.c powerpc-isa205-vsx32l.c powerpc-isa205-altivec64l.c + rm -f powerpc-isa205-vsx64l.c + rm -f s390-linux32.c s390-linux64.c s390x-linux64.c ++ rm -f s390-linux32v1.c s390-linux32v2.c s390-linux64v1.c ++ rm -f s390-linux64v2.c s390x-linux64v1.c s390x-linux64v2.c ++ rm -f s390-te-linux32.c s390-te-linux64.c + rm -f tic6x-c64xp-linux.c tic6x-c64x-linux.c tic6x-c62x-linux.c + rm -f xml-builtin.c stamp-xml + rm -f i386-avx.c i386-avx-linux.c +@@ -658,12 +661,16 @@ s390-linux64v1.c : $(srcdir)/../regforma + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390-linux64v1.dat s390-linux64v1.c + s390-linux64v2.c : $(srcdir)/../regformats/s390-linux64v2.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390-linux64v2.dat s390-linux64v2.c ++s390-te-linux64.c : $(srcdir)/../regformats/s390-te-linux64.dat $(regdat_sh) ++ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390-te-linux64.dat s390-te-linux64.c + s390x-linux64.c : $(srcdir)/../regformats/s390x-linux64.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390x-linux64.dat s390x-linux64.c + s390x-linux64v1.c : $(srcdir)/../regformats/s390x-linux64v1.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390x-linux64v1.dat s390x-linux64v1.c + s390x-linux64v2.c : $(srcdir)/../regformats/s390x-linux64v2.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390x-linux64v2.dat s390x-linux64v2.c ++s390x-te-linux64.c : $(srcdir)/../regformats/s390x-te-linux64.dat $(regdat_sh) ++ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/s390x-te-linux64.dat s390x-te-linux64.c + + tic6x-c64xp-linux.c : $(srcdir)/../regformats/tic6x-c64xp-linux.dat $(regdat_sh) + $(SHELL) $(regdat_sh) $(srcdir)/../regformats/tic6x-c64xp-linux.dat tic6x-c64xp-linux.c +Index: gdb-7.6.1/gdb/gdbserver/configure.srv +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/configure.srv ++++ gdb-7.6.1/gdb/gdbserver/configure.srv +@@ -259,9 +259,11 @@ case "${target}" in + srv_regobj="${srv_regobj} s390-linux64.o" + srv_regobj="${srv_regobj} s390-linux64v1.o" + srv_regobj="${srv_regobj} s390-linux64v2.o" ++ srv_regobj="${srv_regobj} s390-te-linux64.o" + srv_regobj="${srv_regobj} s390x-linux64.o" + srv_regobj="${srv_regobj} s390x-linux64v1.o" + srv_regobj="${srv_regobj} s390x-linux64v2.o" ++ srv_regobj="${srv_regobj} s390x-te-linux64.o" + srv_tgtobj="linux-low.o linux-osdata.o linux-s390-low.o linux-procfs.o" + srv_tgtobj="${srv_tgtobj} linux-ptrace.o" + srv_xmlfiles="s390-linux32.xml" +@@ -270,14 +272,17 @@ case "${target}" in + srv_xmlfiles="${srv_xmlfiles} s390-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux64v1.xml" + srv_xmlfiles="${srv_xmlfiles} s390-linux64v2.xml" ++ srv_xmlfiles="${srv_xmlfiles} s390-te-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64v1.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-linux64v2.xml" ++ srv_xmlfiles="${srv_xmlfiles} s390x-te-linux64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-core32.xml" + srv_xmlfiles="${srv_xmlfiles} s390-core64.xml" + srv_xmlfiles="${srv_xmlfiles} s390x-core64.xml" + srv_xmlfiles="${srv_xmlfiles} s390-acr.xml" + srv_xmlfiles="${srv_xmlfiles} s390-fpr.xml" ++ srv_xmlfiles="${srv_xmlfiles} s390-tdb.xml" + srv_linux_usrregs=yes + srv_linux_regsets=yes + srv_linux_thread_db=yes +Index: gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-s390-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +@@ -59,6 +59,12 @@ void init_registers_s390x_linux64v1 (voi + /* Defined in auto-generated file s390x-linux64v2.c. */ + void init_registers_s390x_linux64v2 (void); + ++/* Defined in auto-generated file s390x-te-linux64.c. */ ++void init_registers_s390x_te_linux64 (void); ++ ++/* Defined in auto-generated file s390-te-linux64.c. */ ++void init_registers_s390_te_linux64 (void); ++ + #define s390_num_regs 52 + + static int s390_regmap[] = { +@@ -365,10 +371,10 @@ s390_check_regset (int pid, int regset, + iov.iov_base = buf; + iov.iov_len = regsize; + +- if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) < 0) +- return 0; +- else ++ if (ptrace (PTRACE_GETREGSET, pid, (long) regset, (long) &iov) >= 0 ++ || errno == ENODATA) + return 1; ++ return 0; + } + + static void +@@ -382,6 +388,7 @@ s390_arch_setup (void) + = s390_check_regset (pid, NT_S390_LAST_BREAK, 8); + int have_regset_system_call + = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4); ++ int have_regset_tdb = s390_check_regset (pid, NT_S390_TDB, 256); + + /* Update target_regsets according to available register sets. */ + for (regset = target_regsets; regset->fill_function != NULL; regset++) +@@ -394,6 +401,8 @@ s390_arch_setup (void) + case NT_S390_SYSTEM_CALL: + regset->size = have_regset_system_call? 4 : 0; + break; ++ case NT_S390_TDB: ++ regset->size = have_regset_tdb ? 256 : 0; + default: + break; + } +@@ -421,6 +430,8 @@ s390_arch_setup (void) + + if (pswm & 1) + { ++ if (have_regset_tdb) ++ init_registers_s390x_te_linux64 (); + if (have_regset_system_call) + init_registers_s390x_linux64v2 (); + else if (have_regset_last_break) +@@ -433,6 +444,8 @@ s390_arch_setup (void) + using the full 64-bit GPRs. */ + else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) + { ++ if (have_regset_tdb) ++ init_registers_s390_te_linux64 (); + if (have_regset_system_call) + init_registers_s390_linux64v2 (); + else if (have_regset_last_break) +Index: gdb-7.6.1/gdb/regformats/s390-te-linux64.dat +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/regformats/s390-te-linux64.dat +@@ -0,0 +1,94 @@ ++# DO NOT EDIT: generated from s390-te-linux64.xml ++name:s390_te_linux64 ++xmltarget:s390-te-linux64.xml ++expedite:r14,r15,pswa ++32:pswm ++32:pswa ++32:r0h ++32:r0l ++32:r1h ++32:r1l ++32:r2h ++32:r2l ++32:r3h ++32:r3l ++32:r4h ++32:r4l ++32:r5h ++32:r5l ++32:r6h ++32:r6l ++32:r7h ++32:r7l ++32:r8h ++32:r8l ++32:r9h ++32:r9l ++32:r10h ++32:r10l ++32:r11h ++32:r11l ++32:r12h ++32:r12l ++32:r13h ++32:r13l ++32:r14h ++32:r14l ++32:r15h ++32:r15l ++32:acr0 ++32:acr1 ++32:acr2 ++32:acr3 ++32:acr4 ++32:acr5 ++32:acr6 ++32:acr7 ++32:acr8 ++32:acr9 ++32:acr10 ++32:acr11 ++32:acr12 ++32:acr13 ++32:acr14 ++32:acr15 ++32:fpc ++64:f0 ++64:f1 ++64:f2 ++64:f3 ++64:f4 ++64:f5 ++64:f6 ++64:f7 ++64:f8 ++64:f9 ++64:f10 ++64:f11 ++64:f12 ++64:f13 ++64:f14 ++64:f15 ++32:orig_r2 ++32:last_break ++32:system_call ++64:tdb0 ++64:tac ++64:tct ++64:atia ++64:tr0 ++64:tr1 ++64:tr2 ++64:tr3 ++64:tr4 ++64:tr5 ++64:tr6 ++64:tr7 ++64:tr8 ++64:tr9 ++64:tr10 ++64:tr11 ++64:tr12 ++64:tr13 ++64:tr14 ++64:tr15 +Index: gdb-7.6.1/gdb/regformats/s390x-te-linux64.dat +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/regformats/s390x-te-linux64.dat +@@ -0,0 +1,78 @@ ++# DO NOT EDIT: generated from s390x-te-linux64.xml ++name:s390x_te_linux64 ++xmltarget:s390x-te-linux64.xml ++expedite:r14,r15,pswa ++64:pswm ++64:pswa ++64:r0 ++64:r1 ++64:r2 ++64:r3 ++64:r4 ++64:r5 ++64:r6 ++64:r7 ++64:r8 ++64:r9 ++64:r10 ++64:r11 ++64:r12 ++64:r13 ++64:r14 ++64:r15 ++32:acr0 ++32:acr1 ++32:acr2 ++32:acr3 ++32:acr4 ++32:acr5 ++32:acr6 ++32:acr7 ++32:acr8 ++32:acr9 ++32:acr10 ++32:acr11 ++32:acr12 ++32:acr13 ++32:acr14 ++32:acr15 ++32:fpc ++64:f0 ++64:f1 ++64:f2 ++64:f3 ++64:f4 ++64:f5 ++64:f6 ++64:f7 ++64:f8 ++64:f9 ++64:f10 ++64:f11 ++64:f12 ++64:f13 ++64:f14 ++64:f15 ++64:orig_r2 ++64:last_break ++32:system_call ++64:tdb0 ++64:tac ++64:tct ++64:atia ++64:tr0 ++64:tr1 ++64:tr2 ++64:tr3 ++64:tr4 ++64:tr5 ++64:tr6 ++64:tr7 ++64:tr8 ++64:tr9 ++64:tr10 ++64:tr11 ++64:tr12 ++64:tr13 ++64:tr14 ++64:tr15 +Index: gdb-7.6.1/gdb/s390-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-nat.c ++++ gdb-7.6.1/gdb/s390-nat.c +@@ -37,10 +37,6 @@ + #include + #include + +-#ifndef HWCAP_S390_HIGH_GPRS +-#define HWCAP_S390_HIGH_GPRS 512 +-#endif +- + #ifndef PTRACE_GETREGSET + #define PTRACE_GETREGSET 0x4204 + #endif +@@ -51,6 +47,7 @@ + + static int have_regset_last_break = 0; + static int have_regset_system_call = 0; ++static int have_regset_tdb = 0; + + /* Map registers to gregset/ptrace offsets. + These arrays are defined in s390-tdep.c. */ +@@ -72,7 +69,7 @@ s390_native_supply (struct regcache *reg + const gdb_byte *regp) + { + for (; map[0] >= 0; map += 2) +- regcache_raw_supply (regcache, map[1], regp + map[0]); ++ regcache_raw_supply (regcache, map[1], regp ? regp + map[0] : NULL); + } + + /* Collect the register REGNO out of the regset described by MAP from +@@ -315,9 +312,14 @@ fetch_regset (struct regcache *regcache, + iov.iov_len = regsize; + + if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) +- perror_with_name (_("Couldn't get register set")); +- +- s390_native_supply (regcache, regmap, buf); ++ { ++ if (errno == ENODATA) ++ s390_native_supply (regcache, regmap, NULL); ++ else ++ perror_with_name (_("Couldn't get register set")); ++ } ++ else ++ s390_native_supply (regcache, regmap, buf); + } + + /* Store all registers in the kernel's register set whose number is REGSET, +@@ -353,10 +355,10 @@ check_regset (int tid, int regset, int r + iov.iov_base = buf; + iov.iov_len = regsize; + +- if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) < 0) +- return 0; +- else ++ if (ptrace (PTRACE_GETREGSET, tid, (long) regset, (long) &iov) >= 0 ++ || errno == ENODATA) + return 1; ++ return 0; + } + + /* Fetch register REGNUM from the child process. If REGNUM is -1, do +@@ -383,6 +385,11 @@ s390_linux_fetch_inferior_registers (str + if (regnum == -1 || regnum == S390_SYSTEM_CALL_REGNUM) + fetch_regset (regcache, tid, NT_S390_SYSTEM_CALL, 4, + s390_regmap_system_call); ++ ++ if (have_regset_tdb) ++ if (regnum == -1 || S390_IS_TDBREGSET_REGNUM (regnum)) ++ fetch_regset (regcache, tid, NT_S390_TDB, s390_sizeof_tdbregset, ++ s390_regmap_tdb); + } + + /* Store register REGNUM back into the child process. If REGNUM is +@@ -625,6 +632,8 @@ s390_read_description (struct target_ops + = check_regset (tid, NT_S390_LAST_BREAK, 8); + have_regset_system_call + = check_regset (tid, NT_S390_SYSTEM_CALL, 4); ++ have_regset_tdb ++ = check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset); + + #ifdef __s390x__ + /* If GDB itself is compiled as 64-bit, we are running on a machine in +@@ -634,12 +643,14 @@ s390_read_description (struct target_ops + that mode, report s390 architecture with 64-bit GPRs. */ + + if (s390_target_wordsize () == 8) +- return (have_regset_system_call? tdesc_s390x_linux64v2 : ++ return (have_regset_tdb ? tdesc_s390x_te_linux64 : ++ have_regset_system_call? tdesc_s390x_linux64v2 : + have_regset_last_break? tdesc_s390x_linux64v1 : + tdesc_s390x_linux64); + + if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) +- return (have_regset_system_call? tdesc_s390_linux64v2 : ++ return (have_regset_tdb ? tdesc_s390_te_linux64 : ++ have_regset_system_call? tdesc_s390_linux64v2 : + have_regset_last_break? tdesc_s390_linux64v1 : + tdesc_s390_linux64); + #endif +Index: gdb-7.6.1/gdb/s390-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.c ++++ gdb-7.6.1/gdb/s390-tdep.c +@@ -44,6 +44,7 @@ + #include "prologue-value.h" + #include "linux-tdep.h" + #include "s390-tdep.h" ++#include "auxv.h" + + #include "stap-probe.h" + #include "ax.h" +@@ -51,6 +52,7 @@ + #include "user-regs.h" + #include "cli/cli-utils.h" + #include ++#include + + #include "features/s390-linux32.c" + #include "features/s390-linux32v1.c" +@@ -58,9 +60,11 @@ + #include "features/s390-linux64.c" + #include "features/s390-linux64v1.c" + #include "features/s390-linux64v2.c" ++#include "features/s390-te-linux64.c" + #include "features/s390x-linux64.c" + #include "features/s390x-linux64v1.c" + #include "features/s390x-linux64v2.c" ++#include "features/s390x-te-linux64.c" + + /* The tdep structure. */ + +@@ -568,6 +572,30 @@ const short s390_regmap_system_call[] = + -1, -1 + }; + ++const short s390_regmap_tdb[] = ++ { ++ 0x00, S390_TDB_DWORD0_REGNUM, ++ 0x08, S390_TDB_ABORT_CODE_REGNUM, ++ 0x10, S390_TDB_CONFLICT_TOKEN_REGNUM, ++ 0x18, S390_TDB_ATIA_REGNUM, ++ 0x80, S390_TDB_R0_REGNUM, ++ 0x88, S390_TDB_R1_REGNUM, ++ 0x90, S390_TDB_R2_REGNUM, ++ 0x98, S390_TDB_R3_REGNUM, ++ 0xa0, S390_TDB_R4_REGNUM, ++ 0xa8, S390_TDB_R5_REGNUM, ++ 0xb0, S390_TDB_R6_REGNUM, ++ 0xb8, S390_TDB_R7_REGNUM, ++ 0xc0, S390_TDB_R8_REGNUM, ++ 0xc8, S390_TDB_R9_REGNUM, ++ 0xd0, S390_TDB_R10_REGNUM, ++ 0xd8, S390_TDB_R11_REGNUM, ++ 0xe0, S390_TDB_R12_REGNUM, ++ 0xe8, S390_TDB_R13_REGNUM, ++ 0xf0, S390_TDB_R14_REGNUM, ++ 0xf8, S390_TDB_R15_REGNUM, ++ -1, -1 ++ }; + + + /* Supply register REGNUM from the register set REGSET to register cache +@@ -579,7 +607,25 @@ s390_supply_regset (const struct regset + const short *map; + for (map = regset->descr; map[0] >= 0; map += 2) + if (regnum == -1 || regnum == map[1]) +- regcache_raw_supply (regcache, map[1], (const char *)regs + map[0]); ++ regcache_raw_supply (regcache, map[1], ++ regs ? (const char *)regs + map[0] : NULL); ++} ++ ++/* Supply the TDB regset. Like s390_supply_regset, but invalidate the ++ TDB registers unless the TDB format field is valid. */ ++ ++static void ++s390_supply_tdb_regset (const struct regset *regset, struct regcache *regcache, ++ int regnum, const void *regs, size_t len) ++{ ++ ULONGEST tdw; ++ enum register_status ret; ++ int i; ++ ++ s390_supply_regset (regset, regcache, regnum, regs, len); ++ ret = regcache_cooked_read_unsigned (regcache, S390_TDB_DWORD0_REGNUM, &tdw); ++ if (ret != REG_VALID || (tdw >> 56) != 1) ++ s390_supply_regset (regset, regcache, regnum, NULL, len); + } + + /* Collect register REGNUM from the register cache REGCACHE and store +@@ -639,6 +685,12 @@ static const struct regset s390_system_c + s390_collect_regset + }; + ++static const struct regset s390_tdb_regset = { ++ s390_regmap_tdb, ++ s390_supply_tdb_regset, ++ s390_collect_regset ++}; ++ + static struct core_regset_section s390_linux32_regset_sections[] = + { + { ".reg", s390_sizeof_gregset, "general-purpose" }, +@@ -687,6 +739,7 @@ static struct core_regset_section s390_l + { ".reg-s390-high-gprs", 16*4, "s390 GPR upper halves" }, + { ".reg-s390-last-break", 8, "s930 last-break address" }, + { ".reg-s390-system-call", 4, "s390 system-call" }, ++ { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" }, + { NULL, 0} + }; + +@@ -711,6 +764,7 @@ static struct core_regset_section s390x_ + { ".reg2", s390_sizeof_fpregset, "floating-point" }, + { ".reg-s390-last-break", 8, "s930 last-break address" }, + { ".reg-s390-system-call", 4, "s390 system-call" }, ++ { ".reg-s390-tdb", s390_sizeof_tdbregset, "s390 TDB" }, + { NULL, 0} + }; + +@@ -739,6 +793,9 @@ s390_regset_from_core_section (struct gd + if (strcmp (sect_name, ".reg-s390-system-call") == 0 && sect_size >= 4) + return &s390_system_call_regset; + ++ if (strcmp (sect_name, ".reg-s390-tdb") == 0 && sect_size >= 256) ++ return &s390_tdb_regset; ++ + return NULL; + } + +@@ -750,6 +807,9 @@ s390_core_read_description (struct gdbar + asection *v1 = bfd_get_section_by_name (abfd, ".reg-s390-last-break"); + asection *v2 = bfd_get_section_by_name (abfd, ".reg-s390-system-call"); + asection *section = bfd_get_section_by_name (abfd, ".reg"); ++ CORE_ADDR hwcap = 0; ++ ++ target_auxv_search (target, AT_HWCAP, &hwcap); + if (!section) + return NULL; + +@@ -757,14 +817,16 @@ s390_core_read_description (struct gdbar + { + case s390_sizeof_gregset: + if (high_gprs) +- return (v2? tdesc_s390_linux64v2 : ++ return ((hwcap & HWCAP_S390_TE) ? tdesc_s390_te_linux64 : ++ v2? tdesc_s390_linux64v2 : + v1? tdesc_s390_linux64v1 : tdesc_s390_linux64); + else + return (v2? tdesc_s390_linux32v2 : + v1? tdesc_s390_linux32v1 : tdesc_s390_linux32); + + case s390x_sizeof_gregset: +- return (v2? tdesc_s390x_linux64v2 : ++ return ((hwcap & HWCAP_S390_TE) ? tdesc_s390x_te_linux64 : ++ v2? tdesc_s390x_linux64v2 : + v1? tdesc_s390x_linux64v1 : tdesc_s390x_linux64); + + default: +@@ -3011,6 +3073,11 @@ s390_gdbarch_init (struct gdbarch_info i + "r0h", "r1h", "r2h", "r3h", "r4h", "r5h", "r6h", "r7h", + "r8h", "r9h", "r10h", "r11h", "r12h", "r13h", "r14h", "r15h" + }; ++ static const char *const tdb_regs[] = { ++ "tdb0", "tac", "tct", "atia", ++ "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7", ++ "tr8", "tr9", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15" ++ }; + const struct tdesc_feature *feature; + int i, valid_p = 1; + +@@ -3088,6 +3155,16 @@ s390_gdbarch_init (struct gdbarch_info i + valid_p = 0; + } + ++ /* Transaction diagnostic block. */ ++ feature = tdesc_find_feature (tdesc, "org.gnu.gdb.s390.tdb"); ++ if (feature) ++ { ++ for (i = 0; i < ARRAY_SIZE (tdb_regs); i++) ++ valid_p &= tdesc_numbered_register (feature, tdesc_data, ++ S390_TDB_DWORD0_REGNUM + i, ++ tdb_regs[i]); ++ } ++ + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); +@@ -3304,7 +3381,9 @@ _initialize_s390_tdep (void) + initialize_tdesc_s390_linux64 (); + initialize_tdesc_s390_linux64v1 (); + initialize_tdesc_s390_linux64v2 (); ++ initialize_tdesc_s390_te_linux64 (); + initialize_tdesc_s390x_linux64 (); + initialize_tdesc_s390x_linux64v1 (); + initialize_tdesc_s390x_linux64v2 (); ++ initialize_tdesc_s390x_te_linux64 (); + } +Index: gdb-7.6.1/gdb/s390-tdep.h +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.h ++++ gdb-7.6.1/gdb/s390-tdep.h +@@ -19,6 +19,16 @@ + #ifndef S390_TDEP_H + #define S390_TDEP_H + ++/* Hardware capabilities. */ ++ ++#ifndef HWCAP_S390_HIGH_GPRS ++#define HWCAP_S390_HIGH_GPRS 512 ++#endif ++ ++#ifndef HWCAP_S390_TE ++#define HWCAP_S390_TE 1024 ++#endif ++ + /* Register information. */ + + /* Program Status Word. */ +@@ -98,8 +108,29 @@ + #define S390_ORIG_R2_REGNUM 67 + #define S390_LAST_BREAK_REGNUM 68 + #define S390_SYSTEM_CALL_REGNUM 69 ++/* Transaction diagnostic block. */ ++#define S390_TDB_DWORD0_REGNUM 70 ++#define S390_TDB_ABORT_CODE_REGNUM 71 ++#define S390_TDB_CONFLICT_TOKEN_REGNUM 72 ++#define S390_TDB_ATIA_REGNUM 73 ++#define S390_TDB_R0_REGNUM 74 ++#define S390_TDB_R1_REGNUM 75 ++#define S390_TDB_R2_REGNUM 76 ++#define S390_TDB_R3_REGNUM 77 ++#define S390_TDB_R4_REGNUM 78 ++#define S390_TDB_R5_REGNUM 79 ++#define S390_TDB_R6_REGNUM 80 ++#define S390_TDB_R7_REGNUM 81 ++#define S390_TDB_R8_REGNUM 82 ++#define S390_TDB_R9_REGNUM 83 ++#define S390_TDB_R10_REGNUM 84 ++#define S390_TDB_R11_REGNUM 85 ++#define S390_TDB_R12_REGNUM 86 ++#define S390_TDB_R13_REGNUM 87 ++#define S390_TDB_R14_REGNUM 88 ++#define S390_TDB_R15_REGNUM 89 + /* Total. */ +-#define S390_NUM_REGS 70 ++#define S390_NUM_REGS 90 + + /* Special register usage. */ + #define S390_SP_REGNUM S390_R15_REGNUM +@@ -114,6 +145,9 @@ + #define S390_IS_FPREGSET_REGNUM(i) \ + ((i) >= S390_FPC_REGNUM && (i) <= S390_F15_REGNUM) + ++#define S390_IS_TDBREGSET_REGNUM(i) \ ++ ((i) >= S390_TDB_DWORD0_REGNUM && (i) <= S390_TDB_R15_REGNUM) ++ + /* Core file register sets, defined in s390-tdep.c. */ + #define s390_sizeof_gregset 0x90 + extern const short s390_regmap_gregset[]; +@@ -124,6 +158,8 @@ extern const short s390_regmap_fpregset[ + extern const short s390_regmap_last_break[]; + extern const short s390x_regmap_last_break[]; + extern const short s390_regmap_system_call[]; ++extern const short s390_regmap_tdb[]; ++#define s390_sizeof_tdbregset 0x100 + + /* GNU/Linux target descriptions. */ + extern struct target_desc *tdesc_s390_linux32; +@@ -132,9 +168,11 @@ extern struct target_desc *tdesc_s390_li + extern struct target_desc *tdesc_s390_linux64; + extern struct target_desc *tdesc_s390_linux64v1; + extern struct target_desc *tdesc_s390_linux64v2; ++extern struct target_desc *tdesc_s390_te_linux64; + extern struct target_desc *tdesc_s390x_linux64; + extern struct target_desc *tdesc_s390x_linux64v1; + extern struct target_desc *tdesc_s390x_linux64v2; ++extern struct target_desc *tdesc_s390x_te_linux64; + + #endif + +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/s390-tdbregs.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/s390-tdbregs.c +@@ -0,0 +1,64 @@ ++/* Copyright 2008-2013 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ 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 3 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, see . */ ++ ++#include ++ ++static void ++my_tbegin () ++{ ++ __asm__ volatile ++ ( "1: .byte 0xe5,0x60,0x00,0x00,0xff,0x00\n" ++ " jnz 1b" ++ : /* no return value */ ++ : /* no inputs */ ++ : "cc", "memory" ); ++} ++ ++static void ++my_tend () ++{ ++ __asm__ volatile ++ ( " .byte 0xb2,0xf8,0x00,0x00" ++ : /* no return value */ ++ : /* no inputs */ ++ : "cc", "memory" ); ++} ++ ++void ++try_transaction (void) ++{ ++ my_tbegin (); ++ my_tend (); ++} ++ ++void ++crash_in_transaction (void) ++{ ++ volatile char *p = 0; ++ ++ my_tbegin (); ++ *p = 5; /* FAULT */ ++ my_tend (); ++} ++ ++int ++main (int argc, char *argv[]) ++{ ++ try_transaction (); ++ crash_in_transaction (); ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/s390-tdbregs.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/s390-tdbregs.exp +@@ -0,0 +1,75 @@ ++# Copyright 2004-2013 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 3 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, see . ++ ++# Please email any bugs, comments, and/or additions to this file to: ++# bug-gdb@gnu.org ++ ++# This file is part of the gdb testsuite. ++ ++ ++if { ![istarget s390-*-*] && ![istarget s390x-*-* ] } { ++ verbose "Skipping s390 TDB register tests." ++ return ++} ++ ++set testfile "s390-tdbregs" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [get_compiler_info] } { ++ return -1 ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ ++ executable [list debug]] != "" } { ++ fail "compile failed" ++ return ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if { ![runto_main] } then { ++ gdb_suppress_tests ++} ++ ++gdb_test_multiple "next" "check for TE support" { ++ -re "Program received signal SIGILL,.*\r\n$gdb_prompt $" { ++ unsupported "No TE support." ++ return ++ } ++ -re "\[0-9\]+.*\r\n$gdb_prompt $" { ++ pass "TE support available" ++ } ++ -re "$gdb_prompt $" { ++ unsupported "No TE support (unknown error)." ++ return ++ } ++} ++ ++set crashline [gdb_get_line_number "FAULT"] ++ ++gdb_test "print \$tdb0" "\\\$\[0-9\]+ = " "tdb0 unavailable" ++gdb_test "print \$tr0" "\\\$\[0-9\]+ = " "tr0 unavailable" ++gdb_test "next" \ ++ "Program received signal SIGSEGV, .*" \ ++ "crash in transaction" ++gdb_test "print/x \$tdb0" "\\\$\[0-9\]+ = 0x1.*" "tdb0 available" ++gdb_test "set print symbol-filename" "" "set print symbol-filename" ++gdb_test "print/a \$atia" \ ++ "" \ ++ "ATIA points to crash" diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-4of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-4of9.patch new file mode 100644 index 0000000..4b19bb2 --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-4of9.patch @@ -0,0 +1,148 @@ +From 6682d9595ed8d9b9bba5470bfd7fd1ccd378f19a Mon Sep 17 00:00:00 2001 +From: Andreas Arnez +Date: Tue, 5 Nov 2013 18:43:50 +0100 +Subject: [PATCH] S390: Fix TDB regset recognition + +When checking for the presence of the TDB regset, the current code +interprets ENODATA from PTRACE_GETREGSET as an indication that the TDB +regset *could* occur on this system, but the inferior stopped outside +a transaction. However, the Linux kernel actually reports ENODATA +even on systems without the transactional execution facility. Thus +the logic is now changed to check the TE field in the HWCAP as well. + +This version also checks the existence of the TDB regset -- just to be +on the safe side when running on TE-enabled hardware with a kernel +that does not offer the TDB regset for some reason. + +gdb/ + * s390-linux-nat.c (s390_read_description): Consider the TE field + in the HWCAP for determining 'have_regset_tdb'. + +gdbserver/ + * linux-s390-low.c (HWCAP_S390_TE): New define. + (s390_arch_setup): Consider the TE field in the HWCAP for + determining 'have_regset_tdb'. +--- + gdb/ChangeLog | 5 +++++ + gdb/gdbserver/ChangeLog | 6 ++++++ + gdb/gdbserver/linux-s390-low.c | 48 ++++++++++++++++++++++++++---------------- + gdb/s390-linux-nat.c | 5 +++-- + 4 files changed, 44 insertions(+), 20 deletions(-) + +Index: gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-s390-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +@@ -32,6 +32,10 @@ + #define HWCAP_S390_HIGH_GPRS 512 + #endif + ++#ifndef HWCAP_S390_TE ++#define HWCAP_S390_TE 1024 ++#endif ++ + #ifndef PTRACE_GETREGSET + #define PTRACE_GETREGSET 0x4204 + #endif +@@ -390,23 +394,6 @@ s390_arch_setup (void) + = s390_check_regset (pid, NT_S390_SYSTEM_CALL, 4); + int have_regset_tdb = s390_check_regset (pid, NT_S390_TDB, 256); + +- /* Update target_regsets according to available register sets. */ +- for (regset = target_regsets; regset->fill_function != NULL; regset++) +- if (regset->get_request == PTRACE_GETREGSET) +- switch (regset->nt_type) +- { +- case NT_S390_LAST_BREAK: +- regset->size = have_regset_last_break? 8 : 0; +- break; +- case NT_S390_SYSTEM_CALL: +- regset->size = have_regset_system_call? 4 : 0; +- break; +- case NT_S390_TDB: +- regset->size = have_regset_tdb ? 256 : 0; +- default: +- break; +- } +- + /* Assume 31-bit inferior process. */ + if (have_regset_system_call) + init_registers_s390_linux32v2 (); +@@ -424,6 +411,7 @@ s390_arch_setup (void) + { + unsigned int pswm; + struct regcache *regcache = new_register_cache (); ++ + fetch_inferior_registers (regcache, find_regno ("pswm")); + collect_register_by_name (regcache, "pswm", &pswm); + free_register_cache (regcache); +@@ -431,8 +419,12 @@ s390_arch_setup (void) + if (pswm & 1) + { + if (have_regset_tdb) ++ have_regset_tdb = ++ (s390_get_hwcap () & HWCAP_S390_TE) != 0; ++ ++ if (have_regset_tdb) + init_registers_s390x_te_linux64 (); +- if (have_regset_system_call) ++ else if (have_regset_system_call) + init_registers_s390x_linux64v2 (); + else if (have_regset_last_break) + init_registers_s390x_linux64v1 (); +@@ -445,6 +437,9 @@ s390_arch_setup (void) + else if (s390_get_hwcap () & HWCAP_S390_HIGH_GPRS) + { + if (have_regset_tdb) ++ have_regset_tdb = (s390_get_hwcap () & HWCAP_S390_TE) != 0; ++ ++ if (have_regset_tdb) + init_registers_s390_te_linux64 (); + if (have_regset_system_call) + init_registers_s390_linux64v2 (); +@@ -458,6 +453,22 @@ s390_arch_setup (void) + } + } + #endif ++ /* Update target_regsets according to available register sets. */ ++ for (regset = target_regsets; regset->fill_function != NULL; regset++) ++ if (regset->get_request == PTRACE_GETREGSET) ++ switch (regset->nt_type) ++ { ++ case NT_S390_LAST_BREAK: ++ regset->size = have_regset_last_break? 8 : 0; ++ break; ++ case NT_S390_SYSTEM_CALL: ++ regset->size = have_regset_system_call? 4 : 0; ++ break; ++ case NT_S390_TDB: ++ regset->size = have_regset_tdb ? 256 : 0; ++ default: ++ break; ++ } + } + + +Index: gdb-7.6.1/gdb/s390-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-nat.c ++++ gdb-7.6.1/gdb/s390-nat.c +@@ -632,8 +632,6 @@ s390_read_description (struct target_ops + = check_regset (tid, NT_S390_LAST_BREAK, 8); + have_regset_system_call + = check_regset (tid, NT_S390_SYSTEM_CALL, 4); +- have_regset_tdb +- = check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset); + + #ifdef __s390x__ + /* If GDB itself is compiled as 64-bit, we are running on a machine in +@@ -642,6 +640,9 @@ s390_read_description (struct target_ops + addressing mode, but the kernel supports using 64-bit registers in + that mode, report s390 architecture with 64-bit GPRs. */ + ++ have_regset_tdb = (s390_get_hwcap () & HWCAP_S390_TE) ? ++ check_regset (tid, NT_S390_TDB, s390_sizeof_tdbregset) : 0; ++ + if (s390_target_wordsize () == 8) + return (have_regset_tdb ? tdesc_s390x_te_linux64 : + have_regset_system_call? tdesc_s390x_linux64v2 : diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-5of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-5of9.patch new file mode 100644 index 0000000..11abcbb --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-5of9.patch @@ -0,0 +1,68 @@ +From 098dbe61246fd65ea5e3825d77afb31d52c43153 Mon Sep 17 00:00:00 2001 +From: Andreas Arnez +Date: Fri, 12 Dec 2014 14:14:20 +0100 +Subject: [PATCH 7/9] gdbserver: Prevent stale/random values in register cache + +When fetch_inferior_registers does not update all registers, this +patch assures that no stale register values remain in the register +cache. On Linux platforms using the regsets interface, when one of +the ptrace calls used for fetching the register values returns an +error, this patch also avoids copying the random data returned from +ptrace into the register cache. All unfetched registers are marked +"unavailable" instead. + +gdb/gdbserver/ChangeLog: + + * linux-low.c (regsets_fetch_inferior_registers): Do not invoke + the regset's store function when ptrace returned an error. + * regcache.c (get_thread_regcache): Invalidate register cache + before fetching inferior's registers. +--- + gdb/gdbserver/ChangeLog | 7 +++++++ + gdb/gdbserver/linux-low.c | 11 ++++++----- + gdb/gdbserver/regcache.c | 3 +++ + 3 files changed, 16 insertions(+), 5 deletions(-) + +Index: gdb-7.6.1/gdb/gdbserver/linux-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-low.c +@@ -4080,8 +4080,6 @@ regsets_fetch_inferior_registers (struct + /* If we get EIO on a regset, do not try it again for + this process. */ + disabled_regsets[regset - target_regsets] = 1; +- free (buf); +- continue; + } + else + { +@@ -4091,9 +4089,12 @@ regsets_fetch_inferior_registers (struct + perror (s); + } + } +- else if (regset->type == GENERAL_REGS) +- saw_general_regs = 1; +- regset->store_function (regcache, buf); ++ else ++ { ++ if (regset->type == GENERAL_REGS) ++ saw_general_regs = 1; ++ regset->store_function (regcache, buf); ++ } + regset ++; + free (buf); + } +Index: gdb-7.6.1/gdb/gdbserver/regcache.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/regcache.c ++++ gdb-7.6.1/gdb/gdbserver/regcache.c +@@ -47,6 +47,9 @@ get_thread_regcache (struct thread_info + struct thread_info *saved_inferior = current_inferior; + + current_inferior = thread; ++ /* Invalidate all registers, to prevent stale left-overs. */ ++ memset (regcache->register_status, REG_UNAVAILABLE, ++ num_registers); + fetch_inferior_registers (regcache, -1); + current_inferior = saved_inferior; + regcache->registers_valid = 1; diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-6of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-6of9.patch new file mode 100644 index 0000000..397d40e --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-6of9.patch @@ -0,0 +1,80 @@ +From feea5f36a9dd65a0ff279c71744423c419b77ada Mon Sep 17 00:00:00 2001 +From: Andreas Arnez +Date: Fri, 12 Dec 2014 14:14:21 +0100 +Subject: [PATCH 8/9] gdbserver: Support read-only regsets in linux-low.c + +For GNU/Linux targets using the regsets interface, this change +supports regsets that can be read but not written. The S390 "last +break" regset is an example. So far it had been defined with +regset->set_request == PTRACE_GETREGSET, such that the respective +ptrace call does not cause any harm. Now we just skip the whole +read/modify/write sequence for regsets that do not define a +fill_function. + +gdb/gdbserver/ChangeLog: + + * linux-low.c (regsets_store_inferior_registers): Skip regsets + without a fill_function. + * linux-s390-low.c (s390_fill_last_break): Remove. + (s390_regsets): Set fill_function to NULL for NT_S390_LAST_BREAK. + (s390_arch_setup): Use regset's size instead of fill_function for + loop end condition. +--- + gdb/gdbserver/ChangeLog | 9 +++++++++ + gdb/gdbserver/linux-low.c | 3 ++- + gdb/gdbserver/linux-s390-low.c | 14 ++++---------- + 3 files changed, 15 insertions(+), 11 deletions(-) + +Index: gdb-7.6.1/gdb/gdbserver/linux-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-low.c +@@ -4120,7 +4120,8 @@ regsets_store_inferior_registers (struct + void *buf, *data; + int nt_type, res; + +- if (regset->size == 0 || disabled_regsets[regset - target_regsets]) ++ if (regset->size == 0 || disabled_regsets[regset - target_regsets] ++ || regset->fill_function == NULL) + { + regset ++; + continue; +Index: gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-s390-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +@@ -264,12 +264,6 @@ static void s390_fill_gregset (struct re + /* Fill and store functions for extended register sets. */ + + static void +-s390_fill_last_break (struct regcache *regcache, void *buf) +-{ +- /* Last break address is read-only. */ +-} +- +-static void + s390_store_last_break (struct regcache *regcache, const void *buf) + { + supply_register_by_name (regcache, "last_break", +@@ -290,9 +284,9 @@ s390_store_system_call (struct regcache + + struct regset_info target_regsets[] = { + { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL }, +- /* Last break address is read-only; do not attempt PTRACE_SETREGSET. */ +- { PTRACE_GETREGSET, PTRACE_GETREGSET, NT_S390_LAST_BREAK, 0, +- EXTENDED_REGS, s390_fill_last_break, s390_store_last_break }, ++ /* Last break address is read-only; no fill function. */ ++ { PTRACE_GETREGSET, -1, NT_S390_LAST_BREAK, 0, EXTENDED_REGS, ++ NULL, s390_store_last_break }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0, + EXTENDED_REGS, s390_fill_system_call, s390_store_system_call }, + { 0, 0, 0, -1, -1, NULL, NULL } +@@ -454,7 +448,7 @@ s390_arch_setup (void) + } + #endif + /* Update target_regsets according to available register sets. */ +- for (regset = target_regsets; regset->fill_function != NULL; regset++) ++ for (regset = target_regsets; regset->size >= 0; regset++) + if (regset->get_request == PTRACE_GETREGSET) + switch (regset->nt_type) + { diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-7of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-7of9.patch new file mode 100644 index 0000000..fac2db6 --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-7of9.patch @@ -0,0 +1,76 @@ +From e5a9158d093d53f2bb1057359ac381dcdf6d4305 Mon Sep 17 00:00:00 2001 +From: Andreas Arnez +Date: Fri, 12 Dec 2014 14:14:21 +0100 +Subject: [PATCH 9/9] S390: Fix gdbserver support for TDB + +This makes gdbserver actually provide values for the TDB registers +when the inferior was stopped in a transaction. The change in +linux-low.c is needed to suppress the warning for an unavailable TDB. + +The test case 's390-tdbregs.exp' passes with this patch and fails +without. + +gdb/gdbserver/ChangeLog: + + * linux-low.c (regsets_fetch_inferior_registers): Suppress the + warning upon ENODATA from ptrace. + * linux-s390-low.c (s390_store_tdb): New. + (s390_regsets): Add regset for NT_S390_TDB. +--- + gdb/gdbserver/ChangeLog | 7 +++++++ + gdb/gdbserver/linux-low.c | 6 ++++++ + gdb/gdbserver/linux-s390-low.c | 17 +++++++++++++++++ + 3 files changed, 30 insertions(+) + +Index: gdb-7.6.1/gdb/gdbserver/linux-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-low.c +@@ -4183,6 +4183,12 @@ regsets_store_inferior_registers (struct + free (buf); + return 0; + } ++ else if (errno == ENODATA) ++ { ++ /* ENODATA may be returned if the regset is currently ++ not "active". This can happen in normal operation, ++ so suppress the warning in this case. */ ++ } + else + { + perror ("Warning: ptrace(regsets_store_inferior_registers)"); +Index: gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbserver/linux-s390-low.c ++++ gdb-7.6.1/gdb/gdbserver/linux-s390-low.c +@@ -282,6 +282,20 @@ s390_store_system_call (struct regcache + supply_register_by_name (regcache, "system_call", buf); + } + ++static void ++s390_store_tdb (struct regcache *regcache, const void *buf) ++{ ++ int tdb0 = find_regno ("tdb0"); ++ int tr0 = find_regno ("tr0"); ++ int i; ++ ++ for (i = 0; i < 4; i++) ++ supply_register (regcache, tdb0 + i, (const char *) buf + 8 * i); ++ ++ for (i = 0; i < 16; i++) ++ supply_register (regcache, tr0 + i, (const char *) buf + 8 * (16 + i)); ++} ++ + struct regset_info target_regsets[] = { + { 0, 0, 0, 0, GENERAL_REGS, s390_fill_gregset, NULL }, + /* Last break address is read-only; no fill function. */ +@@ -289,6 +303,9 @@ struct regset_info target_regsets[] = { + NULL, s390_store_last_break }, + { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_S390_SYSTEM_CALL, 0, + EXTENDED_REGS, s390_fill_system_call, s390_store_system_call }, ++ /* TDB is read-only. */ ++ { PTRACE_GETREGSET, -1, NT_S390_TDB, 0, EXTENDED_REGS, ++ NULL, s390_store_tdb }, + { 0, 0, 0, -1, -1, NULL, NULL } + }; + diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-8of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-8of9.patch new file mode 100644 index 0000000..9288bcf --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-8of9.patch @@ -0,0 +1,44 @@ +From d5552aabd6c68147421819577108b51ff25ea064 Mon Sep 17 00:00:00 2001 +From: Andreas Arnez +Date: Tue, 2 Dec 2014 10:47:30 +0100 +Subject: [PATCH] S390: Fix 'expedite' for s390-te-linux64 + +Fix a typo in the expedited registers for s390-te-linux64. + +gdb/ChangeLog: + + * features/Makefile (s390-te-linux64-expedite): Replace + non-existant r14 and r15 by r14l and r15l, respectively. + * regformats/s390-te-linux64.dat: Regenerate. +--- + gdb/ChangeLog | 6 ++++++ + gdb/features/Makefile | 2 +- + gdb/regformats/s390-te-linux64.dat | 2 +- + 3 files changed, 8 insertions(+), 2 deletions(-) + +Index: gdb-7.6.1/gdb/features/Makefile +=================================================================== +--- gdb-7.6.1.orig/gdb/features/Makefile ++++ gdb-7.6.1/gdb/features/Makefile +@@ -83,7 +83,7 @@ s390-linux32v2-expedite = r14,r15,pswa + s390-linux64-expedite = r14l,r15l,pswa + s390-linux64v1-expedite = r14l,r15l,pswa + s390-linux64v2-expedite = r14l,r15l,pswa +-s390-te-linux64-expedite = r14,r15,pswa ++s390-te-linux64-expedite = r14l,r15l,pswa + s390x-linux64-expedite = r14,r15,pswa + s390x-linux64v1-expedite = r14,r15,pswa + s390x-linux64v2-expedite = r14,r15,pswa +Index: gdb-7.6.1/gdb/regformats/s390-te-linux64.dat +=================================================================== +--- gdb-7.6.1.orig/gdb/regformats/s390-te-linux64.dat ++++ gdb-7.6.1/gdb/regformats/s390-te-linux64.dat +@@ -1,7 +1,7 @@ + # DO NOT EDIT: generated from s390-te-linux64.xml + name:s390_te_linux64 + xmltarget:s390-te-linux64.xml +-expedite:r14,r15,pswa ++expedite:r14l,r15l,pswa + 32:pswm + 32:pswa + 32:r0h diff --git a/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-9of9.patch b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-9of9.patch new file mode 100644 index 0000000..2dfd2c5 --- /dev/null +++ b/SOURCES/gdb-rhbz1105165-ibm-tdb-support-system-z-9of9.patch @@ -0,0 +1,69 @@ +commit 2492f0d005f0390eabb3deb58aa7db7fcd716763 +Author: Andreas Arnez +Date: Fri May 8 12:50:47 2015 +0200 + + S390: Fix for inadvertently setting 24-bit mode in fill_gregset + + On 64-bit S390 platforms, for programs compiled with -m31, it could + happen that GDB inadvertently cleared the inferior's 31-bit addressing + mode bit and left the inferior running in 24-bit addressing mode. In + particular this occurred with checkpoint.exp, when the "restore" + command needed to create a new regcache copy: At the time when the + PSWM register was copied over, the addressing mode bit was taken from + the PSWA register, which was still zero since it had not been copied + yet. And when the PSWA register was copied, the addressing mode was + not updated again. + + The fix affects fill_gregset, where the bits "belonging" to each of + the PSWA and PSWM registers are now carefully separated. The + addressing mode bit is no longer touched when writing PSWM, and -- + more importantly -- it *is* written when writing PSWA. + + gdb/ChangeLog: + + * s390-linux-nat.c (fill_gregset): Avoid relying on the PSWA + register in the regcache when treating the PSWM register, and vice + versa. + +Index: gdb-7.6.1/gdb/s390-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-nat.c ++++ gdb-7.6.1/gdb/s390-nat.c +@@ -174,19 +174,28 @@ fill_gregset (const struct regcache *reg + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + ULONGEST pswa, pswm; + gdb_byte buf[4]; ++ gdb_byte *pswm_p = (gdb_byte *) regp + 0; ++ gdb_byte *pswa_p = (gdb_byte *) regp + 8; + +- regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf); +- pswm = extract_unsigned_integer (buf, 4, byte_order); +- regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf); +- pswa = extract_unsigned_integer (buf, 4, byte_order); ++ pswm = extract_unsigned_integer (pswm_p, 8, byte_order); + + if (regno == -1 || regno == S390_PSWM_REGNUM) +- store_unsigned_integer (psw_p[0], 8, byte_order, +- ((pswm & 0xfff7ffff) << 32) | +- (pswa & 0x80000000)); ++ { ++ pswm &= 0x80000000; ++ regcache_raw_collect (regcache, S390_PSWM_REGNUM, buf); ++ pswm |= (extract_unsigned_integer (buf, 4, byte_order) ++ & 0xfff7ffff) << 32; ++ } + if (regno == -1 || regno == S390_PSWA_REGNUM) +- store_unsigned_integer (psw_p[1], 8, byte_order, +- pswa & 0x7fffffff); ++ { ++ regcache_raw_collect (regcache, S390_PSWA_REGNUM, buf); ++ pswa = extract_unsigned_integer (buf, 4, byte_order); ++ pswm ^= (pswm ^ pswa) & 0x80000000; ++ pswa &= 0x7fffffff; ++ store_unsigned_integer (pswa_p, 8, byte_order, pswa); ++ } ++ ++ store_unsigned_integer (pswm_p, 8, byte_order, pswm); + } + return; + } diff --git a/SOURCES/gdb-rhbz1149207-catch-syscall-after-fork.patch b/SOURCES/gdb-rhbz1149207-catch-syscall-after-fork.patch new file mode 100644 index 0000000..8345b18 --- /dev/null +++ b/SOURCES/gdb-rhbz1149207-catch-syscall-after-fork.patch @@ -0,0 +1,136 @@ + NOTE: This patch has been forwardported from RHEL-6.7. + +URL: +Message-ID: <1368136582.30058.7.camel@soleil> + + From: Philippe Waroquiers + To: gdb-patches at sourceware dot org + Subject: RFA: fix gdb_assert caused by 'catch signal ...' and fork + Date: Thu, 09 May 2013 23:56:22 +0200 + + The attached patch fixes a gdb_assert caused by the combination of catch + signal and fork: + break-catch-sig.c:152: internal-error: signal_catchpoint_remove_location: Assertion `signal_catch_counts[iter] > 0' failed. + + The problem is that the signal_catch_counts is decremented by detach_breakpoints. + The fix consists in not detaching breakpoint locations of type bp_loc_other. + The patch introduces a new test. + +Comments by Sergio Durigan Junior: + + I addded a specific testcase for this patch, which tests exactly the + issue that the customer is facing. This patch does not solve the + whole problem of catching a syscall and forking (for more details, + see , + specifically comment #3), but it solves the issue reported by the + customer. + + I also removed the original testcase of this patch, because it + relied on "catch signal", which is a command that is not implemented + in this version of GDB. + +commit bd9673a4ded96ea5c108601501c8e59003ea1be6 +Author: Philippe Waroquiers +Date: Tue May 21 18:47:05 2013 +0000 + + Fix internal error caused by interaction between catch signal and fork + +Index: gdb-7.6.1/gdb/breakpoint.c +=================================================================== +--- gdb-7.6.1.orig/gdb/breakpoint.c ++++ gdb-7.6.1/gdb/breakpoint.c +@@ -3542,6 +3542,15 @@ detach_breakpoints (ptid_t ptid) + if (bl->pspace != inf->pspace) + continue; + ++ /* This function must physically remove breakpoints locations ++ from the specified ptid, without modifying the breakpoint ++ package's state. Locations of type bp_loc_other are only ++ maintained at GDB side. So, there is no need to remove ++ these bp_loc_other locations. Moreover, removing these ++ would modify the breakpoint package's state. */ ++ if (bl->loc_type == bp_loc_other) ++ continue; ++ + if (bl->inserted) + val |= remove_breakpoint_1 (bl, mark_inserted); + } +Index: gdb-7.6.1/gdb/testsuite/gdb.base/gdb-rhbz1149207-catch-syscall-fork.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/gdb-rhbz1149207-catch-syscall-fork.c +@@ -0,0 +1,11 @@ ++#include ++#include ++ ++int ++main (int argc, char **argv) ++{ ++ if (fork () == 0) ++ sleep (1); ++ chdir ("."); ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.base/gdb-rhbz1149207-catch-syscall-fork.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.base/gdb-rhbz1149207-catch-syscall-fork.exp +@@ -0,0 +1,58 @@ ++# Copyright 2015 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 3 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, see . ++ ++if { [is_remote target] || ![isnative] } then { ++ continue ++} ++ ++set testfile "gdb-rhbz1149207-catch-syscall-fork" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++# Until "catch syscall" is implemented on other targets... ++if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then { ++ continue ++} ++ ++# This shall be updated whenever 'catch syscall' is implemented ++# on some architecture. ++#if { ![istarget "i\[34567\]86-*-linux*"] ++if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"] ++ && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"] ++ && ![istarget "sparc-*-linux*"] && ![istarget "sparc64-*-linux*"] } { ++ continue ++} ++ ++if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested ${testfile}.exp ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load $binfile ++ ++if { ![runto_main] } { ++ return -1 ++} ++ ++gdb_test "catch syscall chdir" \ ++ "Catchpoint $decimal \\\(syscall (.)?chdir(.)? \\\[$decimal\\\]\\\)" \ ++ "catch syscall chdir" ++ ++gdb_test "continue" \ ++ "Continuing\.\r\n.*\r\nCatchpoint $decimal \\\(call to syscall .?chdir.?.*" \ ++ "continue from catch syscall after fork" diff --git a/SOURCES/gdb-rhbz1184724-gdb-internal-error-num-lwps.patch b/SOURCES/gdb-rhbz1184724-gdb-internal-error-num-lwps.patch new file mode 100644 index 0000000..8526288 --- /dev/null +++ b/SOURCES/gdb-rhbz1184724-gdb-internal-error-num-lwps.patch @@ -0,0 +1,568 @@ +From 6681535d2cecea1f67255c140f11b217518a2f4e Mon Sep 17 00:00:00 2001 +From: Pedro Alves +Date: Wed, 17 Jun 2015 20:41:05 +0100 +Subject: [PATCH] Fix BZ1184724 - gdb output a internal-error: Assertion + `num_lwps (GET_PID (inferior_ptid)) == 1' + +The real issue with this bug is in the ptrace error: + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + (gdb) c + Continuing. + netcfStateCleanup () at interface/interface_backend_netcf.c:116 + 116 } + ptrace: No such process. + ^^^^^^^^^^^^^^^^^^^^^^^^ + (gdb) quit + Inferior 1 [process 11205] will be detached. + Quit anyway? (y or n) y + [Thread 0x7fefdf322880 (LWP 11205) exited] + + ../../gdb/linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The assertion is just a consequence. + +So the main fix is to backport the GDB [1] bits of upstream 23f238d3 +(Fix race exposed by gdb.threads/killed.exp). That makes +linux_resume_one_lwp detect when the LWP being resumed disappears. +However, we need to backport also part of 8a99810d (linux-nat.c: clean +up pending status checking and resuming LWPs), which is what +introduced the centralized linux_resume_one_lwp in the first place, +and also one bit from 8817a6f2 (PR gdb/15713 - errors from +i386_linux_resume lead to lock-up), which makes linux_nat_resume not +clear the leader LWP's lwp->stopped flag too early, otherwise we'd hit +the new assertion in check_ptrace_stopped_lwp_gone. + +The test is new (not a backport), and without the fix triggers the +"detach" assertion shown above. + +[1] - The equivalent GDBserver bits are harder to backport, as they +rely on GDB exceptions, which GDBserver 7.6.1 doesn't support yet. +Fortunately, GDBserver already handles ESRCH from within its +linux_resume_one_lwp, so doesn't trigger this particular bug and +passes the test. + +gdb/ChangeLog: +2015-06-17 Pedro Alves + + * common/linux-procfs.c (linux_proc_pid_is_trace_stopped): New + function. + * common/linux-procfs.h (linux_proc_pid_is_trace_stopped): New + declaration. + * linux-nat.c (linux_resume_one_lwp_throw, check_ptrace_stopped_lwp_gone) + (linux_resume_one_lwp): New functions. + (resume_lwp): Use linux_resume_one_lwp. + (linux_nat_resume_callback): Skip if LWP is the same as the passed + in data pointer. + (linux_nat_resume): Don't clear the selected LWP's stopped flag + before resuming the sibling LWPs. Instead pass LWP to + linux_nat_resume_callback. Use linux_resume_one_lwp. + (linux_handle_extended_wait, linux_nat_filter_event) + (linux_nat_wait_1): Use linux_resume_one_lwp. + (resume_stopped_resumed_lwps): Try register reads in TRY/CATCH and + swallows errors if the LWP is gone. Use + linux_resume_one_lwp_throw instead of linux_resume_one_lwp. + +gdb/testsuite/ChangeLog: +2015-06-17 Pedro Alves + + * gdb.threads/thread-kills-process.c: New file. + * gdb.threads/thread-kills-process.exp: New file. +--- + gdb/ChangeLog | 13 ++ + gdb/common/linux-procfs.c | 6 + + gdb/common/linux-procfs.h | 2 + + gdb/linux-nat.c | 200 +++++++++++++-------- + gdb/testsuite/gdb.threads/thread-kills-process.c | 62 +++++++ + gdb/testsuite/gdb.threads/thread-kills-process.exp | 70 ++++++++ + 6 files changed, 277 insertions(+), 76 deletions(-) + create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.c + create mode 100644 gdb/testsuite/gdb.threads/thread-kills-process.exp + +Index: gdb-7.6.1/gdb/common/linux-procfs.c +=================================================================== +--- gdb-7.6.1.orig/gdb/common/linux-procfs.c ++++ gdb-7.6.1/gdb/common/linux-procfs.c +@@ -111,6 +111,12 @@ linux_proc_pid_is_stopped (pid_t pid) + return linux_proc_pid_has_state (pid, "T (stopped)"); + } + ++int ++linux_proc_pid_is_trace_stopped (pid_t pid) ++{ ++ return linux_proc_pid_has_state (pid, "T (tracing stop)"); ++} ++ + /* See linux-procfs.h declaration. */ + + int +Index: gdb-7.6.1/gdb/common/linux-procfs.h +=================================================================== +--- gdb-7.6.1.orig/gdb/common/linux-procfs.h ++++ gdb-7.6.1/gdb/common/linux-procfs.h +@@ -36,6 +36,8 @@ extern pid_t linux_proc_get_tracerpid (p + + extern int linux_proc_pid_is_stopped (pid_t pid); + ++extern int linux_proc_pid_is_trace_stopped (pid_t pid); ++ + /* Return non-zero if PID is a zombie. */ + + extern int linux_proc_pid_is_zombie (pid_t pid); +Index: gdb-7.6.1/gdb/linux-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/linux-nat.c ++++ gdb-7.6.1/gdb/linux-nat.c +@@ -1928,6 +1928,85 @@ linux_nat_detach (struct target_ops *ops + linux_ops->to_detach (ops, args, from_tty); + } + ++/* Resume execution of the inferior process. If STEP is nonzero, ++ single-step it. If SIGNAL is nonzero, give it that signal. */ ++ ++static void ++linux_resume_one_lwp_throw (struct lwp_info *lp, int step, ++ enum gdb_signal signo) ++{ ++ ptid_t ptid; ++ ++ lp->step = step; ++ ++ if (linux_nat_prepare_to_resume != NULL) ++ linux_nat_prepare_to_resume (lp); ++ ++ ptid = pid_to_ptid (GET_LWP (lp->ptid)); ++ linux_ops->to_resume (linux_ops, ptid, step, signo); ++ ++ /* Successfully resumed. Clear state that no longer makes sense, ++ and mark the LWP as running. Must not do this before resuming ++ otherwise if that fails other code will be confused. E.g., we'd ++ later try to stop the LWP and hang forever waiting for a stop ++ status. Note that we must not throw after this is cleared, ++ otherwise handle_zombie_lwp_error would get confused. */ ++ lp->stopped = 0; ++ lp->stopped_by_watchpoint = 0; ++ registers_changed_ptid (lp->ptid); ++} ++ ++/* Called when we try to resume a stopped LWP and that errors out. If ++ the LWP is no longer in ptrace-stopped state (meaning it's zombie, ++ or about to become), discard the error, clear any pending status ++ the LWP may have, and return true (we'll collect the exit status ++ soon enough). Otherwise, return false. */ ++ ++static int ++check_ptrace_stopped_lwp_gone (struct lwp_info *lp) ++{ ++ /* If we get an error after resuming the LWP successfully, we'd ++ confuse !T state for the LWP being gone. */ ++ gdb_assert (lp->stopped); ++ ++ /* We can't just check whether the LWP is in 'Z (Zombie)' state, ++ because even if ptrace failed with ESRCH, the tracee may be "not ++ yet fully dead", but already refusing ptrace requests. In that ++ case the tracee has 'R (Running)' state for a little bit ++ (observed in Linux 3.18). See also the note on ESRCH in the ++ ptrace(2) man page. Instead, check whether the LWP has any state ++ other than ptrace-stopped. */ ++ ++ /* Don't assume anything if /proc/PID/status can't be read. */ ++ if (linux_proc_pid_is_trace_stopped (ptid_get_lwp (lp->ptid)) == 0) ++ { ++ lp->status = 0; ++ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE; ++ lp->stopped_by_watchpoint = 0; ++ return 1; ++ } ++ return 0; ++} ++ ++/* Like linux_resume_one_lwp_throw, but no error is thrown if the LWP ++ disappears while we try to resume it. */ ++ ++static void ++linux_resume_one_lwp (struct lwp_info *lp, int step, enum gdb_signal signo) ++{ ++ volatile struct gdb_exception ex; ++ ++ TRY_CATCH (ex, RETURN_MASK_ERROR) ++ { ++ linux_resume_one_lwp_throw (lp, step, signo); ++ } ++ if (ex.reason < 0) ++ { ++ if (!check_ptrace_stopped_lwp_gone (lp)) ++ throw_exception (ex); ++ } ++} ++ + /* Resume LP. */ + + static void +@@ -1956,14 +2035,7 @@ resume_lwp (struct lwp_info *lp, int ste + : "0"), + step ? "step" : "resume"); + +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, +- pid_to_ptid (GET_LWP (lp->ptid)), +- step, signo); +- lp->stopped = 0; +- lp->step = step; +- lp->stopped_by_watchpoint = 0; ++ linux_resume_one_lwp (lp, step, signo); + } + else + { +@@ -1982,13 +2054,17 @@ resume_lwp (struct lwp_info *lp, int ste + } + } + +-/* Resume LWP, with the last stop signal, if it is in pass state. */ ++/* Callback for iterate_over_lwps. If LWP is EXCEPT, do nothing. ++ Resume LWP with the last stop signal, if it is in pass state. */ + + static int +-linux_nat_resume_callback (struct lwp_info *lp, void *data) ++linux_nat_resume_callback (struct lwp_info *lp, void *except) + { + enum gdb_signal signo = GDB_SIGNAL_0; + ++ if (lp == except) ++ return 0; ++ + if (lp->stopped) + { + struct thread_info *thread; +@@ -2108,20 +2184,10 @@ linux_nat_resume (struct target_ops *ops + return; + } + +- /* Mark LWP as not stopped to prevent it from being continued by +- linux_nat_resume_callback. */ +- lp->stopped = 0; +- + if (resume_many) +- iterate_over_lwps (ptid, linux_nat_resume_callback, NULL); ++ iterate_over_lwps (ptid, linux_nat_resume_callback, lp); + +- /* Convert to something the lower layer understands. */ +- ptid = pid_to_ptid (GET_LWP (lp->ptid)); +- +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, ptid, step, signo); +- lp->stopped_by_watchpoint = 0; ++ linux_resume_one_lwp (lp, step, signo); + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, +@@ -2287,11 +2353,7 @@ linux_handle_syscall_trap (struct lwp_in + + /* Note that gdbarch_get_syscall_number may access registers, hence + fill a regcache. */ +- registers_changed (); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- lp->step, GDB_SIGNAL_0); ++ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0); + return 1; + } + +@@ -2486,22 +2548,15 @@ linux_handle_extended_wait (struct lwp_i + fprintf_unfiltered (gdb_stdlog, + "LHEW: resuming new LWP %ld\n", + GET_LWP (new_lp->ptid)); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (new_lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid), +- 0, GDB_SIGNAL_0); +- new_lp->stopped = 0; ++ ++ linux_resume_one_lwp (new_lp, 0, GDB_SIGNAL_0); + } + } + + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LHEW: resuming parent LWP %d\n", pid); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- 0, GDB_SIGNAL_0); +- ++ linux_resume_one_lwp (lp, 0, GDB_SIGNAL_0); + return 1; + } + +@@ -3382,12 +3437,7 @@ linux_nat_filter_event (int lwpid, int s + { + /* This is a delayed SIGSTOP. */ + +- registers_changed (); +- +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- lp->step, GDB_SIGNAL_0); ++ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, 0, 0 (discard SIGSTOP)\n", +@@ -3395,7 +3445,6 @@ linux_nat_filter_event (int lwpid, int s + "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid)); + +- lp->stopped = 0; + gdb_assert (lp->resumed); + + /* Discard the event. */ +@@ -3416,11 +3465,7 @@ linux_nat_filter_event (int lwpid, int s + /* This is a delayed SIGINT. */ + lp->ignore_sigint = 0; + +- registers_changed (); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- lp->step, GDB_SIGNAL_0); ++ linux_resume_one_lwp (lp, lp->step, GDB_SIGNAL_0); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, 0, 0 (discard SIGINT)\n", +@@ -3428,7 +3473,6 @@ linux_nat_filter_event (int lwpid, int s + "PTRACE_SINGLESTEP" : "PTRACE_CONT", + target_pid_to_str (lp->ptid)); + +- lp->stopped = 0; + gdb_assert (lp->resumed); + + /* Discard the event. */ +@@ -3796,11 +3840,7 @@ retry: + other threads to run. On the other hand, not resuming + newly attached threads may cause an unwanted delay in + getting them running. */ +- registers_changed (); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- lp->step, signo); ++ linux_resume_one_lwp (lp, lp->step, signo); + if (debug_linux_nat) + fprintf_unfiltered (gdb_stdlog, + "LLW: %s %s, %s (preempt 'handle')\n", +@@ -3810,7 +3850,6 @@ retry: + (signo != GDB_SIGNAL_0 + ? strsignal (gdb_signal_to_host (signo)) + : "0")); +- lp->stopped = 0; + goto retry; + } + +@@ -3935,32 +3974,41 @@ resume_stopped_resumed_lwps (struct lwp_ + { + struct regcache *regcache = get_thread_regcache (lp->ptid); + struct gdbarch *gdbarch = get_regcache_arch (regcache); +- CORE_ADDR pc = regcache_read_pc (regcache); ++ volatile struct gdb_exception ex; + + gdb_assert (is_executing (lp->ptid)); + +- /* Don't bother if there's a breakpoint at PC that we'd hit +- immediately, and we're not waiting for this LWP. */ +- if (!ptid_match (lp->ptid, *wait_ptid_p)) ++ TRY_CATCH (ex, RETURN_MASK_ERROR) + { +- if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc)) +- return 0; +- } ++ CORE_ADDR pc = regcache_read_pc (regcache); ++ int leave_stopped = 0; + +- if (debug_linux_nat) +- fprintf_unfiltered (gdb_stdlog, +- "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n", +- target_pid_to_str (lp->ptid), +- paddress (gdbarch, pc), +- lp->step); ++ /* Don't bother if there's a breakpoint at PC that we'd hit ++ immediately, and we're not waiting for this LWP. */ ++ if (!ptid_match (lp->ptid, *wait_ptid_p)) ++ { ++ if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc)) ++ leave_stopped = 1; ++ } + +- registers_changed (); +- if (linux_nat_prepare_to_resume != NULL) +- linux_nat_prepare_to_resume (lp); +- linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)), +- lp->step, GDB_SIGNAL_0); +- lp->stopped = 0; +- lp->stopped_by_watchpoint = 0; ++ if (!leave_stopped) ++ { ++ if (debug_linux_nat) ++ fprintf_unfiltered (gdb_stdlog, ++ "RSRL: resuming stopped-resumed LWP %s at " ++ "%s: step=%d\n", ++ target_pid_to_str (lp->ptid), ++ paddress (gdbarch, pc), ++ lp->step); ++ ++ linux_resume_one_lwp_throw (lp, lp->step, GDB_SIGNAL_0); ++ } ++ } ++ if (ex.reason < 0) ++ { ++ if (!check_ptrace_stopped_lwp_gone (lp)) ++ throw_exception (ex); ++ } + } + + return 0; +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.c +@@ -0,0 +1,62 @@ ++/* Copyright 2015 Free Software Foundation, Inc. ++ ++ This file is part of GDB. ++ ++ 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 3 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, see . */ ++ ++#include ++#include ++ ++volatile int call_exit; ++static pthread_barrier_t barrier; ++#define NUMTHREADS 256 ++ ++void * ++thread_function (void *arg) ++{ ++ pthread_barrier_wait (&barrier); ++ ++ while (!call_exit) ++ usleep (1); ++ ++ _exit (0); ++ return NULL; ++} ++ ++void ++all_threads_started (void) ++{ ++ call_exit = 1; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ pthread_t threads[NUMTHREADS]; ++ int i; ++ ++ pthread_barrier_init (&barrier, NULL, NUMTHREADS + 1); ++ ++ for (i = 0; i < NUMTHREADS; ++i) ++ pthread_create (&threads[i], NULL, thread_function, NULL); ++ ++ pthread_barrier_wait (&barrier); ++ ++ all_threads_started (); ++ ++ for (i = 0; i < NUMTHREADS; ++i) ++ pthread_join (threads[i], NULL); ++ ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/thread-kills-process.exp +@@ -0,0 +1,70 @@ ++# Copyright (C) 2015 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 3 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, see . ++ ++standard_testfile ++ ++if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ return -1 ++} ++ ++clean_restart ${binfile} ++if {![runto_main]} { ++ fail "Couldn't run to main" ++ return ++} ++ ++gdb_breakpoint "all_threads_started" ++ ++gdb_continue_to_breakpoint "all_threads_started" ++ ++# Update the thread list, otherwise when testing against GDBserver, ++# GDB won't know about thread 2. (Only necessary with GDB < 7.9.) ++gdb_test "info threads" ".*" ++ ++# Select any thread but the leader. ++gdb_test "thread 2" ".*" "switch to non-leader thread" ++ ++# Delete breakpoints so that GDB doesn't switch back the to leader to ++# step over its breakpoint. ++delete_breakpoints ++ ++# Let threads exit the process on next resume. ++gdb_test "p call_exit = 0" " = 0" ++ ++# While GDB is busy resuming all threads one by one, one of the ++# threads should manage to exit the process. GDB should handle that ++# gracefully instead of erroring out. ++# ++# gdb_continue_to_end doesn't work with GDBserver until the ++# introduction of the "exit_is_reliable" board variable ++# (b477a5e649150) in GDB 7.7. ++#gdb_continue_to_end "" continue 1 ++gdb_test "continue" "$inferior_exited_re normally.*" ++ ++# On the buggy GDB where the "continue" above would error out, a ++# subsequent "detach" (e.g., the user tries to quit GDB, and quit ++# offers to detach) would hit this assertion: ++# ++# linux-nat.c:1869: internal-error: linux_nat_detach: Assertion `num_lwps (GET_PID (inferior_ptid)) == 1' failed. ++ ++# That was a consequence of the original bug, but let's make sure that ++# even when "continue" is handled properly, detach doesn't stumble on ++# anything stale. ++gdb_test "detach" "The program is not being run\\." \ ++ "detach after exit" ++ ++# Likewise "continue". ++gdb_test "continue" "The program is not being run\\." \ ++ "continue after exit" diff --git a/SOURCES/gdb-rhbz1190506-segv-in-ko-ppc64.patch b/SOURCES/gdb-rhbz1190506-segv-in-ko-ppc64.patch new file mode 100644 index 0000000..6ae16d5 --- /dev/null +++ b/SOURCES/gdb-rhbz1190506-segv-in-ko-ppc64.patch @@ -0,0 +1,220 @@ +commit 80c570537e380c1b8e48754c0ddbce2abcde2d00 +Author: Jan Kratochvil +Date: Thu Feb 26 14:08:01 2015 +0100 + + SEGV in ppc64_elf_get_synthetic_symtab reading a separate debug file + + The attached patch fixes the SEGV and lets GDB successfully + load all kernel modules installed by default on RHEL 7. + + Valgrind on F-21 x86_64 host has shown me more clear what is the problem: + + Reading symbols from /home/jkratoch/t/cordic.ko...Reading symbols from + /home/jkratoch/t/cordic.ko.debug...================================================================= + ==22763==ERROR: AddressSanitizer: heap-use-after-free on address 0x6120000461c8 at pc 0x150cdbd bp 0x7fffffffc7e0 sp 0x7fffffffc7d0 + READ of size 8 at 0x6120000461c8 thread T0 + #0 0x150cdbc in ppc64_elf_get_synthetic_symtab /home/jkratoch/redhat/gdb-test-asan/bfd/elf64-ppc.c:3282 + #1 0x8c5274 in elf_read_minimal_symbols /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1205 + #2 0x8c55e7 in elf_symfile_read /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1268 + [...] + 0x6120000461c8 is located 264 bytes inside of 288-byte region [0x6120000460c0,0x6120000461e0) + freed by thread T0 here: + #0 0x7ffff715454f in __interceptor_free (/lib64/libasan.so.1+0x5754f) + #1 0xde9cde in xfree common/common-utils.c:98 + #2 0x9a04f7 in do_my_cleanups common/cleanups.c:155 + #3 0x9a05d3 in do_cleanups common/cleanups.c:177 + #4 0x8c538a in elf_read_minimal_symbols /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1229 + #5 0x8c55e7 in elf_symfile_read /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1268 + [...] + previously allocated by thread T0 here: + #0 0x7ffff71547c7 in malloc (/lib64/libasan.so.1+0x577c7) + #1 0xde9b95 in xmalloc common/common-utils.c:41 + #2 0x8c4da2 in elf_read_minimal_symbols /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1147 + #3 0x8c55e7 in elf_symfile_read /home/jkratoch/redhat/gdb-test-asan/gdb/elfread.c:1268 + [...] + SUMMARY: AddressSanitizer: heap-use-after-free /home/jkratoch/redhat/gdb-test-asan/bfd/elf64-ppc.c:3282 ppc64_elf_get_synthetic_symtab + [...] + ==22763==ABORTING + + A similar case a few lines later I have fixed in 2010 by: + https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=3f1eff0a2c7f0e7078f011f55b8e7f710aae0cc2 + + My testcase does not always reproduce it but at least a bit: + * GDB without ppc64 target (even as a secondary one) is reported as "untested" + * ASAN-built GDB with ppc64 target always crashes (and PASSes with this fix) + * unpatched non-ASAN-built GDB with ppc64 target crashes from commandline + * unpatched non-ASAN-built GDB with ppc64 target PASSes from runtest (?) + + gdb/ChangeLog + 2015-02-26 Jan Kratochvil + + * elfread.c (elf_read_minimal_symbols): Use bfd_alloc for + bfd_canonicalize_symtab. + + gdb/testsuite/ChangeLog + 2015-02-26 Jan Kratochvil + + * gdb.arch/cordic.ko.bz2: New file. + * gdb.arch/cordic.ko.debug.bz2: New file. + * gdb.arch/ppc64-symtab-cordic.exp: New file. + +Index: gdb-7.6.1/gdb/elfread.c +=================================================================== +--- gdb-7.6.1.orig/gdb/elfread.c ++++ gdb-7.6.1/gdb/elfread.c +@@ -2308,8 +2308,10 @@ elf_symfile_read (struct objfile *objfil + + if (storage_needed > 0) + { +- symbol_table = (asymbol **) xmalloc (storage_needed); +- make_cleanup (xfree, symbol_table); ++ /* Memory gets permanently referenced from ABFD after ++ bfd_canonicalize_symtab so it must not get freed before ABFD gets. */ ++ ++ symbol_table = bfd_alloc (abfd, storage_needed); + symcount = bfd_canonicalize_symtab (objfile->obfd, symbol_table); + + if (symcount < 0) +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/ppc64-symtab-cordic.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/ppc64-symtab-cordic.exp +@@ -0,0 +1,51 @@ ++# Copyright 2015 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 3 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, see . ++ ++standard_testfile ++ ++set kobz2uufile ${srcdir}/${subdir}/cordic.ko.bz2.uu ++set kofile ${objdir}/${subdir}/cordic.ko ++set kodebugbz2uufile ${srcdir}/${subdir}/cordic.ko.debug.bz2.uu ++set kodebugfile ${objdir}/${subdir}/cordic.ko.debug ++ ++if {[catch "system \"uudecode -o - ${kobz2uufile} | bzip2 -dc >${kofile}\""] != 0} { ++ untested "failed bzip2 for ${kobz2uufile}" ++ return -1 ++} ++if {[catch "system \"uudecode -o - ${kodebugbz2uufile} | bzip2 -dc >${kodebugfile}\""] != 0} { ++ untested "failed bzip2 for ${kodebugbz2uufile}" ++ return -1 ++} ++ ++gdb_exit ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++ ++# This test won't work properly if system debuginfo is installed. ++# Test message is suppressed by "" as otherwise we could print PASS+UNTESTED ++# result to gdb.sum making a false feeling the issue has been tested. ++gdb_test_no_output "set debug-file-directory" "" ++ ++gdb_load ${kofile} ++ ++set test "show architecture" ++gdb_test_multiple $test $test { ++ -re "\r\nThe target architecture is set automatically \\(currently powerpc:common64\\)\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re "\r\nThe target architecture is set automatically \\(currently .*\\)\r\n$gdb_prompt $" { ++ untested "powerpc:common64 is not supported" ++ } ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/cordic.ko.bz2.uu +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/cordic.ko.bz2.uu +@@ -0,0 +1,53 @@ ++begin 664 cordic.ko.bz2.uu ++M0EIH.3%!62936:QR$J<`!:7____________^___________]__O_U__]_N]] ++M__?W__Z[T`88O`VP73FU<IZADTR`/4]0#(T,U&@]0#0`9`,FC33&IM(S4!M30`:``:-&@`TT0`````& ++M@```!H#(`````````-``-&@`````````:&@-```R:`2)(2GHIYI,F%-E/4T& ++M@&U&:FU#Q3TGJ-#0T:'J&AH!IM1H&1H/2,@`#U,AH&@`:`#0`:``:``````# ++M(U?UGYM5,T:_>+G'N@2C!1`YAHM*$?TZ#1VWC-*HMEMC`L[FZ949K<@VVOMY ++MU)8$>DL`F?4./0/$L*"![J$&9GBD5L68$)"T^%J\L*M>Y6]*.ZV?-,M+74MS ++M7X1*XFVMS`GJ:<:C<>QUJ_';N$*3SYGC0I2/;CC),,OZ-.I9"LJNAL9IU>5*1JOU=!B=\KO8P"K$KJZ@,&_@O]-`%Q ++M1"!+@F22E`B(B(@&PPF@)2B(@!#;?@NJE`@OH($-@%RQ&,9BF;=PFGNYNN:] ++M1K+-8+.R,EQTLVUO+WYI(QK5X:^84TW9M(`M6"/LM(AH5ZP0%:Q(T[0KMI%) ++MK'8N$JP[&$L?9VM]HM)E94:/1MLZAN$17YE)SG=9KFW(7T\)"%!;##C5+>4R ++M+&1/XU>[&0[7.2$D6]MR[.4/('!2/<'"D!H!-4U+CBQA3B#6>9V[R5=#84J#]Y?XUP#19NF-!"]] ++MX_SK#=\A1G\0*HM7:I&QL4I3$C,G5,]\X`ACXR-CR8>6HC1/&?-/$G_7L%R3..'6)YM[Y+VR5V9@ ++M2Y>@7D>:F^&RN0-`,\AXMIV$:@$3N<4DN9049W"\_/7-IY&R65X)I4Q-F@8VBEF@* ++M2GT.9G)TIA2EFR449J7+31?[-I>_N+>]O;TK_]Z++'W8)0:4[C0(@1SIU1;6 ++MR61G=;D\6<;;6L]O66.,1>-&K5+O61ZG%00&>8%2K2K4JDQ7K$04 ++MX0V/:9#BX'_EBFQ2RA2<,L[,X82(-+!@L-S).E+:14JL6#4*`O3:#L""$LFP ++ML6XHO((,4$J_%NGA(G!-`/E`OT*I%?LI>VE0.T&E3,.D5DU77T%K3SE84QM4 ++M$Z7R$'][%^7LT7^N;%L,*@M0%QKZ=EAF"6DBJT1D3)*O1J//3L3!/"Y1ME[Z ++M;X#WO\Q#AF/8,0P(F$_,)1B7`PF#AEAA'-^RO3K/65R$&64,K9P@T904AC%D ++M0DYNK'=<]Y\B><\2GZ*(!ZXD9I)%_5]P'EOE,)W&A)$+"D("%PAH1,B+EFDI ++M!,)F/LQ1>WRLFH;:IH<2$*#V)$9#%O.HL&6)@RP)U[0)RL9S4(0;B)T#H5"X ++M&Z`6P3@'37WRBX^=+*>0?3)D!K;W>WTTBC,"$.MX6MVUWV)^U1P?[LI/6A$8 ++M#^333)CO]9Z/55B?/R5TR?-./&C+(&A[):L7T-MT:"JPH.M@Z)$TTB$NC^Z1 ++M$FHE%T(C1-:Y93\]R_U&6A-O.3_)/0K&;LK]9Z%>?Q>4_L&TM>J:2S3BFC/> ++MN^\3B,# ++MA6QOQMY*]TJV12V[4+J+-P=Q?/MV=Q2Y%@*"\<12OVLPHS(E+340BRPFZI/$ ++M,;[5&:J8,\D"&@9CK"#&OP@<"A!3ND%9S*EA'6D3JLC"T6<9:`!E;3O(&G94 ++MIT-`CL3%A?;_(NKY1#S-PYZ#Q/58AEZZY4LG'0B(3B$`4$0P0_XNY(IPH2%8 ++#Y"5. ++` ++end +Index: gdb-7.6.1/gdb/testsuite/gdb.arch/cordic.ko.debug.bz2.uu +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.arch/cordic.ko.debug.bz2.uu +@@ -0,0 +1,24 @@ ++begin 664 cordic.ko.debug.bz2.uu ++M0EIH.3%!62936;;3U;4``^=______^==:W]63^U^1+_O_V"H4V#`)$A@F@90 ++M"D$!"""2P`,!Q0-*1AHB-4])ZGI-#3U`T:8C0``-``-`:-#0`:#T@!IH-&@- ++M!HA$\D](])E)Z(V@)A#30TT,1@`C-`)@(!H8"8!,--!!@``````````$P``` ++M`$8``F``2)$FF@FDVIZGJ>BFF1A-/-)HVJ'J8`#U3,H:#"-D@'H:@8CT&("] ++M???6F=%1'FNGCPP"I4HL6ZE@2>=E(>L$@&5?>9ZJAI%`&%I2P2MAW226F58= ++M!Z[0:D$@C,S$%$*-\ZZF[U##1Q9M=6V$MAXS#$,A5@8IA,-^8#:S#*JAEJUA ++M.ZJWN+EH.Z>`5$02]B/^B\^*GMP%%$,#,BH!`%2&""YD(Z$``3/9]@Y;'/LR ++M6_C%]&YT&1HR5[H(&VQ`9U[/&/_IX]&CA3,4BW\%WK:>,KF?AA?;I0M)HJHA ++M))0E$!$-PFTDHB!1$`@;;*T0".1!";2&QM!L,.,TDA*LQ:G*A?T5HS.EQQ-^ ++MXX9F.PV"$H]V,TTRF$T%@NHPIQ2[]T6@8*!#(2$CYW1@8Y(S,WQ[.UM[GKY. ++M"Y^V=].AINN_ ++MT#7-^3M?A9*J-8-<-'1M[-.*2H82JW<$8`0=$2U,`K^AD\-A$N6%@!,)D\40 ++MG+A5S!8)K\D>T%$6+5VX1Q3?#S@85ELW\N1-;@7B98=FRJ21(E>-R[9:8#GQ6&((U`"<&M?(D**&1(`:P ++MAXD/K49))+)4^H3%*:%H4QQ2+J4.>B,&7.N<`R,SB0A!LB3&(`J?03!*`8:! ++M$Z0H8&G/30D@`M$O`Z5)%-CU'QCR@Z6&_RJIJ@M5&8H8&$O*6ESP4],\P7^+ ++*N2*<*$A;:>K:@``` ++` ++end diff --git a/SOURCES/gdb-rhbz1197665-fix-applyframefilter-backport.patch b/SOURCES/gdb-rhbz1197665-fix-applyframefilter-backport.patch new file mode 100644 index 0000000..fb90df2 --- /dev/null +++ b/SOURCES/gdb-rhbz1197665-fix-applyframefilter-backport.patch @@ -0,0 +1,285 @@ +commit 21909fa1c6d934bfa0c7ad3ef95909db48f6f756 +Author: Tom Tromey +Date: Wed Jan 22 08:10:01 2014 -0700 + + fix crash in frame filters + + apply_frame_filter calls ensure_python_env before computing the + gdbarch to use. This means that python_gdbarch can be NULL while in + Python code, and if a frame filter depends on this somehow (easy to + do), gdb will crash. + + The fix is to compute the gdbarch first. + + Built and regtested on x86-64 Fedora 18. + New test case included. + + 2014-01-23 Tom Tromey + + PR python/16491: + * python/py-framefilter.c (apply_frame_filter): Call + ensure_python_env after computing gdbarch. + + 2014-01-23 Tom Tromey + + PR python/16491: + * gdb.python/py-framefilter.py (Reverse_Function.function): Read a + string from an inferior frame. + * gdb.python/py-framefilter-mi.exp: Update. + +Index: gdb-7.6.1/gdb/python/py-framefilter.c +=================================================================== +--- gdb-7.6.1.orig/gdb/python/py-framefilter.c ++++ gdb-7.6.1/gdb/python/py-framefilter.c +@@ -1468,18 +1468,18 @@ apply_frame_filter (struct frame_info *f + PyObject *item; + htab_t levels_printed; + +- cleanups = ensure_python_env (gdbarch, current_language); +- + TRY_CATCH (except, RETURN_MASK_ALL) + { + gdbarch = get_frame_arch (frame); + } + if (except.reason < 0) + { +- gdbpy_convert_exception (except); +- goto error; ++ /* Let gdb try to print the stack trace. */ ++ return PY_BT_NO_FILTERS; + } + ++ cleanups = ensure_python_env (gdbarch, current_language); ++ + iterable = bootstrap_python_frame_filters (frame, frame_low, frame_high); + + if (iterable == NULL) +Index: gdb-7.6.1/gdb/testsuite/gdb.python/py-framefilter-mi.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.python/py-framefilter-mi.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.python/py-framefilter-mi.exp +@@ -66,10 +66,10 @@ mi_continue_to_line [gdb_get_line_number + "step to breakpoint" + + mi_gdb_test "-stack-list-frames" \ +- "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*},frame={level=\"27\",addr=\"$hex\",func=\"niam\".*}\\\].*" \ ++ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne.*\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*},frame={level=\"27\",addr=\"$hex\",func=\"niam\".*}\\\].*" \ + "filtered stack listing" + mi_gdb_test "-stack-list-frames 0 3" \ +- "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*}\\\]" \ ++ "\\^done,stack=\\\[frame={level=\"0\",addr=\"$hex\",func=\"cnuf_dne.*\".*},frame={level=\"1\",addr=\"$hex\",func=\"acnuf\".*},frame={level=\"2\",addr=\"$hex\",func=\"bcnuf\".*},frame={level=\"3\",addr=\"$hex\",func=\"acnuf\".*}\\\]" \ + "filtered stack list 0 3" + mi_gdb_test "-stack-list-frames 22 24" \ + "\\^done,stack=\\\[frame={level=\"22\",addr=\"$hex\",func=\"1cnuf\".*,children=\\\[frame={level=\"23\",addr=\"$hex\",func=\"func2\".*}\\\]},frame={level=\"24\",addr=\"$hex\",func=\"3cnuf\".*}\\\]" \ +Index: gdb-7.6.1/gdb/testsuite/gdb.python/py-framefilter.py +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.python/py-framefilter.py ++++ gdb-7.6.1/gdb/testsuite/gdb.python/py-framefilter.py +@@ -30,8 +30,11 @@ class Reverse_Function (FrameDecorator): + fname = str (self.fobj.function()) + if (fname == None or fname == ""): + return None ++ if fname == 'end_func': ++ extra = self.fobj.inferior_frame().read_var('str').string() + else: +- fname = fname[::-1] ++ extra = '' ++ fname = fname[::-1] + extra + return fname + + class Dummy (FrameDecorator): +Index: gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv-gdb.py.in +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv-gdb.py.in +@@ -0,0 +1,48 @@ ++# Copyright (C) 2013 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 3 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, see . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++import gdb ++import itertools ++from gdb.FrameDecorator import FrameDecorator ++ ++ ++class FrameObjFile (): ++ ++ def __init__ (self): ++ self.name = "Filter1" ++ self.priority = 1 ++ self.enabled = False ++ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self ++ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self ++ ++ def filter (self, frame_iter): ++ return frame_iter ++ ++class FrameObjFile2 (): ++ ++ def __init__ (self): ++ self.name = "Filter2" ++ self.priority = 100 ++ self.enabled = True ++ gdb.current_progspace().frame_filters ["Progspace" + self.name] = self ++ gdb.current_objfile().frame_filters ["ObjectFile" + self.name] = self ++ ++ def filter (self, frame_iter): ++ return frame_iter ++ ++FrameObjFile() ++FrameObjFile2() +Index: gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv.exp +@@ -0,0 +1,76 @@ ++# Copyright (C) 2013-2015 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 3 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, see . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++ ++# This test is specifically crafted for RH BZ 1197665. ++ ++load_lib gdb-python.exp ++ ++standard_testfile py-framefilter.c ++ ++# We cannot use prepare_for_testing as we have to set the safe-patch ++# to check objfile and progspace printers. ++if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} { ++ return -1 ++} ++ ++# Start with a fresh gdb. ++gdb_exit ++gdb_start ++ ++# Skip all tests if Python scripting is not enabled. ++if { [skip_python_tests] } { continue } ++ ++# Make the -gdb.py script available to gdb, it is automagically loaded by gdb. ++# Care is taken to put it in the same directory as the binary so that ++# gdb will find it. ++set remote_obj_python_file \ ++ [remote_download \ ++ host ${srcdir}/${subdir}/${testfile}-gdb.py.in \ ++ ${subdir}/${testfile}-gdb.py] ++ ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_test_no_output "set auto-load safe-path ${remote_obj_python_file}" \ ++ "set auto-load safe-path" ++gdb_load ${binfile} ++# Verify gdb loaded the script. ++gdb_test "info auto-load python-scripts" "Yes.*/${testfile}-gdb.py.*" \ ++ "Test auto-load had loaded python scripts" ++ ++if ![runto_main] then { ++ perror "couldn't run to breakpoint" ++ return ++} ++gdb_test_no_output "set python print-stack full" \ ++ "Set python print-stack to full" ++ ++# Load global frame-filters ++set remote_python_file [remote_download host ${srcdir}/${subdir}/${testfile}.py] ++gdb_test_no_output "python execfile ('${remote_python_file}')" \ ++ "Load python file" ++ ++gdb_breakpoint [gdb_get_line_number "Backtrace end breakpoint"] ++gdb_breakpoint [gdb_get_line_number "Inner test breakpoint"] ++gdb_continue_to_breakpoint "Inner test breakpoint" ++ ++# Test multiple local blocks. ++gdb_test "bt full no-filters" \ ++ ".*#0.*end_func.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ ++ "bt full no-filters" ++gdb_test "bt full" \ ++ ".*#0.*cnuf_dne.*h = 9.*f = 42.*g = 19.*bar = $hex \"Inside block x2\".*d = 15.*e = 14.*foo = $hex \"Inside block\".*str = $hex \"The End\".*st2 = $hex \"Is Near\".*b = 12.*c = 5.*" \ ++ "bt full with filters" +Index: gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv.py +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.python/rhbz1197665-apply-frame-filter-segv.py +@@ -0,0 +1,56 @@ ++# Copyright (C) 2013-2015 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 3 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, see . ++ ++# This file is part of the GDB testsuite. It tests Python-based ++# frame-filters. ++ ++# This test is specifically crafted for RH BZ 1197665. ++ ++import gdb ++import itertools ++from gdb.FrameDecorator import FrameDecorator ++import copy ++ ++class Reverse_Function (FrameDecorator): ++ ++ def __init__(self, fobj): ++ super(Reverse_Function, self).__init__(fobj) ++ self.fobj = fobj ++ ++ def function (self): ++ # This function call should not fail. ++ gdb.target_charset () ++ ++ fname = str (self.fobj.function()) ++ if (fname == None or fname == ""): ++ return None ++ else: ++ fname = fname[::-1] ++ return fname ++ ++class FrameFilter (): ++ ++ def __init__ (self): ++ self.name = "Reverse" ++ self.priority = 100 ++ self.enabled = True ++ gdb.frame_filters [self.name] = self ++ ++ def filter (self, frame_iter): ++ frame_iter = itertools.imap (Reverse_Function, ++ frame_iter) ++ return frame_iter ++ ++FrameFilter() diff --git a/SOURCES/gdb-rhbz1210135-internal-error-linux_nat_post_attach_wait.patch b/SOURCES/gdb-rhbz1210135-internal-error-linux_nat_post_attach_wait.patch new file mode 100644 index 0000000..0d23bdb --- /dev/null +++ b/SOURCES/gdb-rhbz1210135-internal-error-linux_nat_post_attach_wait.patch @@ -0,0 +1,158 @@ + NOTE: This patch has been forwardported to RHEL-7.2. It is originally + from RHEL-6.7. + + Message-ID: <54E37CE7.50703@redhat.com> + Date: Tue, 17 Feb 2015 17:39:51 +0000 + From: Pedro Alves + To: Sergio Durigan Junior + Subject: [debug-list] [PATCH] RH BZ #1162264 - gdb/linux-nat.c:1411: + internal-error:, + linux_nat_post_attach_wait: Assertion `pid == new_pid' failed. + + Hi. + + Ref: https://bugzilla.redhat.com/show_bug.cgi?id=1162264 + + So I spend a few more hours today trying to reproduce the + EACCES, to no avail. Also, unfortunately, none of the attach + bugs exposed by attach-many-short-lived-threads.exp test + can explain this. + + It seems to be that really the best we can do is cope with + the error, like in the patch below. + + Note that the backtrace at + + https://bugzilla.redhat.com/show_bug.cgi?id=1162264#c3 : + + shows that this triggers for the main thread already: + + ... + #6 0x000000000044fd2e in linux_nat_post_attach_wait (ptid=..., first=1, cloned=0x1d84368, + ... + + (note "first=1"). + + For upstream, I think linux_nat_attach should be adjusted to work + like gdbserver -- that is, leave the initial waitpid to the main + wait code, like all other events, instead of synchronously + doing waitpid(PID). That'll get rid of linux_nat_post_attach_wait + altogether. But that's too invasive for a bug fix. + + >From 072c61aeb9adc64e1eb45c120061b85fbf6f4d25 Mon Sep 17 00:00:00 2001 + From: Pedro Alves + Date: Tue, 17 Feb 2015 17:11:05 +0000 + Subject: [PATCH] RH BZ #1162264 - gdb/linux-nat.c:1411: internal-error: + linux_nat_post_attach_wait: Assertion `pid == new_pid' failed. + + According to BZ #1162264, it can happen that we manage to attach to a + process, but then waitpid on it fails with EACCES. That's unexpected, + and gdb hits an assertion. But given this is an error that is out of + our control, we should handle it gracefully. I wasn't able to + reproduce the EACCES, but hacking in the error, like: + + | --- a/gdb/linux-nat.c + | +++ b/gdb/linux-nat.c + | @@ -1409,7 +1409,7 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned, + | *cloned = 1; + | } + | + | - if (new_pid != pid) + | + if (new_pid != pid || 1) + | { + | int saved_errno = errno; + | + | @@ -1423,6 +1423,7 @@ linux_nat_post_attach_wait (ptid_t ptid, int first, int *cloned, + | ptrace (PTRACE_DETACH, pid, 0, 0); + | + | errno = saved_errno; + | + errno = EACCES; + | perror_with_name (_("waitpid")); + | } + + ... I could confirm that the error handling works properly. On the + EACCES case, we get: + + (gdb) attach 1202 + Attaching to process 1202 + Unable to attach: waitpid: Permission denied. + (gdb) info inferiors + Num Description Executable + * 1 + (gdb) + + No test because the conditions that lead to the waitpid error are + unknown. + + gdb/ChangeLog: + 2015-02-17 Pedro Alves + + * linux-nat.c: Include "exceptions.h". + (linux_nat_post_attach_wait): If waitpid returns an excepted + result, detach and error out instead of asserting. + (linux_nat_attach): Wrap linux_nat_post_attach_wait in TRY_CATCH. + Mourn inferior and rethrow in case of error while waiting for the + initial stop. +--- + gdb/linux-nat.c | 34 +++++++++++++++++++++++++++++++--- + 1 file changed, 31 insertions(+), 3 deletions(-) + +Index: gdb-7.6.1/gdb/linux-nat.c +=================================================================== +--- gdb-7.6.1.orig/gdb/linux-nat.c ++++ gdb-7.6.1/gdb/linux-nat.c +@@ -1397,7 +1397,22 @@ linux_nat_post_attach_wait (ptid_t ptid, + *cloned = 1; + } + +- gdb_assert (pid == new_pid); ++ if (new_pid != pid) ++ { ++ int saved_errno = errno; ++ ++ /* Unexpected waitpid result. EACCES has been observed on RHEL ++ 6.5 (RH BZ #1162264). This is most likely a kernel bug, thus ++ out of our control, so treat it as invalid input. The LWP's ++ state is indeterminate at this point, so best we can do is ++ error out, otherwise we'd probably end up wedged later on. ++ ++ In case we're still attached. */ ++ ptrace (PTRACE_DETACH, pid, 0, 0); ++ ++ errno = saved_errno; ++ perror_with_name (_("waitpid")); ++ } + + if (!WIFSTOPPED (status)) + { +@@ -1621,7 +1636,7 @@ static void + linux_nat_attach (struct target_ops *ops, char *args, int from_tty) + { + struct lwp_info *lp; +- int status; ++ int status = 0; + ptid_t ptid; + volatile struct gdb_exception ex; + +@@ -1659,8 +1674,19 @@ linux_nat_attach (struct target_ops *ops + /* Add the initial process as the first LWP to the list. */ + lp = add_initial_lwp (ptid); + +- status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned, +- &lp->signalled); ++ TRY_CATCH (ex, RETURN_MASK_ERROR) ++ { ++ status = linux_nat_post_attach_wait (lp->ptid, 1, &lp->cloned, ++ &lp->signalled); ++ } ++ if (ex.reason < 0) ++ { ++ target_terminal_ours (); ++ target_mourn_inferior (); ++ ++ error (_("Unable to attach: %s"), ex.message); ++ } ++ + if (!WIFSTOPPED (status)) + { + if (WIFEXITED (status)) diff --git a/SOURCES/gdb-rhbz1210889-thread-call-clone.patch b/SOURCES/gdb-rhbz1210889-thread-call-clone.patch new file mode 100644 index 0000000..5ea2e02 --- /dev/null +++ b/SOURCES/gdb-rhbz1210889-thread-call-clone.patch @@ -0,0 +1,236 @@ + NOTE: This patch has been forwardported from RHEL-6.7. + + From: Pedro Alves + Date: Fri, 20 Feb 2015 19:10:08 +0000 + Subject: [PATCH] PR18006: internal error if threaded program calls + clone(CLONE_VM) + + On GNU/Linux, if a pthreaded program has a thread call clone(CLONE_VM) + directly, and then that clone LWP hits a debug event (breakpoint, + etc.) GDB internal errors. Threaded programs shouldn't really be + calling clone directly, but GDB shouldn't crash either. + + The crash looks like this: + + (gdb) break clone_fn + Breakpoint 1 at 0x4007d8: file clone-thread_db.c, line 35. + (gdb) r + ... + [Thread debugging using libthread_db enabled] + ... + [New Thread 0x7ffff7fc2700 (LWP 3886)] + ../../gdb/linux-thread-db.c:437: internal-error: thread_get_info_callback: Assertion `inout->thread_info != NULL' failed. + A problem internal to GDB has been detected, + further debugging may prove unreliable. + + The problem is that 'clone' ends up clearing the parent thread's tid + field in glibc's thread data structure. For x86_64, the glibc code in + question is here: + + sysdeps/unix/sysv/linux/x86_64/clone.S: + + ... + testq $CLONE_THREAD, %rdi + jne 1f + testq $CLONE_VM, %rdi + movl $-1, %eax <---- + jne 2f + movl $SYS_ify(getpid), %eax + syscall + 2: movl %eax, %fs:PID + movl %eax, %fs:TID <---- + 1: + + When GDB refreshes the thread list out of libthread_db, it finds a + thread with LWP with pid -1 (the clone's parent), which naturally + isn't yet on the thread list. GDB then tries to attach to that bogus + LWP id, that fails, and then GDB gets confused. + + The fix is to detect the bad PID early. + + Tested on x86-64 Fedora 20. GDBserver doesn't need any fix. + + gdb/ChangeLog: + 2015-02-20 Pedro Alves + + PR threads/18006 + * linux-thread-db.c (thread_get_info_callback): Return early if + the thread's lwp id is -1. + (check_event): On TD_DEATH, if the thread is not on the thread + list, warn instead of erroring out. + + gdb/testsuite/ChangeLog: + 2015-02-20 Pedro Alves + + PR threads/18006 + * gdb.threads/clone-thread_db.c: New file. + * gdb.threads/clone-thread_db.exp: New file. +--- + gdb/linux-thread-db.c | 14 +++-- + gdb/testsuite/gdb.threads/clone-thread_db.c | 73 +++++++++++++++++++++++++++ + gdb/testsuite/gdb.threads/clone-thread_db.exp | 44 ++++++++++++++++ + 3 files changed, 128 insertions(+), 3 deletions(-) + create mode 100644 gdb/testsuite/gdb.threads/clone-thread_db.c + create mode 100644 gdb/testsuite/gdb.threads/clone-thread_db.exp + +Index: gdb-7.6.1/gdb/linux-thread-db.c +=================================================================== +--- gdb-7.6.1.orig/gdb/linux-thread-db.c ++++ gdb-7.6.1/gdb/linux-thread-db.c +@@ -422,6 +422,14 @@ thread_get_info_callback (const td_thrha + error (_("thread_get_info_callback: cannot get thread info: %s"), + thread_db_err_str (err)); + ++ if (ti.ti_lid == -1) ++ { ++ /* We'll get this if a threaded program has a thread call clone ++ with CLONE_VM. `clone' sets the pthread LID of the new LWP ++ to -1, which ends up clearing the parent thread's LID. */ ++ return 0; ++ } ++ + /* Fill the cache. */ + thread_ptid = ptid_build (info->pid, ti.ti_lid, 0); + inout->thread_info = find_thread_ptid (thread_ptid); +@@ -1454,9 +1462,9 @@ check_event (ptid_t ptid) + case TD_DEATH: + + if (!in_thread_list (ptid)) +- error (_("Spurious thread death event.")); +- +- detach_thread (ptid); ++ warning (_("Spurious thread death event.")); ++ else ++ detach_thread (ptid); + + break; + +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.c +@@ -0,0 +1,75 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2015 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 3 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, see . ++ ++ Test that GDB doesn't lose an event for a thread it didn't know ++ about, until an event is reported for it. */ ++ ++#define _GNU_SOURCE ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define STACK_SIZE 0x1000 ++ ++int clone_pid; ++ ++static int ++clone_fn (void *unused) ++{ ++ return 0; ++} ++ ++void * ++thread_fn (void *arg) ++{ ++ unsigned char *stack; ++ int res; ++ ++ stack = malloc (STACK_SIZE); ++ assert (stack != NULL); ++ ++#ifdef __ia64__ ++ clone_pid = __clone2 (clone_fn, stack, STACK_SIZE, CLONE_VM, NULL); ++#else ++ clone_pid = clone (clone_fn, stack + STACK_SIZE, CLONE_VM, NULL); ++#endif ++ ++ assert (clone_pid > 0); ++ ++ /* Wait for child. */ ++ res = waitpid (clone_pid, NULL, __WCLONE); ++ assert (res != -1); ++ ++ return NULL; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ pthread_t child; ++ ++ alarm (300); ++ ++ pthread_create (&child, NULL, thread_fn, NULL); ++ pthread_join (child, NULL); ++ ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.threads/clone-thread_db.exp +@@ -0,0 +1,44 @@ ++# This testcase is part of GDB, the GNU debugger. ++ ++# Copyright 2015 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 3 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, see . ++ ++# This only works on targets with the Linux kernel. ++if ![istarget *-*-linux*] { ++ return ++} ++ ++set testfile "clone-thread_db" ++set srcfile ${testfile}.c ++set binfile ${objdir}/${subdir}/${testfile} ++ ++if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { ++ untested $testfile.exp ++ return -1 ++} ++ ++gdb_start ++gdb_reinitialize_dir $srcdir/$subdir ++gdb_load ${binfile} ++ ++if ![runto_main] { ++ untested "could not run to main" ++ return -1 ++} ++ ++gdb_test "break clone_fn" "Breakpoint.*at.*file.*$srcfile.*line.*" ++gdb_test "continue" "clone_fn .* at .*" "continue to clone_fn" ++ ++gdb_test "continue" "exited normally.*" "continue to end" diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-1of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-1of7.patch new file mode 100644 index 0000000..cd55b33 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-1of7.patch @@ -0,0 +1,418 @@ + Date: Mon, 15 Apr 2013 11:04:10 -0700 + Message-ID: + Subject: Re: [RFA] Fix solib-precsave.exp,solib-reverse.exp + From: Doug Evans + To: Pedro Alves + Cc: gdb-patches + + On Mon, Apr 15, 2013 at 10:33 AM, Pedro Alves wrote: + > On 04/13/2013 12:13 AM, Doug Evans wrote: + >> Hi. + >> + >> These two tests are failing for me. + >> They make the assumption that debug info for libc isn't installed. + >> + >> To fix this I've created a library of wrappers for the affected libc + >> functions and compiled it without debug info. + >> + >> Ok to check in? + > + > This the certainly the right idea for fixing the problem, but it took me a + > while to realize that the fact that the functions currently called are + > printf and sleep, and that the new library has wrappers for those has no + > importance. They really are just used as proxy for "functions in library + > with no debug info". Not even the output of printf is used. I think that + > calling the library a syscall wrapper makes it prone to causing such doubt + > and confusion in other readers (of either the patch or the resulting code + > in the tree), as it has caused me. + > + > How about we just call it "shr1", and have it export some non-libc related + > functions like e.g., "shr1_foo" and "shr1_bar"? + + Blech. That's how I originally had it. + The original code used printf and sleep and I figured someone would + want to keep them. + I don't have a preference for either way. Anyone else? + In any case we need to document that one cannot call libc functions + (or similar) as is. + + >> int main () + >> @@ -27,16 +31,25 @@ int main () + >> char* cptr = "String 1"; + >> int b[2] = {5,8}; + >> + >> + /* Call these functions once before we start testing so that they get + >> + resolved by the dynamic loader. If the system has debug info for + >> + the dynamic loader installed, reverse-stepping for the first call + >> + will otherwise record being in the dynamic loader, which is not what + > + > reverse-stepping doesn't record. Did you mean "report", or even + > "reverse-stepping the first call will otherwise stop in the + > dynamic loader", perhaps? + + Yeah. + +commit c2a96e8cafeeda6132399e9ea94dafad6366ccc5 +Author: Doug Evans +Date: Mon May 6 22:07:13 2013 +0000 + + * gdb.reverse/shr.h: New file. + * gdb.reverse/shr1.c: New file. + * gdb.reverse/shr2.c: #include "shr.h". + * gdb.reverse/solib-reverse.c: Remove #include . + #include "shr.h". Replace calls to printf,sleep to call shr1 instead. + * gdb.reverse/solib-precsave.exp: Build shr2.sl. + Update tests using sleep/printf to use shr2.sl instead. + * gdb.reverse/solib-reverse.exp: Ditt.o + +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/shr1.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/shr1.c +@@ -0,0 +1,24 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2013 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 3 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, see . */ ++ ++#include "shr.h" ++ ++void ++shr1 (const char *s) ++{ ++ /* nothing to do */ ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/shr2.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.reverse/shr2.c ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/shr2.c +@@ -15,6 +15,8 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + ++#include "shr.h" ++ + #ifdef PROTOTYPES + int shr2(int x) + #else +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/shr.h +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/shr.h +@@ -0,0 +1,24 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2013 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 3 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, see . */ ++ ++#ifndef GDB_REVERSE_SHR_H ++#define GDB_REVERSE_SHR_H ++ ++extern void shr1 (const char *); ++extern int shr2 (int); ++ ++#endif /* GDB_REVERSE_SHR_H */ +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-precsave.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.reverse/solib-precsave.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-precsave.exp +@@ -26,20 +26,30 @@ if {[skip_shlib_tests]} { + + standard_testfile solib-reverse.c + set precsave [standard_output_file solib.precsave] +-set libfile "shr2" +-set libsrc ${libfile}.c +-set library [standard_output_file ${libfile}.sl] ++set lib1file "shr1" ++set lib1src ${lib1file}.c ++set library1 [standard_output_file ${lib1file}.sl] ++set lib2file "shr2" ++set lib2src ${lib2file}.c ++set library2 [standard_output_file ${lib2file}.sl] + + if [get_compiler_info] { + return -1 + } + +-if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} "debug"] != "" } { +- untested "Could not compile shared library." ++# Compile the first without debug info so that ++# stepping and reverse stepping doesn't end up inside them. ++if { [gdb_compile_shlib ${srcdir}/${subdir}/${lib1src} ${library1} ""] != "" } { ++ untested "Could not compile shared library1." + return -1 + } + +-set exec_opts [list debug shlib=${library}] ++if { [gdb_compile_shlib ${srcdir}/${subdir}/${lib2src} ${library2} "debug"] != "" } { ++ untested "Could not compile shared library2." ++ return -1 ++} ++ ++set exec_opts [list debug shlib=${library1} shlib=${library2}] + + # Attempt to prevent -Wl,-z,relro which may happen by default with some + # toolchain configurations. Due to PR corefiles/11804 GDB will then produce +@@ -57,12 +67,17 @@ if { [gdb_compile ${srcdir}/${subdir}/${ + gdb_exit + gdb_start + +-# Clear it to never find any separate system debug infos. +-gdb_test_no_output "set debug-file-directory" ++# Note: The test previously did "set debug-file-directory" to (try to) ++# ensure the debug info for the dynamic loader and libc weren't found. ++# This doesn't work if the debug info is in the .debug subdirectory. ++# Avoiding debug info for system libraries is not germaine to this test ++# and is no longer attempted. Instead, the test does not make assumptions ++# about whether the debug info is present or not. + + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} +-gdb_load_shlibs $library ++gdb_load_shlibs $library1 ++gdb_load_shlibs $library2 + + runto main + +@@ -99,15 +114,10 @@ set end_part_one [gdb_get_line_number " + set end_part_two [gdb_get_line_number " end part two" "$srcfile"] + gdb_test "until $end_part_one" " end part one.*" "run until end part one" + +-gdb_test "reverse-step" " sleep three .*" "reverse-step third sleep" +-gdb_test "reverse-step" " sleep two .*" "reverse-step second sleep" +-gdb_test "reverse-step" " sleep one .*" \ +- "reverse-step first sleep, dynsym resolve" +- +-gdb_test "reverse-step" " printf three .*" "reverse-step third printf" +-gdb_test "reverse-step" " printf two .*" "reverse-step second printf" +-gdb_test "reverse-step" " printf one .*" \ +- "reverse-step first printf, dynsym resolve" ++gdb_test "reverse-step" " shr1 three .*" "reverse-step third shr1" ++gdb_test "reverse-step" " shr1 two .*" "reverse-step second shr1" ++gdb_test "reverse-step" " shr1 one .*" "reverse-step first shr1" ++ + gdb_test "reverse-step" " generic statement.*" "reverse-step generic" + + +@@ -119,15 +129,10 @@ gdb_test "reverse-step" " generic statem + + gdb_test "until $end_part_one" " end part one.*" "forward to end part one" + +-gdb_test "reverse-next" " sleep three .*" "reverse-next third sleep" +-gdb_test "reverse-next" " sleep two .*" "reverse-next second sleep" +-gdb_test "reverse-next" " sleep one .*" \ +- "reverse-next first sleep, dynsym resolve" +- +-gdb_test "reverse-next" " printf three .*" "reverse-next third printf" +-gdb_test "reverse-next" " printf two .*" "reverse-next second printf" +-gdb_test "reverse-next" " printf one .*" \ +- "reverse-next first printf, dynsym resolve" ++gdb_test "reverse-next" " shr1 three .*" "reverse-next third shr1" ++gdb_test "reverse-next" " shr1 two .*" "reverse-next second shr1" ++gdb_test "reverse-next" " shr1 one .*" "reverse-next first shr1" ++ + gdb_test "reverse-next" " generic statement.*" "reverse-next generic" + + +@@ -135,11 +140,11 @@ gdb_test "reverse-next" " generic statem + # Test reverse-step into debuggable solib function + # + +-gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function one" ++gdb_test "reverse-step" "${lib2src}.*" "reverse-step into solib function one" + gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function one" + gdb_test "reverse-step" " middle part two.*" "reverse-step back to main one" + +-gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function two" ++gdb_test "reverse-step" "${lib2src}.*" "reverse-step into solib function two" + gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function two" + gdb_test "reverse-step" " begin part two.*" "reverse-step back to main two" + +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-reverse.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.reverse/solib-reverse.c ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-reverse.c +@@ -15,28 +15,33 @@ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +-/* Test reverse debugging of shared libraries. */ ++/* Test reverse debugging of shared libraries. + +-#include ++ N.B. Do not call system routines here, we don't want to have to deal with ++ whether or not there is debug info present for them. */ + +-/* Shared library function */ +-extern int shr2(int); ++#include "shr.h" + + int main () + { + char* cptr = "String 1"; + int b[2] = {5,8}; + ++ /* Call these functions once before we start testing so that they get ++ resolved by the dynamic loader. If the system has debug info for ++ the dynamic loader installed, reverse-stepping for the first call ++ will otherwise stop in the dynamic loader, which is not what we want. */ ++ shr1 (""); ++ shr2 (0); ++ + b[0] = shr2(12); /* begin part two */ + b[1] = shr2(17); /* middle part two */ + + b[0] = 6; b[1] = 9; /* generic statement, end part two */ +- printf ("message 1\n"); /* printf one */ +- printf ("message 2\n"); /* printf two */ +- printf ("message 3\n"); /* printf three */ +- sleep (0); /* sleep one */ +- sleep (0); /* sleep two */ +- sleep (0); /* sleep three */ ++ ++ shr1 ("message 1\n"); /* shr1 one */ ++ shr1 ("message 2\n"); /* shr1 two */ ++ shr1 ("message 3\n"); /* shr1 three */ + + return 0; /* end part one */ + } /* end of main */ +Index: gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-reverse.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.reverse/solib-reverse.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.reverse/solib-reverse.exp +@@ -24,20 +24,30 @@ if {[skip_shlib_tests]} { + } + + standard_testfile +-set libfile "shr2" +-set libsrc ${libfile}.c +-set library [standard_output_file ${libfile}.sl] ++set lib1file "shr1" ++set lib1src ${lib1file}.c ++set library1 [standard_output_file ${lib1file}.sl] ++set lib2file "shr2" ++set lib2src ${lib2file}.c ++set library2 [standard_output_file ${lib2file}.sl] + + if [get_compiler_info] { + return -1 + } + +-if { [gdb_compile_shlib ${srcdir}/${subdir}/${libsrc} ${library} "debug"] != "" } { +- untested "Could not compile shared library." ++# Compile the first without debug info so that ++# stepping and reverse stepping doesn't end up inside them. ++if { [gdb_compile_shlib ${srcdir}/${subdir}/${lib1src} ${library1} ""] != "" } { ++ untested "Could not compile shared library1." + return -1 + } + +-set exec_opts [list debug shlib=${library}] ++if { [gdb_compile_shlib ${srcdir}/${subdir}/${lib2src} ${library2} "debug"] != "" } { ++ untested "Could not compile shared library2." ++ return -1 ++} ++ ++set exec_opts [list debug shlib=${library1} shlib=${library2}] + + if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile} executable $exec_opts] != "" } { + untested "Could not compile $binfile." +@@ -49,12 +59,17 @@ if { [gdb_compile ${srcdir}/${subdir}/${ + gdb_exit + gdb_start + +-# Clear it to never find any separate system debug infos. +-gdb_test_no_output "set debug-file-directory" ++# Note: The test previously did "set debug-file-directory" to (try to) ++# ensure the debug info for the dynamic loader and libc weren't found. ++# This doesn't work if the debug info is in the .debug subdirectory. ++# Avoiding debug info for system libraries is not germaine to this test ++# and is no longer attempted. Instead, the test does not make assumptions ++# about whether the debug info is present or not. + + gdb_reinitialize_dir $srcdir/$subdir + gdb_load ${binfile} +-gdb_load_shlibs $library ++gdb_load_shlibs $library1 ++gdb_load_shlibs $library2 + + runto main + +@@ -73,15 +88,10 @@ set end_part_one [gdb_get_line_number " + set end_part_two [gdb_get_line_number " end part two" "$srcfile"] + gdb_test "until $end_part_one" " end part one.*" "run until end part one" + +-gdb_test "reverse-step" " sleep three .*" "reverse-step third sleep" +-gdb_test "reverse-step" " sleep two .*" "reverse-step second sleep" +-gdb_test "reverse-step" " sleep one .*" \ +- "reverse-step first sleep, dynsym resolve" +- +-gdb_test "reverse-step" " printf three .*" "reverse-step third printf" +-gdb_test "reverse-step" " printf two .*" "reverse-step second printf" +-gdb_test "reverse-step" " printf one .*" \ +- "reverse-step first printf, dynsym resolve" ++gdb_test "reverse-step" " shr1 three .*" "reverse-step third shr1" ++gdb_test "reverse-step" " shr1 two .*" "reverse-step second shr1" ++gdb_test "reverse-step" " shr1 one .*" "reverse-step first shr1" ++ + gdb_test "reverse-step" " generic statement.*" "reverse-step generic" + + +@@ -93,15 +103,10 @@ gdb_test "reverse-step" " generic statem + + gdb_test "until $end_part_one" " end part one.*" "forward to end part one" + +-gdb_test "reverse-next" " sleep three .*" "reverse-next third sleep" +-gdb_test "reverse-next" " sleep two .*" "reverse-next second sleep" +-gdb_test "reverse-next" " sleep one .*" \ +- "reverse-next first sleep, dynsym resolve" +- +-gdb_test "reverse-next" " printf three .*" "reverse-next third printf" +-gdb_test "reverse-next" " printf two .*" "reverse-next second printf" +-gdb_test "reverse-next" " printf one .*" \ +- "reverse-next first printf, dynsym resolve" ++gdb_test "reverse-next" " shr1 three .*" "reverse-next third shr1" ++gdb_test "reverse-next" " shr1 two .*" "reverse-next second shr1" ++gdb_test "reverse-next" " shr1 one .*" "reverse-next first shr1" ++ + gdb_test "reverse-next" " generic statement.*" "reverse-next generic" + + +@@ -109,11 +114,11 @@ gdb_test "reverse-next" " generic statem + # Test reverse-step into debuggable solib function + # + +-gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function one" ++gdb_test "reverse-step" "${lib2src}.*" "reverse-step into solib function one" + gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function one" + gdb_test "reverse-step" " middle part two.*" "reverse-step back to main one" + +-gdb_test "reverse-step" "${libsrc}.*" "reverse-step into solib function two" ++gdb_test "reverse-step" "${lib2src}.*" "reverse-step into solib function two" + gdb_test "reverse-step" "return 2.x.*" "reverse-step within solib function two" + gdb_test "reverse-step" " begin part two.*" "reverse-step back to main two" + diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-2of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-2of7.patch new file mode 100644 index 0000000..0ef08f3 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-2of7.patch @@ -0,0 +1,459 @@ + NOTE: The testcase part of this patch has been removed. + +commit 5ce0145de764dc9c6e92daf2f843fa6e496c49d0 +Author: Pedro Alves +Date: Tue Dec 17 20:47:36 2013 +0000 + + "tfind" across unavailable-stack frames. + + Like when stepping, the current stack frame location is expected to be + printed as result of tfind command, if that results in moving to a + different function. In tfind_1 we see: + + if (from_tty + && (has_stack_frames () || traceframe_number >= 0)) + { + enum print_what print_what; + + /* NOTE: in imitation of the step command, try to determine + whether we have made a transition from one function to + another. If so, we'll print the "stack frame" (ie. the new + function and it's arguments) -- otherwise we'll just show the + new source line. */ + + if (frame_id_eq (old_frame_id, + get_frame_id (get_current_frame ()))) + print_what = SRC_LINE; + else + print_what = SRC_AND_LOC; + + print_stack_frame (get_selected_frame (NULL), 1, print_what, 1); + do_displays (); + } + + However, when we haven't collected any registers in the tracepoint + (collect $regs), that doesn't actually work: + + (gdb) tstart + (gdb) info tracepoints + Num Type Disp Enb Address What + 1 tracepoint keep y 0x080483b7 in func0 + at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28 + collect testload + installed on target + 2 tracepoint keep y 0x080483bc in func1 + at ../.././../git/gdb/testsuite/gdb.trace/circ.c:32 + collect testload + installed on target + (gdb) c + Continuing. + + Breakpoint 3, end () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:72 + 72 } + (gdb) tstop + (gdb) tfind start + Found trace frame 0, tracepoint 1 + #0 func0 () at ../.././../git/gdb/testsuite/gdb.trace/circ.c:28 + 28 } + (gdb) tfind + Found trace frame 1, tracepoint 2 + 32 } + (gdb) + + When we don't have info about the stack available + (UNWIND_UNAVAILABLE), frames end up with outer_frame_id as frame ID. + And in the scenario above, the issue is that both frames before and + after the second tfind (the frames for func0 an func1) have the same + id (outer_frame_id), so the frame_id_eq check returns false, even + though the frames were of different functions. GDB knows that, + because the PC is inferred from the tracepoint's address, even if no + registers were collected. + + To fix this, this patch adds support for frame ids with a valid code + address, but stack address, and then makes the unwinders + use that instead of the catch-all outer_frame_id for such frames. The + frame_id_eq check in tfind_1 then automatically does the right thing + as expected. + + I tested with --directory=gdb.trace/ , before/after the patch, and + compared the resulting gdb.logs, then adjusted the tests to expect the + extra output that came out. Turns out that was only circ.exp, the + original test that actually brought this issue to light. + + Tested on x86_64 Fedora 17, native and gdbserver. + + gdb/ + 2013-12-17 Pedro Alves + + * frame.h (enum frame_id_stack_status): New enum. + (struct frame_id) : Adjust comment. + : Delete field, replaced with ... + : ... this new field. + (frame_id_build_unavailable_stack): Declare. + * frame.c (frame_addr_hash, fprint_field, outer_frame_id) + (frame_id_build_special): Adjust. + (frame_id_build_unavailable_stack): New function. + (frame_id_build, frame_id_build_wild): Adjust. + (frame_id_p, frame_id_eq, frame_id_inner): Adjust to take into + account frames with unavailable stack. + + * amd64-tdep.c (amd64_frame_this_id) + (amd64_sigtramp_frame_this_id, amd64_epilogue_frame_this_id): Use + frame_id_build_unavailable_stack. + * dwarf2-frame.c (dwarf2_frame_this_id): Likewise. + * i386-tdep.c (i386_frame_this_id, i386_epilogue_frame_this_id) + (i386_sigtramp_frame_this_id): Likewise. + + gdb/testsuite/ + 2013-12-17 Pedro Alves + + * gdb.trace/circ.exp: Expect frame info to be printed when + switching between frames with unavailable stack, but different + functions. + +Index: gdb-7.6.1/gdb/amd64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/amd64-tdep.c ++++ gdb-7.6.1/gdb/amd64-tdep.c +@@ -2403,15 +2403,16 @@ amd64_frame_this_id (struct frame_info * + struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (this_frame)); + + if (!cache->base_p) +- return; +- +- /* 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 (this_frame)) +- return; ++ (*this_id) = frame_id_build_unavailable_stack (cache->pc); ++ else if (cache->base == 0) ++ { ++ /* This marks the outermost frame. */ ++ return; ++ } ++ else ++ /* Detect OS dependent outermost frames; such as `clone'. */ ++ if (tdep->outermost_frame_p && tdep->outermost_frame_p (this_frame)) ++ return; + + (*this_id) = frame_id_build (cache->base + 16, cache->pc); + } +@@ -2528,9 +2529,14 @@ amd64_sigtramp_frame_this_id (struct fra + amd64_sigtramp_frame_cache (this_frame, this_cache); + + if (!cache->base_p) +- return; +- +- (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame)); ++ (*this_id) = frame_id_build_unavailable_stack (get_frame_pc (this_frame)); ++ else if (cache->base == 0) ++ { ++ /* This marks the outermost frame. */ ++ return; ++ } ++ else ++ (*this_id) = frame_id_build (cache->base + 16, get_frame_pc (this_frame)); + } + + static struct value * +@@ -2699,9 +2705,9 @@ amd64_epilogue_frame_this_id (struct fra + this_cache); + + if (!cache->base_p) +- return; +- +- (*this_id) = frame_id_build (cache->base + 8, cache->pc); ++ (*this_id) = frame_id_build_unavailable_stack (cache->pc); ++ else ++ (*this_id) = frame_id_build (cache->base + 8, cache->pc); + } + + static const struct frame_unwind amd64_epilogue_frame_unwind = +Index: gdb-7.6.1/gdb/dwarf2-frame.c +=================================================================== +--- gdb-7.6.1.orig/gdb/dwarf2-frame.c ++++ gdb-7.6.1/gdb/dwarf2-frame.c +@@ -1265,12 +1265,11 @@ dwarf2_frame_this_id (struct frame_info + dwarf2_frame_cache (this_frame, this_cache); + + if (cache->unavailable_retaddr) ++ (*this_id) = frame_id_build_unavailable_stack (get_frame_func (this_frame)); ++ else if (cache->undefined_retaddr) + return; +- +- if (cache->undefined_retaddr) +- return; +- +- (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); ++ else ++ (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); + } + + static struct value * +Index: gdb-7.6.1/gdb/frame.c +=================================================================== +--- gdb-7.6.1.orig/gdb/frame.c ++++ gdb-7.6.1/gdb/frame.c +@@ -147,10 +147,11 @@ frame_addr_hash (const void *ap) + const struct frame_id f_id = frame->this_id.value; + hashval_t hash = 0; + +- gdb_assert (f_id.stack_addr_p || f_id.code_addr_p ++ gdb_assert (f_id.stack_status != FID_STACK_INVALID ++ || f_id.code_addr_p + || f_id.special_addr_p); + +- if (f_id.stack_addr_p) ++ if (f_id.stack_status == FID_STACK_VALID) + hash = iterative_hash (&f_id.stack_addr, + sizeof (f_id.stack_addr), hash); + if (f_id.code_addr_p) +@@ -290,13 +291,23 @@ void + fprint_frame_id (struct ui_file *file, struct frame_id id) + { + fprintf_unfiltered (file, "{"); +- fprint_field (file, "stack", id.stack_addr_p, id.stack_addr); ++ ++ if (id.stack_status == FID_STACK_INVALID) ++ fprintf_unfiltered (file, "!stack"); ++ else if (id.stack_status == FID_STACK_UNAVAILABLE) ++ fprintf_unfiltered (file, "stack="); ++ else ++ fprintf_unfiltered (file, "stack=%s", hex_string (id.stack_addr)); + fprintf_unfiltered (file, ","); ++ + fprint_field (file, "code", id.code_addr_p, id.code_addr); + fprintf_unfiltered (file, ","); ++ + fprint_field (file, "special", id.special_addr_p, id.special_addr); ++ + if (id.artificial_depth) + fprintf_unfiltered (file, ",artificial=%d", id.artificial_depth); ++ + fprintf_unfiltered (file, "}"); + } + +@@ -446,7 +457,7 @@ frame_unwind_caller_id (struct frame_inf + } + + const struct frame_id null_frame_id; /* All zeros. */ +-const struct frame_id outer_frame_id = { 0, 0, 0, 0, 0, 1, 0 }; ++const struct frame_id outer_frame_id = { 0, 0, 0, FID_STACK_INVALID, 0, 1, 0 }; + + struct frame_id + frame_id_build_special (CORE_ADDR stack_addr, CORE_ADDR code_addr, +@@ -455,7 +466,7 @@ frame_id_build_special (CORE_ADDR stack_ + struct frame_id id = null_frame_id; + + id.stack_addr = stack_addr; +- id.stack_addr_p = 1; ++ id.stack_status = FID_STACK_VALID; + id.code_addr = code_addr; + id.code_addr_p = 1; + id.special_addr = special_addr; +@@ -463,13 +474,26 @@ frame_id_build_special (CORE_ADDR stack_ + return id; + } + ++/* See frame.h. */ ++ ++struct frame_id ++frame_id_build_unavailable_stack (CORE_ADDR code_addr) ++{ ++ struct frame_id id = null_frame_id; ++ ++ id.stack_status = FID_STACK_UNAVAILABLE; ++ id.code_addr = code_addr; ++ id.code_addr_p = 1; ++ return id; ++} ++ + struct frame_id + frame_id_build (CORE_ADDR stack_addr, CORE_ADDR code_addr) + { + struct frame_id id = null_frame_id; + + id.stack_addr = stack_addr; +- id.stack_addr_p = 1; ++ id.stack_status = FID_STACK_VALID; + id.code_addr = code_addr; + id.code_addr_p = 1; + return id; +@@ -481,7 +505,7 @@ frame_id_build_wild (CORE_ADDR stack_add + struct frame_id id = null_frame_id; + + id.stack_addr = stack_addr; +- id.stack_addr_p = 1; ++ id.stack_status = FID_STACK_VALID; + return id; + } + +@@ -491,7 +515,7 @@ frame_id_p (struct frame_id l) + int p; + + /* The frame is valid iff it has a valid stack address. */ +- p = l.stack_addr_p; ++ p = l.stack_status != FID_STACK_INVALID; + /* outer_frame_id is also valid. */ + if (!p && memcmp (&l, &outer_frame_id, sizeof (l)) == 0) + p = 1; +@@ -518,19 +542,20 @@ frame_id_eq (struct frame_id l, struct f + { + int eq; + +- if (!l.stack_addr_p && l.special_addr_p +- && !r.stack_addr_p && r.special_addr_p) ++ if (l.stack_status == FID_STACK_INVALID && l.special_addr_p ++ && r.stack_status == FID_STACK_INVALID && r.special_addr_p) + /* The outermost frame marker is equal to itself. This is the + dodgy thing about outer_frame_id, since between execution steps + we might step into another function - from which we can't + unwind either. More thought required to get rid of + outer_frame_id. */ + eq = 1; +- else if (!l.stack_addr_p || !r.stack_addr_p) ++ else if (l.stack_status == FID_STACK_INVALID ++ || r.stack_status == FID_STACK_INVALID) + /* Like a NaN, if either ID is invalid, the result is false. + Note that a frame ID is invalid iff it is the null frame ID. */ + eq = 0; +- else if (l.stack_addr != r.stack_addr) ++ else if (l.stack_status != r.stack_status || l.stack_addr != r.stack_addr) + /* If .stack addresses are different, the frames are different. */ + eq = 0; + else if (l.code_addr_p && r.code_addr_p && l.code_addr != r.code_addr) +@@ -597,8 +622,9 @@ frame_id_inner (struct gdbarch *gdbarch, + { + int inner; + +- if (!l.stack_addr_p || !r.stack_addr_p) +- /* Like NaN, any operation involving an invalid ID always fails. */ ++ if (l.stack_status != FID_STACK_VALID || r.stack_status != FID_STACK_VALID) ++ /* Like NaN, any operation involving an invalid ID always fails. ++ Likewise if either ID has an unavailable stack address. */ + inner = 0; + else if (l.artificial_depth > r.artificial_depth + && l.stack_addr == r.stack_addr +Index: gdb-7.6.1/gdb/frame.h +=================================================================== +--- gdb-7.6.1.orig/gdb/frame.h ++++ gdb-7.6.1/gdb/frame.h +@@ -76,6 +76,23 @@ struct block; + struct gdbarch; + struct ui_file; + ++/* Status of a given frame's stack. */ ++ ++enum frame_id_stack_status ++{ ++ /* Stack address is invalid. E.g., this frame is the outermost ++ (i.e., _start), and the stack hasn't been setup yet. */ ++ FID_STACK_INVALID = 0, ++ ++ /* Stack address is valid, and is found in the stack_addr field. */ ++ FID_STACK_VALID = 1, ++ ++ /* Stack address is unavailable. I.e., there's a valid stack, but ++ we don't know where it is (because memory or registers we'd ++ compute it from were not collected). */ ++ FID_STACK_UNAVAILABLE = -1 ++}; ++ + /* The frame object. */ + + struct frame_info; +@@ -97,8 +114,9 @@ struct frame_id + function pointer register or stack pointer register. They are + wrong. + +- This field is valid only if stack_addr_p is true. Otherwise, this +- frame represents the null frame. */ ++ This field is valid only if frame_id.stack_status is ++ FID_STACK_VALID. It will be 0 for other ++ FID_STACK_... statuses. */ + CORE_ADDR stack_addr; + + /* The frame's code address. This shall be constant through out the +@@ -129,7 +147,7 @@ struct frame_id + CORE_ADDR special_addr; + + /* Flags to indicate the above fields have valid contents. */ +- unsigned int stack_addr_p : 1; ++ ENUM_BITFIELD(frame_id_stack_status) stack_status : 2; + unsigned int code_addr_p : 1; + unsigned int special_addr_p : 1; + +@@ -169,6 +187,12 @@ extern struct frame_id frame_id_build_sp + CORE_ADDR code_addr, + CORE_ADDR special_addr); + ++/* Construct a frame ID representing a frame where the stack address ++ exists, but is unavailable. CODE_ADDR is the frame's constant code ++ address (typically the entry point). The special identifier ++ address is set to indicate a wild card. */ ++extern struct frame_id frame_id_build_unavailable_stack (CORE_ADDR code_addr); ++ + /* Construct a wild card frame ID. The parameter is the frame's constant + stack address (typically the outer-bound). The code address as well + as the special identifier address are set to indicate wild cards. */ +Index: gdb-7.6.1/gdb/i386-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/i386-tdep.c ++++ gdb-7.6.1/gdb/i386-tdep.c +@@ -1846,12 +1846,17 @@ i386_frame_this_id (struct frame_info *t + { + struct i386_frame_cache *cache = i386_frame_cache (this_frame, this_cache); + +- /* This marks the outermost frame. */ +- if (cache->base == 0) +- return; +- +- /* See the end of i386_push_dummy_call. */ +- (*this_id) = frame_id_build (cache->base + 8, cache->pc); ++ if (!cache->base_p) ++ (*this_id) = frame_id_build_unavailable_stack (cache->pc); ++ else if (cache->base == 0) ++ { ++ /* This marks the outermost frame. */ ++ } ++ else ++ { ++ /* See the end of i386_push_dummy_call. */ ++ (*this_id) = frame_id_build (cache->base + 8, cache->pc); ++ } + } + + static enum unwind_stop_reason +@@ -2032,9 +2037,9 @@ i386_epilogue_frame_this_id (struct fram + i386_epilogue_frame_cache (this_frame, this_cache); + + if (!cache->base_p) +- return; +- +- (*this_id) = frame_id_build (cache->base + 8, cache->pc); ++ (*this_id) = frame_id_build_unavailable_stack (cache->pc); ++ else ++ (*this_id) = frame_id_build (cache->base + 8, cache->pc); + } + + static struct value * +@@ -2226,10 +2231,12 @@ i386_sigtramp_frame_this_id (struct fram + i386_sigtramp_frame_cache (this_frame, this_cache); + + if (!cache->base_p) +- return; +- +- /* See the end of i386_push_dummy_call. */ +- (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame)); ++ (*this_id) = frame_id_build_unavailable_stack (get_frame_pc (this_frame)); ++ else ++ { ++ /* See the end of i386_push_dummy_call. */ ++ (*this_id) = frame_id_build (cache->base + 8, get_frame_pc (this_frame)); ++ } + } + + static struct value * diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-3of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-3of7.patch new file mode 100644 index 0000000..3b426d2 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-3of7.patch @@ -0,0 +1,176 @@ + Message-ID: <548343C8.1020109@gmail.com> + Date: Sun, 07 Dec 2014 01:58:32 +0800 + From: Wei-cheng Wang + To: uweigand at de dot ibm dot com, gdb-patches at sourceware dot org + Subject: Re: [PATCH 1/3 v2] Process record support for PowerPC + + 2014-12-06 Wei-cheng Wang + + * rs6000-tdep.c (rs6000_in_function_epilogue_p): Rename to + rs6000_in_function_epilogue_frame_p and add an argument + for frame_info. + (rs6000_epilogue_frame_cache, rs6000_epilogue_frame_this_id, + rs6000_epilogue_frame_prev_register, rs6000_epilogue_frame_sniffer): + New functions. + (rs6000_epilogue_frame_unwind): New. + (rs6000_gdbarch_init): Append epilogue unwinder. + + +commit 2608dbf8a3ee666ac0a7d5d7c45611d489edcda5 +Author: Wei-cheng Wang +Date: Sat Jan 17 14:29:16 2015 +0800 + + Epilogue unwinder for PowerPC. + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -873,14 +873,14 @@ insn_changes_sp_or_jumps (unsigned long + limit for the size of an epilogue. */ + + static int +-rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) ++rs6000_in_function_epilogue_frame_p (struct frame_info *curfrm, ++ struct gdbarch *gdbarch, CORE_ADDR pc) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + bfd_byte insn_buf[PPC_INSN_SIZE]; + CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end; + unsigned long insn; +- struct frame_info *curfrm; + + /* Find the search limits based on function boundaries and hard limit. */ + +@@ -893,8 +893,6 @@ rs6000_in_function_epilogue_p (struct gd + epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE; + if (epilogue_end > func_end) epilogue_end = func_end; + +- curfrm = get_current_frame (); +- + /* Scan forward until next 'blr'. */ + + for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE) +@@ -935,6 +933,15 @@ rs6000_in_function_epilogue_p (struct gd + return 0; + } + ++/* Implementation of gdbarch_in_function_epilogue_p. */ ++ ++static int ++rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) ++{ ++ return rs6000_in_function_epilogue_frame_p (get_current_frame (), ++ gdbarch, pc); ++} ++ + /* Get the ith function argument for the current function. */ + static CORE_ADDR + rs6000_fetch_pointer_argument (struct frame_info *frame, int argi, +@@ -3388,6 +3395,89 @@ static const struct frame_unwind rs6000_ + NULL, + default_frame_sniffer + }; ++ ++static struct rs6000_frame_cache * ++rs6000_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache) ++{ ++ volatile struct gdb_exception ex; ++ struct rs6000_frame_cache *cache; ++ struct gdbarch *gdbarch = get_frame_arch (this_frame); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ CORE_ADDR sp; ++ ++ if (*this_cache) ++ return *this_cache; ++ ++ cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache); ++ (*this_cache) = cache; ++ cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); ++ ++ TRY_CATCH (ex, RETURN_MASK_ERROR) ++ { ++ /* At this point the stack looks as if we just entered the ++ function, and the return address is stored in LR. */ ++ CORE_ADDR sp, lr; ++ ++ sp = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); ++ lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum); ++ ++ cache->base = sp; ++ cache->initial_sp = sp; ++ ++ trad_frame_set_value (cache->saved_regs, ++ gdbarch_pc_regnum (gdbarch), lr); ++ } ++ if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR) ++ throw_exception (ex); ++ ++ return cache; ++} ++ ++static void ++rs6000_epilogue_frame_this_id (struct frame_info *this_frame, ++ void **this_cache, struct frame_id *this_id) ++{ ++ CORE_ADDR pc; ++ struct rs6000_frame_cache *info = ++ rs6000_epilogue_frame_cache (this_frame, this_cache); ++ ++ pc = get_frame_func (this_frame); ++ if (info->base == 0) ++ (*this_id) = frame_id_build_unavailable_stack (pc); ++ else ++ (*this_id) = frame_id_build (info->base, pc); ++} ++ ++static struct value * ++rs6000_epilogue_frame_prev_register (struct frame_info *this_frame, ++ void **this_cache, int regnum) ++{ ++ struct rs6000_frame_cache *info = ++ rs6000_epilogue_frame_cache (this_frame, this_cache); ++ return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); ++} ++ ++static int ++rs6000_epilogue_frame_sniffer (const struct frame_unwind *self, ++ struct frame_info *this_frame, ++ void **this_prologue_cache) ++{ ++ if (frame_relative_level (this_frame) == 0) ++ return rs6000_in_function_epilogue_frame_p (this_frame, ++ get_frame_arch (this_frame), ++ get_frame_pc (this_frame)); ++ else ++ return 0; ++} ++ ++static const struct frame_unwind rs6000_epilogue_frame_unwind = ++{ ++ NORMAL_FRAME, ++ default_frame_unwind_stop_reason, ++ rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register, ++ NULL, ++ rs6000_epilogue_frame_sniffer ++}; + + + static CORE_ADDR +@@ -4207,6 +4297,7 @@ rs6000_gdbarch_init (struct gdbarch_info + case GDB_OSABI_NETBSD_ELF: + case GDB_OSABI_UNKNOWN: + set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); ++ frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); + set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id); + frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); +@@ -4215,6 +4306,7 @@ rs6000_gdbarch_init (struct gdbarch_info + set_gdbarch_believe_pcc_promotion (gdbarch, 1); + + set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); ++ frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); + set_gdbarch_dummy_id (gdbarch, rs6000_dummy_id); + frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-4of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-4of7.patch new file mode 100644 index 0000000..c65490b --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-4of7.patch @@ -0,0 +1,2248 @@ + Message-ID: <549C48EA.9060206@gmail.com> + Date: Fri, 26 Dec 2014 01:27:06 +0800 + From: Wei-cheng Wang + To: Ulrich Weigand + CC: gdb-patches at sourceware dot org + Subject: Re: [PATCH 2/3 v4] Process record support for PowerPC + + On 12/18/2014 2:41 AM, Ulrich Weigand wrote: + > you seem to have removed all the 32-bit struct sizes here. Your last + > iteration had different values for many of those structs for wordsize 4 + > vs. wordsize 8, and I think we need to keep them. + + Oops, this is a mistake. I'm sorry. + Fixed now :) + + Thanks, + Wei-cheng + + -- + + 2014-12-06 Wei-cheng Wang + Ulrich Weigand + + * configure.tgt (powerpc*-*-linux): Add linux-record.o to + gdb_target_obs. + (ppc_linux_record_tdep, ppc64_linux_record_tdep): New for linux syscall + record. + (ppc_canonicalize_syscall, ppc_linux_syscall_record, + ppc_linux_record_signal, ppc_init_linux_record_tdep): New functions. + (ppc_linux_init_abi): Set process_record, process_record_signal. + * ppc-tdep.h (struct gdbarch_tdep): Add ppc_syscall_record and + ppc_linux_record_tdep to gdbarch_tdep. + (ppc_process_record): New declaration. + * rs6000-tdep.c (ppc_record_vsr, ppc_process_record_op4, + ppc_process_record_op19, ppc_process_record_op31, + ppc_process_record_op59, ppc_process_record_op60, + ppc_process_record_op63, ppc_process_record): New functions. + + changelog for testsuite + + 2014-12-06 Wei-cheng Wang + + * lib/gdb.exp (supports_process_record): Return true for + powerpc*-*-linux*. + (supports_reverse): Likewise. + + +commit b4cdae6fe51e532e0b1069c6960b14a610182d14 +Author: Wei-cheng Wang +Date: Sat Jan 17 14:30:33 2015 +0800 + + Reverse debugging for PowerPC. + +Index: gdb-7.6.1/gdb/configure.tgt +=================================================================== +--- gdb-7.6.1.orig/gdb/configure.tgt ++++ gdb-7.6.1/gdb/configure.tgt +@@ -428,7 +428,8 @@ powerpc*-*-linux*) + ppc64-tdep.o solib-svr4.o solib-spu.o \ + spu-multiarch.o \ + glibc-tdep.o symfile-mem.o linux-tdep.o \ +- ravenscar-thread.o ppc-ravenscar-thread.o" ++ ravenscar-thread.o ppc-ravenscar-thread.o \ ++ linux-record.o " + gdb_sim=../sim/ppc/libsim.a + build_gdbserver=yes + ;; +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -50,6 +50,8 @@ + #include "spu-tdep.h" + #include "xml-syscall.h" + #include "linux-tdep.h" ++#include "linux-record.h" ++#include "record-full.h" + + #include "stap-probe.h" + #include "ax.h" +@@ -812,6 +814,167 @@ ppc_linux_get_syscall_number (struct gdb + return ret; + } + ++/* PPC process record-replay */ ++ ++static struct linux_record_tdep ppc_linux_record_tdep; ++static struct linux_record_tdep ppc64_linux_record_tdep; ++ ++static enum gdb_syscall ++ppc_canonicalize_syscall (int syscall) ++{ ++ /* See arch/powerpc/include/uapi/asm/unistd.h */ ++ ++ if (syscall <= 165) ++ return syscall; ++ else if (syscall >= 167 && syscall <= 190) /* Skip query_module 166 */ ++ return syscall + 1; ++ else if (syscall >= 192 && syscall <= 197) /* mmap2 */ ++ return syscall; ++ else if (syscall == 208) /* tkill */ ++ return gdb_sys_tkill; ++ else if (syscall >= 207 && syscall <= 220) /* gettid */ ++ return syscall + 224 - 207; ++ else if (syscall >= 234 && syscall <= 239) /* exit_group */ ++ return syscall + 252 - 234; ++ else if (syscall >= 240 && syscall <=248) /* timer_create */ ++ return syscall += 259 - 240; ++ else if (syscall >= 250 && syscall <=251) /* tgkill */ ++ return syscall + 270 - 250; ++ else if (syscall == 336) ++ return gdb_sys_recv; ++ else if (syscall == 337) ++ return gdb_sys_recvfrom; ++ else if (syscall == 342) ++ return gdb_sys_recvmsg; ++ return -1; ++} ++ ++static int ++ppc_linux_syscall_record (struct regcache *regcache) ++{ ++ struct gdbarch *gdbarch = get_regcache_arch (regcache); ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ ULONGEST scnum; ++ enum gdb_syscall syscall_gdb; ++ int ret; ++ int i; ++ ++ regcache_raw_read_unsigned (regcache, tdep->ppc_gp0_regnum, &scnum); ++ syscall_gdb = ppc_canonicalize_syscall (scnum); ++ ++ if (syscall_gdb < 0) ++ { ++ printf_unfiltered (_("Process record and replay target doesn't " ++ "support syscall number %d\n"), (int) scnum); ++ return 0; ++ } ++ ++ if (syscall_gdb == gdb_sys_sigreturn ++ || syscall_gdb == gdb_sys_rt_sigreturn) ++ { ++ int i, j; ++ int regsets[] = { tdep->ppc_gp0_regnum, ++ tdep->ppc_fp0_regnum, ++ tdep->ppc_vr0_regnum, ++ tdep->ppc_vsr0_upper_regnum }; ++ ++ for (j = 0; j < 4; j++) ++ { ++ if (regsets[j] == -1) ++ continue; ++ for (i = 0; i < 32; i++) ++ { ++ if (record_full_arch_list_add_reg (regcache, regsets[j] + i)) ++ return -1; ++ } ++ } ++ ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum)) ++ return -1; ++ ++ return 0; ++ } ++ ++ if (tdep->wordsize == 8) ++ ret = record_linux_system_call (syscall_gdb, regcache, ++ &ppc64_linux_record_tdep); ++ else ++ ret = record_linux_system_call (syscall_gdb, regcache, ++ &ppc_linux_record_tdep); ++ ++ if (ret != 0) ++ return ret; ++ ++ /* Record registers clobbered during syscall. */ ++ for (i = 3; i <= 12; i++) ++ { ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i)) ++ return -1; ++ } ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 0)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum)) ++ return -1; ++ ++ return 0; ++} ++ ++static int ++ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache, ++ enum gdb_signal signal) ++{ ++ /* See handle_rt_signal64 in arch/powerpc/kernel/signal_64.c ++ handle_rt_signal32 in arch/powerpc/kernel/signal_32.c ++ arch/powerpc/include/asm/ptrace.h ++ for details. */ ++ const int SIGNAL_FRAMESIZE = 128; ++ const int sizeof_rt_sigframe = 1440 * 2 + 8 * 2 + 4 * 6 + 8 + 8 + 128 + 512; ++ ULONGEST sp; ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int i; ++ ++ for (i = 3; i <= 12; i++) ++ { ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i)) ++ return -1; ++ } ++ ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum)) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, gdbarch_pc_regnum (gdbarch))) ++ return -1; ++ if (record_full_arch_list_add_reg (regcache, gdbarch_sp_regnum (gdbarch))) ++ return -1; ++ ++ /* Record the change in the stack. ++ frame-size = sizeof (struct rt_sigframe) + SIGNAL_FRAMESIZE */ ++ regcache_raw_read_unsigned (regcache, gdbarch_sp_regnum (gdbarch), &sp); ++ sp -= SIGNAL_FRAMESIZE; ++ sp -= sizeof_rt_sigframe; ++ ++ if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe)) ++ return -1; ++ ++ if (record_full_arch_list_add_end ()) ++ return -1; ++ ++ return 0; ++} ++ + static void + ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) + { +@@ -1287,6 +1450,234 @@ static const struct frame_unwind ppu2spu + ppu2spu_prev_arch, + }; + ++/* Initialize linux_record_tdep if not initialized yet. */ ++ ++static void ++ppc_init_linux_record_tdep (struct linux_record_tdep *record_tdep, ++ int wordsize) ++{ ++ /* Simply return if it had been initialized. */ ++ if (record_tdep->size_pointer != 0) ++ return; ++ ++ /* These values are the size of the type that will be used in a system ++ call. They are obtained from Linux Kernel source. */ ++ ++ if (wordsize == 8) ++ { ++ record_tdep->size_pointer = 8; ++ record_tdep->size__old_kernel_stat = 32; ++ record_tdep->size_tms = 32; ++ record_tdep->size_loff_t = 8; ++ record_tdep->size_flock = 32; ++ record_tdep->size_oldold_utsname = 45; ++ record_tdep->size_ustat = 32; ++ record_tdep->size_old_sigaction = 152; ++ record_tdep->size_old_sigset_t = 128; ++ record_tdep->size_rlimit = 16; ++ record_tdep->size_rusage = 144; ++ record_tdep->size_timeval = 16; ++ record_tdep->size_timezone = 8; ++ record_tdep->size_old_gid_t = 4; ++ record_tdep->size_old_uid_t = 4; ++ record_tdep->size_fd_set = 128; ++ record_tdep->size_dirent = 280; ++ record_tdep->size_dirent64 = 280; ++ record_tdep->size_statfs = 120; ++ record_tdep->size_statfs64 = 120; ++ record_tdep->size_sockaddr = 16; ++ record_tdep->size_int = 4; ++ record_tdep->size_long = 8; ++ record_tdep->size_ulong = 8; ++ record_tdep->size_msghdr = 56; ++ record_tdep->size_itimerval = 32; ++ record_tdep->size_stat = 144; ++ record_tdep->size_old_utsname = 325; ++ record_tdep->size_sysinfo = 112; ++ record_tdep->size_msqid_ds = 120; ++ record_tdep->size_shmid_ds = 112; ++ record_tdep->size_new_utsname = 390; ++ record_tdep->size_timex = 208; ++ record_tdep->size_mem_dqinfo = 24; ++ record_tdep->size_if_dqblk = 72; ++ record_tdep->size_fs_quota_stat = 80; ++ record_tdep->size_timespec = 16; ++ record_tdep->size_pollfd = 8; ++ record_tdep->size_NFS_FHSIZE = 32; ++ record_tdep->size_knfsd_fh = 132; ++ record_tdep->size_TASK_COMM_LEN = 32; ++ record_tdep->size_sigaction = 152; ++ record_tdep->size_sigset_t = 128; ++ record_tdep->size_siginfo_t = 128; ++ record_tdep->size_cap_user_data_t = 8; ++ record_tdep->size_stack_t = 24; ++ record_tdep->size_off_t = 8; ++ record_tdep->size_stat64 = 104; ++ record_tdep->size_gid_t = 4; ++ record_tdep->size_uid_t = 4; ++ record_tdep->size_PAGE_SIZE = 0x10000; /* 64KB */ ++ record_tdep->size_flock64 = 32; ++ record_tdep->size_io_event = 32; ++ record_tdep->size_iocb = 64; ++ record_tdep->size_epoll_event = 16; ++ record_tdep->size_itimerspec = 32; ++ record_tdep->size_mq_attr = 64; ++ record_tdep->size_siginfo = 128; ++ record_tdep->size_termios = 44; ++ record_tdep->size_pid_t = 4; ++ record_tdep->size_winsize = 8; ++ record_tdep->size_serial_struct = 72; ++ record_tdep->size_serial_icounter_struct = 80; ++ record_tdep->size_size_t = 8; ++ record_tdep->size_iovec = 16; ++ } ++ else if (wordsize == 4) ++ { ++ record_tdep->size_pointer = 4; ++ record_tdep->size__old_kernel_stat = 32; ++ record_tdep->size_tms = 16; ++ record_tdep->size_loff_t = 8; ++ record_tdep->size_flock = 16; ++ record_tdep->size_oldold_utsname = 45; ++ record_tdep->size_ustat = 20; ++ record_tdep->size_old_sigaction = 152; ++ record_tdep->size_old_sigset_t = 128; ++ record_tdep->size_rlimit = 8; ++ record_tdep->size_rusage = 72; ++ record_tdep->size_timeval = 8; ++ record_tdep->size_timezone = 8; ++ record_tdep->size_old_gid_t = 4; ++ record_tdep->size_old_uid_t = 4; ++ record_tdep->size_fd_set = 128; ++ record_tdep->size_dirent = 268; ++ record_tdep->size_dirent64 = 280; ++ record_tdep->size_statfs = 64; ++ record_tdep->size_statfs64 = 88; ++ record_tdep->size_sockaddr = 16; ++ record_tdep->size_int = 4; ++ record_tdep->size_long = 4; ++ record_tdep->size_ulong = 4; ++ record_tdep->size_msghdr = 28; ++ record_tdep->size_itimerval = 16; ++ record_tdep->size_stat = 88; ++ record_tdep->size_old_utsname = 325; ++ record_tdep->size_sysinfo = 64; ++ record_tdep->size_msqid_ds = 68; ++ record_tdep->size_shmid_ds = 60; ++ record_tdep->size_new_utsname = 390; ++ record_tdep->size_timex = 128; ++ record_tdep->size_mem_dqinfo = 24; ++ record_tdep->size_if_dqblk = 72; ++ record_tdep->size_fs_quota_stat = 80; ++ record_tdep->size_timespec = 8; ++ record_tdep->size_pollfd = 8; ++ record_tdep->size_NFS_FHSIZE = 32; ++ record_tdep->size_knfsd_fh = 132; ++ record_tdep->size_TASK_COMM_LEN = 32; ++ record_tdep->size_sigaction = 140; ++ record_tdep->size_sigset_t = 128; ++ record_tdep->size_siginfo_t = 128; ++ record_tdep->size_cap_user_data_t = 4; ++ record_tdep->size_stack_t = 12; ++ record_tdep->size_off_t = 4; ++ record_tdep->size_stat64 = 104; ++ record_tdep->size_gid_t = 4; ++ record_tdep->size_uid_t = 4; ++ record_tdep->size_PAGE_SIZE = 0x10000; /* 64KB */ ++ record_tdep->size_flock64 = 32; ++ record_tdep->size_io_event = 32; ++ record_tdep->size_iocb = 64; ++ record_tdep->size_epoll_event = 16; ++ record_tdep->size_itimerspec = 16; ++ record_tdep->size_mq_attr = 32; ++ record_tdep->size_siginfo = 128; ++ record_tdep->size_termios = 44; ++ record_tdep->size_pid_t = 4; ++ record_tdep->size_winsize = 8; ++ record_tdep->size_serial_struct = 60; ++ record_tdep->size_serial_icounter_struct = 80; ++ record_tdep->size_size_t = 4; ++ record_tdep->size_iovec = 8; ++ } ++ else ++ internal_error (__FILE__, __LINE__, _("unexpected wordsize")); ++ ++ /* These values are the second argument of system call "sys_fcntl" ++ and "sys_fcntl64". They are obtained from Linux Kernel source. */ ++ record_tdep->fcntl_F_GETLK = 5; ++ record_tdep->fcntl_F_GETLK64 = 12; ++ record_tdep->fcntl_F_SETLK64 = 13; ++ record_tdep->fcntl_F_SETLKW64 = 14; ++ ++ record_tdep->arg1 = PPC_R0_REGNUM + 3; ++ record_tdep->arg2 = PPC_R0_REGNUM + 4; ++ record_tdep->arg3 = PPC_R0_REGNUM + 5; ++ record_tdep->arg4 = PPC_R0_REGNUM + 6; ++ record_tdep->arg5 = PPC_R0_REGNUM + 7; ++ record_tdep->arg6 = PPC_R0_REGNUM + 8; ++ ++ /* These values are the second argument of system call "sys_ioctl". ++ They are obtained from Linux Kernel source. ++ See arch/powerpc/include/uapi/asm/ioctls.h. */ ++ record_tdep->ioctl_TCGETS = 0x403c7413; ++ record_tdep->ioctl_TCSETS = 0x803c7414; ++ record_tdep->ioctl_TCSETSW = 0x803c7415; ++ record_tdep->ioctl_TCSETSF = 0x803c7416; ++ record_tdep->ioctl_TCGETA = 0x40147417; ++ record_tdep->ioctl_TCSETA = 0x80147418; ++ record_tdep->ioctl_TCSETAW = 0x80147419; ++ record_tdep->ioctl_TCSETAF = 0x8014741c; ++ record_tdep->ioctl_TCSBRK = 0x2000741d; ++ record_tdep->ioctl_TCXONC = 0x2000741e; ++ record_tdep->ioctl_TCFLSH = 0x2000741f; ++ record_tdep->ioctl_TIOCEXCL = 0x540c; ++ record_tdep->ioctl_TIOCNXCL = 0x540d; ++ record_tdep->ioctl_TIOCSCTTY = 0x540e; ++ record_tdep->ioctl_TIOCGPGRP = 0x40047477; ++ record_tdep->ioctl_TIOCSPGRP = 0x80047476; ++ record_tdep->ioctl_TIOCOUTQ = 0x40047473; ++ record_tdep->ioctl_TIOCSTI = 0x5412; ++ record_tdep->ioctl_TIOCGWINSZ = 0x40087468; ++ record_tdep->ioctl_TIOCSWINSZ = 0x80087467; ++ record_tdep->ioctl_TIOCMGET = 0x5415; ++ record_tdep->ioctl_TIOCMBIS = 0x5416; ++ record_tdep->ioctl_TIOCMBIC = 0x5417; ++ record_tdep->ioctl_TIOCMSET = 0x5418; ++ record_tdep->ioctl_TIOCGSOFTCAR = 0x5419; ++ record_tdep->ioctl_TIOCSSOFTCAR = 0x541a; ++ record_tdep->ioctl_FIONREAD = 0x4004667f; ++ record_tdep->ioctl_TIOCINQ = 0x4004667f; ++ record_tdep->ioctl_TIOCLINUX = 0x541c; ++ record_tdep->ioctl_TIOCCONS = 0x541d; ++ record_tdep->ioctl_TIOCGSERIAL = 0x541e; ++ record_tdep->ioctl_TIOCSSERIAL = 0x541f; ++ record_tdep->ioctl_TIOCPKT = 0x5420; ++ record_tdep->ioctl_FIONBIO = 0x8004667e; ++ record_tdep->ioctl_TIOCNOTTY = 0x5422; ++ record_tdep->ioctl_TIOCSETD = 0x5423; ++ record_tdep->ioctl_TIOCGETD = 0x5424; ++ record_tdep->ioctl_TCSBRKP = 0x5425; ++ record_tdep->ioctl_TIOCSBRK = 0x5427; ++ record_tdep->ioctl_TIOCCBRK = 0x5428; ++ record_tdep->ioctl_TIOCGSID = 0x5429; ++ record_tdep->ioctl_TIOCGPTN = 0x40045430; ++ record_tdep->ioctl_TIOCSPTLCK = 0x80045431; ++ record_tdep->ioctl_FIONCLEX = 0x20006602; ++ record_tdep->ioctl_FIOCLEX = 0x20006601; ++ record_tdep->ioctl_FIOASYNC = 0x8004667d; ++ record_tdep->ioctl_TIOCSERCONFIG = 0x5453; ++ record_tdep->ioctl_TIOCSERGWILD = 0x5454; ++ record_tdep->ioctl_TIOCSERSWILD = 0x5455; ++ record_tdep->ioctl_TIOCGLCKTRMIOS = 0x5456; ++ record_tdep->ioctl_TIOCSLCKTRMIOS = 0x5457; ++ record_tdep->ioctl_TIOCSERGSTRUCT = 0x5458; ++ record_tdep->ioctl_TIOCSERGETLSR = 0x5459; ++ record_tdep->ioctl_TIOCSERGETMULTI = 0x545a; ++ record_tdep->ioctl_TIOCSERSETMULTI = 0x545b; ++ record_tdep->ioctl_TIOCMIWAIT = 0x545c; ++ record_tdep->ioctl_TIOCGICOUNT = 0x545d; ++ record_tdep->ioctl_FIOQSIZE = 0x40086680; ++} + + static void + ppc_linux_init_abi (struct gdbarch_info info, +@@ -1486,6 +1877,14 @@ ppc_linux_init_abi (struct gdbarch_info + } + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); ++ ++ /* Support reverse debugging. */ ++ set_gdbarch_process_record (gdbarch, ppc_process_record); ++ set_gdbarch_process_record_signal (gdbarch, ppc_linux_record_signal); ++ tdep->ppc_syscall_record = ppc_linux_syscall_record; ++ ++ ppc_init_linux_record_tdep (&ppc_linux_record_tdep, 4); ++ ppc_init_linux_record_tdep (&ppc64_linux_record_tdep, 8); + } + + /* Provide a prototype to silence -Wmissing-prototypes. */ +Index: gdb-7.6.1/gdb/ppc-tdep.h +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-tdep.h ++++ gdb-7.6.1/gdb/ppc-tdep.h +@@ -259,6 +259,8 @@ struct gdbarch_tdep + /* ISA-specific types. */ + struct type *ppc_builtin_type_vec64; + struct type *ppc_builtin_type_vec128; ++ ++ int (*ppc_syscall_record) (struct regcache *regcache); + }; + + +@@ -318,6 +320,9 @@ extern CORE_ADDR ppc_insn_d_field (unsig + + extern CORE_ADDR ppc_insn_ds_field (unsigned int insn); + ++extern int ppc_process_record (struct gdbarch *gdbarch, ++ struct regcache *regcache, CORE_ADDR addr); ++ + /* Instruction size. */ + #define PPC_INSN_SIZE 4 + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -39,6 +39,8 @@ + #include "dwarf2-frame.h" + #include "target-descriptions.h" + #include "user-regs.h" ++#include "record-full.h" ++#include "auxv.h" + + #include "libbfd.h" /* for bfd_default_set_arch_mach */ + #include "coff/internal.h" /* for libcoff.h */ +@@ -3682,6 +3684,1689 @@ bfd_uses_spe_extensions (bfd *abfd) + return success; + } + ++/* These are macros for parsing instruction fields (I.1.6.28) */ ++ ++#define PPC_FIELD(value, from, len) \ ++ (((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1)) ++#define PPC_SEXT(v, bs) \ ++ ((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \ ++ ^ ((CORE_ADDR) 1 << ((bs) - 1))) \ ++ - ((CORE_ADDR) 1 << ((bs) - 1))) ++#define PPC_OP6(insn) PPC_FIELD (insn, 0, 6) ++#define PPC_EXTOP(insn) PPC_FIELD (insn, 21, 10) ++#define PPC_RT(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_RS(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_RA(insn) PPC_FIELD (insn, 11, 5) ++#define PPC_RB(insn) PPC_FIELD (insn, 16, 5) ++#define PPC_NB(insn) PPC_FIELD (insn, 16, 5) ++#define PPC_VRT(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_FRT(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_SPR(insn) (PPC_FIELD (insn, 11, 5) \ ++ | (PPC_FIELD (insn, 16, 5) << 5)) ++#define PPC_BO(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_T(insn) PPC_FIELD (insn, 6, 5) ++#define PPC_D(insn) PPC_SEXT (PPC_FIELD (insn, 16, 16), 16) ++#define PPC_DS(insn) PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) ++#define PPC_BIT(insn,n) ((insn & (1 << (31 - (n)))) ? 1 : 0) ++#define PPC_OE(insn) PPC_BIT (insn, 21) ++#define PPC_RC(insn) PPC_BIT (insn, 31) ++#define PPC_Rc(insn) PPC_BIT (insn, 21) ++#define PPC_LK(insn) PPC_BIT (insn, 31) ++#define PPC_TX(insn) PPC_BIT (insn, 31) ++#define PPC_LEV(insn) PPC_FIELD (insn, 20, 7) ++ ++#define PPC_XT(insn) ((PPC_TX (insn) << 5) | PPC_T (insn)) ++#define PPC_XER_NB(xer) (xer & 0x7f) ++ ++/* Record Vector-Scalar Registers. */ ++ ++static int ++ppc_record_vsr (struct regcache *regcache, struct gdbarch_tdep *tdep, int vsr) ++{ ++ if (vsr < 0 || vsr >= 64) ++ return -1; ++ ++ if (vsr >= 32) ++ { ++ if (tdep->ppc_vr0_regnum >= 0) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_vr0_regnum + vsr - 32); ++ } ++ else ++ { ++ if (tdep->ppc_fp0_regnum >= 0) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fp0_regnum + vsr); ++ if (tdep->ppc_vsr0_upper_regnum >= 0) ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vsr0_upper_regnum + vsr); ++ } ++ ++ return 0; ++} ++ ++/* Parse instructions of primary opcode-4. */ ++ ++static int ++ppc_process_record_op4 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_FIELD (insn, 21, 11); ++ ++ switch (ext & 0x3f) ++ { ++ case 32: /* Vector Multiply-High-Add Signed Halfword Saturate */ ++ case 33: /* Vector Multiply-High-Round-Add Signed Halfword Saturate */ ++ case 39: /* Vector Multiply-Sum Unsigned Halfword Saturate */ ++ case 41: /* Vector Multiply-Sum Signed Halfword Saturate */ ++ record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); ++ /* FALL-THROUGH */ ++ case 42: /* Vector Select */ ++ case 43: /* Vector Permute */ ++ case 44: /* Vector Shift Left Double by Octet Immediate */ ++ case 45: /* Vector Permute and Exclusive-OR */ ++ case 60: /* Vector Add Extended Unsigned Quadword Modulo */ ++ case 61: /* Vector Add Extended & write Carry Unsigned Quadword */ ++ case 62: /* Vector Subtract Extended Unsigned Quadword Modulo */ ++ case 63: /* Vector Subtract Extended & write Carry Unsigned Quadword */ ++ case 34: /* Vector Multiply-Low-Add Unsigned Halfword Modulo */ ++ case 36: /* Vector Multiply-Sum Unsigned Byte Modulo */ ++ case 37: /* Vector Multiply-Sum Mixed Byte Modulo */ ++ case 38: /* Vector Multiply-Sum Unsigned Halfword Modulo */ ++ case 40: /* Vector Multiply-Sum Signed Halfword Modulo */ ++ case 46: /* Vector Multiply-Add Single-Precision */ ++ case 47: /* Vector Negative Multiply-Subtract Single-Precision */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ return 0; ++ } ++ ++ switch ((ext & 0x1ff)) ++ { ++ /* 5.16 Decimal Integer Arithmetic Instructions */ ++ case 1: /* Decimal Add Modulo */ ++ case 65: /* Decimal Subtract Modulo */ ++ ++ /* Bit-21 should be set. */ ++ if (!PPC_BIT (insn, 21)) ++ break; ++ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ } ++ ++ /* Bit-21 is used for RC */ ++ switch (ext & 0x3ff) ++ { ++ case 6: /* Vector Compare Equal To Unsigned Byte */ ++ case 70: /* Vector Compare Equal To Unsigned Halfword */ ++ case 134: /* Vector Compare Equal To Unsigned Word */ ++ case 199: /* Vector Compare Equal To Unsigned Doubleword */ ++ case 774: /* Vector Compare Greater Than Signed Byte */ ++ case 838: /* Vector Compare Greater Than Signed Halfword */ ++ case 902: /* Vector Compare Greater Than Signed Word */ ++ case 967: /* Vector Compare Greater Than Signed Doubleword */ ++ case 518: /* Vector Compare Greater Than Unsigned Byte */ ++ case 646: /* Vector Compare Greater Than Unsigned Word */ ++ case 582: /* Vector Compare Greater Than Unsigned Halfword */ ++ case 711: /* Vector Compare Greater Than Unsigned Doubleword */ ++ case 966: /* Vector Compare Bounds Single-Precision */ ++ case 198: /* Vector Compare Equal To Single-Precision */ ++ case 454: /* Vector Compare Greater Than or Equal To Single-Precision */ ++ case 710: /* Vector Compare Greater Than Single-Precision */ ++ if (PPC_Rc (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ return 0; ++ } ++ ++ switch (ext) ++ { ++ case 142: /* Vector Pack Unsigned Halfword Unsigned Saturate */ ++ case 206: /* Vector Pack Unsigned Word Unsigned Saturate */ ++ case 270: /* Vector Pack Signed Halfword Unsigned Saturate */ ++ case 334: /* Vector Pack Signed Word Unsigned Saturate */ ++ case 398: /* Vector Pack Signed Halfword Signed Saturate */ ++ case 462: /* Vector Pack Signed Word Signed Saturate */ ++ case 1230: /* Vector Pack Unsigned Doubleword Unsigned Saturate */ ++ case 1358: /* Vector Pack Signed Doubleword Unsigned Saturate */ ++ case 1486: /* Vector Pack Signed Doubleword Signed Saturate */ ++ case 512: /* Vector Add Unsigned Byte Saturate */ ++ case 576: /* Vector Add Unsigned Halfword Saturate */ ++ case 640: /* Vector Add Unsigned Word Saturate */ ++ case 768: /* Vector Add Signed Byte Saturate */ ++ case 832: /* Vector Add Signed Halfword Saturate */ ++ case 896: /* Vector Add Signed Word Saturate */ ++ case 1536: /* Vector Subtract Unsigned Byte Saturate */ ++ case 1600: /* Vector Subtract Unsigned Halfword Saturate */ ++ case 1664: /* Vector Subtract Unsigned Word Saturate */ ++ case 1792: /* Vector Subtract Signed Byte Saturate */ ++ case 1856: /* Vector Subtract Signed Halfword Saturate */ ++ case 1920: /* Vector Subtract Signed Word Saturate */ ++ ++ case 1544: /* Vector Sum across Quarter Unsigned Byte Saturate */ ++ case 1800: /* Vector Sum across Quarter Signed Byte Saturate */ ++ case 1608: /* Vector Sum across Quarter Signed Halfword Saturate */ ++ case 1672: /* Vector Sum across Half Signed Word Saturate */ ++ case 1928: /* Vector Sum across Signed Word Saturate */ ++ case 970: /* Vector Convert To Signed Fixed-Point Word Saturate */ ++ case 906: /* Vector Convert To Unsigned Fixed-Point Word Saturate */ ++ record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); ++ /* FALL-THROUGH */ ++ case 12: /* Vector Merge High Byte */ ++ case 14: /* Vector Pack Unsigned Halfword Unsigned Modulo */ ++ case 76: /* Vector Merge High Halfword */ ++ case 78: /* Vector Pack Unsigned Word Unsigned Modulo */ ++ case 140: /* Vector Merge High Word */ ++ case 268: /* Vector Merge Low Byte */ ++ case 332: /* Vector Merge Low Halfword */ ++ case 396: /* Vector Merge Low Word */ ++ case 526: /* Vector Unpack High Signed Byte */ ++ case 590: /* Vector Unpack High Signed Halfword */ ++ case 654: /* Vector Unpack Low Signed Byte */ ++ case 718: /* Vector Unpack Low Signed Halfword */ ++ case 782: /* Vector Pack Pixel */ ++ case 846: /* Vector Unpack High Pixel */ ++ case 974: /* Vector Unpack Low Pixel */ ++ case 1102: /* Vector Pack Unsigned Doubleword Unsigned Modulo */ ++ case 1614: /* Vector Unpack High Signed Word */ ++ case 1676: /* Vector Merge Odd Word */ ++ case 1742: /* Vector Unpack Low Signed Word */ ++ case 1932: /* Vector Merge Even Word */ ++ case 524: /* Vector Splat Byte */ ++ case 588: /* Vector Splat Halfword */ ++ case 652: /* Vector Splat Word */ ++ case 780: /* Vector Splat Immediate Signed Byte */ ++ case 844: /* Vector Splat Immediate Signed Halfword */ ++ case 908: /* Vector Splat Immediate Signed Word */ ++ case 452: /* Vector Shift Left */ ++ case 708: /* Vector Shift Right */ ++ case 1036: /* Vector Shift Left by Octet */ ++ case 1100: /* Vector Shift Right by Octet */ ++ case 0: /* Vector Add Unsigned Byte Modulo */ ++ case 64: /* Vector Add Unsigned Halfword Modulo */ ++ case 128: /* Vector Add Unsigned Word Modulo */ ++ case 192: /* Vector Add Unsigned Doubleword Modulo */ ++ case 256: /* Vector Add Unsigned Quadword Modulo */ ++ case 320: /* Vector Add & write Carry Unsigned Quadword */ ++ case 384: /* Vector Add and Write Carry-Out Unsigned Word */ ++ case 8: /* Vector Multiply Odd Unsigned Byte */ ++ case 72: /* Vector Multiply Odd Unsigned Halfword */ ++ case 136: /* Vector Multiply Odd Unsigned Word */ ++ case 264: /* Vector Multiply Odd Signed Byte */ ++ case 328: /* Vector Multiply Odd Signed Halfword */ ++ case 392: /* Vector Multiply Odd Signed Word */ ++ case 520: /* Vector Multiply Even Unsigned Byte */ ++ case 584: /* Vector Multiply Even Unsigned Halfword */ ++ case 648: /* Vector Multiply Even Unsigned Word */ ++ case 776: /* Vector Multiply Even Signed Byte */ ++ case 840: /* Vector Multiply Even Signed Halfword */ ++ case 904: /* Vector Multiply Even Signed Word */ ++ case 137: /* Vector Multiply Unsigned Word Modulo */ ++ case 1024: /* Vector Subtract Unsigned Byte Modulo */ ++ case 1088: /* Vector Subtract Unsigned Halfword Modulo */ ++ case 1152: /* Vector Subtract Unsigned Word Modulo */ ++ case 1216: /* Vector Subtract Unsigned Doubleword Modulo */ ++ case 1280: /* Vector Subtract Unsigned Quadword Modulo */ ++ case 1344: /* Vector Subtract & write Carry Unsigned Quadword */ ++ case 1408: /* Vector Subtract and Write Carry-Out Unsigned Word */ ++ case 1282: /* Vector Average Signed Byte */ ++ case 1346: /* Vector Average Signed Halfword */ ++ case 1410: /* Vector Average Signed Word */ ++ case 1026: /* Vector Average Unsigned Byte */ ++ case 1090: /* Vector Average Unsigned Halfword */ ++ case 1154: /* Vector Average Unsigned Word */ ++ case 258: /* Vector Maximum Signed Byte */ ++ case 322: /* Vector Maximum Signed Halfword */ ++ case 386: /* Vector Maximum Signed Word */ ++ case 450: /* Vector Maximum Signed Doubleword */ ++ case 2: /* Vector Maximum Unsigned Byte */ ++ case 66: /* Vector Maximum Unsigned Halfword */ ++ case 130: /* Vector Maximum Unsigned Word */ ++ case 194: /* Vector Maximum Unsigned Doubleword */ ++ case 770: /* Vector Minimum Signed Byte */ ++ case 834: /* Vector Minimum Signed Halfword */ ++ case 898: /* Vector Minimum Signed Word */ ++ case 962: /* Vector Minimum Signed Doubleword */ ++ case 514: /* Vector Minimum Unsigned Byte */ ++ case 578: /* Vector Minimum Unsigned Halfword */ ++ case 642: /* Vector Minimum Unsigned Word */ ++ case 706: /* Vector Minimum Unsigned Doubleword */ ++ case 1028: /* Vector Logical AND */ ++ case 1668: /* Vector Logical Equivalent */ ++ case 1092: /* Vector Logical AND with Complement */ ++ case 1412: /* Vector Logical NAND */ ++ case 1348: /* Vector Logical OR with Complement */ ++ case 1156: /* Vector Logical OR */ ++ case 1284: /* Vector Logical NOR */ ++ case 1220: /* Vector Logical XOR */ ++ case 4: /* Vector Rotate Left Byte */ ++ case 132: /* Vector Rotate Left Word VX-form */ ++ case 68: /* Vector Rotate Left Halfword */ ++ case 196: /* Vector Rotate Left Doubleword */ ++ case 260: /* Vector Shift Left Byte */ ++ case 388: /* Vector Shift Left Word */ ++ case 324: /* Vector Shift Left Halfword */ ++ case 1476: /* Vector Shift Left Doubleword */ ++ case 516: /* Vector Shift Right Byte */ ++ case 644: /* Vector Shift Right Word */ ++ case 580: /* Vector Shift Right Halfword */ ++ case 1732: /* Vector Shift Right Doubleword */ ++ case 772: /* Vector Shift Right Algebraic Byte */ ++ case 900: /* Vector Shift Right Algebraic Word */ ++ case 836: /* Vector Shift Right Algebraic Halfword */ ++ case 964: /* Vector Shift Right Algebraic Doubleword */ ++ case 10: /* Vector Add Single-Precision */ ++ case 74: /* Vector Subtract Single-Precision */ ++ case 1034: /* Vector Maximum Single-Precision */ ++ case 1098: /* Vector Minimum Single-Precision */ ++ case 842: /* Vector Convert From Signed Fixed-Point Word */ ++ case 778: /* Vector Convert From Unsigned Fixed-Point Word */ ++ case 714: /* Vector Round to Single-Precision Integer toward -Infinity */ ++ case 522: /* Vector Round to Single-Precision Integer Nearest */ ++ case 650: /* Vector Round to Single-Precision Integer toward +Infinity */ ++ case 586: /* Vector Round to Single-Precision Integer toward Zero */ ++ case 394: /* Vector 2 Raised to the Exponent Estimate Floating-Point */ ++ case 458: /* Vector Log Base 2 Estimate Floating-Point */ ++ case 266: /* Vector Reciprocal Estimate Single-Precision */ ++ case 330: /* Vector Reciprocal Square Root Estimate Single-Precision */ ++ case 1288: /* Vector AES Cipher */ ++ case 1289: /* Vector AES Cipher Last */ ++ case 1352: /* Vector AES Inverse Cipher */ ++ case 1353: /* Vector AES Inverse Cipher Last */ ++ case 1480: /* Vector AES SubBytes */ ++ case 1730: /* Vector SHA-512 Sigma Doubleword */ ++ case 1666: /* Vector SHA-256 Sigma Word */ ++ case 1032: /* Vector Polynomial Multiply-Sum Byte */ ++ case 1160: /* Vector Polynomial Multiply-Sum Word */ ++ case 1096: /* Vector Polynomial Multiply-Sum Halfword */ ++ case 1224: /* Vector Polynomial Multiply-Sum Doubleword */ ++ case 1292: /* Vector Gather Bits by Bytes by Doubleword */ ++ case 1794: /* Vector Count Leading Zeros Byte */ ++ case 1858: /* Vector Count Leading Zeros Halfword */ ++ case 1922: /* Vector Count Leading Zeros Word */ ++ case 1986: /* Vector Count Leading Zeros Doubleword */ ++ case 1795: /* Vector Population Count Byte */ ++ case 1859: /* Vector Population Count Halfword */ ++ case 1923: /* Vector Population Count Word */ ++ case 1987: /* Vector Population Count Doubleword */ ++ case 1356: /* Vector Bit Permute Quadword */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ return 0; ++ ++ case 1604: /* Move To Vector Status and Control Register */ ++ record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); ++ return 0; ++ case 1540: /* Move From Vector Status and Control Register */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ return 0; ++ } ++ ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 4-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse instructions of primary opcode-19. */ ++ ++static int ++ppc_process_record_op19 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_EXTOP (insn); ++ ++ switch (ext) ++ { ++ case 0: /* Move Condition Register Field */ ++ case 33: /* Condition Register NOR */ ++ case 129: /* Condition Register AND with Complement */ ++ case 193: /* Condition Register XOR */ ++ case 225: /* Condition Register NAND */ ++ case 257: /* Condition Register AND */ ++ case 289: /* Condition Register Equivalent */ ++ case 417: /* Condition Register OR with Complement */ ++ case 449: /* Condition Register OR */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 16: /* Branch Conditional */ ++ case 560: /* Branch Conditional to Branch Target Address Register */ ++ if ((PPC_BO (insn) & 0x4) == 0) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); ++ /* FALL-THROUGH */ ++ case 528: /* Branch Conditional to Count Register */ ++ if (PPC_LK (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); ++ return 0; ++ ++ case 150: /* Instruction Synchronize */ ++ /* Do nothing. */ ++ return 0; ++ } ++ ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 19-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse instructions of primary opcode-31. */ ++ ++static int ++ppc_process_record_op31 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_EXTOP (insn); ++ int tmp, nr, nb, i; ++ CORE_ADDR at_dcsz, ea = 0; ++ ULONGEST rb, ra, xer; ++ int size = 0; ++ ++ /* These instructions have OE bit. */ ++ switch (ext & 0x1ff) ++ { ++ /* These write RT and XER. Update CR if RC is set. */ ++ case 8: /* Subtract from carrying */ ++ case 10: /* Add carrying */ ++ case 136: /* Subtract from extended */ ++ case 138: /* Add extended */ ++ case 200: /* Subtract from zero extended */ ++ case 202: /* Add to zero extended */ ++ case 232: /* Subtract from minus one extended */ ++ case 234: /* Add to minus one extended */ ++ /* CA is always altered, but SO/OV are only altered when OE=1. ++ In any case, XER is always altered. */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ ++ /* These write RT. Update CR if RC is set and update XER if OE is set. */ ++ case 40: /* Subtract from */ ++ case 104: /* Negate */ ++ case 233: /* Multiply low doubleword */ ++ case 235: /* Multiply low word */ ++ case 266: /* Add */ ++ case 393: /* Divide Doubleword Extended Unsigned */ ++ case 395: /* Divide Word Extended Unsigned */ ++ case 425: /* Divide Doubleword Extended */ ++ case 427: /* Divide Word Extended */ ++ case 457: /* Divide Doubleword Unsigned */ ++ case 459: /* Divide Word Unsigned */ ++ case 489: /* Divide Doubleword */ ++ case 491: /* Divide Word */ ++ if (PPC_OE (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ /* FALL-THROUGH */ ++ case 9: /* Multiply High Doubleword Unsigned */ ++ case 11: /* Multiply High Word Unsigned */ ++ case 73: /* Multiply High Doubleword */ ++ case 75: /* Multiply High Word */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ } ++ ++ if ((ext & 0x1f) == 15) ++ { ++ /* Integer Select. bit[16:20] is used for BC. */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ } ++ ++ switch (ext) ++ { ++ case 78: /* Determine Leftmost Zero Byte */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ ++ /* These only write RT. */ ++ case 19: /* Move from condition register */ ++ /* Move From One Condition Register Field */ ++ case 74: /* Add and Generate Sixes */ ++ case 74 | 0x200: /* Add and Generate Sixes (bit-21 dont-care) */ ++ case 302: /* Move From Branch History Rolling Buffer */ ++ case 339: /* Move From Special Purpose Register */ ++ case 371: /* Move From Time Base [Phased-Out] */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ ++ /* These only write to RA. */ ++ case 51: /* Move From VSR Doubleword */ ++ case 115: /* Move From VSR Word and Zero */ ++ case 122: /* Population count bytes */ ++ case 378: /* Population count words */ ++ case 506: /* Population count doublewords */ ++ case 154: /* Parity Word */ ++ case 186: /* Parity Doubleword */ ++ case 252: /* Bit Permute Doubleword */ ++ case 282: /* Convert Declets To Binary Coded Decimal */ ++ case 314: /* Convert Binary Coded Decimal To Declets */ ++ case 508: /* Compare bytes */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ return 0; ++ ++ /* These write CR and optional RA. */ ++ case 792: /* Shift Right Algebraic Word */ ++ case 794: /* Shift Right Algebraic Doubleword */ ++ case 824: /* Shift Right Algebraic Word Immediate */ ++ case 826: /* Shift Right Algebraic Doubleword Immediate (413) */ ++ case 826 | 1: /* Shift Right Algebraic Doubleword Immediate (413) */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 0: /* Compare */ ++ case 32: /* Compare logical */ ++ case 144: /* Move To Condition Register Fields */ ++ /* Move To One Condition Register Field */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ /* These write to RT. Update RA if 'update indexed.' */ ++ case 53: /* Load Doubleword with Update Indexed */ ++ case 119: /* Load Byte and Zero with Update Indexed */ ++ case 311: /* Load Halfword and Zero with Update Indexed */ ++ case 55: /* Load Word and Zero with Update Indexed */ ++ case 375: /* Load Halfword Algebraic with Update Indexed */ ++ case 373: /* Load Word Algebraic with Update Indexed */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 21: /* Load Doubleword Indexed */ ++ case 52: /* Load Byte And Reserve Indexed */ ++ case 116: /* Load Halfword And Reserve Indexed */ ++ case 20: /* Load Word And Reserve Indexed */ ++ case 84: /* Load Doubleword And Reserve Indexed */ ++ case 87: /* Load Byte and Zero Indexed */ ++ case 279: /* Load Halfword and Zero Indexed */ ++ case 23: /* Load Word and Zero Indexed */ ++ case 343: /* Load Halfword Algebraic Indexed */ ++ case 341: /* Load Word Algebraic Indexed */ ++ case 790: /* Load Halfword Byte-Reverse Indexed */ ++ case 534: /* Load Word Byte-Reverse Indexed */ ++ case 532: /* Load Doubleword Byte-Reverse Indexed */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ return 0; ++ ++ case 597: /* Load String Word Immediate */ ++ case 533: /* Load String Word Indexed */ ++ if (ext == 597) ++ { ++ nr = PPC_NB (insn); ++ if (nr == 0) ++ nr = 32; ++ } ++ else ++ { ++ regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer); ++ nr = PPC_XER_NB (xer); ++ } ++ ++ nr = (nr + 3) >> 2; ++ ++ /* If n=0, the contents of register RT are undefined. */ ++ if (nr == 0) ++ nr = 1; ++ ++ for (i = 0; i < nr; i++) ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum ++ + ((PPC_RT (insn) + i) & 0x1f)); ++ return 0; ++ ++ case 276: /* Load Quadword And Reserve Indexed */ ++ tmp = tdep->ppc_gp0_regnum + (PPC_RT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ return 0; ++ ++ /* These write VRT. */ ++ case 6: /* Load Vector for Shift Left Indexed */ ++ case 38: /* Load Vector for Shift Right Indexed */ ++ case 7: /* Load Vector Element Byte Indexed */ ++ case 39: /* Load Vector Element Halfword Indexed */ ++ case 71: /* Load Vector Element Word Indexed */ ++ case 103: /* Load Vector Indexed */ ++ case 359: /* Load Vector Indexed LRU */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_vr0_regnum + PPC_VRT (insn)); ++ return 0; ++ ++ /* These write FRT. Update RA if 'update indexed.' */ ++ case 567: /* Load Floating-Point Single with Update Indexed */ ++ case 631: /* Load Floating-Point Double with Update Indexed */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 535: /* Load Floating-Point Single Indexed */ ++ case 599: /* Load Floating-Point Double Indexed */ ++ case 855: /* Load Floating-Point as Integer Word Algebraic Indexed */ ++ case 887: /* Load Floating-Point as Integer Word and Zero Indexed */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ return 0; ++ ++ case 791: /* Load Floating-Point Double Pair Indexed */ ++ tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ return 0; ++ ++ case 179: /* Move To VSR Doubleword */ ++ case 211: /* Move To VSR Word Algebraic */ ++ case 243: /* Move To VSR Word and Zero */ ++ case 588: /* Load VSX Scalar Doubleword Indexed */ ++ case 524: /* Load VSX Scalar Single-Precision Indexed */ ++ case 76: /* Load VSX Scalar as Integer Word Algebraic Indexed */ ++ case 12: /* Load VSX Scalar as Integer Word and Zero Indexed */ ++ case 844: /* Load VSX Vector Doubleword*2 Indexed */ ++ case 332: /* Load VSX Vector Doubleword & Splat Indexed */ ++ case 780: /* Load VSX Vector Word*4 Indexed */ ++ ppc_record_vsr (regcache, tdep, PPC_XT (insn)); ++ return 0; ++ ++ /* These write RA. Update CR if RC is set. */ ++ case 24: /* Shift Left Word */ ++ case 26: /* Count Leading Zeros Word */ ++ case 27: /* Shift Left Doubleword */ ++ case 28: /* AND */ ++ case 58: /* Count Leading Zeros Doubleword */ ++ case 60: /* AND with Complement */ ++ case 124: /* NOR */ ++ case 284: /* Equivalent */ ++ case 316: /* XOR */ ++ case 476: /* NAND */ ++ case 412: /* OR with Complement */ ++ case 444: /* OR */ ++ case 536: /* Shift Right Word */ ++ case 539: /* Shift Right Doubleword */ ++ case 922: /* Extend Sign Halfword */ ++ case 954: /* Extend Sign Byte */ ++ case 986: /* Extend Sign Word */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ return 0; ++ ++ /* Store memory. */ ++ case 181: /* Store Doubleword with Update Indexed */ ++ case 183: /* Store Word with Update Indexed */ ++ case 247: /* Store Byte with Update Indexed */ ++ case 439: /* Store Half Word with Update Indexed */ ++ case 695: /* Store Floating-Point Single with Update Indexed */ ++ case 759: /* Store Floating-Point Double with Update Indexed */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 135: /* Store Vector Element Byte Indexed */ ++ case 167: /* Store Vector Element Halfword Indexed */ ++ case 199: /* Store Vector Element Word Indexed */ ++ case 231: /* Store Vector Indexed */ ++ case 487: /* Store Vector Indexed LRU */ ++ case 716: /* Store VSX Scalar Doubleword Indexed */ ++ case 140: /* Store VSX Scalar as Integer Word Indexed */ ++ case 652: /* Store VSX Scalar Single-Precision Indexed */ ++ case 972: /* Store VSX Vector Doubleword*2 Indexed */ ++ case 908: /* Store VSX Vector Word*4 Indexed */ ++ case 149: /* Store Doubleword Indexed */ ++ case 151: /* Store Word Indexed */ ++ case 215: /* Store Byte Indexed */ ++ case 407: /* Store Half Word Indexed */ ++ case 694: /* Store Byte Conditional Indexed */ ++ case 726: /* Store Halfword Conditional Indexed */ ++ case 150: /* Store Word Conditional Indexed */ ++ case 214: /* Store Doubleword Conditional Indexed */ ++ case 182: /* Store Quadword Conditional Indexed */ ++ case 662: /* Store Word Byte-Reverse Indexed */ ++ case 918: /* Store Halfword Byte-Reverse Indexed */ ++ case 660: /* Store Doubleword Byte-Reverse Indexed */ ++ case 663: /* Store Floating-Point Single Indexed */ ++ case 727: /* Store Floating-Point Double Indexed */ ++ case 919: /* Store Floating-Point Double Pair Indexed */ ++ case 983: /* Store Floating-Point as Integer Word Indexed */ ++ if (ext == 694 || ext == 726 || ext == 150 || ext == 214 || ext == 182) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ ++ ra = 0; ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RB (insn), &rb); ++ ea = ra + rb; ++ ++ switch (ext) ++ { ++ case 183: /* Store Word with Update Indexed */ ++ case 199: /* Store Vector Element Word Indexed */ ++ case 140: /* Store VSX Scalar as Integer Word Indexed */ ++ case 652: /* Store VSX Scalar Single-Precision Indexed */ ++ case 151: /* Store Word Indexed */ ++ case 150: /* Store Word Conditional Indexed */ ++ case 662: /* Store Word Byte-Reverse Indexed */ ++ case 663: /* Store Floating-Point Single Indexed */ ++ case 695: /* Store Floating-Point Single with Update Indexed */ ++ case 983: /* Store Floating-Point as Integer Word Indexed */ ++ size = 4; ++ break; ++ case 247: /* Store Byte with Update Indexed */ ++ case 135: /* Store Vector Element Byte Indexed */ ++ case 215: /* Store Byte Indexed */ ++ case 694: /* Store Byte Conditional Indexed */ ++ size = 1; ++ break; ++ case 439: /* Store Halfword with Update Indexed */ ++ case 167: /* Store Vector Element Halfword Indexed */ ++ case 407: /* Store Halfword Indexed */ ++ case 726: /* Store Halfword Conditional Indexed */ ++ case 918: /* Store Halfword Byte-Reverse Indexed */ ++ size = 2; ++ break; ++ case 181: /* Store Doubleword with Update Indexed */ ++ case 716: /* Store VSX Scalar Doubleword Indexed */ ++ case 149: /* Store Doubleword Indexed */ ++ case 214: /* Store Doubleword Conditional Indexed */ ++ case 660: /* Store Doubleword Byte-Reverse Indexed */ ++ case 727: /* Store Floating-Point Double Indexed */ ++ case 759: /* Store Floating-Point Double with Update Indexed */ ++ size = 8; ++ break; ++ case 972: /* Store VSX Vector Doubleword*2 Indexed */ ++ case 908: /* Store VSX Vector Word*4 Indexed */ ++ case 182: /* Store Quadword Conditional Indexed */ ++ case 231: /* Store Vector Indexed */ ++ case 487: /* Store Vector Indexed LRU */ ++ case 919: /* Store Floating-Point Double Pair Indexed */ ++ size = 16; ++ break; ++ default: ++ gdb_assert (0); ++ } ++ ++ /* Align address for Store Vector instructions. */ ++ switch (ext) ++ { ++ case 167: /* Store Vector Element Halfword Indexed */ ++ addr = addr & ~0x1ULL; ++ break; ++ ++ case 199: /* Store Vector Element Word Indexed */ ++ addr = addr & ~0x3ULL; ++ break; ++ ++ case 231: /* Store Vector Indexed */ ++ case 487: /* Store Vector Indexed LRU */ ++ addr = addr & ~0xfULL; ++ break; ++ } ++ ++ if (record_full_arch_list_add_mem (addr, size) != 0) ++ return -1; ++ return 0; ++ ++ case 725: /* Store String Word Immediate */ ++ ra = 0; ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &ra); ++ ea += ra; ++ ++ nb = PPC_NB (insn); ++ if (nb == 0) ++ nb = 32; ++ ++ if (record_full_arch_list_add_mem (ea, nb) != 0) ++ return -1; ++ ++ return 0; ++ ++ case 661: /* Store String Word Indexed */ ++ ra = 0; ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &ra); ++ ea += ra; ++ ++ regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer); ++ nb = PPC_XER_NB (xer); ++ ++ if (nb != 0) ++ { ++ regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &rb); ++ ea += rb; ++ if (record_full_arch_list_add_mem (ea, nb) != 0) ++ return -1; ++ } ++ ++ return 0; ++ ++ case 467: /* Move To Special Purpose Register */ ++ switch (PPC_SPR (insn)) ++ { ++ case 1: /* XER */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ return 0; ++ case 8: /* LR */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); ++ return 0; ++ case 9: /* CTR */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); ++ return 0; ++ case 256: /* VRSAVE */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_vrsave_regnum); ++ return 0; ++ } ++ ++ goto UNKNOWN_OP; ++ ++ case 147: /* Move To Split Little Endian */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_ps_regnum); ++ return 0; ++ ++ case 512: /* Move to Condition Register from XER */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ return 0; ++ ++ case 4: /* Trap Word */ ++ case 68: /* Trap Doubleword */ ++ case 430: /* Clear BHRB */ ++ case 598: /* Synchronize */ ++ case 62: /* Wait for Interrupt */ ++ case 22: /* Instruction Cache Block Touch */ ++ case 854: /* Enforce In-order Execution of I/O */ ++ case 246: /* Data Cache Block Touch for Store */ ++ case 54: /* Data Cache Block Store */ ++ case 86: /* Data Cache Block Flush */ ++ case 278: /* Data Cache Block Touch */ ++ case 758: /* Data Cache Block Allocate */ ++ case 982: /* Instruction Cache Block Invalidate */ ++ return 0; ++ ++ case 654: /* Transaction Begin */ ++ case 686: /* Transaction End */ ++ case 718: /* Transaction Check */ ++ case 750: /* Transaction Suspend or Resume */ ++ case 782: /* Transaction Abort Word Conditional */ ++ case 814: /* Transaction Abort Doubleword Conditional */ ++ case 846: /* Transaction Abort Word Conditional Immediate */ ++ case 878: /* Transaction Abort Doubleword Conditional Immediate */ ++ case 910: /* Transaction Abort */ ++ fprintf_unfiltered (gdb_stdlog, "Cannot record Transaction instructions. " ++ "%08x at %08lx, 31-%d.\n", insn, addr, ext); ++ return -1; ++ ++ case 1014: /* Data Cache Block set to Zero */ ++ if (target_auxv_search (¤t_target, AT_DCACHEBSIZE, &at_dcsz) <= 0 ++ || at_dcsz == 0) ++ at_dcsz = 128; /* Assume 128-byte cache line size (POWER8) */ ++ ++ ra = 0; ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RB (insn), &rb); ++ ea = (ra + rb) & ~((ULONGEST) (at_dcsz - 1)); ++ if (record_full_arch_list_add_mem (ea, at_dcsz) != 0) ++ return -1; ++ return 0; ++ } ++ ++UNKNOWN_OP: ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 31-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse instructions of primary opcode-59. */ ++ ++static int ++ppc_process_record_op59 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_EXTOP (insn); ++ ++ switch (ext & 0x1f) ++ { ++ case 18: /* Floating Divide */ ++ case 20: /* Floating Subtract */ ++ case 21: /* Floating Add */ ++ case 22: /* Floating Square Root */ ++ case 24: /* Floating Reciprocal Estimate */ ++ case 25: /* Floating Multiply */ ++ case 26: /* Floating Reciprocal Square Root Estimate */ ++ case 28: /* Floating Multiply-Subtract */ ++ case 29: /* Floating Multiply-Add */ ++ case 30: /* Floating Negative Multiply-Subtract */ ++ case 31: /* Floating Negative Multiply-Add */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ ++ return 0; ++ } ++ ++ switch (ext) ++ { ++ case 2: /* DFP Add */ ++ case 3: /* DFP Quantize */ ++ case 34: /* DFP Multiply */ ++ case 35: /* DFP Reround */ ++ case 67: /* DFP Quantize Immediate */ ++ case 99: /* DFP Round To FP Integer With Inexact */ ++ case 227: /* DFP Round To FP Integer Without Inexact */ ++ case 258: /* DFP Convert To DFP Long! */ ++ case 290: /* DFP Convert To Fixed */ ++ case 514: /* DFP Subtract */ ++ case 546: /* DFP Divide */ ++ case 770: /* DFP Round To DFP Short! */ ++ case 802: /* DFP Convert From Fixed */ ++ case 834: /* DFP Encode BCD To DPD */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 130: /* DFP Compare Ordered */ ++ case 162: /* DFP Test Exponent */ ++ case 194: /* DFP Test Data Class */ ++ case 226: /* DFP Test Data Group */ ++ case 642: /* DFP Compare Unordered */ ++ case 674: /* DFP Test Significance */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 66: /* DFP Shift Significand Left Immediate */ ++ case 98: /* DFP Shift Significand Right Immediate */ ++ case 322: /* DFP Decode DPD To BCD */ ++ case 354: /* DFP Extract Biased Exponent */ ++ case 866: /* DFP Insert Biased Exponent */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 846: /* Floating Convert From Integer Doubleword Single */ ++ case 974: /* Floating Convert From Integer Doubleword Unsigned ++ Single */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ ++ return 0; ++ } ++ ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 59-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse instructions of primary opcode-60. */ ++ ++static int ++ppc_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_EXTOP (insn); ++ int tmp; ++ ++ switch (ext >> 2) ++ { ++ case 0: /* VSX Scalar Add Single-Precision */ ++ case 32: /* VSX Scalar Add Double-Precision */ ++ case 24: /* VSX Scalar Divide Single-Precision */ ++ case 56: /* VSX Scalar Divide Double-Precision */ ++ case 176: /* VSX Scalar Copy Sign Double-Precision */ ++ case 33: /* VSX Scalar Multiply-Add Double-Precision */ ++ case 41: /* ditto */ ++ case 1: /* VSX Scalar Multiply-Add Single-Precision */ ++ case 9: /* ditto */ ++ case 160: /* VSX Scalar Maximum Double-Precision */ ++ case 168: /* VSX Scalar Minimum Double-Precision */ ++ case 49: /* VSX Scalar Multiply-Subtract Double-Precision */ ++ case 57: /* ditto */ ++ case 17: /* VSX Scalar Multiply-Subtract Single-Precision */ ++ case 25: /* ditto */ ++ case 48: /* VSX Scalar Multiply Double-Precision */ ++ case 16: /* VSX Scalar Multiply Single-Precision */ ++ case 161: /* VSX Scalar Negative Multiply-Add Double-Precision */ ++ case 169: /* ditto */ ++ case 129: /* VSX Scalar Negative Multiply-Add Single-Precision */ ++ case 137: /* ditto */ ++ case 177: /* VSX Scalar Negative Multiply-Subtract Double-Precision */ ++ case 185: /* ditto */ ++ case 145: /* VSX Scalar Negative Multiply-Subtract Single-Precision */ ++ case 153: /* ditto */ ++ case 40: /* VSX Scalar Subtract Double-Precision */ ++ case 8: /* VSX Scalar Subtract Single-Precision */ ++ case 96: /* VSX Vector Add Double-Precision */ ++ case 64: /* VSX Vector Add Single-Precision */ ++ case 120: /* VSX Vector Divide Double-Precision */ ++ case 88: /* VSX Vector Divide Single-Precision */ ++ case 97: /* VSX Vector Multiply-Add Double-Precision */ ++ case 105: /* ditto */ ++ case 65: /* VSX Vector Multiply-Add Single-Precision */ ++ case 73: /* ditto */ ++ case 224: /* VSX Vector Maximum Double-Precision */ ++ case 192: /* VSX Vector Maximum Single-Precision */ ++ case 232: /* VSX Vector Minimum Double-Precision */ ++ case 200: /* VSX Vector Minimum Single-Precision */ ++ case 113: /* VSX Vector Multiply-Subtract Double-Precision */ ++ case 121: /* ditto */ ++ case 81: /* VSX Vector Multiply-Subtract Single-Precision */ ++ case 89: /* ditto */ ++ case 112: /* VSX Vector Multiply Double-Precision */ ++ case 80: /* VSX Vector Multiply Single-Precision */ ++ case 225: /* VSX Vector Negative Multiply-Add Double-Precision */ ++ case 233: /* ditto */ ++ case 193: /* VSX Vector Negative Multiply-Add Single-Precision */ ++ case 201: /* ditto */ ++ case 241: /* VSX Vector Negative Multiply-Subtract Double-Precision */ ++ case 249: /* ditto */ ++ case 209: /* VSX Vector Negative Multiply-Subtract Single-Precision */ ++ case 217: /* ditto */ ++ case 104: /* VSX Vector Subtract Double-Precision */ ++ case 72: /* VSX Vector Subtract Single-Precision */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ case 240: /* VSX Vector Copy Sign Double-Precision */ ++ case 208: /* VSX Vector Copy Sign Single-Precision */ ++ case 130: /* VSX Logical AND */ ++ case 138: /* VSX Logical AND with Complement */ ++ case 186: /* VSX Logical Equivalence */ ++ case 178: /* VSX Logical NAND */ ++ case 170: /* VSX Logical OR with Complement */ ++ case 162: /* VSX Logical NOR */ ++ case 146: /* VSX Logical OR */ ++ case 154: /* VSX Logical XOR */ ++ case 18: /* VSX Merge High Word */ ++ case 50: /* VSX Merge Low Word */ ++ case 10: /* VSX Permute Doubleword Immediate (DM=0) */ ++ case 10 | 0x20: /* VSX Permute Doubleword Immediate (DM=1) */ ++ case 10 | 0x40: /* VSX Permute Doubleword Immediate (DM=2) */ ++ case 10 | 0x60: /* VSX Permute Doubleword Immediate (DM=3) */ ++ case 2: /* VSX Shift Left Double by Word Immediate (SHW=0) */ ++ case 2 | 0x20: /* VSX Shift Left Double by Word Immediate (SHW=1) */ ++ case 2 | 0x40: /* VSX Shift Left Double by Word Immediate (SHW=2) */ ++ case 2 | 0x60: /* VSX Shift Left Double by Word Immediate (SHW=3) */ ++ ppc_record_vsr (regcache, tdep, PPC_XT (insn)); ++ return 0; ++ ++ case 61: /* VSX Scalar Test for software Divide Double-Precision */ ++ case 125: /* VSX Vector Test for software Divide Double-Precision */ ++ case 93: /* VSX Vector Test for software Divide Single-Precision */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 35: /* VSX Scalar Compare Unordered Double-Precision */ ++ case 43: /* VSX Scalar Compare Ordered Double-Precision */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ } ++ ++ switch ((ext >> 2) & 0x7f) /* Mask out Rc-bit. */ ++ { ++ case 99: /* VSX Vector Compare Equal To Double-Precision */ ++ case 67: /* VSX Vector Compare Equal To Single-Precision */ ++ case 115: /* VSX Vector Compare Greater Than or ++ Equal To Double-Precision */ ++ case 83: /* VSX Vector Compare Greater Than or ++ Equal To Single-Precision */ ++ case 107: /* VSX Vector Compare Greater Than Double-Precision */ ++ case 75: /* VSX Vector Compare Greater Than Single-Precision */ ++ if (PPC_Rc (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ ppc_record_vsr (regcache, tdep, PPC_XT (insn)); ++ return 0; ++ } ++ ++ switch (ext >> 1) ++ { ++ case 265: /* VSX Scalar round Double-Precision to ++ Single-Precision and Convert to ++ Single-Precision format */ ++ case 344: /* VSX Scalar truncate Double-Precision to ++ Integer and Convert to Signed Integer ++ Doubleword format with Saturate */ ++ case 88: /* VSX Scalar truncate Double-Precision to ++ Integer and Convert to Signed Integer Word ++ Format with Saturate */ ++ case 328: /* VSX Scalar truncate Double-Precision integer ++ and Convert to Unsigned Integer Doubleword ++ Format with Saturate */ ++ case 72: /* VSX Scalar truncate Double-Precision to ++ Integer and Convert to Unsigned Integer Word ++ Format with Saturate */ ++ case 329: /* VSX Scalar Convert Single-Precision to ++ Double-Precision format */ ++ case 376: /* VSX Scalar Convert Signed Integer ++ Doubleword to floating-point format and ++ Round to Double-Precision format */ ++ case 312: /* VSX Scalar Convert Signed Integer ++ Doubleword to floating-point format and ++ round to Single-Precision */ ++ case 360: /* VSX Scalar Convert Unsigned Integer ++ Doubleword to floating-point format and ++ Round to Double-Precision format */ ++ case 296: /* VSX Scalar Convert Unsigned Integer ++ Doubleword to floating-point format and ++ Round to Single-Precision */ ++ case 73: /* VSX Scalar Round to Double-Precision Integer ++ Using Round to Nearest Away */ ++ case 107: /* VSX Scalar Round to Double-Precision Integer ++ Exact using Current rounding mode */ ++ case 121: /* VSX Scalar Round to Double-Precision Integer ++ Using Round toward -Infinity */ ++ case 105: /* VSX Scalar Round to Double-Precision Integer ++ Using Round toward +Infinity */ ++ case 89: /* VSX Scalar Round to Double-Precision Integer ++ Using Round toward Zero */ ++ case 90: /* VSX Scalar Reciprocal Estimate Double-Precision */ ++ case 26: /* VSX Scalar Reciprocal Estimate Single-Precision */ ++ case 281: /* VSX Scalar Round to Single-Precision */ ++ case 74: /* VSX Scalar Reciprocal Square Root Estimate ++ Double-Precision */ ++ case 10: /* VSX Scalar Reciprocal Square Root Estimate ++ Single-Precision */ ++ case 75: /* VSX Scalar Square Root Double-Precision */ ++ case 11: /* VSX Scalar Square Root Single-Precision */ ++ case 393: /* VSX Vector round Double-Precision to ++ Single-Precision and Convert to ++ Single-Precision format */ ++ case 472: /* VSX Vector truncate Double-Precision to ++ Integer and Convert to Signed Integer ++ Doubleword format with Saturate */ ++ case 216: /* VSX Vector truncate Double-Precision to ++ Integer and Convert to Signed Integer Word ++ Format with Saturate */ ++ case 456: /* VSX Vector truncate Double-Precision to ++ Integer and Convert to Unsigned Integer ++ Doubleword format with Saturate */ ++ case 200: /* VSX Vector truncate Double-Precision to ++ Integer and Convert to Unsigned Integer Word ++ Format with Saturate */ ++ case 457: /* VSX Vector Convert Single-Precision to ++ Double-Precision format */ ++ case 408: /* VSX Vector truncate Single-Precision to ++ Integer and Convert to Signed Integer ++ Doubleword format with Saturate */ ++ case 152: /* VSX Vector truncate Single-Precision to ++ Integer and Convert to Signed Integer Word ++ Format with Saturate */ ++ case 392: /* VSX Vector truncate Single-Precision to ++ Integer and Convert to Unsigned Integer ++ Doubleword format with Saturate */ ++ case 136: /* VSX Vector truncate Single-Precision to ++ Integer and Convert to Unsigned Integer Word ++ Format with Saturate */ ++ case 504: /* VSX Vector Convert and round Signed Integer ++ Doubleword to Double-Precision format */ ++ case 440: /* VSX Vector Convert and round Signed Integer ++ Doubleword to Single-Precision format */ ++ case 248: /* VSX Vector Convert Signed Integer Word to ++ Double-Precision format */ ++ case 184: /* VSX Vector Convert and round Signed Integer ++ Word to Single-Precision format */ ++ case 488: /* VSX Vector Convert and round Unsigned ++ Integer Doubleword to Double-Precision format */ ++ case 424: /* VSX Vector Convert and round Unsigned ++ Integer Doubleword to Single-Precision format */ ++ case 232: /* VSX Vector Convert and round Unsigned ++ Integer Word to Double-Precision format */ ++ case 168: /* VSX Vector Convert and round Unsigned ++ Integer Word to Single-Precision format */ ++ case 201: /* VSX Vector Round to Double-Precision ++ Integer using round to Nearest Away */ ++ case 235: /* VSX Vector Round to Double-Precision ++ Integer Exact using Current rounding mode */ ++ case 249: /* VSX Vector Round to Double-Precision ++ Integer using round toward -Infinity */ ++ case 233: /* VSX Vector Round to Double-Precision ++ Integer using round toward +Infinity */ ++ case 217: /* VSX Vector Round to Double-Precision ++ Integer using round toward Zero */ ++ case 218: /* VSX Vector Reciprocal Estimate Double-Precision */ ++ case 154: /* VSX Vector Reciprocal Estimate Single-Precision */ ++ case 137: /* VSX Vector Round to Single-Precision Integer ++ Using Round to Nearest Away */ ++ case 171: /* VSX Vector Round to Single-Precision Integer ++ Exact Using Current rounding mode */ ++ case 185: /* VSX Vector Round to Single-Precision Integer ++ Using Round toward -Infinity */ ++ case 169: /* VSX Vector Round to Single-Precision Integer ++ Using Round toward +Infinity */ ++ case 153: /* VSX Vector Round to Single-Precision Integer ++ Using round toward Zero */ ++ case 202: /* VSX Vector Reciprocal Square Root Estimate ++ Double-Precision */ ++ case 138: /* VSX Vector Reciprocal Square Root Estimate ++ Single-Precision */ ++ case 203: /* VSX Vector Square Root Double-Precision */ ++ case 139: /* VSX Vector Square Root Single-Precision */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ case 345: /* VSX Scalar Absolute Value Double-Precision */ ++ case 267: /* VSX Scalar Convert Scalar Single-Precision to ++ Vector Single-Precision format Non-signalling */ ++ case 331: /* VSX Scalar Convert Single-Precision to ++ Double-Precision format Non-signalling */ ++ case 361: /* VSX Scalar Negative Absolute Value Double-Precision */ ++ case 377: /* VSX Scalar Negate Double-Precision */ ++ case 473: /* VSX Vector Absolute Value Double-Precision */ ++ case 409: /* VSX Vector Absolute Value Single-Precision */ ++ case 489: /* VSX Vector Negative Absolute Value Double-Precision */ ++ case 425: /* VSX Vector Negative Absolute Value Single-Precision */ ++ case 505: /* VSX Vector Negate Double-Precision */ ++ case 441: /* VSX Vector Negate Single-Precision */ ++ case 164: /* VSX Splat Word */ ++ ppc_record_vsr (regcache, tdep, PPC_XT (insn)); ++ return 0; ++ ++ case 106: /* VSX Scalar Test for software Square Root ++ Double-Precision */ ++ case 234: /* VSX Vector Test for software Square Root ++ Double-Precision */ ++ case 170: /* VSX Vector Test for software Square Root ++ Single-Precision */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ } ++ ++ if (((ext >> 3) & 0x3) == 3) /* VSX Select */ ++ { ++ ppc_record_vsr (regcache, tdep, PPC_XT (insn)); ++ return 0; ++ } ++ ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 60-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse instructions of primary opcode-63. */ ++ ++static int ++ppc_process_record_op63 (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr, uint32_t insn) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ int ext = PPC_EXTOP (insn); ++ int tmp; ++ ++ switch (ext & 0x1f) ++ { ++ case 18: /* Floating Divide */ ++ case 20: /* Floating Subtract */ ++ case 21: /* Floating Add */ ++ case 22: /* Floating Square Root */ ++ case 24: /* Floating Reciprocal Estimate */ ++ case 25: /* Floating Multiply */ ++ case 26: /* Floating Reciprocal Square Root Estimate */ ++ case 28: /* Floating Multiply-Subtract */ ++ case 29: /* Floating Multiply-Add */ ++ case 30: /* Floating Negative Multiply-Subtract */ ++ case 31: /* Floating Negative Multiply-Add */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 23: /* Floating Select */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ } ++ ++ switch (ext) ++ { ++ case 2: /* DFP Add Quad */ ++ case 3: /* DFP Quantize Quad */ ++ case 34: /* DFP Multiply Quad */ ++ case 35: /* DFP Reround Quad */ ++ case 67: /* DFP Quantize Immediate Quad */ ++ case 99: /* DFP Round To FP Integer With Inexact Quad */ ++ case 227: /* DFP Round To FP Integer Without Inexact Quad */ ++ case 258: /* DFP Convert To DFP Extended Quad */ ++ case 514: /* DFP Subtract Quad */ ++ case 546: /* DFP Divide Quad */ ++ case 770: /* DFP Round To DFP Long Quad */ ++ case 802: /* DFP Convert From Fixed Quad */ ++ case 834: /* DFP Encode BCD To DPD Quad */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 130: /* DFP Compare Ordered Quad */ ++ case 162: /* DFP Test Exponent Quad */ ++ case 194: /* DFP Test Data Class Quad */ ++ case 226: /* DFP Test Data Group Quad */ ++ case 642: /* DFP Compare Unordered Quad */ ++ case 674: /* DFP Test Significance Quad */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 66: /* DFP Shift Significand Left Immediate Quad */ ++ case 98: /* DFP Shift Significand Right Immediate Quad */ ++ case 322: /* DFP Decode DPD To BCD Quad */ ++ case 866: /* DFP Insert Biased Exponent Quad */ ++ tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 290: /* DFP Convert To Fixed Quad */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ break; ++ ++ case 354: /* DFP Extract Biased Exponent Quad */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 12: /* Floating Round to Single-Precision */ ++ case 14: /* Floating Convert To Integer Word */ ++ case 15: /* Floating Convert To Integer Word ++ with round toward Zero */ ++ case 142: /* Floating Convert To Integer Word Unsigned */ ++ case 143: /* Floating Convert To Integer Word Unsigned ++ with round toward Zero */ ++ case 392: /* Floating Round to Integer Nearest */ ++ case 424: /* Floating Round to Integer Toward Zero */ ++ case 456: /* Floating Round to Integer Plus */ ++ case 488: /* Floating Round to Integer Minus */ ++ case 814: /* Floating Convert To Integer Doubleword */ ++ case 815: /* Floating Convert To Integer Doubleword ++ with round toward Zero */ ++ case 846: /* Floating Convert From Integer Doubleword */ ++ case 942: /* Floating Convert To Integer Doubleword Unsigned */ ++ case 943: /* Floating Convert To Integer Doubleword Unsigned ++ with round toward Zero */ ++ case 974: /* Floating Convert From Integer Doubleword Unsigned */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ return 0; ++ ++ case 583: /* Move From FPSCR */ ++ case 8: /* Floating Copy Sign */ ++ case 40: /* Floating Negate */ ++ case 72: /* Floating Move Register */ ++ case 136: /* Floating Negative Absolute Value */ ++ case 264: /* Floating Absolute Value */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ case 838: /* Floating Merge Odd Word */ ++ case 966: /* Floating Merge Even Word */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ return 0; ++ ++ case 38: /* Move To FPSCR Bit 1 */ ++ case 70: /* Move To FPSCR Bit 0 */ ++ case 134: /* Move To FPSCR Field Immediate */ ++ case 711: /* Move To FPSCR Fields */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ break; ++ ++ case 0: /* Floating Compare Unordered */ ++ case 32: /* Floating Compare Ordered */ ++ case 64: /* Move to Condition Register from FPSCR */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); ++ /* FALL-THROUGH */ ++ case 128: /* Floating Test for software Divide */ ++ case 160: /* Floating Test for software Square Root */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ return 0; ++ ++ } ++ ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, 59-%d.\n", insn, addr, ext); ++ return -1; ++} ++ ++/* Parse the current instruction and record the values of the registers and ++ memory that will be changed in current instruction to "record_arch_list". ++ Return -1 if something wrong. */ ++ ++int ++ppc_process_record (struct gdbarch *gdbarch, struct regcache *regcache, ++ CORE_ADDR addr) ++{ ++ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ++ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); ++ uint32_t insn; ++ int op6, tmp, i; ++ ++ insn = read_memory_unsigned_integer (addr, 4, byte_order); ++ op6 = PPC_OP6 (insn); ++ ++ switch (op6) ++ { ++ case 2: /* Trap Doubleword Immediate */ ++ case 3: /* Trap Word Immediate */ ++ /* Do nothing. */ ++ break; ++ ++ case 4: ++ if (ppc_process_record_op4 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ case 17: /* System call */ ++ if (PPC_LEV (insn) != 0) ++ goto UNKNOWN_OP; ++ ++ if (tdep->ppc_syscall_record != NULL) ++ { ++ if (tdep->ppc_syscall_record (regcache) != 0) ++ return -1; ++ } ++ else ++ { ++ printf_unfiltered (_("no syscall record support\n")); ++ return -1; ++ } ++ break; ++ ++ case 7: /* Multiply Low Immediate */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ break; ++ ++ case 8: /* Subtract From Immediate Carrying */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ break; ++ ++ case 10: /* Compare Logical Immediate */ ++ case 11: /* Compare Immediate */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ break; ++ ++ case 13: /* Add Immediate Carrying and Record */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ /* FALL-THROUGH */ ++ case 12: /* Add Immediate Carrying */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); ++ /* FALL-THROUGH */ ++ case 14: /* Add Immediate */ ++ case 15: /* Add Immediate Shifted */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ break; ++ ++ case 16: /* Branch Conditional */ ++ if ((PPC_BO (insn) & 0x4) == 0) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); ++ /* FALL-THROUGH */ ++ case 18: /* Branch */ ++ if (PPC_LK (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); ++ break; ++ ++ case 19: ++ if (ppc_process_record_op19 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ case 20: /* Rotate Left Word Immediate then Mask Insert */ ++ case 21: /* Rotate Left Word Immediate then AND with Mask */ ++ case 23: /* Rotate Left Word then AND with Mask */ ++ case 30: /* Rotate Left Doubleword Immediate then Clear Left */ ++ /* Rotate Left Doubleword Immediate then Clear Right */ ++ /* Rotate Left Doubleword Immediate then Clear */ ++ /* Rotate Left Doubleword then Clear Left */ ++ /* Rotate Left Doubleword then Clear Right */ ++ /* Rotate Left Doubleword Immediate then Mask Insert */ ++ if (PPC_RC (insn)) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ break; ++ ++ case 28: /* AND Immediate */ ++ case 29: /* AND Immediate Shifted */ ++ record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); ++ /* FALL-THROUGH */ ++ case 24: /* OR Immediate */ ++ case 25: /* OR Immediate Shifted */ ++ case 26: /* XOR Immediate */ ++ case 27: /* XOR Immediate Shifted */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ break; ++ ++ case 31: ++ if (ppc_process_record_op31 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ case 33: /* Load Word and Zero with Update */ ++ case 35: /* Load Byte and Zero with Update */ ++ case 41: /* Load Halfword and Zero with Update */ ++ case 43: /* Load Halfword Algebraic with Update */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 32: /* Load Word and Zero */ ++ case 34: /* Load Byte and Zero */ ++ case 40: /* Load Halfword and Zero */ ++ case 42: /* Load Halfword Algebraic */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ break; ++ ++ case 46: /* Load Multiple Word */ ++ for (i = PPC_RT (insn); i < 32; i++) ++ record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i); ++ break; ++ ++ case 56: /* Load Quadword */ ++ tmp = tdep->ppc_gp0_regnum + (PPC_RT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ break; ++ ++ case 49: /* Load Floating-Point Single with Update */ ++ case 51: /* Load Floating-Point Double with Update */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 48: /* Load Floating-Point Single */ ++ case 50: /* Load Floating-Point Double */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_fp0_regnum + PPC_FRT (insn)); ++ break; ++ ++ case 47: /* Store Multiple Word */ ++ { ++ ULONGEST addr = 0; ++ ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn), ++ &addr); ++ ++ addr += PPC_D (insn); ++ if (record_full_arch_list_add_mem (addr, 4 * (32 - PPC_RS (insn))) != 0) ++ return -1; ++ } ++ break; ++ ++ case 37: /* Store Word with Update */ ++ case 39: /* Store Byte with Update */ ++ case 45: /* Store Halfword with Update */ ++ case 53: /* Store Floating-Point Single with Update */ ++ case 55: /* Store Floating-Point Double with Update */ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ /* FALL-THROUGH */ ++ case 36: /* Store Word */ ++ case 38: /* Store Byte */ ++ case 44: /* Store Halfword */ ++ case 52: /* Store Floating-Point Single */ ++ case 54: /* Store Floating-Point Double */ ++ { ++ ULONGEST addr = 0; ++ int size = -1; ++ ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn), ++ &addr); ++ addr += PPC_D (insn); ++ ++ if (op6 == 36 || op6 == 37 || op6 == 52 || op6 == 53) ++ size = 4; ++ else if (op6 == 54 || op6 == 55) ++ size = 8; ++ else if (op6 == 44 || op6 == 45) ++ size = 2; ++ else if (op6 == 38 || op6 == 39) ++ size = 1; ++ else ++ gdb_assert (0); ++ ++ if (record_full_arch_list_add_mem (addr, size) != 0) ++ return -1; ++ } ++ break; ++ ++ case 57: /* Load Floating-Point Double Pair */ ++ if (PPC_FIELD (insn, 30, 2) != 0) ++ goto UNKNOWN_OP; ++ tmp = tdep->ppc_fp0_regnum + (PPC_RT (insn) & ~1); ++ record_full_arch_list_add_reg (regcache, tmp); ++ record_full_arch_list_add_reg (regcache, tmp + 1); ++ break; ++ ++ case 58: /* Load Doubleword */ ++ /* Load Doubleword with Update */ ++ /* Load Word Algebraic */ ++ if (PPC_FIELD (insn, 30, 2) > 2) ++ goto UNKNOWN_OP; ++ ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RT (insn)); ++ if (PPC_BIT (insn, 31)) ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn)); ++ break; ++ ++ case 59: ++ if (ppc_process_record_op59 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ case 60: ++ if (ppc_process_record_op60 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ case 61: /* Store Floating-Point Double Pair */ ++ case 62: /* Store Doubleword */ ++ /* Store Doubleword with Update */ ++ /* Store Quadword with Update */ ++ { ++ ULONGEST addr = 0; ++ int size; ++ int sub2 = PPC_FIELD (insn, 30, 2); ++ ++ if ((op6 == 61 && sub2 != 0) || (op6 == 62 && sub2 > 2)) ++ goto UNKNOWN_OP; ++ ++ if (PPC_RA (insn) != 0) ++ regcache_raw_read_unsigned (regcache, ++ tdep->ppc_gp0_regnum + PPC_RA (insn), ++ &addr); ++ ++ size = ((op6 == 61) || sub2 == 2) ? 16 : 8; ++ ++ addr += PPC_DS (insn) << 2; ++ if (record_full_arch_list_add_mem (addr, size) != 0) ++ return -1; ++ ++ if (op6 == 62 && sub2 == 1) ++ record_full_arch_list_add_reg (regcache, ++ tdep->ppc_gp0_regnum + ++ PPC_RA (insn)); ++ ++ break; ++ } ++ ++ case 63: ++ if (ppc_process_record_op63 (gdbarch, regcache, addr, insn) != 0) ++ return -1; ++ break; ++ ++ default: ++UNKNOWN_OP: ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " ++ "%08x at %08lx, %d.\n", insn, addr, op6); ++ return -1; ++ } ++ ++ if (record_full_arch_list_add_reg (regcache, PPC_PC_REGNUM)) ++ return -1; ++ if (record_full_arch_list_add_end ()) ++ return -1; ++ return 0; ++} ++ + /* Initialize the current architecture based on INFO. If possible, re-use an + architecture from ARCHES, which is a list of architectures already created + during this debugging session. +Index: gdb-7.6.1/gdb/testsuite/lib/gdb.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/lib/gdb.exp ++++ gdb-7.6.1/gdb/testsuite/lib/gdb.exp +@@ -1784,7 +1784,8 @@ proc supports_process_record {} { + return [target_info gdb,use_precord] + } + +- if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] } { ++ if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] ++ || [istarget "powerpc*-*-linux*"] } { + return 1 + } + +@@ -1799,7 +1800,8 @@ proc supports_reverse {} { + return [target_info gdb,can_reverse] + } + +- if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] } { ++ if { [istarget "x86_64-*-linux*"] || [istarget "i\[34567\]86-*-linux*"] ++ || [istarget "powerpc*-*-linux*"] } { + return 1 + } + diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-5of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-5of7.patch new file mode 100644 index 0000000..ac43ca4 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-5of7.patch @@ -0,0 +1,252 @@ + Message-ID: <5491BE7E.2060708@gmail.com> + Date: Thu, 18 Dec 2014 01:33:50 +0800 + From: Wei-cheng Wang + To: Ulrich Weigand + CC: gdb-patches at sourceware dot org + Subject: Re: [PATCH 3/3 v2] Process record support for PowerPC + + On 2014/12/9 上午 03:13, Ulrich Weigand wrote: + > Wei-cheng Wang wrote: + >> * ppc-linux-tdep.c (powerpc_linux_in_dynsym_resolve_code): + >> Scan PLT stub backward for reverse debugging. + >> (ppc_linux_init_abi): set powerpc_linux_in_dynsym_resolve_code + >> for both 32-bit and 64-bit. + > + > As I said in the reply to the 0/3 mail, I really think it would be + > better to handle this within the PPC skip_trampoline_code implementation, + > instead of having in_dynsym_resolve_code suddenly also cover the + > trampolines ... + + Hi, + + See the new patch, I moved the for-loop into skip_trampoline_code, + and removed in_dynsym_resolve_code. + + > It seems odd to have in_dynsym_resolve_code call into + > skip_trampoline_code. Is there a reason why the skip_trampoline_code + > implementation cannot accept a PC in the middle of the sequence? + + I thought skip-trampoline is used to find the target address for + inserting step-resume breakpoint, so it doesn't make sense for + reverse-stepping, because we are just stepping from the target address. + And for forward-stepping, when we reach the very first instruction of + trampoline code, we can just skip the resolving code by inserting + a step-resume breakpoint, so we don't have to step through the resolving + code and check whether we are in the middle of trampoline code. + + in_dynsym_resolve_code is used to check whether we are in (the middle of) + the resolving code, so we can keep going to step though the resolving code. + Therefor I thought in_dynsym_resolve_code is the proper place to implement. + + Since skip-trampoline-code had implemented the plt-stub pattern-match code + we need, by calling it in in-dynsym-resolve-code, we don't need to have + duplicate pattern-match code in both functions. + + Wei-cheng, + Thanks + + -- + + 2014-12-06 Wei-cheng Wang + + * ppc-linux-tdep.c (ppc_skip_trampoline_code): + Scan PLT stub backward for reverse debugging. + * ppc64-tdep.c (ppc64_skip_trampoline_code): Likewise. + + +commit cf90fd9a07e8998540bf74f293d348a6653ac120 +Author: Wei-cheng Wang +Date: Sat Jan 17 14:30:59 2015 +0800 + + Skip-trampoline for PowerPC reverse-stepping. + +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -20,6 +20,7 @@ + #include "defs.h" + #include "frame.h" + #include "gdbcore.h" ++#include "inferior.h" + #include "ppc-tdep.h" + #include "ppc64-tdep.h" + #include "elf-bfd.h" +@@ -464,35 +465,66 @@ ppc64_skip_trampoline_code (struct frame + ARRAY_SIZE (ppc64_standard_linkage8)))) + - 1]; + CORE_ADDR target; ++ int scan_limit, i; + +- if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns)) +- pc = ppc64_standard_linkage4_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, insns)) +- pc = ppc64_standard_linkage3_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, insns)) +- pc = ppc64_standard_linkage4_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5, insns) +- && (insns[8] != 0 || insns[9] != 0)) +- pc = ppc64_standard_linkage3_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4, insns) +- && (insns[9] != 0 || insns[10] != 0)) +- pc = ppc64_standard_linkage4_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, insns) +- && (insns[8] != 0 || insns[9] != 0)) +- pc = ppc64_standard_linkage3_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, insns) +- && (insns[10] != 0 || insns[11] != 0)) +- pc = ppc64_standard_linkage2_target (frame, pc, insns); +- else if (ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1, insns)) +- pc = ppc64_standard_linkage1_target (frame, pc, insns); +- else +- return 0; +- +- /* The PLT descriptor will either point to the already resolved target +- address, or else to a glink stub. As the latter carry synthetic @plt +- symbols, find_solib_trampoline_target should be able to resolve them. */ +- target = find_solib_trampoline_target (frame, pc); +- return target ? target : pc; ++ scan_limit = 1; ++ /* When reverse-debugging, scan backward to check whether we are ++ in the middle of trampoline code. */ ++ if (execution_direction == EXEC_REVERSE) ++ scan_limit = ARRAY_SIZE (insns) - 1; ++ ++ for (i = 0; i < scan_limit; i++) ++ { ++ if (i < ARRAY_SIZE (ppc64_standard_linkage8) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage8, insns)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage7) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage7, ++ insns)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage6) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage6, ++ insns)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage5) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage5, ++ insns) ++ && (insns[8] != 0 || insns[9] != 0)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage4) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage4, ++ insns) ++ && (insns[9] != 0 || insns[10] != 0)) ++ pc = ppc64_standard_linkage4_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage3) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage3, ++ insns) ++ && (insns[8] != 0 || insns[9] != 0)) ++ pc = ppc64_standard_linkage3_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage2) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage2, ++ insns) ++ && (insns[10] != 0 || insns[11] != 0)) ++ pc = ppc64_standard_linkage2_target (frame, pc, insns); ++ else if (i < ARRAY_SIZE (ppc64_standard_linkage1) - 1 ++ && ppc_insns_match_pattern (frame, pc, ppc64_standard_linkage1, ++ insns)) ++ pc = ppc64_standard_linkage1_target (frame, pc, insns); ++ else ++ { ++ /* Scan backward one more instructions if doesn't match. */ ++ pc -= 4; ++ continue; ++ } ++ ++ /* The PLT descriptor will either point to the already resolved target ++ address, or else to a glink stub. As the latter carry synthetic @plt ++ symbols, find_solib_trampoline_target should be able to resolve them. */ ++ target = find_solib_trampoline_target (frame, pc); ++ return target ? target : pc; ++ } ++ ++ return 0; + } + + /* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -52,6 +52,7 @@ + #include "linux-tdep.h" + #include "linux-record.h" + #include "record-full.h" ++#include "inferior.h" + + #include "stap-probe.h" + #include "ax.h" +@@ -362,31 +363,50 @@ ppc_skip_trampoline_code (struct frame_i + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR target = 0; ++ int scan_limit, i; + +- if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf)) +- { +- /* Insn pattern is +- lis r11, xxxx +- lwz r11, xxxx(r11) +- Branch target is in r11. */ +- +- target = (ppc_insn_d_field (insnbuf[0]) << 16) +- | ppc_insn_d_field (insnbuf[1]); +- target = read_memory_unsigned_integer (target, 4, byte_order); +- } ++ scan_limit = 1; ++ /* When reverse-debugging, scan backward to check whether we are ++ in the middle of trampoline code. */ ++ if (execution_direction == EXEC_REVERSE) ++ scan_limit = 4; /* At more 4 instructions. */ + +- if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf)) ++ for (i = 0; i < scan_limit; i++) + { +- /* Insn pattern is +- lwz r11, xxxx(r30) +- Branch target is in r11. */ +- +- target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30) +- + ppc_insn_d_field (insnbuf[0]); +- target = read_memory_unsigned_integer (target, 4, byte_order); ++ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf)) ++ { ++ /* Insn pattern is ++ lis r11, xxxx ++ lwz r11, xxxx(r11) ++ Branch target is in r11. */ ++ ++ target = (ppc_insn_d_field (insnbuf[0]) << 16) ++ | ppc_insn_d_field (insnbuf[1]); ++ target = read_memory_unsigned_integer (target, 4, byte_order); ++ } ++ else if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, ++ insnbuf)) ++ { ++ /* Insn pattern is ++ lwz r11, xxxx(r30) ++ Branch target is in r11. */ ++ ++ target = get_frame_register_unsigned (frame, ++ tdep->ppc_gp0_regnum + 30) ++ + ppc_insn_d_field (insnbuf[0]); ++ target = read_memory_unsigned_integer (target, 4, byte_order); ++ } ++ else ++ { ++ /* Scan backward one more instructions if doesn't match. */ ++ pc -= 4; ++ continue; ++ } ++ ++ return target; + } + +- return target; ++ return 0; + } + + /* Wrappers to handle Linux-only registers. */ diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-6of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-6of7.patch new file mode 100644 index 0000000..f8e3ff3 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-6of7.patch @@ -0,0 +1,131 @@ + Message-ID: <54BB676B.2090101@gmail.com> + Date: Sun, 18 Jan 2015 15:57:31 +0800 + From: Wei-cheng Wang + To: Jan Kratochvil + CC: Ulrich Weigand , gdb-patches at sourceware dot org, Joel Brobecker + Subject: Re: Broken build: rs6000-tdep.c: 32-bit host --enable-targets=all --enable-64-bit-bfd [Re: [PATCH 2/3 v4] Process record support for PowerPC] + + On 2015/1/18 下午 02:59, Jan Kratochvil wrote: + > GDB has paddress(), core_addr_to_string() and hex_string() instead while the + > codebase uses these three interchangeably. But the codebase uses even the + > %lx+long form. + + Using %s+paddress instead of %lx+long in this patch. + + Thanks, + Wei-cheng + + +commit 810c102655475827a3174fb64b5e14beaa57ec3f +Author: Wei-cheng Wang +Date: Sun Jan 18 15:20:46 2015 +0800 + + Fix format warning in rs6000t-dep.c + +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -3405,7 +3405,6 @@ rs6000_epilogue_frame_cache (struct fram + struct rs6000_frame_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +- CORE_ADDR sp; + + if (*this_cache) + return *this_cache; +@@ -4006,8 +4005,8 @@ ppc_process_record_op4 (struct gdbarch * + return 0; + } + +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 4-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 4-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -4049,8 +4048,8 @@ ppc_process_record_op19 (struct gdbarch + return 0; + } + +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 19-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 19-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -4507,7 +4506,8 @@ ppc_process_record_op31 (struct gdbarch + case 878: /* Transaction Abort Doubleword Conditional Immediate */ + case 910: /* Transaction Abort */ + fprintf_unfiltered (gdb_stdlog, "Cannot record Transaction instructions. " +- "%08x at %08lx, 31-%d.\n", insn, addr, ext); ++ "%08x at %s, 31-%d.\n", ++ insn, paddress (gdbarch, addr), ext); + return -1; + + case 1014: /* Data Cache Block set to Zero */ +@@ -4526,8 +4526,8 @@ ppc_process_record_op31 (struct gdbarch + } + + UNKNOWN_OP: +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 31-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 31-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -4618,8 +4618,8 @@ ppc_process_record_op59 (struct gdbarch + return 0; + } + +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 59-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 59-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -4631,7 +4631,6 @@ ppc_process_record_op60 (struct gdbarch + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); +- int tmp; + + switch (ext >> 2) + { +@@ -4901,8 +4900,8 @@ ppc_process_record_op60 (struct gdbarch + return 0; + } + +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 60-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 60-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -5067,8 +5066,8 @@ ppc_process_record_op63 (struct gdbarch + + } + +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, 59-%d.\n", insn, addr, ext); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, 59-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; + } + +@@ -5347,8 +5346,8 @@ ppc_process_record (struct gdbarch *gdba + + default: + UNKNOWN_OP: +- fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record " +- "%08x at %08lx, %d.\n", insn, addr, op6); ++ fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " ++ "at %s, %d.\n", insn, paddress (gdbarch, addr), op6); + return -1; + } + diff --git a/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-7of7.patch b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-7of7.patch new file mode 100644 index 0000000..4922423 --- /dev/null +++ b/SOURCES/gdb-rhbz1218710-reverse-debugging-ppc-7of7.patch @@ -0,0 +1,284 @@ + Message-ID: <54BD2C4B.7010102@gmail.com> + Date: Tue, 20 Jan 2015 00:09:47 +0800 + From: Wei-cheng Wang + To: Joel Brobecker + CC: Ulrich Weigand , gdb-patches at sourceware dot org + Subject: Re: [PATCH 2/3 v4] Process record support for PowerPC + + On 2015/1/19 下午 03:48, Joel Brobecker wrote: + >> Using %s+paddress instead of %lx+long in this patch. + > The change looks fine to me, but there is no ChangeLog. + + Hi Joel, + + ChangeLog is in my last mail. Re-post below for your review. + + 2015-01-18 Wei-cheng Wang + + * rs6000-tdep.c (ppc_process_record_op4, ppc_process_record_op19, + ppc_process_record_op31, ppc_process_record_op59, + ppc_process_record_op60, ppc_process_record_op63, + ppc_process_record): Fix -Wformat warning. + * rs6000-tdep.c (rs6000_epilogue_frame_cache, ppc_process_record_op60): + Remove unused variables. + + > Also, I ended glancing at some of the patches you recently pushed, + > and noticed that you added a lot of new functions for which there + > is no introductory comment describing the function's behavior and + > arguments. It is now mandatory that all new functions, no matter + > how trivial, have such introductory comment. Would you mind going + > back over your patches, and send a patch that adds the missing + > comments, please? + + I've added the missing comments. See below. + + Thanks, + Wei-cheng + + + 2015-01-18 Wei-cheng Wang + + * ppc-linux-tdep.c (ppc_skip_trampoline_code, + ppc_canonicalize_syscall, ppc_linux_syscall_record, + ppc_linux_record_signal, ppc_init_linux_record_tdep): Add comments. + * ppc64-tdep.c (ppc64_skip_trampoline_code): Likewise. + * rs6000-tdep.c (rs6000_epilogue_frame_cache, + rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register, + rs6000_epilogue_frame_sniffer, ppc_record_vsr, ppc_process_record_op4, + ppc_process_record_op19, ppc_process_record_op31, + ppc_process_record_op59, ppc_process_record_op60, + ppc_process_record_op63): Likewise. + +commit ddeca1dffbe346eea03b893bf3c5bc46e4439e93 +Author: Wei-cheng Wang +Date: Mon Jan 19 23:34:07 2015 +0800 + + Add missing comments in rs6000-tdep.c, ppc64-tdep.c and ppc-linux-tdep.c. + + gdb/ChangeLog: + + * ppc-linux-tdep.c (ppc_skip_trampoline_code, + ppc_canonicalize_syscall, ppc_linux_syscall_record, + ppc_linux_record_signal, ppc_init_linux_record_tdep): Add comments. + * ppc64-tdep.c (ppc64_skip_trampoline_code): Likewise. + * rs6000-tdep.c (rs6000_epilogue_frame_cache, + rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register, + rs6000_epilogue_frame_sniffer, ppc_record_vsr, ppc_process_record_op4, + ppc_process_record_op19, ppc_process_record_op31, + ppc_process_record_op59, ppc_process_record_op60, + ppc_process_record_op63): Likewise. + +Index: gdb-7.6.1/gdb/ppc64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc64-tdep.c ++++ gdb-7.6.1/gdb/ppc64-tdep.c +@@ -449,7 +449,10 @@ ppc64_standard_linkage4_target (struct f + + + /* Given that we've begun executing a call trampoline at PC, return +- the entry point of the function the trampoline will go to. */ ++ the entry point of the function the trampoline will go to. ++ ++ When the execution direction is EXEC_REVERSE, scan backward to ++ check whether we are in the middle of a PLT stub. */ + + CORE_ADDR + ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -353,7 +353,12 @@ powerpc_linux_in_dynsym_resolve_code (CO + return 0; + } + +-/* Follow PLT stub to actual routine. */ ++/* Follow PLT stub to actual routine. ++ ++ When the execution direction is EXEC_REVERSE, scan backward to ++ check whether we are in the middle of a PLT stub. Currently, ++ we only look-behind at most 4 instructions (the max length of PLT ++ stub sequence. */ + + static CORE_ADDR + ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +@@ -839,11 +844,16 @@ ppc_linux_get_syscall_number (struct gdb + static struct linux_record_tdep ppc_linux_record_tdep; + static struct linux_record_tdep ppc64_linux_record_tdep; + ++/* ppc_canonicalize_syscall maps from the native PowerPC Linux set of ++ syscall ids into a canonical set of syscall ids used by process ++ record. (See arch/powerpc/include/uapi/asm/unistd.h in kernel tree.) ++ Return -1 if this system call is not supported by process record. ++ Otherwise, return the syscall number for preocess reocrd of given ++ SYSCALL. */ ++ + static enum gdb_syscall + ppc_canonicalize_syscall (int syscall) + { +- /* See arch/powerpc/include/uapi/asm/unistd.h */ +- + if (syscall <= 165) + return syscall; + else if (syscall >= 167 && syscall <= 190) /* Skip query_module 166 */ +@@ -869,6 +879,9 @@ ppc_canonicalize_syscall (int syscall) + return -1; + } + ++/* Record registers which might be clobbered during system call. ++ Return 0 if successful. */ ++ + static int + ppc_linux_syscall_record (struct regcache *regcache) + { +@@ -949,6 +962,9 @@ ppc_linux_syscall_record (struct regcach + return 0; + } + ++/* Record registers which might be clobbered during signal handling. ++ Return 0 if successful. */ ++ + static int + ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache, + enum gdb_signal signal) +@@ -1470,7 +1486,9 @@ static const struct frame_unwind ppu2spu + ppu2spu_prev_arch, + }; + +-/* Initialize linux_record_tdep if not initialized yet. */ ++/* Initialize linux_record_tdep if not initialized yet. ++ WORDSIZE is 4 or 8 for 32- or 64-bit PowerPC Linux respectively. ++ Sizes of data structures are initialized accordingly. */ + + static void + ppc_init_linux_record_tdep (struct linux_record_tdep *record_tdep, +Index: gdb-7.6.1/gdb/rs6000-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/rs6000-tdep.c ++++ gdb-7.6.1/gdb/rs6000-tdep.c +@@ -3398,6 +3398,9 @@ static const struct frame_unwind rs6000_ + default_frame_sniffer + }; + ++/* Allocate and initialize a frame cache for an epilogue frame. ++ SP is restored and prev-PC is stored in LR. */ ++ + static struct rs6000_frame_cache * + rs6000_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache) + { +@@ -3434,6 +3437,9 @@ rs6000_epilogue_frame_cache (struct fram + return cache; + } + ++/* Implementation of frame_unwind.this_id, as defined in frame_unwind.h. ++ Return the frame ID of an epilogue frame. */ ++ + static void + rs6000_epilogue_frame_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +@@ -3449,6 +3455,9 @@ rs6000_epilogue_frame_this_id (struct fr + (*this_id) = frame_id_build (info->base, pc); + } + ++/* Implementation of frame_unwind.prev_register, as defined in frame_unwind.h. ++ Return the register value of REGNUM in previous frame. */ ++ + static struct value * + rs6000_epilogue_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +@@ -3458,6 +3467,9 @@ rs6000_epilogue_frame_prev_register (str + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); + } + ++/* Implementation of frame_unwind.sniffer, as defined in frame_unwind.h. ++ Check whether this an epilogue frame. */ ++ + static int + rs6000_epilogue_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, +@@ -3471,6 +3483,9 @@ rs6000_epilogue_frame_sniffer (const str + return 0; + } + ++/* Frame unwinder for epilogue frame. This is required for reverse step-over ++ a function without debug information. */ ++ + static const struct frame_unwind rs6000_epilogue_frame_unwind = + { + NORMAL_FRAME, +@@ -3717,7 +3732,9 @@ bfd_uses_spe_extensions (bfd *abfd) + #define PPC_XT(insn) ((PPC_TX (insn) << 5) | PPC_T (insn)) + #define PPC_XER_NB(xer) (xer & 0x7f) + +-/* Record Vector-Scalar Registers. */ ++/* Record Vector-Scalar Registers. ++ For VSR less than 32, it's represented by an FPR and an VSR-upper register. ++ Otherwise, it's just a VR register. Record them accordingly. */ + + static int + ppc_record_vsr (struct regcache *regcache, struct gdbarch_tdep *tdep, int vsr) +@@ -3742,11 +3759,12 @@ ppc_record_vsr (struct regcache *regcach + return 0; + } + +-/* Parse instructions of primary opcode-4. */ ++/* Parse and record instructions primary opcode-4 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op4 (struct gdbarch *gdbarch, struct regcache *regcache, +- CORE_ADDR addr, uint32_t insn) ++ CORE_ADDR addr, uint32_t insn) + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_FIELD (insn, 21, 11); +@@ -4010,7 +4028,8 @@ ppc_process_record_op4 (struct gdbarch * + return -1; + } + +-/* Parse instructions of primary opcode-19. */ ++/* Parse and record instructions of primary opcode-19 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op19 (struct gdbarch *gdbarch, struct regcache *regcache, +@@ -4053,7 +4072,8 @@ ppc_process_record_op19 (struct gdbarch + return -1; + } + +-/* Parse instructions of primary opcode-31. */ ++/* Parse and record instructions of primary opcode-31 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op31 (struct gdbarch *gdbarch, struct regcache *regcache, +@@ -4531,7 +4551,8 @@ UNKNOWN_OP: + return -1; + } + +-/* Parse instructions of primary opcode-59. */ ++/* Parse and record instructions of primary opcode-59 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op59 (struct gdbarch *gdbarch, struct regcache *regcache, +@@ -4623,7 +4644,8 @@ ppc_process_record_op59 (struct gdbarch + return -1; + } + +-/* Parse instructions of primary opcode-60. */ ++/* Parse and record instructions of primary opcode-60 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache, +@@ -4905,7 +4927,8 @@ ppc_process_record_op60 (struct gdbarch + return -1; + } + +-/* Parse instructions of primary opcode-63. */ ++/* Parse and record instructions of primary opcode-63 at ADDR. ++ Return 0 if successful. */ + + static int + ppc_process_record_op63 (struct gdbarch *gdbarch, struct regcache *regcache, diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-1of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-1of8.patch new file mode 100644 index 0000000..76107e7 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-1of8.patch @@ -0,0 +1,257 @@ +commit 1ec56e88aa9b052ab10b806d82fbdbc8d153d977 +Author: Pedro Alves +Date: Fri Nov 22 13:17:46 2013 +0000 + + Eliminate dwarf2_frame_cache recursion, don't unwind from the dwarf2 sniffer (move dwarf2_tailcall_sniffer_first elsewhere). + + Two rationales, same patch. + + TL;DR 1: + + dwarf2_frame_cache recursion is evil. dwarf2_frame_cache calls + dwarf2_tailcall_sniffer_first which then recurses into + dwarf2_frame_cache. + + TL;DR 2: + + An unwinder trying to unwind is evil. dwarf2_frame_sniffer calls + dwarf2_frame_cache which calls dwarf2_tailcall_sniffer_first which + then tries to unwind the PC of the previous frame. + + Avoid all that by deferring dwarf2_tailcall_sniffer_first until it's + really necessary. + + Rationale 1 + =========== + + A frame sniffer should not try to unwind, because that bypasses all + the validation checks done by get_prev_frame. The UNWIND_SAME_ID + scenario is one such case where GDB is currently broken because (in + part) of this (the next patch adds a test that would fail without + this). + + GDB goes into an infinite loop in value_fetch_lazy, here: + + while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) + { + frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); + ... + new_val = get_frame_register_value (frame, regnum); + } + + (top-gdb) bt + #0 value_fetch_lazy (val=0x11516d0) at ../../src/gdb/value.c:3510 + #1 0x0000000000584bd8 in value_optimized_out (value=0x11516d0) at ../../src/gdb/value.c:1096 + #2 0x00000000006fe7a1 in frame_register_unwind (frame=0x1492600, regnum=16, optimizedp=0x7fffffffcdec, unavailablep=0x7fffffffcde8, lvalp=0x7fffffffcdd8, addrp= + 0x7fffffffcde0, realnump=0x7fffffffcddc, bufferp=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:940 + #3 0x00000000006fea3a in frame_unwind_register (frame=0x1492600, regnum=16, buf=0x7fffffffce10 "@\316\377\377\377\177") at ../../src/gdb/frame.c:990 + #4 0x0000000000473b9b in i386_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/i386-tdep.c:1771 + #5 0x0000000000601dfa in gdbarch_unwind_pc (gdbarch=0xf54660, next_frame=0x1492600) at ../../src/gdb/gdbarch.c:2870 + #6 0x0000000000693db5 in dwarf2_tailcall_sniffer_first (this_frame=0x1492600, tailcall_cachep=0x14926f0, entry_cfa_sp_offsetp=0x7fffffffcf00) + at ../../src/gdb/dwarf2-frame-tailcall.c:389 + #7 0x0000000000690928 in dwarf2_frame_cache (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1245 + #8 0x0000000000690f46 in dwarf2_frame_sniffer (self=0x8e4980, this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/dwarf2-frame.c:1423 + #9 0x000000000070203b in frame_unwind_find_by_frame (this_frame=0x1492600, this_cache=0x1492618) at ../../src/gdb/frame-unwind.c:112 + #10 0x00000000006fd681 in get_frame_id (fi=0x1492600) at ../../src/gdb/frame.c:408 + #11 0x00000000007006c2 in get_prev_frame_1 (this_frame=0xdc1860) at ../../src/gdb/frame.c:1826 + #12 0x0000000000700b7a in get_prev_frame (this_frame=0xdc1860) at ../../src/gdb/frame.c:2056 + #13 0x0000000000514588 in frame_info_to_frame_object (frame=0xdc1860) at ../../src/gdb/python/py-frame.c:322 + #14 0x000000000051784c in bootstrap_python_frame_filters (frame=0xdc1860, frame_low=0, frame_high=-1) at ../../src/gdb/python/py-framefilter.c:1396 + #15 0x0000000000517a6f in apply_frame_filter (frame=0xdc1860, flags=7, args_type=CLI_SCALAR_VALUES, out=0xed7a90, frame_low=0, frame_high=-1) + at ../../src/gdb/python/py-framefilter.c:1492 + #16 0x00000000005e77b0 in backtrace_command_1 (count_exp=0x0, show_locals=0, no_filters=0, from_tty=1) at ../../src/gdb/stack.c:1777 + #17 0x00000000005e7c0f in backtrace_command (arg=0x0, from_tty=1) at ../../src/gdb/stack.c:1891 + #18 0x00000000004e37a7 in do_cfunc (c=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:107 + #19 0x00000000004e683c in cmd_func (cmd=0xda4fa0, args=0x0, from_tty=1) at ../../src/gdb/cli/cli-decode.c:1882 + #20 0x00000000006f35ed in execute_command (p=0xcc66c2 "", from_tty=1) at ../../src/gdb/top.c:468 + #21 0x00000000005f8853 in command_handler (command=0xcc66c0 "bt") at ../../src/gdb/event-top.c:435 + #22 0x00000000005f8e12 in command_line_handler (rl=0xfe05f0 "@") at ../../src/gdb/event-top.c:632 + #23 0x000000000074d2c6 in rl_callback_read_char () at ../../src/readline/callback.c:220 + #24 0x00000000005f8375 in rl_callback_read_char_wrapper (client_data=0x0) at ../../src/gdb/event-top.c:164 + #25 0x00000000005f876a in stdin_event_handler (error=0, client_data=0x0) at ../../src/gdb/event-top.c:375 + #26 0x00000000005f72fa in handle_file_event (data=...) at ../../src/gdb/event-loop.c:768 + #27 0x00000000005f67a3 in process_event () at ../../src/gdb/event-loop.c:342 + #28 0x00000000005f686a in gdb_do_one_event () at ../../src/gdb/event-loop.c:406 + #29 0x00000000005f68bb in start_event_loop () at ../../src/gdb/event-loop.c:431 + #30 0x00000000005f83a7 in cli_command_loop (data=0x0) at ../../src/gdb/event-top.c:179 + #31 0x00000000005eeed3 in current_interp_command_loop () at ../../src/gdb/interps.c:327 + #32 0x00000000005ef8ff in captured_command_loop (data=0x0) at ../../src/gdb/main.c:267 + #33 0x00000000005ed2f6 in catch_errors (func=0x5ef8e4 , func_args=0x0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) + at ../../src/gdb/exceptions.c:524 + #34 0x00000000005f0d21 in captured_main (data=0x7fffffffd9e0) at ../../src/gdb/main.c:1067 + #35 0x00000000005ed2f6 in catch_errors (func=0x5efb9b , func_args=0x7fffffffd9e0, errstring=0x8b6554 "", mask=RETURN_MASK_ALL) + at ../../src/gdb/exceptions.c:524 + #36 0x00000000005f0d57 in gdb_main (args=0x7fffffffd9e0) at ../../src/gdb/main.c:1076 + #37 0x000000000045bb6a in main (argc=4, argv=0x7fffffffdae8) at ../../src/gdb/gdb.c:34 + (top-gdb) + + GDB is trying to unwind the PC register of the previous frame (frame + #5 above), starting from the frame being sniffed (the THIS frame). + But the THIS frame's unwinder says the PC of the previous frame is + actually the same as the previous's frame's next frame (which is the + same frame we started with, the THIS frame), therefore it returns an + lval_register lazy value with frame set to THIS frame. And so the + value_fetch_lazy loop never ends. + + + Rationale 2 + =========== + + As an experiment, I tried making dwarf2-frame.c:read_addr_from_reg use + address_from_register. That caused a bunch of regressions, but it + actually took me a long while to figure out what was going on. Turns + out dwarf2-frame.c:read_addr_from_reg is called while computing the + frame's CFA, from within dwarf2_frame_cache. address_from_register + wants to create a register with frame_id set to the frame being + constructed. To create the frame id, we again call dwarf2_frame_cache, + which given: + + static struct dwarf2_frame_cache * + dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) + { + ... + if (*this_cache) + return *this_cache; + + returns an incomplete object to the caller: + static void + dwarf2_frame_this_id (struct frame_info *this_frame, void **this_cache, + struct frame_id *this_id) + { + struct dwarf2_frame_cache *cache = + dwarf2_frame_cache (this_frame, this_cache); + ... + (*this_id) = frame_id_build (cache->cfa, get_frame_func (this_frame)); + } + + As cache->cfa is still 0 (we were trying to compute it!), and + get_frame_id recalls this id from here on, we end up with a broken + frame id in recorded for this frame. Later, when inspecting locals, + the dwarf machinery needs to know the selected frame's base, which + calls get_frame_base: + + CORE_ADDR + get_frame_base (struct frame_info *fi) + { + return get_frame_id (fi).stack_addr; + } + + which as seen above then returns 0 ... + + So I gave up using address_from_register. + + But, the pain of investigating this made me want to have GDB itself + assert that recursion never happens here. So I wrote a patch to do + that. But, it triggers on current mainline, because + dwarf2_tailcall_sniffer_first, called from dwarf2_frame_cache, unwinds + the this_frame. + + A sniffer shouldn't be trying to unwind, exactly because of this sort + of tricky issue. The patch defers calling + dwarf2_tailcall_sniffer_first until it's really necessary, in + dwarf2_frame_prev_register (thus actually outside the sniffer path). + As this makes the call to dwarf2_frame_sniffer in dwarf2_frame_cache + unnecessary again, the patch removes that too. + + Tested on x86_64 Fedora 17. + + gdb/ + 2013-11-22 Pedro Alves + + PR 16155 + * dwarf2-frame.c (struct dwarf2_frame_cache) + : New fields. + (dwarf2_frame_cache): Adjust to use the new cache fields instead + of locals. Don't call dwarf2_tailcall_sniffer_first here. + (dwarf2_frame_prev_register): Call it here, but only once. + +Index: gdb-7.6.1/gdb/dwarf2-frame.c +=================================================================== +--- gdb-7.6.1.orig/gdb/dwarf2-frame.c ++++ gdb-7.6.1/gdb/dwarf2-frame.c +@@ -984,12 +984,22 @@ struct dwarf2_frame_cache + /* The .text offset. */ + CORE_ADDR text_offset; + ++ /* True if we already checked whether this frame is the bottom frame ++ of a virtual tail call frame chain. */ ++ int checked_tailcall_bottom; ++ + /* If not NULL then this frame is the bottom frame of a TAILCALL_FRAME + sequence. If NULL then it is a normal case with no TAILCALL_FRAME + involved. Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this field does not apply for + them. */ + void *tailcall_cache; ++ ++ /* The number of bytes to subtract from TAILCALL_FRAME frames frame ++ base to get the SP, to simulate the return address pushed on the ++ stack. */ ++ LONGEST entry_cfa_sp_offset; ++ int entry_cfa_sp_offset_p; + }; + + /* A cleanup that sets a pointer to NULL. */ +@@ -1014,8 +1024,6 @@ dwarf2_frame_cache (struct frame_info *t + struct dwarf2_fde *fde; + volatile struct gdb_exception ex; + CORE_ADDR entry_pc; +- LONGEST entry_cfa_sp_offset; +- int entry_cfa_sp_offset_p = 0; + const gdb_byte *instr; + + if (*this_cache) +@@ -1080,8 +1088,8 @@ dwarf2_frame_cache (struct frame_info *t + && (gdbarch_dwarf2_reg_to_regnum (gdbarch, fs->regs.cfa_reg) + == gdbarch_sp_regnum (gdbarch))) + { +- entry_cfa_sp_offset = fs->regs.cfa_offset; +- entry_cfa_sp_offset_p = 1; ++ cache->entry_cfa_sp_offset = fs->regs.cfa_offset; ++ cache->entry_cfa_sp_offset_p = 1; + } + } + else +@@ -1230,13 +1238,6 @@ incomplete CFI data; unspecified registe + cache->undefined_retaddr = 1; + + do_cleanups (old_chain); +- +- /* Try to find a virtual tail call frames chain with bottom (callee) frame +- starting at THIS_FRAME. */ +- dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache, +- (entry_cfa_sp_offset_p +- ? &entry_cfa_sp_offset : NULL)); +- + discard_cleanups (reset_cache_cleanup); + return cache; + } +@@ -1282,6 +1283,16 @@ dwarf2_frame_prev_register (struct frame + CORE_ADDR addr; + int realnum; + ++ /* Check whether THIS_FRAME is the bottom frame of a virtual tail ++ call frame chain. */ ++ if (!cache->checked_tailcall_bottom) ++ { ++ cache->checked_tailcall_bottom = 1; ++ dwarf2_tailcall_sniffer_first (this_frame, &cache->tailcall_cache, ++ (cache->entry_cfa_sp_offset_p ++ ? &cache->entry_cfa_sp_offset : NULL)); ++ } ++ + /* Non-bottom frames of a virtual tail call frames chain use + dwarf2_tailcall_frame_unwind unwinder so this code does not apply for + them. If dwarf2_tailcall_prev_register_first does not have specific value +@@ -1408,10 +1419,6 @@ dwarf2_frame_sniffer (const struct frame + if (self->type != NORMAL_FRAME) + return 0; + +- /* Preinitializa the cache so that TAILCALL_FRAME can find the record by +- dwarf2_tailcall_sniffer_first. */ +- dwarf2_frame_cache (this_frame, this_cache); +- + return 1; + } + diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-2of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-2of8.patch new file mode 100644 index 0000000..3dcafd2 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-2of8.patch @@ -0,0 +1,819 @@ +commit 33f8fe58b9a55a0075a90cc9080a1716221a3f81 +Author: Pedro Alves +Date: Fri Nov 22 11:51:59 2013 +0000 + + Don't let two frames with the same id end up in the frame chain. + + The UNWIND_SAME_ID check is done between THIS_FRAME and the next frame + when we go try to unwind the previous frame. But at this point, it's + already too late -- we ended up with two frames with the same ID in + the frame chain. Each frame having its own ID is an invariant assumed + throughout GDB. This patch applies the UNWIND_SAME_ID detection + earlier, right after the previous frame is unwound, discarding the dup + frame if a cycle is detected. + + The patch includes a new test that fails before the change. Before + the patch, the test causes an infinite loop in GDB, after the patch, + the UNWIND_SAME_ID logic kicks in and makes the backtrace stop with: + + Backtrace stopped: previous frame identical to this frame (corrupt stack?) + + The test uses dwarf CFI to emulate a corrupted stack with a cycle. It + has a function with registers marked DW_CFA_same_value (most + importantly RSP/RIP), so that GDB computes the same ID for that frame + and its caller. IOW, something like this: + + #0 - frame_id_1 + #1 - frame_id_2 + #2 - frame_id_3 + #3 - frame_id_4 + #4 - frame_id_4 <<<< outermost (UNWIND_SAME_ID). + + (The test's code is just a copy of dw2-reg-undefined.S / + dw2-reg-undefined.c, adjusted to use DW_CFA_same_value instead of + DW_CFA_undefined, and to mark a different set of registers.) + + The infinite loop is here, in value_fetch_lazy: + + while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) + { + frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); + ... + new_val = get_frame_register_value (frame, regnum); + } + + get_frame_register_value can return a lazy register value pointing to + the next frame. This means that the register wasn't clobbered by + FRAME; the debugger should therefore retrieve its value from the next + frame. + + To be clear, get_frame_register_value unwinds the value in question + from the next frame: + + struct value * + get_frame_register_value (struct frame_info *frame, int regnum) + { + return frame_unwind_register_value (frame->next, regnum); + ^^^^^^^^^^^ + } + + In other words, if we get a lazy lval_register, it should have the + frame ID of the _next_ frame, never of FRAME. + + At this point in value_fetch_lazy, the whole relevant chunk of the + stack up to frame #4 has already been unwound. The loop always + "unlazies" lval_registers in the "next/innermost" direction, not in + the "prev/unwind further/outermost" direction. + + So say we're looking at frame #4. get_frame_register_value in frame + #4 can return a lazy register value of frame #3. So the next + iteration, frame_find_by_id tries to read the register from frame #3. + But, since frame #4 happens to have same id as frame #3, + frame_find_by_id returns frame #4 instead. Rinse, repeat, and we have + an infinite loop. + + This is an old latent problem, exposed by the recent addition of the + frame stash. Before we had a stash, frame_find_by_id(frame_id_4) + would walk over all frames starting at the current frame, and would + always find #3 first. The stash happens to return #4 instead: + + struct frame_info * + frame_find_by_id (struct frame_id id) + { + struct frame_info *frame, *prev_frame; + + ... + /* Try using the frame stash first. Finding it there removes the need + to perform the search by looping over all frames, which can be very + CPU-intensive if the number of frames is very high (the loop is O(n) + and get_prev_frame performs a series of checks that are relatively + expensive). This optimization is particularly useful when this function + is called from another function (such as value_fetch_lazy, case + VALUE_LVAL (val) == lval_register) which already loops over all frames, + making the overall behavior O(n^2). */ + frame = frame_stash_find (id); + if (frame) + return frame; + + for (frame = get_current_frame (); ; frame = prev_frame) + { + + gdb/ + 2013-11-22 Pedro Alves + + PR 16155 + * frame.c (get_prev_frame_1): Do the UNWIND_SAME_ID check between + this frame and the new previous frame, not between this frame and + the next frame. + + gdb/testsuite/ + 2013-11-22 Pedro Alves + + PR 16155 + * gdb.dwarf2/dw2-dup-frame.S: New file. + * gdb.dwarf2/dw2-dup-frame.c: New file. + * gdb.dwarf2/dw2-dup-frame.exp: New file. + +Index: gdb-7.6.1/gdb/frame.c +=================================================================== +--- gdb-7.6.1.orig/gdb/frame.c ++++ gdb-7.6.1/gdb/frame.c +@@ -1689,6 +1689,7 @@ get_prev_frame_1 (struct frame_info *thi + { + struct frame_id this_id; + struct gdbarch *gdbarch; ++ struct frame_info *prev_frame; + + gdb_assert (this_frame != NULL); + gdbarch = get_frame_arch (this_frame); +@@ -1790,22 +1791,6 @@ get_prev_frame_1 (struct frame_info *thi + } + } + +- /* Check that this and the next frame are not identical. If they +- are, there is most likely a stack cycle. As with the inner-than +- test above, avoid comparing the inner-most and sentinel frames. */ +- if (this_frame->level > 0 +- && frame_id_eq (this_id, get_frame_id (this_frame->next))) +- { +- if (frame_debug) +- { +- fprintf_unfiltered (gdb_stdlog, "-> "); +- fprint_frame (gdb_stdlog, NULL); +- fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); +- } +- this_frame->stop_reason = UNWIND_SAME_ID; +- return NULL; +- } +- + /* Check that this and the next frame do not unwind the PC register + to the same memory location. If they do, then even though they + have different frame IDs, the new frame will be bogus; two +@@ -1853,7 +1838,31 @@ get_prev_frame_1 (struct frame_info *thi + } + } + +- return get_prev_frame_raw (this_frame); ++ prev_frame = get_prev_frame_raw (this_frame); ++ ++ /* Check that this and the prev frame are not identical. If they ++ are, there is most likely a stack cycle. Unlike the tests above, ++ we do this right after creating the prev frame, to avoid ever ++ ending up with two frames with the same id in the frame ++ chain. */ ++ if (prev_frame != NULL ++ && frame_id_eq (get_frame_id (prev_frame), ++ get_frame_id (this_frame))) ++ { ++ if (frame_debug) ++ { ++ fprintf_unfiltered (gdb_stdlog, "-> "); ++ fprint_frame (gdb_stdlog, NULL); ++ fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); ++ } ++ this_frame->stop_reason = UNWIND_SAME_ID; ++ /* Unlink. */ ++ prev_frame->next = NULL; ++ this_frame->prev = NULL; ++ return NULL; ++ } ++ ++ return prev_frame; + } + + /* Construct a new "struct frame_info" and link it previous to +Index: gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.S +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.S +@@ -0,0 +1,540 @@ ++/* ++ Copyright 2013 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 3 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, see . */ ++ ++ /* The FDE entry for "stop_frame" in the .debug_frame section has ++ been hand modified to mark a set of registers as DW_CFA_same_value. ++ Otherwise this file is as generated by gcc 4.7.2 for x86_64. */ ++ .file "dw2-dup-frame.c" ++ .text ++.Ltext0: ++ .globl stop_frame ++ .type stop_frame, @function ++stop_frame: ++.LFB0: ++ .file 1 "dw2-dup-frame.c" ++ .loc 1 19 0 ++ pushq %rbp ++.LCFI0: ++ movq %rsp, %rbp ++.LCFI1: ++ .loc 1 22 0 ++ popq %rbp ++.LCFI2: ++ ret ++.LFE0: ++ .size stop_frame, .-stop_frame ++ .globl first_frame ++ .type first_frame, @function ++first_frame: ++.LFB1: ++ .loc 1 26 0 ++ pushq %rbp ++.LCFI3: ++ movq %rsp, %rbp ++.LCFI4: ++ .loc 1 27 0 ++ movl $0, %eax ++ call stop_frame ++ .loc 1 28 0 ++ popq %rbp ++.LCFI5: ++ ret ++.LFE1: ++ .size first_frame, .-first_frame ++ .globl main ++ .type main, @function ++main: ++.LFB2: ++ .loc 1 32 0 ++ pushq %rbp ++.LCFI6: ++ movq %rsp, %rbp ++.LCFI7: ++ .loc 1 33 0 ++ movl $0, %eax ++ call first_frame ++ .loc 1 35 0 ++ movl $0, %eax ++ .loc 1 36 0 ++ popq %rbp ++.LCFI8: ++ ret ++.LFE2: ++ .size main, .-main ++ .section .debug_frame,"",@progbits ++.Lframe0: ++ .long .LECIE0-.LSCIE0 ++.LSCIE0: ++ .long 0xffffffff ++ .byte 0x1 ++ .string "" ++ .uleb128 0x1 ++ .sleb128 -8 ++ .byte 0x10 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .byte 0x90 ++ .uleb128 0x1 ++ .align 8 ++.LECIE0: ++ /* This FDE entry, for stop_frame was modified to mark ++ registers 0 -> 16 (rax..ra/rip) as being DW_CFA_same_value. */ ++.LSFDE0: ++ .long .LEFDE0-.LASFDE0 ++.LASFDE0: ++ .long .Lframe0 ++ .quad .LFB0 ++ .quad .LFE0-.LFB0 ++ ++ /* START OF NEW CONTENT. */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x0 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x1 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x2 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x3 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x4 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x5 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x6 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x7 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x8 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x9 /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xa /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xb /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xc /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xd /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xe /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0xf /* ULEB128 register */ ++ .byte 0x8 /* DW_CFA_same_value */ ++ .uleb128 0x10 /* ULEB128 register */ ++ /* END OF NEW CONTENT. */ ++ ++ .byte 0x4 ++ .long .LCFI0-.LFB0 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI2-.LCFI1 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE0: ++.LSFDE2: ++ .long .LEFDE2-.LASFDE2 ++.LASFDE2: ++ .long .Lframe0 ++ .quad .LFB1 ++ .quad .LFE1-.LFB1 ++ .byte 0x4 ++ .long .LCFI3-.LFB1 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI4-.LCFI3 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI5-.LCFI4 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE2: ++.LSFDE4: ++ .long .LEFDE4-.LASFDE4 ++.LASFDE4: ++ .long .Lframe0 ++ .quad .LFB2 ++ .quad .LFE2-.LFB2 ++ .byte 0x4 ++ .long .LCFI6-.LFB2 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI7-.LCFI6 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI8-.LCFI7 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE4: ++ .section .eh_frame,"a",@progbits ++.Lframe1: ++ .long .LECIE1-.LSCIE1 ++.LSCIE1: ++ .long 0 ++ .byte 0x1 ++ .string "zR" ++ .uleb128 0x1 ++ .sleb128 -8 ++ .byte 0x10 ++ .uleb128 0x1 ++ .byte 0x3 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .byte 0x90 ++ .uleb128 0x1 ++ .align 8 ++.LECIE1: ++.LSFDE7: ++ .long .LEFDE7-.LASFDE7 ++.LASFDE7: ++ .long .LASFDE7-.Lframe1 ++ .long .LFB0 ++ .long .LFE0-.LFB0 ++ .uleb128 0 ++ .byte 0x4 ++ .long .LCFI0-.LFB0 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI1-.LCFI0 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI2-.LCFI1 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE7: ++.LSFDE9: ++ .long .LEFDE9-.LASFDE9 ++.LASFDE9: ++ .long .LASFDE9-.Lframe1 ++ .long .LFB1 ++ .long .LFE1-.LFB1 ++ .uleb128 0 ++ .byte 0x4 ++ .long .LCFI3-.LFB1 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI4-.LCFI3 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI5-.LCFI4 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE9: ++.LSFDE11: ++ .long .LEFDE11-.LASFDE11 ++.LASFDE11: ++ .long .LASFDE11-.Lframe1 ++ .long .LFB2 ++ .long .LFE2-.LFB2 ++ .uleb128 0 ++ .byte 0x4 ++ .long .LCFI6-.LFB2 ++ .byte 0xe ++ .uleb128 0x10 ++ .byte 0x86 ++ .uleb128 0x2 ++ .byte 0x4 ++ .long .LCFI7-.LCFI6 ++ .byte 0xd ++ .uleb128 0x6 ++ .byte 0x4 ++ .long .LCFI8-.LCFI7 ++ .byte 0xc ++ .uleb128 0x7 ++ .uleb128 0x8 ++ .align 8 ++.LEFDE11: ++ .text ++.Letext0: ++ .section .debug_info,"",@progbits ++.Ldebug_info0: ++ .long 0x8c ++ .value 0x2 ++ .long .Ldebug_abbrev0 ++ .byte 0x8 ++ .uleb128 0x1 ++ .long .LASF2 ++ .byte 0x1 ++ .long .LASF3 ++ .long .LASF4 ++ .quad .Ltext0 ++ .quad .Letext0 ++ .long .Ldebug_line0 ++ .uleb128 0x2 ++ .byte 0x1 ++ .long .LASF0 ++ .byte 0x1 ++ .byte 0x12 ++ .quad .LFB0 ++ .quad .LFE0 ++ .long .LLST0 ++ .byte 0x1 ++ .uleb128 0x3 ++ .byte 0x1 ++ .long .LASF1 ++ .byte 0x1 ++ .byte 0x19 ++ .quad .LFB1 ++ .quad .LFE1 ++ .long .LLST1 ++ .byte 0x1 ++ .uleb128 0x4 ++ .byte 0x1 ++ .long .LASF5 ++ .byte 0x1 ++ .byte 0x1f ++ .long 0x88 ++ .quad .LFB2 ++ .quad .LFE2 ++ .long .LLST2 ++ .byte 0x1 ++ .uleb128 0x5 ++ .byte 0x4 ++ .byte 0x5 ++ .string "int" ++ .byte 0 ++ .section .debug_abbrev,"",@progbits ++.Ldebug_abbrev0: ++ .uleb128 0x1 ++ .uleb128 0x11 ++ .byte 0x1 ++ .uleb128 0x25 ++ .uleb128 0xe ++ .uleb128 0x13 ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x1b ++ .uleb128 0xe ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x10 ++ .uleb128 0x6 ++ .byte 0 ++ .byte 0 ++ .uleb128 0x2 ++ .uleb128 0x2e ++ .byte 0 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .uleb128 0x2117 ++ .uleb128 0xc ++ .byte 0 ++ .byte 0 ++ .uleb128 0x3 ++ .uleb128 0x2e ++ .byte 0 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .uleb128 0x2116 ++ .uleb128 0xc ++ .byte 0 ++ .byte 0 ++ .uleb128 0x4 ++ .uleb128 0x2e ++ .byte 0 ++ .uleb128 0x3f ++ .uleb128 0xc ++ .uleb128 0x3 ++ .uleb128 0xe ++ .uleb128 0x3a ++ .uleb128 0xb ++ .uleb128 0x3b ++ .uleb128 0xb ++ .uleb128 0x49 ++ .uleb128 0x13 ++ .uleb128 0x11 ++ .uleb128 0x1 ++ .uleb128 0x12 ++ .uleb128 0x1 ++ .uleb128 0x40 ++ .uleb128 0x6 ++ .uleb128 0x2116 ++ .uleb128 0xc ++ .byte 0 ++ .byte 0 ++ .uleb128 0x5 ++ .uleb128 0x24 ++ .byte 0 ++ .uleb128 0xb ++ .uleb128 0xb ++ .uleb128 0x3e ++ .uleb128 0xb ++ .uleb128 0x3 ++ .uleb128 0x8 ++ .byte 0 ++ .byte 0 ++ .byte 0 ++ .section .debug_loc,"",@progbits ++.Ldebug_loc0: ++.LLST0: ++ .quad .LFB0-.Ltext0 ++ .quad .LCFI0-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad .LCFI0-.Ltext0 ++ .quad .LCFI1-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 16 ++ .quad .LCFI1-.Ltext0 ++ .quad .LCFI2-.Ltext0 ++ .value 0x2 ++ .byte 0x76 ++ .sleb128 16 ++ .quad .LCFI2-.Ltext0 ++ .quad .LFE0-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad 0 ++ .quad 0 ++.LLST1: ++ .quad .LFB1-.Ltext0 ++ .quad .LCFI3-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad .LCFI3-.Ltext0 ++ .quad .LCFI4-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 16 ++ .quad .LCFI4-.Ltext0 ++ .quad .LCFI5-.Ltext0 ++ .value 0x2 ++ .byte 0x76 ++ .sleb128 16 ++ .quad .LCFI5-.Ltext0 ++ .quad .LFE1-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad 0 ++ .quad 0 ++.LLST2: ++ .quad .LFB2-.Ltext0 ++ .quad .LCFI6-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad .LCFI6-.Ltext0 ++ .quad .LCFI7-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 16 ++ .quad .LCFI7-.Ltext0 ++ .quad .LCFI8-.Ltext0 ++ .value 0x2 ++ .byte 0x76 ++ .sleb128 16 ++ .quad .LCFI8-.Ltext0 ++ .quad .LFE2-.Ltext0 ++ .value 0x2 ++ .byte 0x77 ++ .sleb128 8 ++ .quad 0 ++ .quad 0 ++ .section .debug_aranges,"",@progbits ++ .long 0x2c ++ .value 0x2 ++ .long .Ldebug_info0 ++ .byte 0x8 ++ .byte 0 ++ .value 0 ++ .value 0 ++ .quad .Ltext0 ++ .quad .Letext0-.Ltext0 ++ .quad 0 ++ .quad 0 ++ .section .debug_line,"",@progbits ++.Ldebug_line0: ++ .section .debug_str,"MS",@progbits,1 ++.LASF0: ++ .string "stop_frame" ++.LASF3: ++ .string "dw2-reg-undefined.c" ++.LASF2: ++ .string "GNU C 4.7.2" ++.LASF1: ++ .string "first_frame" ++.LASF5: ++ .string "main" ++.LASF4: ++ .string "/home/username/src/gdb/testsuite/gdb.dwarf2" ++ .ident "GCC: (GNU) 4.7.2" ++ .section .note.GNU-stack,"",@progbits +Index: gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.c +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.c +@@ -0,0 +1,36 @@ ++/* ++ Copyright 2013 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 3 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, see . */ ++ ++void ++stop_frame () ++{ ++ /* The debug information for this frame is modified in the accompanying ++ .S file, to mark a set of registers as being DW_CFA_same_value. */ ++} ++ ++void ++first_frame () ++{ ++ stop_frame (); ++} ++ ++int ++main () ++{ ++ first_frame (); ++ ++ return 0; ++} +Index: gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.exp +=================================================================== +--- /dev/null ++++ gdb-7.6.1/gdb/testsuite/gdb.dwarf2/dw2-dup-frame.exp +@@ -0,0 +1,44 @@ ++# Copyright 2013 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 3 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, see . ++load_lib dwarf.exp ++ ++# This test can only be run on targets which support DWARF-2 and use gas. ++if {![dwarf2_support]} { ++ return 0 ++} ++ ++# This test can only be run on x86_64 targets. ++if {![istarget "x86_64-*-*"] || ![is_lp64_target]} { ++ return 0 ++} ++ ++standard_testfile .S ++ ++if { [prepare_for_testing $testfile.exp $testfile $srcfile {nodebug}] } { ++ return -1 ++} ++ ++if ![runto stop_frame] { ++ perror "Failed to stop in stop_frame" ++ return -1 ++} ++ ++gdb_test "bt" \ ++ "#0 stop_frame \[^\r\n\]*\r\nBacktrace stopped: previous frame identical to this frame \\(corrupt stack\\?\\)" \ ++ "backtrace from stop_frame" ++ ++gdb_test "up" \ ++ "Initial frame selected; you cannot go up\\\." \ ++ "up from stop_frame" diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-3of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-3of8.patch new file mode 100644 index 0000000..23e70cc --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-3of8.patch @@ -0,0 +1,246 @@ +commit 194cca41192efa65f710967e3149bbc813c12b22 +Author: Pedro Alves +Date: Thu Nov 21 15:20:09 2013 +0000 + + Make use of the frame stash to detect wider stack cycles. + + Given we already have the frame id stash, which holds the ids of all + frames in the chain, detecting corrupted stacks with wide stack cycles + with non-consecutive dup frame ids is just as cheap as just detecting + cycles in consecutive frames: + + #0 frame_id1 + #1 frame_id2 + #2 frame_id3 + #3 frame_id1 + #4 frame_id2 + #5 frame_id3 + #6 frame_id1 + ... forever ... + + We just need to check whether the stash already knows about a given + frame id instead of comparing the ids of the previous/this frames. + + Tested on x86_64 Fedora 17. + + gdb/ + 2013-11-22 Pedro Alves + Tom Tromey + + * frame.c (frame_stash_add): Now returns whether a frame with the + same ID was already known. + (compute_frame_id): New function, factored out from get_frame_id. + (get_frame_id): No longer lazilly compute the frame id here. + (get_prev_frame_if_no_cycle): New function. Detects wider stack + cycles. + (get_prev_frame_1): Use it instead of get_prev_frame_raw directly, + and checking for stack cycles here. + +Index: gdb-7.6.1/gdb/frame.c +=================================================================== +--- gdb-7.6.1.orig/gdb/frame.c ++++ gdb-7.6.1/gdb/frame.c +@@ -189,23 +189,31 @@ frame_stash_create (void) + NULL); + } + +-/* Internal function to add a frame to the frame_stash hash table. Do +- not store frames below 0 as they may not have any addresses to +- calculate a hash. */ ++/* Internal function to add a frame to the frame_stash hash table. ++ Returns false if a frame with the same ID was already stashed, true ++ otherwise. */ + +-static void ++static int + frame_stash_add (struct frame_info *frame) + { +- /* Do not stash frames below level 0. */ +- if (frame->level >= 0) +- { +- struct frame_info **slot; ++ struct frame_info **slot; + +- slot = (struct frame_info **) htab_find_slot (frame_stash, +- frame, +- INSERT); +- *slot = frame; +- } ++ /* Do not try to stash the sentinel frame. */ ++ gdb_assert (frame->level >= 0); ++ ++ slot = (struct frame_info **) htab_find_slot (frame_stash, ++ frame, ++ INSERT); ++ ++ /* If we already have a frame in the stack with the same id, we ++ either have a stack cycle (corrupted stack?), or some bug ++ elsewhere in GDB. In any case, ignore the duplicate and return ++ an indication to the caller. */ ++ if (*slot != NULL) ++ return 0; ++ ++ *slot = frame; ++ return 1; + } + + /* Internal function to search the frame stash for an entry with the +@@ -397,6 +405,34 @@ skip_artificial_frames (struct frame_inf + return frame; + } + ++/* Compute the frame's uniq ID that can be used to, later, re-find the ++ frame. */ ++ ++static void ++compute_frame_id (struct frame_info *fi) ++{ ++ gdb_assert (!fi->this_id.p); ++ ++ if (frame_debug) ++ fprintf_unfiltered (gdb_stdlog, "{ compute_frame_id (fi=%d) ", ++ fi->level); ++ /* Find the unwinder. */ ++ if (fi->unwind == NULL) ++ frame_unwind_find_by_frame (fi, &fi->prologue_cache); ++ /* Find THIS frame's ID. */ ++ /* Default to outermost if no ID is found. */ ++ fi->this_id.value = outer_frame_id; ++ fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); ++ gdb_assert (frame_id_p (fi->this_id.value)); ++ fi->this_id.p = 1; ++ if (frame_debug) ++ { ++ fprintf_unfiltered (gdb_stdlog, "-> "); ++ fprint_frame_id (gdb_stdlog, fi->this_id.value); ++ fprintf_unfiltered (gdb_stdlog, " }\n"); ++ } ++} ++ + /* Return a frame uniq ID that can be used to, later, re-find the + frame. */ + +@@ -406,29 +442,7 @@ get_frame_id (struct frame_info *fi) + if (fi == NULL) + return null_frame_id; + +- if (!fi->this_id.p) +- { +- if (frame_debug) +- fprintf_unfiltered (gdb_stdlog, "{ get_frame_id (fi=%d) ", +- fi->level); +- /* Find the unwinder. */ +- if (fi->unwind == NULL) +- frame_unwind_find_by_frame (fi, &fi->prologue_cache); +- /* Find THIS frame's ID. */ +- /* Default to outermost if no ID is found. */ +- fi->this_id.value = outer_frame_id; +- fi->unwind->this_id (fi, &fi->prologue_cache, &fi->this_id.value); +- gdb_assert (frame_id_p (fi->this_id.value)); +- fi->this_id.p = 1; +- if (frame_debug) +- { +- fprintf_unfiltered (gdb_stdlog, "-> "); +- fprint_frame_id (gdb_stdlog, fi->this_id.value); +- fprintf_unfiltered (gdb_stdlog, " }\n"); +- } +- frame_stash_add (fi); +- } +- ++ gdb_assert (fi->this_id.p); + return fi->this_id.value; + } + +@@ -1678,6 +1692,42 @@ frame_register_unwind_location (struct f + } + } + ++/* Get the previous raw frame, and check that it is not identical to ++ same other frame frame already in the chain. If it is, there is ++ most likely a stack cycle, so we discard it, and mark THIS_FRAME as ++ outermost, with UNWIND_SAME_ID stop reason. Unlike the other ++ validity tests, that compare THIS_FRAME and the next frame, we do ++ this right after creating the previous frame, to avoid ever ending ++ up with two frames with the same id in the frame chain. */ ++ ++static struct frame_info * ++get_prev_frame_if_no_cycle (struct frame_info *this_frame) ++{ ++ struct frame_info *prev_frame; ++ ++ prev_frame = get_prev_frame_raw (this_frame); ++ if (prev_frame == NULL) ++ return NULL; ++ ++ compute_frame_id (prev_frame); ++ if (frame_stash_add (prev_frame)) ++ return prev_frame; ++ ++ /* Another frame with the same id was already in the stash. We just ++ detected a cycle. */ ++ if (frame_debug) ++ { ++ fprintf_unfiltered (gdb_stdlog, "-> "); ++ fprint_frame (gdb_stdlog, NULL); ++ fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); ++ } ++ this_frame->stop_reason = UNWIND_SAME_ID; ++ /* Unlink. */ ++ prev_frame->next = NULL; ++ this_frame->prev = NULL; ++ return NULL; ++} ++ + /* Return a "struct frame_info" corresponding to the frame that called + THIS_FRAME. Returns NULL if there is no such frame. + +@@ -1689,7 +1739,6 @@ get_prev_frame_1 (struct frame_info *thi + { + struct frame_id this_id; + struct gdbarch *gdbarch; +- struct frame_info *prev_frame; + + gdb_assert (this_frame != NULL); + gdbarch = get_frame_arch (this_frame); +@@ -1732,7 +1781,7 @@ get_prev_frame_1 (struct frame_info *thi + until we have unwound all the way down to the previous non-inline + frame. */ + if (get_frame_type (this_frame) == INLINE_FRAME) +- return get_prev_frame_raw (this_frame); ++ return get_prev_frame_if_no_cycle (this_frame); + + /* Check that this frame is unwindable. If it isn't, don't try to + unwind to the prev frame. */ +@@ -1838,31 +1887,7 @@ get_prev_frame_1 (struct frame_info *thi + } + } + +- prev_frame = get_prev_frame_raw (this_frame); +- +- /* Check that this and the prev frame are not identical. If they +- are, there is most likely a stack cycle. Unlike the tests above, +- we do this right after creating the prev frame, to avoid ever +- ending up with two frames with the same id in the frame +- chain. */ +- if (prev_frame != NULL +- && frame_id_eq (get_frame_id (prev_frame), +- get_frame_id (this_frame))) +- { +- if (frame_debug) +- { +- fprintf_unfiltered (gdb_stdlog, "-> "); +- fprint_frame (gdb_stdlog, NULL); +- fprintf_unfiltered (gdb_stdlog, " // this frame has same ID }\n"); +- } +- this_frame->stop_reason = UNWIND_SAME_ID; +- /* Unlink. */ +- prev_frame->next = NULL; +- this_frame->prev = NULL; +- return NULL; +- } +- +- return prev_frame; ++ return get_prev_frame_if_no_cycle (this_frame); + } + + /* Construct a new "struct frame_info" and link it previous to diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-4of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-4of8.patch new file mode 100644 index 0000000..8073669 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-4of8.patch @@ -0,0 +1,61 @@ +commit 6eeee81c8e59511962bdd83df5e7785bfdf871d2 +Author: Tom Tromey +Date: Fri Nov 22 17:38:44 2013 +0000 + + Detect infinite loop in value_fetch_lazy's lval_register handling. + + If value_fetch_lazy loops infinitely while unwrapping lval_register + values, it means we either somehow ended up with two frames with the + same ID in the frame chain, or some code is trying to unwind behind + get_prev_frame's back (e.g., a frame unwind sniffer trying to unwind). + In any case, it should always be an internal error to end up in this + situation. + + This patch adds a check and throws an internal error if the same frame + is returned. + + 2013-11-22 Tom Tromey + Pedro Alves + + PR backtrace/16155 + * value.c (value_fetch_lazy): Internal error if + get_frame_register_value returns the same register. + +Index: gdb-7.6.1/gdb/valops.c +=================================================================== +--- gdb-7.6.1.orig/gdb/valops.c ++++ gdb-7.6.1/gdb/valops.c +@@ -1093,7 +1093,9 @@ value_fetch_lazy (struct value *val) + + while (VALUE_LVAL (new_val) == lval_register && value_lazy (new_val)) + { +- frame = frame_find_by_id (VALUE_FRAME_ID (new_val)); ++ struct frame_id frame_id = VALUE_FRAME_ID (new_val); ++ ++ frame = frame_find_by_id (frame_id); + regnum = VALUE_REGNUM (new_val); + + gdb_assert (frame != NULL); +@@ -1107,6 +1109,22 @@ value_fetch_lazy (struct value *val) + regnum, type)); + + new_val = get_frame_register_value (frame, regnum); ++ ++ /* If we get another lazy lval_register value, it means the ++ register is found by reading it from the next frame. ++ get_frame_register_value should never return a value with ++ the frame id pointing to FRAME. If it does, it means we ++ either have two consecutive frames with the same frame id ++ in the frame chain, or some code is trying to unwind ++ behind get_prev_frame's back (e.g., a frame unwind ++ sniffer trying to unwind), bypassing its validations. In ++ any case, it should always be an internal error to end up ++ in this situation. */ ++ if (VALUE_LVAL (new_val) == lval_register ++ && value_lazy (new_val) ++ && frame_id_eq (VALUE_FRAME_ID (new_val), frame_id)) ++ internal_error (__FILE__, __LINE__, ++ _("infinite loop while fetching a register")); + } + + /* If it's still lazy (for instance, a saved register on the diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-5of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-5of8.patch new file mode 100644 index 0000000..21c6b7e --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-5of8.patch @@ -0,0 +1,69 @@ +commit 2d6f0de676f46ebd8bb7d98a0093aa081e17e94b +Author: Yao Qi +Date: Mon Jun 30 11:47:51 2014 +0800 + + Tweak gdb.trace/tfile.c for thumb mode + + We see the fail below happens on thumb related multi-libs + (-mthumb -march={armv4t,armv7-a}), + + target tfile tfile-basic.tf ^M + warning: Uploaded tracepoint 1 has no source location, using raw address^M + warning: Breakpoint address adjusted from 0x00008959 to 0x00008958.^M + Tracepoint 3 at 0x8958: file /scratch/yqi/arm-none-linux-gnueabi/src/gdb-trunk/gdb/testsuite/gdb.trace/tfile.c, line 91.^M + Created tracepoint 3 for target's tracepoint 1 at 0x8959.^M + warning: Breakpoint address adjusted from 0x00008959 to 0x00008958.^M + warning: Breakpoint address adjusted from 0x00008959 to 0x00008958.^M + warning: Breakpoint address adjusted from 0x00008959 to 0x00008958.^M + (gdb) FAIL: gdb.trace/tfile.exp: complete-command 'target tfile' + + The address of write_basic_trace_file is two-bytes aligned, + + (gdb) p write_basic_trace_file + $1 = {void (void)} 0x8958 + + but the ld sets the LSB of every reference to the function address + (indicating the address is in thumb mode), so "&write_basic_trace_file" + in the program becomes 0x8959, which is saved in the trace file. That + is why the warnnings are emitted. + + This patch is to clear the LSB of the function address written to trace + file in thumb and thumb2 mode. This patch fixes the fail above. + + gdb/testsuite: + + 2014-07-10 Yao Qi + + * gdb.trace/tfile.c (write_basic_trace_file) + [__thumb__||__thumb2__]: Clear the Thumb bit of the function + address written to trace file. + +Index: gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.trace/tfile.c ++++ gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +@@ -68,6 +68,7 @@ write_basic_trace_file (void) + { + int fd, int_x; + short short_x; ++ long func_addr; + + fd = start_trace_file ("basic.tf"); + +@@ -86,8 +87,14 @@ write_basic_trace_file (void) + /* Dump tracepoint definitions, in syntax similar to that used + for reconnection uploads. */ + /* FIXME need a portable way to print function address in hex */ +- snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", +- (long) &write_basic_trace_file); ++ func_addr = (long) &write_basic_trace_file; ++#if defined(__thumb__) || defined(__thumb2__) ++ /* Although Thumb functions are two-byte aligned, function ++ pointers have the Thumb bit set. Clear it. */ ++ func_addr &= ~1; ++#endif ++ ++ snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", func_addr); + write (fd, spbuf, strlen (spbuf)); + /* (Note that we would only need actions defined if we wanted to + test tdump.) */ diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-6of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-6of8.patch new file mode 100644 index 0000000..1cce577 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-6of8.patch @@ -0,0 +1,88 @@ +commit 62261490a36c6911c5eb61be7cddcfb1bd19ba18 +Author: Pedro Alves +Date: Thu Jan 16 17:43:26 2014 +0000 + + Fix gdb.trace/mi-traceframe-changed.exp on s390. + + The test fails on s390 with: + + -trace-find frame-number 0^M + &"PC not available\n"^M + ^done,found="1",tracepoint="1",traceframe="0",frame={level="-1",addr="",func="??",args=[]}^M + (gdb) ^M + FAIL: gdb.trace/mi-traceframe-changed.exp: tfile: -trace-find frame-number 0 + + tfile knows to infer the PC from the tracepoint's address if the PC + wasn't collected (tfile_fetch_registers) but, that only works on + targets whose PC register is a raw register, and on s390, the PC + register is a pseudo register. + + But even if GDB doesn't know how to infer the value of PC, saying the + current frame is level -1 is a bug: + + ^done,found="1",tracepoint="1",traceframe="0",frame={level="-1",addr="",func="??",args=[]}^M + ^^^^^^^^^ + + '-1' is the level of the sentinel frame, which should never be visible. + + This is caused by the s390's heuristic unwinder accepting the frame + (the fallback heuristic unwinders _always_ accept the frame), but then + the unwind->this_id method throws that "PC not available\n" error. + + IOW, the s390's heuristic unwinder was never adjusted to handle + unavailable register values gracefully, which can happen with e.g., a + trimmed core file too. + + This is just the minimal necessary for + frames, which at least gets us: + + (gdb) tfind + Found trace frame 0, tracepoint 1 + #0 in ?? () + + That is, frame #0 instead of -1. + + We could get better info out of "info frame" (this patch makes us show + "outermost"), but this change would still be necessary. + + gdb/ + 2014-01-16 Pedro Alves + + * s390-linux-tdep.c (s390_frame_unwind_cache): Swallow + NOT_AVAILABLE_ERROR errors while parsing the prologue or reading + the backchain. + +Index: gdb-7.6.1/gdb/s390-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.c ++++ gdb-7.6.1/gdb/s390-tdep.c +@@ -1995,7 +1995,9 @@ static struct s390_unwind_cache * + s390_frame_unwind_cache (struct frame_info *this_frame, + void **this_prologue_cache) + { ++ volatile struct gdb_exception ex; + struct s390_unwind_cache *info; ++ + if (*this_prologue_cache) + return *this_prologue_cache; + +@@ -2006,10 +2008,15 @@ s390_frame_unwind_cache (struct frame_in + info->frame_base = -1; + info->local_base = -1; + +- /* Try to use prologue analysis to fill the unwind cache. +- If this fails, fall back to reading the stack backchain. */ +- if (!s390_prologue_frame_unwind_cache (this_frame, info)) +- s390_backchain_frame_unwind_cache (this_frame, info); ++ TRY_CATCH (ex, RETURN_MASK_ERROR) ++ { ++ /* Try to use prologue analysis to fill the unwind cache. ++ If this fails, fall back to reading the stack backchain. */ ++ if (!s390_prologue_frame_unwind_cache (this_frame, info)) ++ s390_backchain_frame_unwind_cache (this_frame, info); ++ } ++ if (ex.reason < 0 && ex.error != NOT_AVAILABLE_ERROR) ++ throw_exception (ex); + + return info; + } diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-7of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-7of8.patch new file mode 100644 index 0000000..60e1308 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-7of8.patch @@ -0,0 +1,288 @@ +commit 1b5d0ab34c53d6e896d2c0958b1176e324bb7878 +Author: Pedro Alves +Date: Wed Jul 16 19:25:41 2014 +0100 + + gdb.trace/tfile.c: Remove Thumb bit in one more more, general cleanup + + I noticed that the existing code casts a function's address to 'long', + but that doesn't work correctly on some ABIs, like Win64, where long + is 32-bit and while pointers are 64-bit: + + func_addr = (long) &write_basic_trace_file; + + Fixing that showed there's actually another place in the file that + writes a function address to file, and therefore should clear the + Thumb bit. This commit adds a macro+function pair to centralize the + Thumb bit handling, and uses it in both places. + + The rest is just enough changes to make the file build without + warnings with "-Wall -Wextra" with x86_64-w64-mingw32-gcc and + i686-w64-mingw32-gcc cross compilers, and with -m32/-m64 on x86_64 + GNU/Linux. Currently with x86_64-w64-mingw32-gcc we get: + + $ x86_64-w64-mingw32-gcc tfile.c -Wall -DTFILE_DIR=\"\" + tfile.c: In function 'start_trace_file': + tfile.c:51:23: error: 'S_IRGRP' undeclared (first use in this function) + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + ^ + tfile.c:51:23: note: each undeclared identifier is reported only once for each function it appears in + tfile.c:51:31: error: 'S_IROTH' undeclared (first use in this function) + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + ^ + tfile.c: In function 'add_memory_block': + tfile.c:79:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] + ll_x = (unsigned long) addr; + ^ + tfile.c: In function 'write_basic_trace_file': + tfile.c:113:15: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] + func_addr = (long) &write_basic_trace_file; + ^ + tfile.c:137:3: warning: passing argument 1 of 'add_memory_block' from incompatible pointer type [enabled by default] + add_memory_block (&testglob, sizeof (testglob)); + ^ + tfile.c:72:1: note: expected 'char *' but argument is of type 'int *' + add_memory_block (char *addr, int size) + ^ + tfile.c:139:3: warning: passing argument 1 of 'add_memory_block' from incompatible pointer type [enabled by default] + add_memory_block (&testglob2, 1); + ^ + tfile.c:72:1: note: expected 'char *' but argument is of type 'int *' + add_memory_block (char *addr, int size) + ^ + tfile.c: In function 'write_error_trace_file': + tfile.c:185:3: warning: implicit declaration of function 'alloca' [-Wimplicit-function-declaration] + char *hex = alloca (len * 2 + 1); + ^ + tfile.c:185:15: warning: incompatible implicit declaration of built-in function 'alloca' [enabled by default] + char *hex = alloca (len * 2 + 1); + ^ + tfile.c:211:6: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] + (long) &write_basic_trace_file); + ^ + + Tested on x86_64 Fedora 20, -m64 and -m32. + Tested by Yao on arm targets. + + gdb/testsuite/ + 2014-07-16 Pedro Alves + + * gdb.trace/tfile.c: Include unistd.h and stdint.h. + (start_trace_file): Guard S_IRGRP and S_IROTH uses behind #ifdef. + (tfile_write_64, tfile_write_16, tfile_write_8, tfile_write_addr) + (tfile_write_buf): New functions. + (add_memory_block): Rewrite using the above. + (adjust_function_address): New function. + (FUNCTION_ADDRESS): New macro. + (write_basic_trace_file): Remove short_x local, and use + tfile_write_16. Change type of func_addr local to unsigned long + long. Use FUNCTION_ADDRESS instead of handling the Thumb bit + here. Cast argument of add_memory_block to char pointer. + (write_error_trace_file): Avoid alloca. Use FUNCTION_ADDRESS. + (main): Remove parameters. + * gdb.trace/tfile.exp: Remove nowarnings. + +Index: gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.trace/tfile.c ++++ gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +@@ -3,9 +3,11 @@ + GDB. */ + + #include ++#include + #include + #include + #include ++#include + + char spbuf[200]; + +@@ -23,9 +25,17 @@ int + start_trace_file (char *filename) + { + int fd; ++ mode_t mode = S_IRUSR | S_IWUSR; + +- fd = open (filename, O_WRONLY|O_CREAT|O_APPEND, +- S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); ++#ifdef S_IRGRP ++ mode |= S_IRGRP; ++#endif ++ ++#ifdef S_IROTH ++ mode |= S_IROTH; ++#endif ++ ++ fd = open (filename, O_WRONLY|O_CREAT|O_APPEND, mode); + + if (fd < 0) + return fd; +@@ -44,31 +54,73 @@ finish_trace_file (int fd) + close (fd); + } + ++static void ++tfile_write_64 (uint64_t value) ++{ ++ memcpy (trptr, &value, sizeof (uint64_t)); ++ trptr += sizeof (uint64_t); ++} + +-void +-add_memory_block (char *addr, int size) ++static void ++tfile_write_16 (uint16_t value) ++{ ++ memcpy (trptr, &value, sizeof (uint16_t)); ++ trptr += sizeof (uint16_t); ++} ++ ++static void ++tfile_write_8 (uint8_t value) + { +- short short_x; +- unsigned long long ll_x; ++ memcpy (trptr, &value, sizeof (uint8_t)); ++ trptr += sizeof (uint8_t); ++} + +- *((char *) trptr) = 'M'; +- trptr += 1; +- ll_x = (unsigned long) addr; +- memcpy (trptr, &ll_x, sizeof (unsigned long long)); +- trptr += sizeof (unsigned long long); +- short_x = size; +- memcpy (trptr, &short_x, 2); +- trptr += 2; ++static void ++tfile_write_addr (char *addr) ++{ ++ tfile_write_64 ((uint64_t) (uintptr_t) addr); ++} ++ ++static void ++tfile_write_buf (const void *addr, size_t size) ++{ + memcpy (trptr, addr, size); + trptr += size; + } + + void ++add_memory_block (char *addr, int size) ++{ ++ tfile_write_8 ('M'); ++ tfile_write_addr (addr); ++ tfile_write_16 (size); ++ tfile_write_buf (addr, size); ++} ++ ++/* Adjust a function's address to account for architectural ++ particularities. */ ++ ++static uintptr_t ++adjust_function_address (uintptr_t func_addr) ++{ ++#if defined(__thumb__) || defined(__thumb2__) ++ /* Although Thumb functions are two-byte aligned, function ++ pointers have the Thumb bit set. Clear it. */ ++ return func_addr & ~1; ++#else ++ return func_addr; ++#endif ++} ++ ++/* Get a function's address as an integer. */ ++ ++#define FUNCTION_ADDRESS(FUN) adjust_function_address ((uintptr_t) &FUN) ++ ++void + write_basic_trace_file (void) + { + int fd, int_x; +- short short_x; +- long func_addr; ++ unsigned long long func_addr; + + fd = start_trace_file ("basic.tf"); + +@@ -86,15 +138,9 @@ write_basic_trace_file (void) + + /* Dump tracepoint definitions, in syntax similar to that used + for reconnection uploads. */ +- /* FIXME need a portable way to print function address in hex */ +- func_addr = (long) &write_basic_trace_file; +-#if defined(__thumb__) || defined(__thumb2__) +- /* Although Thumb functions are two-byte aligned, function +- pointers have the Thumb bit set. Clear it. */ +- func_addr &= ~1; +-#endif ++ func_addr = FUNCTION_ADDRESS (write_basic_trace_file); + +- snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", func_addr); ++ snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", func_addr); + write (fd, spbuf, strlen (spbuf)); + /* (Note that we would only need actions defined if we wanted to + test tdump.) */ +@@ -106,14 +152,13 @@ write_basic_trace_file (void) + /* (Encapsulate better if we're going to do lots of this; note that + buffer endianness is the target program's enddianness.) */ + trptr = trbuf; +- short_x = 1; +- memcpy (trptr, &short_x, 2); +- trptr += 2; ++ tfile_write_16 (1); ++ + tfsizeptr = trptr; + trptr += 4; +- add_memory_block (&testglob, sizeof (testglob)); ++ add_memory_block ((char *) &testglob, sizeof (testglob)); + /* Divide a variable between two separate memory blocks. */ +- add_memory_block (&testglob2, 1); ++ add_memory_block ((char *) &testglob2, 1); + add_memory_block (((char*) &testglob2) + 1, sizeof (testglob2) - 1); + /* Go back and patch in the frame size. */ + int_x = trptr - tfsizeptr - sizeof (int); +@@ -158,8 +203,8 @@ write_error_trace_file (void) + { + int fd; + const char made_up[] = "made-up error"; ++ char hex[(sizeof (made_up) - 1) * 2 + 1]; + int len = sizeof (made_up) - 1; +- char *hex = alloca (len * 2 + 1); + + fd = start_trace_file ("error.tf"); + +@@ -183,9 +228,8 @@ write_error_trace_file (void) + + /* Dump tracepoint definitions, in syntax similar to that used + for reconnection uploads. */ +- /* FIXME need a portable way to print function address in hex */ +- snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n", +- (long) &write_basic_trace_file); ++ snprintf (spbuf, sizeof spbuf, "tp T1:%llx:E:0:0\n", ++ (unsigned long long) FUNCTION_ADDRESS (write_basic_trace_file)); + write (fd, spbuf, strlen (spbuf)); + /* (Note that we would only need actions defined if we wanted to + test tdump.) */ +@@ -210,7 +254,7 @@ done_making_trace_files (void) + } + + int +-main (int argc, char **argv, char **envp) ++main (void) + { + write_basic_trace_file (); + +Index: gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.exp +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.trace/tfile.exp ++++ gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.exp +@@ -26,7 +26,7 @@ gdb_exit + gdb_start + standard_testfile + if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \ +- executable {debug nowarnings}] != "" } { ++ executable {debug}] != "" } { + untested ${testfile}.exp + return -1 + } diff --git a/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-8of8.patch b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-8of8.patch new file mode 100644 index 0000000..71f07e2 --- /dev/null +++ b/SOURCES/gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-8of8.patch @@ -0,0 +1,59 @@ +commit 763905a3ad8f98d33bd9319790a8d53904554265 +Author: Yao Qi +Date: Mon Oct 27 16:37:38 2014 +0800 + + Fix trace file fails on powerpc64 + + I see the following fails on powerpc64-linux, + + (gdb) target tfile tfile-basic.tf^M + warning: Uploaded tracepoint 1 has no source location, using raw address^M + Tracepoint 1 at 0x10012358^M + Created tracepoint 1 for target's tracepoint 1 at 0x10012358.^M + (gdb) PASS: gdb.trace/tfile.exp: target tfile tfile-basic.tf + info trace^M + Num Type Disp Enb Address What^M + 1 tracepoint keep y 0x0000000010012358 ^M + installed on target^M + (gdb) FAIL: gdb.trace/tfile.exp: info tracepoints on trace file + + -target-select tfile tfile-basic.tf^M + =thread-group-started,id="i1",pid="1"^M + =thread-created,id="1",group-id="i1"^M + &"warning: Uploaded tracepoint 1 has no source location, using raw address\n"^M + =breakpoint-created,bkpt={number="1",type="tracepoint",disp="keep",enabled="y", + addr="0x0000000010012358",at="",thread-groups=["i1"], + times="0",installed="y",original-location="*0x10012358"}^M + ~"Created tracepoint 1 for target's tracepoint 1 at 0x10012358.\n"^M + ^connected^M + (gdb) ^M + FAIL: gdb.trace/mi-traceframe-changed.exp: tfile: select trace file + + These fails are caused by writing function descriptor address into trace + file instead of function address. This patch is to teach tfile.c to + write function address on powerpc64 target. With this patch applied, + fails in tfile.exp and mi-traceframe-changed.exp are fixed. Is it + OK? + + gdb/testsuite: + + 2014-10-27 Yao Qi + + * gdb.trace/tfile.c (adjust_function_address) + [__powerpc64__ && _CALL_ELF != 2]: Get function address from + function descriptor. + +Index: gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +=================================================================== +--- gdb-7.6.1.orig/gdb/testsuite/gdb.trace/tfile.c ++++ gdb-7.6.1/gdb/testsuite/gdb.trace/tfile.c +@@ -107,6 +107,9 @@ adjust_function_address (uintptr_t func_ + /* Although Thumb functions are two-byte aligned, function + pointers have the Thumb bit set. Clear it. */ + return func_addr & ~1; ++#elif defined __powerpc64__ && _CALL_ELF != 2 ++ /* Get function address from function descriptor. */ ++ return *(uintptr_t *) func_addr; + #else + return func_addr; + #endif diff --git a/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-1of2.patch b/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-1of2.patch new file mode 100644 index 0000000..54bc65f --- /dev/null +++ b/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-1of2.patch @@ -0,0 +1,1120 @@ +commit 05c0465e16a5e2db92f8975aebf2bb5aacb1c542 +Author: Sergio Durigan Junior +Date: Thu Dec 19 18:53:40 2013 -0200 + + Extend SystemTap SDT probe argument parser + + This patch extends the current generic parser for SystemTap SDT probe + arguments. It can be almost considered a cleanup, but the main point of + it is actually to allow the generic parser to accept multiple prefixes + and suffixes for the its operands (i.e., integers, register names, and + register indirection). + + I have chosen to implement this as a list of const strings, and declare + this list as "static" inside each target's method used to initialize + gdbarch. + + This patch is actually a preparation for an upcoming patch for ARM, + which implements the support for multiple integer prefixes (as defined + by ARM's asm spec). And AArch64 will also need this, for the same + reason. + + This patch was regtested on all architectures that it touches (i.e., + i386, x86_64, ARM, PPC/PPC64, s390x and IA-64). No regressions were found. + + 2013-12-19 Sergio Durigan Junior + + * amd64-tdep.c (amd64_init_abi): Declare SystemTap SDT probe + argument prefixes and suffixes. Initialize gdbarch with them. + * arm-linux-tdep.c (arm_linux_init_abi): Likewise. + * gdbarch.c: Regenerate. + * gdbarch.h: Regenerate. + * gdbarch.sh (stap_integer_prefix, stap_integer_suffix) + (stap_register_prefix, stap_register_suffix) + (stap_register_indirection_prefix) + (stap_register_indirection_suffix): Declare as "const char *const + *" instead of "const char *". Adjust printing function. Rename + all of the variables to the plural. + (pstring_list): New function. + * i386-tdep.c (i386_elf_init_abi): Declare SystemTap SDT probe + argument prefixes and suffixes. Initialize gdbarch with them. + * ia64-linux-tdep.c (ia64_linux_init_abi): Likewise. + * ppc-linux-tdep.c (ppc_linux_init_abi): Likewise. + * s390-linux-tdep.c (s390_gdbarch_init): Likewise. + * stap-probe.c (stap_is_generic_prefix): New function. + (stap_is_register_prefix): Likewise. + (stap_is_register_indirection_prefix): Likewise. + (stap_is_integer_prefix): Likewise. + (stap_generic_check_suffix): Likewise. + (stap_check_integer_suffix): Likewise. + (stap_check_register_suffix): Likewise. + (stap_check_register_indirection_suffix): Likewise. + (stap_parse_register_operand): Remove unecessary declarations for + variables holding prefix and suffix information. Use the new + functions listed above for checking for prefixes and suffixes. + (stap_parse_single_operand): Likewise. + +Index: gdb-7.6.1/gdb/amd64-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/amd64-tdep.c ++++ gdb-7.6.1/gdb/amd64-tdep.c +@@ -2867,6 +2867,12 @@ amd64_init_abi (struct gdbarch_info info + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const struct target_desc *tdesc = info.target_desc; ++ static const char *const stap_integer_prefixes[] = { "$", NULL }; ++ static const char *const stap_register_prefixes[] = { "%", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "(", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { ")", ++ NULL }; + + /* AMD64 generally uses `fxsave' instead of `fsave' for saving its + floating-point registers. */ +@@ -2976,10 +2982,12 @@ amd64_init_abi (struct gdbarch_info info + set_gdbarch_gen_return_address (gdbarch, amd64_gen_return_address); + + /* SystemTap variables and functions. */ +- set_gdbarch_stap_integer_prefix (gdbarch, "$"); +- set_gdbarch_stap_register_prefix (gdbarch, "%"); +- set_gdbarch_stap_register_indirection_prefix (gdbarch, "("); +- set_gdbarch_stap_register_indirection_suffix (gdbarch, ")"); ++ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); ++ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); + set_gdbarch_stap_is_single_operand (gdbarch, + i386_stap_is_single_operand); + set_gdbarch_stap_parse_special_token (gdbarch, +Index: gdb-7.6.1/gdb/arm-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/arm-linux-tdep.c ++++ gdb-7.6.1/gdb/arm-linux-tdep.c +@@ -1182,6 +1182,12 @@ static void + arm_linux_init_abi (struct gdbarch_info info, + struct gdbarch *gdbarch) + { ++ static const char *const stap_integer_prefixes[] = { "#", NULL }; ++ static const char *const stap_register_prefixes[] = { "r", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "[", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { "]", ++ NULL }; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + linux_init_abi (info, gdbarch); +@@ -1281,10 +1287,12 @@ arm_linux_init_abi (struct gdbarch_info + set_gdbarch_process_record (gdbarch, arm_process_record); + + /* SystemTap functions. */ +- set_gdbarch_stap_integer_prefix (gdbarch, "#"); +- set_gdbarch_stap_register_prefix (gdbarch, "r"); +- set_gdbarch_stap_register_indirection_prefix (gdbarch, "["); +- set_gdbarch_stap_register_indirection_suffix (gdbarch, "]"); ++ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); ++ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); + set_gdbarch_stap_gdb_register_prefix (gdbarch, "r"); + set_gdbarch_stap_is_single_operand (gdbarch, arm_stap_is_single_operand); + set_gdbarch_stap_parse_special_token (gdbarch, +Index: gdb-7.6.1/gdb/gdbarch.c +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.c ++++ gdb-7.6.1/gdb/gdbarch.c +@@ -86,6 +86,35 @@ pstring (const char *string) + return string; + } + ++/* Helper function to print a list of strings, represented as "const ++ char *const *". The list is printed comma-separated. */ ++ ++static char * ++pstring_list (const char *const *list) ++{ ++ static char ret[100]; ++ const char *const *p; ++ size_t offset = 0; ++ ++ if (list == NULL) ++ return "(null)"; ++ ++ ret[0] = '\0'; ++ for (p = list; *p != NULL && offset < sizeof (ret); ++p) ++ { ++ size_t s = xsnprintf (ret + offset, sizeof (ret) - offset, "%s, ", *p); ++ offset += 2 + s; ++ } ++ ++ if (offset > 0) ++ { ++ gdb_assert (offset - 2 < sizeof (ret)); ++ ret[offset - 2] = '\0'; ++ } ++ ++ return ret; ++} ++ + + /* Maintain the struct gdbarch object. */ + +@@ -264,12 +293,12 @@ struct gdbarch + gdbarch_get_siginfo_type_ftype *get_siginfo_type; + gdbarch_record_special_symbol_ftype *record_special_symbol; + gdbarch_get_syscall_number_ftype *get_syscall_number; +- const char * stap_integer_prefix; +- const char * stap_integer_suffix; +- const char * stap_register_prefix; +- const char * stap_register_suffix; +- const char * stap_register_indirection_prefix; +- const char * stap_register_indirection_suffix; ++ const char *const * stap_integer_prefixes; ++ const char *const * stap_integer_suffixes; ++ const char *const * stap_register_prefixes; ++ const char *const * stap_register_suffixes; ++ const char *const * stap_register_indirection_prefixes; ++ const char *const * stap_register_indirection_suffixes; + const char * stap_gdb_register_prefix; + const char * stap_gdb_register_suffix; + gdbarch_stap_is_single_operand_ftype *stap_is_single_operand; +@@ -436,12 +465,12 @@ struct gdbarch startup_gdbarch = + 0, /* get_siginfo_type */ + 0, /* record_special_symbol */ + 0, /* get_syscall_number */ +- 0, /* stap_integer_prefix */ +- 0, /* stap_integer_suffix */ +- 0, /* stap_register_prefix */ +- 0, /* stap_register_suffix */ +- 0, /* stap_register_indirection_prefix */ +- 0, /* stap_register_indirection_suffix */ ++ 0, /* stap_integer_prefixes */ ++ 0, /* stap_integer_suffixes */ ++ 0, /* stap_register_prefixes */ ++ 0, /* stap_register_suffixes */ ++ 0, /* stap_register_indirection_prefixes */ ++ 0, /* stap_register_indirection_suffixes */ + 0, /* stap_gdb_register_prefix */ + 0, /* stap_gdb_register_suffix */ + 0, /* stap_is_single_operand */ +@@ -741,12 +770,12 @@ verify_gdbarch (struct gdbarch *gdbarch) + /* Skip verify of get_siginfo_type, has predicate. */ + /* Skip verify of record_special_symbol, has predicate. */ + /* Skip verify of get_syscall_number, has predicate. */ +- /* Skip verify of stap_integer_prefix, invalid_p == 0 */ +- /* Skip verify of stap_integer_suffix, invalid_p == 0 */ +- /* Skip verify of stap_register_prefix, invalid_p == 0 */ +- /* Skip verify of stap_register_suffix, invalid_p == 0 */ +- /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */ +- /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */ ++ /* Skip verify of stap_integer_prefixes, invalid_p == 0 */ ++ /* Skip verify of stap_integer_suffixes, invalid_p == 0 */ ++ /* Skip verify of stap_register_prefixes, invalid_p == 0 */ ++ /* Skip verify of stap_register_suffixes, invalid_p == 0 */ ++ /* Skip verify of stap_register_indirection_prefixes, invalid_p == 0 */ ++ /* Skip verify of stap_register_indirection_suffixes, invalid_p == 0 */ + /* Skip verify of stap_gdb_register_prefix, invalid_p == 0 */ + /* Skip verify of stap_gdb_register_suffix, invalid_p == 0 */ + /* Skip verify of stap_is_single_operand, has predicate. */ +@@ -1342,11 +1371,11 @@ gdbarch_dump (struct gdbarch *gdbarch, s + "gdbarch_dump: stap_gdb_register_suffix = %s\n", + pstring (gdbarch->stap_gdb_register_suffix)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_integer_prefix = %s\n", +- pstring (gdbarch->stap_integer_prefix)); ++ "gdbarch_dump: stap_integer_prefixes = %s\n", ++ pstring_list (gdbarch->stap_integer_prefixes)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_integer_suffix = %s\n", +- pstring (gdbarch->stap_integer_suffix)); ++ "gdbarch_dump: stap_integer_suffixes = %s\n", ++ pstring_list (gdbarch->stap_integer_suffixes)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_stap_is_single_operand_p() = %d\n", + gdbarch_stap_is_single_operand_p (gdbarch)); +@@ -1360,17 +1389,17 @@ gdbarch_dump (struct gdbarch *gdbarch, s + "gdbarch_dump: stap_parse_special_token = <%s>\n", + host_address_to_string (gdbarch->stap_parse_special_token)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_register_indirection_prefix = %s\n", +- pstring (gdbarch->stap_register_indirection_prefix)); ++ "gdbarch_dump: stap_register_indirection_prefixes = %s\n", ++ pstring_list (gdbarch->stap_register_indirection_prefixes)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_register_indirection_suffix = %s\n", +- pstring (gdbarch->stap_register_indirection_suffix)); ++ "gdbarch_dump: stap_register_indirection_suffixes = %s\n", ++ pstring_list (gdbarch->stap_register_indirection_suffixes)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_register_prefix = %s\n", +- pstring (gdbarch->stap_register_prefix)); ++ "gdbarch_dump: stap_register_prefixes = %s\n", ++ pstring_list (gdbarch->stap_register_prefixes)); + fprintf_unfiltered (file, +- "gdbarch_dump: stap_register_suffix = %s\n", +- pstring (gdbarch->stap_register_suffix)); ++ "gdbarch_dump: stap_register_suffixes = %s\n", ++ pstring_list (gdbarch->stap_register_suffixes)); + fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_static_transform_name_p() = %d\n", + gdbarch_static_transform_name_p (gdbarch)); +@@ -3971,106 +4000,106 @@ set_gdbarch_get_syscall_number (struct g + gdbarch->get_syscall_number = get_syscall_number; + } + +-const char * +-gdbarch_stap_integer_prefix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_integer_prefixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_integer_prefix, invalid_p == 0 */ ++ /* Skip verify of stap_integer_prefixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_prefix called\n"); +- return gdbarch->stap_integer_prefix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_prefixes called\n"); ++ return gdbarch->stap_integer_prefixes; + } + + void +-set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch, +- const char * stap_integer_prefix) ++set_gdbarch_stap_integer_prefixes (struct gdbarch *gdbarch, ++ const char *const * stap_integer_prefixes) + { +- gdbarch->stap_integer_prefix = stap_integer_prefix; ++ gdbarch->stap_integer_prefixes = stap_integer_prefixes; + } + +-const char * +-gdbarch_stap_integer_suffix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_integer_suffixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_integer_suffix, invalid_p == 0 */ ++ /* Skip verify of stap_integer_suffixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_suffix called\n"); +- return gdbarch->stap_integer_suffix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_integer_suffixes called\n"); ++ return gdbarch->stap_integer_suffixes; + } + + void +-set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch, +- const char * stap_integer_suffix) ++set_gdbarch_stap_integer_suffixes (struct gdbarch *gdbarch, ++ const char *const * stap_integer_suffixes) + { +- gdbarch->stap_integer_suffix = stap_integer_suffix; ++ gdbarch->stap_integer_suffixes = stap_integer_suffixes; + } + +-const char * +-gdbarch_stap_register_prefix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_register_prefixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_register_prefix, invalid_p == 0 */ ++ /* Skip verify of stap_register_prefixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_prefix called\n"); +- return gdbarch->stap_register_prefix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_prefixes called\n"); ++ return gdbarch->stap_register_prefixes; + } + + void +-set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch, +- const char * stap_register_prefix) ++set_gdbarch_stap_register_prefixes (struct gdbarch *gdbarch, ++ const char *const * stap_register_prefixes) + { +- gdbarch->stap_register_prefix = stap_register_prefix; ++ gdbarch->stap_register_prefixes = stap_register_prefixes; + } + +-const char * +-gdbarch_stap_register_suffix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_register_suffixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_register_suffix, invalid_p == 0 */ ++ /* Skip verify of stap_register_suffixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_suffix called\n"); +- return gdbarch->stap_register_suffix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_suffixes called\n"); ++ return gdbarch->stap_register_suffixes; + } + + void +-set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch, +- const char * stap_register_suffix) ++set_gdbarch_stap_register_suffixes (struct gdbarch *gdbarch, ++ const char *const * stap_register_suffixes) + { +- gdbarch->stap_register_suffix = stap_register_suffix; ++ gdbarch->stap_register_suffixes = stap_register_suffixes; + } + +-const char * +-gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_register_indirection_prefixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_register_indirection_prefix, invalid_p == 0 */ ++ /* Skip verify of stap_register_indirection_prefixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_prefix called\n"); +- return gdbarch->stap_register_indirection_prefix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_prefixes called\n"); ++ return gdbarch->stap_register_indirection_prefixes; + } + + void +-set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch, +- const char * stap_register_indirection_prefix) ++set_gdbarch_stap_register_indirection_prefixes (struct gdbarch *gdbarch, ++ const char *const * stap_register_indirection_prefixes) + { +- gdbarch->stap_register_indirection_prefix = stap_register_indirection_prefix; ++ gdbarch->stap_register_indirection_prefixes = stap_register_indirection_prefixes; + } + +-const char * +-gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch) ++const char *const * ++gdbarch_stap_register_indirection_suffixes (struct gdbarch *gdbarch) + { + gdb_assert (gdbarch != NULL); +- /* Skip verify of stap_register_indirection_suffix, invalid_p == 0 */ ++ /* Skip verify of stap_register_indirection_suffixes, invalid_p == 0 */ + if (gdbarch_debug >= 2) +- fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_suffix called\n"); +- return gdbarch->stap_register_indirection_suffix; ++ fprintf_unfiltered (gdb_stdlog, "gdbarch_stap_register_indirection_suffixes called\n"); ++ return gdbarch->stap_register_indirection_suffixes; + } + + void +-set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch, +- const char * stap_register_indirection_suffix) ++set_gdbarch_stap_register_indirection_suffixes (struct gdbarch *gdbarch, ++ const char *const * stap_register_indirection_suffixes) + { +- gdbarch->stap_register_indirection_suffix = stap_register_indirection_suffix; ++ gdbarch->stap_register_indirection_suffixes = stap_register_indirection_suffixes; + } + + const char * +Index: gdb-7.6.1/gdb/gdbarch.h +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.h ++++ gdb-7.6.1/gdb/gdbarch.h +@@ -1030,37 +1030,42 @@ extern LONGEST gdbarch_get_syscall_numbe + extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number); + + /* SystemTap related fields and functions. +- Prefix used to mark an integer constant on the architecture's assembly ++ A NULL-terminated array of prefixes used to mark an integer constant ++ on the architecture's assembly. + For example, on x86 integer constants are written as: + + $10 ;; integer constant 10 + + in this case, this prefix would be the character `$'. */ + +-extern const char * gdbarch_stap_integer_prefix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_integer_prefix (struct gdbarch *gdbarch, const char * stap_integer_prefix); ++extern const char *const * gdbarch_stap_integer_prefixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_integer_prefixes (struct gdbarch *gdbarch, const char *const * stap_integer_prefixes); + +-/* Suffix used to mark an integer constant on the architecture's assembly. */ ++/* A NULL-terminated array of suffixes used to mark an integer constant ++ on the architecture's assembly. */ + +-extern const char * gdbarch_stap_integer_suffix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_integer_suffix (struct gdbarch *gdbarch, const char * stap_integer_suffix); ++extern const char *const * gdbarch_stap_integer_suffixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_integer_suffixes (struct gdbarch *gdbarch, const char *const * stap_integer_suffixes); + +-/* Prefix used to mark a register name on the architecture's assembly. ++/* A NULL-terminated array of prefixes used to mark a register name on ++ the architecture's assembly. + For example, on x86 the register name is written as: + + %eax ;; register eax + + in this case, this prefix would be the character `%'. */ + +-extern const char * gdbarch_stap_register_prefix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_register_prefix (struct gdbarch *gdbarch, const char * stap_register_prefix); ++extern const char *const * gdbarch_stap_register_prefixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_register_prefixes (struct gdbarch *gdbarch, const char *const * stap_register_prefixes); + +-/* Suffix used to mark a register name on the architecture's assembly */ ++/* A NULL-terminated array of suffixes used to mark a register name on ++ the architecture's assembly. */ + +-extern const char * gdbarch_stap_register_suffix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_register_suffix (struct gdbarch *gdbarch, const char * stap_register_suffix); ++extern const char *const * gdbarch_stap_register_suffixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_register_suffixes (struct gdbarch *gdbarch, const char *const * stap_register_suffixes); + +-/* Prefix used to mark a register indirection on the architecture's assembly. ++/* A NULL-terminated array of prefixes used to mark a register ++ indirection on the architecture's assembly. + For example, on x86 the register indirection is written as: + + (%eax) ;; indirecting eax +@@ -1070,10 +1075,11 @@ extern void set_gdbarch_stap_register_su + Please note that we use the indirection prefix also for register + displacement, e.g., `4(%eax)' on x86. */ + +-extern const char * gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_register_indirection_prefix (struct gdbarch *gdbarch, const char * stap_register_indirection_prefix); ++extern const char *const * gdbarch_stap_register_indirection_prefixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_register_indirection_prefixes (struct gdbarch *gdbarch, const char *const * stap_register_indirection_prefixes); + +-/* Suffix used to mark a register indirection on the architecture's assembly. ++/* A NULL-terminated array of suffixes used to mark a register ++ indirection on the architecture's assembly. + For example, on x86 the register indirection is written as: + + (%eax) ;; indirecting eax +@@ -1083,10 +1089,10 @@ extern void set_gdbarch_stap_register_in + Please note that we use the indirection suffix also for register + displacement, e.g., `4(%eax)' on x86. */ + +-extern const char * gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch); +-extern void set_gdbarch_stap_register_indirection_suffix (struct gdbarch *gdbarch, const char * stap_register_indirection_suffix); ++extern const char *const * gdbarch_stap_register_indirection_suffixes (struct gdbarch *gdbarch); ++extern void set_gdbarch_stap_register_indirection_suffixes (struct gdbarch *gdbarch, const char *const * stap_register_indirection_suffixes); + +-/* Prefix used to name a register using GDB's nomenclature. ++/* Prefix(es) used to name a register using GDB's nomenclature. + + For example, on PPC a register is represented by a number in the assembly + language (e.g., `10' is the 10th general-purpose register). However, +Index: gdb-7.6.1/gdb/gdbarch.sh +=================================================================== +--- gdb-7.6.1.orig/gdb/gdbarch.sh ++++ gdb-7.6.1/gdb/gdbarch.sh +@@ -823,29 +823,34 @@ M:LONGEST:get_syscall_number:ptid_t ptid + + # SystemTap related fields and functions. + +-# Prefix used to mark an integer constant on the architecture's assembly ++# A NULL-terminated array of prefixes used to mark an integer constant ++# on the architecture's assembly. + # For example, on x86 integer constants are written as: + # + # \$10 ;; integer constant 10 + # + # in this case, this prefix would be the character \`\$\'. +-v:const char *:stap_integer_prefix:::0:0::0:pstring (gdbarch->stap_integer_prefix) ++v:const char *const *:stap_integer_prefixes:::0:0::0:pstring_list (gdbarch->stap_integer_prefixes) + +-# Suffix used to mark an integer constant on the architecture's assembly. +-v:const char *:stap_integer_suffix:::0:0::0:pstring (gdbarch->stap_integer_suffix) ++# A NULL-terminated array of suffixes used to mark an integer constant ++# on the architecture's assembly. ++v:const char *const *:stap_integer_suffixes:::0:0::0:pstring_list (gdbarch->stap_integer_suffixes) + +-# Prefix used to mark a register name on the architecture's assembly. ++# A NULL-terminated array of prefixes used to mark a register name on ++# the architecture's assembly. + # For example, on x86 the register name is written as: + # + # \%eax ;; register eax + # + # in this case, this prefix would be the character \`\%\'. +-v:const char *:stap_register_prefix:::0:0::0:pstring (gdbarch->stap_register_prefix) ++v:const char *const *:stap_register_prefixes:::0:0::0:pstring_list (gdbarch->stap_register_prefixes) + +-# Suffix used to mark a register name on the architecture's assembly +-v:const char *:stap_register_suffix:::0:0::0:pstring (gdbarch->stap_register_suffix) ++# A NULL-terminated array of suffixes used to mark a register name on ++# the architecture's assembly. ++v:const char *const *:stap_register_suffixes:::0:0::0:pstring_list (gdbarch->stap_register_suffixes) + +-# Prefix used to mark a register indirection on the architecture's assembly. ++# A NULL-terminated array of prefixes used to mark a register ++# indirection on the architecture's assembly. + # For example, on x86 the register indirection is written as: + # + # \(\%eax\) ;; indirecting eax +@@ -854,9 +859,10 @@ v:const char *:stap_register_suffix:::0: + # + # Please note that we use the indirection prefix also for register + # displacement, e.g., \`4\(\%eax\)\' on x86. +-v:const char *:stap_register_indirection_prefix:::0:0::0:pstring (gdbarch->stap_register_indirection_prefix) ++v:const char *const *:stap_register_indirection_prefixes:::0:0::0:pstring_list (gdbarch->stap_register_indirection_prefixes) + +-# Suffix used to mark a register indirection on the architecture's assembly. ++# A NULL-terminated array of suffixes used to mark a register ++# indirection on the architecture's assembly. + # For example, on x86 the register indirection is written as: + # + # \(\%eax\) ;; indirecting eax +@@ -865,9 +871,9 @@ v:const char *:stap_register_indirection + # + # Please note that we use the indirection suffix also for register + # displacement, e.g., \`4\(\%eax\)\' on x86. +-v:const char *:stap_register_indirection_suffix:::0:0::0:pstring (gdbarch->stap_register_indirection_suffix) ++v:const char *const *:stap_register_indirection_suffixes:::0:0::0:pstring_list (gdbarch->stap_register_indirection_suffixes) + +-# Prefix used to name a register using GDB's nomenclature. ++# Prefix(es) used to name a register using GDB's nomenclature. + # + # For example, on PPC a register is represented by a number in the assembly + # language (e.g., \`10\' is the 10th general-purpose register). However, +@@ -1478,6 +1484,35 @@ pstring (const char *string) + return string; + } + ++/* Helper function to print a list of strings, represented as "const ++ char *const *". The list is printed comma-separated. */ ++ ++static char * ++pstring_list (const char *const *list) ++{ ++ static char ret[100]; ++ const char *const *p; ++ size_t offset = 0; ++ ++ if (list == NULL) ++ return "(null)"; ++ ++ ret[0] = '\0'; ++ for (p = list; *p != NULL && offset < sizeof (ret); ++p) ++ { ++ size_t s = xsnprintf (ret + offset, sizeof (ret) - offset, "%s, ", *p); ++ offset += 2 + s; ++ } ++ ++ if (offset > 0) ++ { ++ gdb_assert (offset - 2 < sizeof (ret)); ++ ret[offset - 2] = '\0'; ++ } ++ ++ return ret; ++} ++ + EOF + + # gdbarch open the gdbarch object +Index: gdb-7.6.1/gdb/i386-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/i386-tdep.c ++++ gdb-7.6.1/gdb/i386-tdep.c +@@ -3767,14 +3767,23 @@ i386_stap_parse_special_token (struct gd + void + i386_elf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { ++ static const char *const stap_integer_prefixes[] = { "$", NULL }; ++ static const char *const stap_register_prefixes[] = { "%", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "(", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { ")", ++ NULL }; ++ + /* We typically use stabs-in-ELF with the SVR4 register numbering. */ + set_gdbarch_stab_reg_to_regnum (gdbarch, i386_svr4_reg_to_regnum); + + /* Registering SystemTap handlers. */ +- set_gdbarch_stap_integer_prefix (gdbarch, "$"); +- set_gdbarch_stap_register_prefix (gdbarch, "%"); +- set_gdbarch_stap_register_indirection_prefix (gdbarch, "("); +- set_gdbarch_stap_register_indirection_suffix (gdbarch, ")"); ++ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); ++ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); + set_gdbarch_stap_is_single_operand (gdbarch, + i386_stap_is_single_operand); + set_gdbarch_stap_parse_special_token (gdbarch, +Index: gdb-7.6.1/gdb/ppc-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/ppc-linux-tdep.c ++++ gdb-7.6.1/gdb/ppc-linux-tdep.c +@@ -1723,6 +1723,11 @@ ppc_linux_init_abi (struct gdbarch_info + { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; ++ static const char *const stap_integer_prefixes[] = { "i", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "(", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { ")", ++ NULL }; + + linux_init_abi (info, gdbarch); + +@@ -1741,9 +1746,11 @@ ppc_linux_init_abi (struct gdbarch_info + set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number); + + /* SystemTap functions. */ +- set_gdbarch_stap_integer_prefix (gdbarch, "i"); +- set_gdbarch_stap_register_indirection_prefix (gdbarch, "("); +- set_gdbarch_stap_register_indirection_suffix (gdbarch, ")"); ++ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); + set_gdbarch_stap_gdb_register_prefix (gdbarch, "r"); + set_gdbarch_stap_is_single_operand (gdbarch, ppc_stap_is_single_operand); + set_gdbarch_stap_parse_special_token (gdbarch, +Index: gdb-7.6.1/gdb/s390-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/s390-tdep.c ++++ gdb-7.6.1/gdb/s390-tdep.c +@@ -3032,6 +3032,11 @@ s390_gdbarch_init (struct gdbarch_info i + int have_linux_v1 = 0; + int have_linux_v2 = 0; + int first_pseudo_reg, last_pseudo_reg; ++ static const char *const stap_register_prefixes[] = { "%", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "(", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { ")", ++ NULL }; + + /* Default ABI and register size. */ + switch (info.bfd_arch_info->mach) +@@ -3364,9 +3369,11 @@ s390_gdbarch_init (struct gdbarch_info i + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); + + /* SystemTap functions. */ +- set_gdbarch_stap_register_prefix (gdbarch, "%"); +- set_gdbarch_stap_register_indirection_prefix (gdbarch, "("); +- set_gdbarch_stap_register_indirection_suffix (gdbarch, ")"); ++ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); + set_gdbarch_stap_is_single_operand (gdbarch, s390_stap_is_single_operand); + + return gdbarch; +Index: gdb-7.6.1/gdb/stap-probe.c +=================================================================== +--- gdb-7.6.1.orig/gdb/stap-probe.c ++++ gdb-7.6.1/gdb/stap-probe.c +@@ -346,6 +346,191 @@ stap_get_expected_argument_type (struct + } + } + ++/* Helper function to check for a generic list of prefixes. GDBARCH ++ is the current gdbarch being used. S is the expression being ++ analyzed. If R is not NULL, it will be used to return the found ++ prefix. PREFIXES is the list of expected prefixes. ++ ++ This function does a case-insensitive match. ++ ++ Return 1 if any prefix has been found, zero otherwise. */ ++ ++static int ++stap_is_generic_prefix (struct gdbarch *gdbarch, const char *s, ++ const char **r, const char *const *prefixes) ++{ ++ const char *const *p; ++ ++ if (prefixes == NULL) ++ { ++ if (r != NULL) ++ *r = ""; ++ ++ return 1; ++ } ++ ++ for (p = prefixes; *p != NULL; ++p) ++ { ++ if (strncasecmp (s, *p, strlen (*p)) == 0) ++ { ++ if (r != NULL) ++ *r = *p; ++ ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Return 1 if S points to a register prefix, zero otherwise. For a ++ description of the arguments, look at stap_is_generic_prefix. */ ++ ++static int ++stap_is_register_prefix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *t = gdbarch_stap_register_prefixes (gdbarch); ++ ++ return stap_is_generic_prefix (gdbarch, s, r, t); ++} ++ ++/* Return 1 if S points to a register indirection prefix, zero ++ otherwise. For a description of the arguments, look at ++ stap_is_generic_prefix. */ ++ ++static int ++stap_is_register_indirection_prefix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *t = gdbarch_stap_register_indirection_prefixes (gdbarch); ++ ++ return stap_is_generic_prefix (gdbarch, s, r, t); ++} ++ ++/* Return 1 if S points to an integer prefix, zero otherwise. For a ++ description of the arguments, look at stap_is_generic_prefix. ++ ++ This function takes care of analyzing whether we are dealing with ++ an expected integer prefix, or, if there is no integer prefix to be ++ expected, whether we are dealing with a digit. It does a ++ case-insensitive match. */ ++ ++static int ++stap_is_integer_prefix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *t = gdbarch_stap_integer_prefixes (gdbarch); ++ const char *const *p; ++ ++ if (t == NULL) ++ { ++ /* A NULL value here means that integers do not have a prefix. ++ We just check for a digit then. */ ++ if (r != NULL) ++ *r = ""; ++ ++ return isdigit (*s); ++ } ++ ++ for (p = t; *p != NULL; ++p) ++ { ++ size_t len = strlen (*p); ++ ++ if ((len == 0 && isdigit (*s)) ++ || (len > 0 && strncasecmp (s, *p, len) == 0)) ++ { ++ /* Integers may or may not have a prefix. The "len == 0" ++ check covers the case when integers do not have a prefix ++ (therefore, we just check if we have a digit). The call ++ to "strncasecmp" covers the case when they have a ++ prefix. */ ++ if (r != NULL) ++ *r = *p; ++ ++ return 1; ++ } ++ } ++ ++ return 0; ++} ++ ++/* Helper function to check for a generic list of suffixes. If we are ++ not expecting any suffixes, then it just returns 1. If we are ++ expecting at least one suffix, then it returns 1 if a suffix has ++ been found, zero otherwise. GDBARCH is the current gdbarch being ++ used. S is the expression being analyzed. If R is not NULL, it ++ will be used to return the found suffix. SUFFIXES is the list of ++ expected suffixes. This function does a case-insensitive ++ match. */ ++ ++static int ++stap_generic_check_suffix (struct gdbarch *gdbarch, const char *s, ++ const char **r, const char *const *suffixes) ++{ ++ const char *const *p; ++ int found = 0; ++ ++ if (suffixes == NULL) ++ { ++ if (r != NULL) ++ *r = ""; ++ ++ return 1; ++ } ++ ++ for (p = suffixes; *p != NULL; ++p) ++ if (strncasecmp (s, *p, strlen (*p)) == 0) ++ { ++ if (r != NULL) ++ *r = *p; ++ ++ found = 1; ++ break; ++ } ++ ++ return found; ++} ++ ++/* Return 1 if S points to an integer suffix, zero otherwise. For a ++ description of the arguments, look at ++ stap_generic_check_suffix. */ ++ ++static int ++stap_check_integer_suffix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *p = gdbarch_stap_integer_suffixes (gdbarch); ++ ++ return stap_generic_check_suffix (gdbarch, s, r, p); ++} ++ ++/* Return 1 if S points to a register suffix, zero otherwise. For a ++ description of the arguments, look at ++ stap_generic_check_suffix. */ ++ ++static int ++stap_check_register_suffix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *p = gdbarch_stap_register_suffixes (gdbarch); ++ ++ return stap_generic_check_suffix (gdbarch, s, r, p); ++} ++ ++/* Return 1 if S points to a register indirection suffix, zero ++ otherwise. For a description of the arguments, look at ++ stap_generic_check_suffix. */ ++ ++static int ++stap_check_register_indirection_suffix (struct gdbarch *gdbarch, const char *s, ++ const char **r) ++{ ++ const char *const *p = gdbarch_stap_register_indirection_suffixes (gdbarch); ++ ++ return stap_generic_check_suffix (gdbarch, s, r, p); ++} ++ + /* Function responsible for parsing a register operand according to + SystemTap parlance. Assuming: + +@@ -385,24 +570,14 @@ stap_parse_register_operand (struct stap + const char *start; + char *regname; + int len; +- +- /* Prefixes for the parser. */ +- const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch); +- const char *reg_ind_prefix +- = gdbarch_stap_register_indirection_prefix (gdbarch); + const char *gdb_reg_prefix = gdbarch_stap_gdb_register_prefix (gdbarch); +- int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0; +- int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0; + int gdb_reg_prefix_len = gdb_reg_prefix ? strlen (gdb_reg_prefix) : 0; +- +- /* Suffixes for the parser. */ +- const char *reg_suffix = gdbarch_stap_register_suffix (gdbarch); +- const char *reg_ind_suffix +- = gdbarch_stap_register_indirection_suffix (gdbarch); + const char *gdb_reg_suffix = gdbarch_stap_gdb_register_suffix (gdbarch); +- int reg_suffix_len = reg_suffix ? strlen (reg_suffix) : 0; +- int reg_ind_suffix_len = reg_ind_suffix ? strlen (reg_ind_suffix) : 0; + int gdb_reg_suffix_len = gdb_reg_suffix ? strlen (gdb_reg_suffix) : 0; ++ const char *reg_prefix; ++ const char *reg_ind_prefix; ++ const char *reg_suffix; ++ const char *reg_ind_suffix; + + /* Checking for a displacement argument. */ + if (*p->arg == '+') +@@ -436,11 +611,10 @@ stap_parse_register_operand (struct stap + } + + /* Getting rid of register indirection prefix. */ +- if (reg_ind_prefix +- && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0) ++ if (stap_is_register_indirection_prefix (gdbarch, p->arg, ®_ind_prefix)) + { + indirect_p = 1; +- p->arg += reg_ind_prefix_len; ++ p->arg += strlen (reg_ind_prefix); + } + + if (disp_p && !indirect_p) +@@ -448,8 +622,8 @@ stap_parse_register_operand (struct stap + p->saved_arg); + + /* Getting rid of register prefix. */ +- if (reg_prefix && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0) +- p->arg += reg_prefix_len; ++ if (stap_is_register_prefix (gdbarch, p->arg, ®_prefix)) ++ p->arg += strlen (reg_prefix); + + /* Now we should have only the register name. Let's extract it and get + the associated number. */ +@@ -507,23 +681,21 @@ stap_parse_register_operand (struct stap + } + + /* Getting rid of the register name suffix. */ +- if (reg_suffix) +- { +- if (strncmp (p->arg, reg_suffix, reg_suffix_len) != 0) +- error (_("Missing register name suffix `%s' on expression `%s'."), +- reg_suffix, p->saved_arg); +- +- p->arg += reg_suffix_len; +- } ++ if (stap_check_register_suffix (gdbarch, p->arg, ®_suffix)) ++ p->arg += strlen (reg_suffix); ++ else ++ error (_("Missing register name suffix on expression `%s'."), ++ p->saved_arg); + + /* Getting rid of the register indirection suffix. */ +- if (indirect_p && reg_ind_suffix) ++ if (indirect_p) + { +- if (strncmp (p->arg, reg_ind_suffix, reg_ind_suffix_len) != 0) +- error (_("Missing indirection suffix `%s' on expression `%s'."), +- reg_ind_suffix, p->saved_arg); +- +- p->arg += reg_ind_suffix_len; ++ if (stap_check_register_indirection_suffix (gdbarch, p->arg, ++ ®_ind_suffix)) ++ p->arg += strlen (reg_ind_suffix); ++ else ++ error (_("Missing indirection suffix on expression `%s'."), ++ p->saved_arg); + } + } + +@@ -546,19 +718,7 @@ static void + stap_parse_single_operand (struct stap_parse_info *p) + { + struct gdbarch *gdbarch = p->gdbarch; +- +- /* Prefixes for the parser. */ +- const char *const_prefix = gdbarch_stap_integer_prefix (gdbarch); +- const char *reg_prefix = gdbarch_stap_register_prefix (gdbarch); +- const char *reg_ind_prefix +- = gdbarch_stap_register_indirection_prefix (gdbarch); +- int const_prefix_len = const_prefix ? strlen (const_prefix) : 0; +- int reg_prefix_len = reg_prefix ? strlen (reg_prefix) : 0; +- int reg_ind_prefix_len = reg_ind_prefix ? strlen (reg_ind_prefix) : 0; +- +- /* Suffixes for the parser. */ +- const char *const_suffix = gdbarch_stap_integer_suffix (gdbarch); +- int const_suffix_len = const_suffix ? strlen (const_suffix) : 0; ++ const char *int_prefix = NULL; + + /* We first try to parse this token as a "special token". */ + if (gdbarch_stap_parse_special_token_p (gdbarch)) +@@ -600,8 +760,7 @@ stap_parse_single_operand (struct stap_p + if (isdigit (*tmp)) + number = strtol (tmp, (char **) &tmp, 10); + +- if (!reg_ind_prefix +- || strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0) ++ if (!stap_is_register_indirection_prefix (gdbarch, tmp, NULL)) + { + /* This is not a displacement. We skip the operator, and deal + with it later. */ +@@ -629,15 +788,22 @@ stap_parse_single_operand (struct stap_p + const char *tmp = p->arg; + long number; + +- /* We can be dealing with a numeric constant (if `const_prefix' is +- NULL), or with a register displacement. */ ++ /* We can be dealing with a numeric constant, or with a register ++ displacement. */ + number = strtol (tmp, (char **) &tmp, 10); + + if (p->inside_paren_p) + tmp = skip_spaces_const (tmp); +- if (!const_prefix && reg_ind_prefix +- && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) != 0) ++ ++ /* If "stap_is_integer_prefix" returns true, it means we can ++ accept integers without a prefix here. But we also need to ++ check whether the next token (i.e., "tmp") is not a register ++ indirection prefix. */ ++ if (stap_is_integer_prefix (gdbarch, p->arg, NULL) ++ && !stap_is_register_indirection_prefix (gdbarch, tmp, NULL)) + { ++ const char *int_suffix; ++ + /* We are dealing with a numeric constant. */ + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type (gdbarch)->builtin_long); +@@ -646,29 +812,25 @@ stap_parse_single_operand (struct stap_p + + p->arg = tmp; + +- if (const_suffix) +- { +- if (strncmp (p->arg, const_suffix, const_suffix_len) == 0) +- p->arg += const_suffix_len; +- else +- error (_("Invalid constant suffix on expression `%s'."), +- p->saved_arg); +- } ++ if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix)) ++ p->arg += strlen (int_suffix); ++ else ++ error (_("Invalid constant suffix on expression `%s'."), ++ p->saved_arg); + } +- else if (reg_ind_prefix +- && strncmp (tmp, reg_ind_prefix, reg_ind_prefix_len) == 0) ++ else if (stap_is_register_indirection_prefix (gdbarch, tmp, NULL)) + stap_parse_register_operand (p); + else + error (_("Unknown numeric token on expression `%s'."), + p->saved_arg); + } +- else if (const_prefix +- && strncmp (p->arg, const_prefix, const_prefix_len) == 0) ++ else if (stap_is_integer_prefix (gdbarch, p->arg, &int_prefix)) + { + /* We are dealing with a numeric constant. */ + long number; ++ const char *int_suffix; + +- p->arg += const_prefix_len; ++ p->arg += strlen (int_prefix); + number = strtol (p->arg, (char **) &p->arg, 10); + + write_exp_elt_opcode (OP_LONG); +@@ -676,19 +838,14 @@ stap_parse_single_operand (struct stap_p + write_exp_elt_longcst (number); + write_exp_elt_opcode (OP_LONG); + +- if (const_suffix) +- { +- if (strncmp (p->arg, const_suffix, const_suffix_len) == 0) +- p->arg += const_suffix_len; +- else +- error (_("Invalid constant suffix on expression `%s'."), +- p->saved_arg); +- } ++ if (stap_check_integer_suffix (gdbarch, p->arg, &int_suffix)) ++ p->arg += strlen (int_suffix); ++ else ++ error (_("Invalid constant suffix on expression `%s'."), ++ p->saved_arg); + } +- else if ((reg_prefix +- && strncmp (p->arg, reg_prefix, reg_prefix_len) == 0) +- || (reg_ind_prefix +- && strncmp (p->arg, reg_ind_prefix, reg_ind_prefix_len) == 0)) ++ else if (stap_is_register_prefix (gdbarch, p->arg, NULL) ++ || stap_is_register_indirection_prefix (gdbarch, p->arg, NULL)) + stap_parse_register_operand (p); + else + error (_("Operator `%c' not recognized on expression `%s'."), diff --git a/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-2of2.patch b/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-2of2.patch new file mode 100644 index 0000000..c85895e --- /dev/null +++ b/SOURCES/gdb-rhbz1247107-backport-aarch64-stap-sdt-support-2of2.patch @@ -0,0 +1,213 @@ +commit 08248ca9fe11040e9a4126cefebc5023d1d67222 +Author: Sergio Durigan Junior +Date: Sat Dec 28 14:14:11 2013 -0200 + + Implement SystemTap SDT probe support for AArch64 + + This commit implements the needed bits for SystemTap SDT probe support + on AArch64 architectures. + + First, I started by looking at AArch64 assembly specification and + filling the necessary options on gdbarch's stap machinery in order to + make the generic asm parser (implemented in stap-probe.c) recognize + AArch64's asm. + + After my last patch for the SystemTap SDT API, which extends it in order + to accept multiple prefixes and suffixes, this patch became simpler. I + also followed Marcus suggestion and did not shared code between 32- and + 64-bit ARM. + + Tom asked me in a previous message how I did my tests. I believe I + replied that, but just in case: I ran the tests on + gdb.base/stap-probe.exp by hand. I also managed to run the tests on + real hardware, and they pass without regressions. + + 2013-12-28 Sergio Durigan Junior + + PR tdep/15653 + * NEWS: Mention SystemTap SDT probe support for AArch64 GNU/Linux. + * aarch64-linux-tdep.c: Include necessary headers for parsing of + SystemTap SDT probes. + (aarch64_stap_is_single_operand): New function. + (aarch64_stap_parse_special_token): Likewise. + (aarch64_linux_init_abi): Declare SystemTap SDT probe argument + prefixes and suffixes. Initialize gdbarch with them. + +Index: gdb-7.6.1/gdb/NEWS +=================================================================== +--- gdb-7.6.1.orig/gdb/NEWS ++++ gdb-7.6.1/gdb/NEWS +@@ -30,6 +30,8 @@ qXfer:libraries-svr4:read's annex + + *** Changes in GDB 7.6 + ++* GDB now supports SystemTap SDT probes on AArch64 GNU/Linux. ++ + * Target record has been renamed to record-full. + Record/replay is now enabled with the "record full" command. + This also affects settings that are associated with full record/replay +Index: gdb-7.6.1/gdb/aarch64-linux-tdep.c +=================================================================== +--- gdb-7.6.1.orig/gdb/aarch64-linux-tdep.c ++++ gdb-7.6.1/gdb/aarch64-linux-tdep.c +@@ -35,6 +35,12 @@ + #include "regcache.h" + #include "regset.h" + ++#include "cli/cli-utils.h" ++#include "stap-probe.h" ++#include "parser-defs.h" ++#include "user-regs.h" ++#include ++ + /* The general-purpose regset consists of 31 X registers, plus SP, PC, + and PSTATE registers, as defined in the AArch64 port of the Linux + kernel. */ +@@ -268,9 +274,129 @@ aarch64_linux_regset_from_core_section ( + return NULL; + } + ++/* Implementation of `gdbarch_stap_is_single_operand', as defined in ++ gdbarch.h. */ ++ ++static int ++aarch64_stap_is_single_operand (struct gdbarch *gdbarch, const char *s) ++{ ++ return (*s == '#' || isdigit (*s) /* Literal number. */ ++ || *s == '[' /* Register indirection. */ ++ || isalpha (*s)); /* Register value. */ ++} ++ ++/* This routine is used to parse a special token in AArch64's assembly. ++ ++ The special tokens parsed by it are: ++ ++ - Register displacement (e.g, [fp, #-8]) ++ ++ It returns one if the special token has been parsed successfully, ++ or zero if the current token is not considered special. */ ++ ++static int ++aarch64_stap_parse_special_token (struct gdbarch *gdbarch, ++ struct stap_parse_info *p) ++{ ++ if (*p->arg == '[') ++ { ++ /* Temporary holder for lookahead. */ ++ const char *tmp = p->arg; ++ char *endp; ++ /* Used to save the register name. */ ++ const char *start; ++ char *regname; ++ int len; ++ int got_minus = 0; ++ long displacement; ++ struct stoken str; ++ ++ ++tmp; ++ start = tmp; ++ ++ /* Register name. */ ++ while (isalnum (*tmp)) ++ ++tmp; ++ ++ if (*tmp != ',') ++ return 0; ++ ++ len = tmp - start; ++ regname = alloca (len + 2); ++ ++ strncpy (regname, start, len); ++ regname[len] = '\0'; ++ ++ if (user_reg_map_name_to_regnum (gdbarch, regname, len) == -1) ++ error (_("Invalid register name `%s' on expression `%s'."), ++ regname, p->saved_arg); ++ ++ ++tmp; ++ tmp = skip_spaces_const (tmp); ++ /* Now we expect a number. It can begin with '#' or simply ++ a digit. */ ++ if (*tmp == '#') ++ ++tmp; ++ ++ if (*tmp == '-') ++ { ++ ++tmp; ++ got_minus = 1; ++ } ++ else if (*tmp == '+') ++ ++tmp; ++ ++ if (!isdigit (*tmp)) ++ return 0; ++ ++ displacement = strtol (tmp, &endp, 10); ++ tmp = endp; ++ ++ /* Skipping last `]'. */ ++ if (*tmp++ != ']') ++ return 0; ++ ++ /* The displacement. */ ++ write_exp_elt_opcode (OP_LONG); ++ write_exp_elt_type (builtin_type (gdbarch)->builtin_long); ++ write_exp_elt_longcst (displacement); ++ write_exp_elt_opcode (OP_LONG); ++ if (got_minus) ++ write_exp_elt_opcode (UNOP_NEG); ++ ++ /* The register name. */ ++ write_exp_elt_opcode (OP_REGISTER); ++ str.ptr = regname; ++ str.length = len; ++ write_exp_string (str); ++ write_exp_elt_opcode (OP_REGISTER); ++ ++ write_exp_elt_opcode (BINOP_ADD); ++ ++ /* Casting to the expected type. */ ++ write_exp_elt_opcode (UNOP_CAST); ++ write_exp_elt_type (lookup_pointer_type (p->arg_type)); ++ write_exp_elt_opcode (UNOP_CAST); ++ ++ write_exp_elt_opcode (UNOP_IND); ++ ++ p->arg = tmp; ++ } ++ else ++ return 0; ++ ++ return 1; ++} ++ + static void + aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) + { ++ static const char *const stap_integer_prefixes[] = { "#", "", NULL }; ++ static const char *const stap_register_prefixes[] = { "", NULL }; ++ static const char *const stap_register_indirection_prefixes[] = { "[", ++ NULL }; ++ static const char *const stap_register_indirection_suffixes[] = { "]", ++ NULL }; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->lowest_pc = 0x8000; +@@ -295,6 +421,17 @@ aarch64_linux_init_abi (struct gdbarch_i + + set_gdbarch_regset_from_core_section (gdbarch, + aarch64_linux_regset_from_core_section); ++ ++ /* SystemTap related. */ ++ set_gdbarch_stap_integer_prefixes (gdbarch, stap_integer_prefixes); ++ set_gdbarch_stap_register_prefixes (gdbarch, stap_register_prefixes); ++ set_gdbarch_stap_register_indirection_prefixes (gdbarch, ++ stap_register_indirection_prefixes); ++ set_gdbarch_stap_register_indirection_suffixes (gdbarch, ++ stap_register_indirection_suffixes); ++ set_gdbarch_stap_is_single_operand (gdbarch, aarch64_stap_is_single_operand); ++ set_gdbarch_stap_parse_special_token (gdbarch, ++ aarch64_stap_parse_special_token); + } + + /* Provide a prototype to silence -Wmissing-prototypes. */ diff --git a/SOURCES/gdb-rhbz1260558-ppc64le-skip_trampoline_code.patch b/SOURCES/gdb-rhbz1260558-ppc64le-skip_trampoline_code.patch new file mode 100644 index 0000000..114cda5 --- /dev/null +++ b/SOURCES/gdb-rhbz1260558-ppc64le-skip_trampoline_code.patch @@ -0,0 +1,229 @@ +https://bugzilla.redhat.com/show_bug.cgi?id=1260558 + +[ppc64le patch v3] Use skip_entrypoint for skip_trampoline_code +https://sourceware.org/ml/gdb-patches/2015-09/msg00183.html + +diff --git a/gdb/linespec.c b/gdb/linespec.c +index 8f102fa..4c29c12 100644 +--- a/gdb/linespec.c ++++ b/gdb/linespec.c +@@ -3423,6 +3423,8 @@ minsym_found (struct linespec_state *sel + sal.pc = SYMBOL_VALUE_ADDRESS (msymbol); + sal.pc = gdbarch_convert_from_func_ptr_addr (gdbarch, sal.pc, + ¤t_target); ++ if (gdbarch_skip_entrypoint_p (gdbarch)) ++ sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc); + } + else + skip_prologue_sal (&sal); +diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c +index bb23b6a..4a0b93a 100644 +--- a/gdb/ppc64-tdep.c ++++ b/gdb/ppc64-tdep.c +@@ -454,8 +454,8 @@ ppc64_standard_linkage4_target (struct frame_info *frame, + When the execution direction is EXEC_REVERSE, scan backward to + check whether we are in the middle of a PLT stub. */ + +-CORE_ADDR +-ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) ++static CORE_ADDR ++ppc64_skip_trampoline_code_1 (struct frame_info *frame, CORE_ADDR pc) + { + #define MAX(a,b) ((a) > (b) ? (a) : (b)) + unsigned int insns[MAX (MAX (MAX (ARRAY_SIZE (ppc64_standard_linkage1), +@@ -530,6 +530,20 @@ ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) + return 0; + } + ++/* Wrapper of ppc64_skip_trampoline_code_1 checking also ++ ppc_elfv2_skip_entrypoint. */ ++ ++CORE_ADDR ++ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) ++{ ++ struct gdbarch *gdbarch = get_frame_arch (frame); ++ ++ pc = ppc64_skip_trampoline_code_1 (frame, pc); ++ if (pc != 0 && gdbarch_skip_entrypoint_p (gdbarch)) ++ pc = gdbarch_skip_entrypoint (gdbarch, pc); ++ return pc; ++} ++ + /* Support for convert_from_func_ptr_addr (ARCH, ADDR, TARG) on PPC64 + GNU/Linux. + +diff --git a/gdb/symtab.c b/gdb/symtab.c +index 1ba691e..07eb78b 100644 +--- a/gdb/symtab.c ++++ b/gdb/symtab.c +@@ -2779,7 +2779,11 @@ find_function_start_sal (struct symbol * + && (sal.symtab->locations_valid + || sal.symtab->language == language_asm)) + { ++ struct gdbarch *gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile); ++ + sal.pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym)); ++ if (gdbarch_skip_entrypoint_p (gdbarch)) ++ sal.pc = gdbarch_skip_entrypoint (gdbarch, sal.pc); + return sal; + } + +diff --git a/gdb/testsuite/gdb.opt/solib-intra-step-lib.c b/gdb/testsuite/gdb.opt/solib-intra-step-lib.c +new file mode 100644 +index 0000000..9ab1211 +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/solib-intra-step-lib.c +@@ -0,0 +1,30 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2015 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 3 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, see . */ ++ ++#include ++ ++void ++shlib_second (int dummy) ++{ /* second-retry */ ++ abort (); /* second-hit */ ++} ++ ++void ++shlib_first (void) ++{ /* first-retry */ ++ shlib_second (0); /* first-hit */ ++} +diff --git a/gdb/testsuite/gdb.opt/solib-intra-step-main.c b/gdb/testsuite/gdb.opt/solib-intra-step-main.c +new file mode 100644 +index 0000000..186bd5f +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/solib-intra-step-main.c +@@ -0,0 +1,25 @@ ++/* This testcase is part of GDB, the GNU debugger. ++ ++ Copyright 2015 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 3 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, see . */ ++ ++extern void shlib_first (void); ++ ++int ++main (void) ++{ ++ shlib_first (); ++ return 0; ++} +diff --git a/gdb/testsuite/gdb.opt/solib-intra-step.exp b/gdb/testsuite/gdb.opt/solib-intra-step.exp +new file mode 100644 +index 0000000..044c4bd +--- /dev/null ++++ b/gdb/testsuite/gdb.opt/solib-intra-step.exp +@@ -0,0 +1,86 @@ ++# Copyright 2015 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 3 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, see . ++ ++standard_testfile ++ ++if {[skip_shlib_tests]} { ++ return 0 ++} ++ ++# Library file. ++set libname "${testfile}-lib" ++set srcfile_lib ${srcdir}/${subdir}/${libname}.c ++set binfile_lib [standard_output_file ${libname}.so] ++set lib_flags [list debug optimize=-O2] ++# Binary file. ++set testfile "${testfile}-main" ++set srcfile ${srcdir}/${subdir}/${testfile}.c ++set binfile [standard_output_file ${testfile}] ++set bin_flags [list debug shlib=${binfile_lib}] ++ ++if [get_compiler_info] { ++ return -1 ++} ++ ++if { [gdb_compile_shlib ${srcfile_lib} ${binfile_lib} $lib_flags] != "" ++ || [gdb_compile ${srcfile} ${binfile} executable $bin_flags] != "" } { ++ untested "Could not compile $binfile_lib or $binfile." ++ return -1 ++} ++ ++clean_restart ${binfile} ++gdb_load_shlibs $binfile_lib ++ ++if ![runto_main] then { ++ return 0 ++} ++ ++set test "first-hit" ++gdb_test_multiple "step" $test { ++ -re " first-hit .*\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re " first-retry .*\r\n$gdb_prompt $" { ++ gdb_test "step" " first-hit .*" "first-hit (optimized)" ++ } ++} ++ ++set test "second-hit" ++gdb_test_multiple "step" $test { ++ -re " second-hit .*\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re " first-retry .*\r\n$gdb_prompt $" { ++ set test "second-hit (optimized 1)" ++ gdb_test_multiple "step" $test { ++ -re " second-hit .*\r\n$gdb_prompt $" { ++ pass $test ++ } ++ -re " first-hit .*\r\n$gdb_prompt $" { ++ gdb_test "step" " second-hit .*" "second-hit (optimized 2)" ++ } ++ } ++ } ++ -re " second-retry .*\r\n$gdb_prompt $" { ++ gdb_test "step" " second-hit .*" "second-hit (optimized 3)" ++ } ++} ++ ++if ![runto_main] then { ++ return 0 ++} ++ ++gdb_breakpoint "shlib_second" ++gdb_continue_to_breakpoint "second-hit" ".* (second-hit|second-retry) .*" diff --git a/SPECS/gdb.spec b/SPECS/gdb.spec index c918ee4..c3c42c2 100644 --- a/SPECS/gdb.spec +++ b/SPECS/gdb.spec @@ -37,7 +37,7 @@ Version: 7.6.1 # The release always contains a leading reserved number, start it at 1. # `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing. -Release: 64%{?dist} +Release: 80%{?dist} License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and BSD and Public Domain Group: Development/Debuggers @@ -666,6 +666,80 @@ Patch972: gdb-rhbz1103894-slow-gstack-performance.patch # BZ 1163339, Jan Kratochvil). Patch976: gdb-rhbz1163339-add-auto-load-scripts-directory.patch +# Fix 'gdb/linux-nat.c:1411: internal-error: +# linux_nat_post_attach_wait: Assertion `pid == new_pid' failed.' +# (Pedro Alves, RH BZ 1210135). +Patch994: gdb-rhbz1210135-internal-error-linux_nat_post_attach_wait.patch + +# Fix 'gdb internal error' [Threaded program calls clone, which +# crashes GDB] (Pedro Alves, RH BZ 1210889). +Patch995: gdb-rhbz1210889-thread-call-clone.patch + +# Fix '`catch syscall' doesn't work for parent after `fork' is called' +# (Philippe Waroquiers, RH BZ 1149207). +Patch996: gdb-rhbz1149207-catch-syscall-after-fork.patch + +# Fix 'ppc64: segv in `gdb -q +# /lib/modules/3.10.0-215.el7.ppc64/kernel/fs/nfsd/nfsd.ko`' (Jan +# Kratochvil, RH BZ 1190506). +Patch997: gdb-rhbz1190506-segv-in-ko-ppc64.patch + +# Fix 'apply_frame_filter() wrong backport' (Tom Tromey, RH BZ +# 1197665). +Patch998: gdb-rhbz1197665-fix-applyframefilter-backport.patch + +# Implement '[7.2 FEAT] Enable reverse debugging support for PowerPC +# on GDB' (Wei-cheng Wang, RH BZ 1218710, thanks to Edjunior Machado +# for backporting). +Patch999: gdb-rhbz1218710-reverse-debugging-ppc-1of7.patch +Patch1000: gdb-rhbz1218710-reverse-debugging-ppc-2of7.patch +Patch1001: gdb-rhbz1218710-reverse-debugging-ppc-3of7.patch +Patch1002: gdb-rhbz1218710-reverse-debugging-ppc-4of7.patch +Patch1003: gdb-rhbz1218710-reverse-debugging-ppc-5of7.patch +Patch1004: gdb-rhbz1218710-reverse-debugging-ppc-6of7.patch +Patch1005: gdb-rhbz1218710-reverse-debugging-ppc-7of7.patch + +# Fix 'gdb invoked oom-killer analyzing a vmcore on aarch64' (Pedro +# Alves, Tom Tromey, RH BZ 1225569). +Patch1006: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-1of8.patch +Patch1007: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-2of8.patch +Patch1008: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-3of8.patch +Patch1009: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-4of8.patch +Patch1010: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-5of8.patch +Patch1011: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-6of8.patch +Patch1012: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-7of8.patch +Patch1013: gdb-rhbz1225569-oom-killer-aarch64-frame-same-id-8of8.patch + +# Fix 'gdb output a internal-error: Assertion `num_lwps (GET_PID +# (inferior_ptid)) == 1' failed' (Pedro Alves, RH BZ 1184724). +Patch1014: gdb-rhbz1184724-gdb-internal-error-num-lwps.patch + +# Fix '[7.2 FEAT] GDB Transactional Diagnostic Block support on System +# z' (Andreas Arnez, RH BZ 1105165). +Patch1015: gdb-rhbz1105165-ibm-tdb-support-system-z-1of9.patch +Patch1016: gdb-rhbz1105165-ibm-tdb-support-system-z-2of9.patch +Patch1017: gdb-rhbz1105165-ibm-tdb-support-system-z-3of9.patch +Patch1018: gdb-rhbz1105165-ibm-tdb-support-system-z-4of9.patch +Patch1019: gdb-rhbz1105165-ibm-tdb-support-system-z-5of9.patch +Patch1020: gdb-rhbz1105165-ibm-tdb-support-system-z-6of9.patch +Patch1021: gdb-rhbz1105165-ibm-tdb-support-system-z-7of9.patch +Patch1022: gdb-rhbz1105165-ibm-tdb-support-system-z-8of9.patch +Patch1023: gdb-rhbz1105165-ibm-tdb-support-system-z-9of9.patch + +# Fix '[ppc64] and [s390x] wrong prologue skip on -O2 -g code' (Jan +# Kratochvil, RH BZ 1084404). +Patch1024: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-1of3.patch +Patch1025: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-2of3.patch +Patch1026: gdb-rhbz1084404-ppc64-s390x-wrong-prologue-skip-O2-g-3of3.patch + +# Fix 'Backport upstream GDB AArch64 SDT probe support to RHEL GDB' +# (Sergio Durigan Junior, RH BZ 1247107). +Patch1027: gdb-rhbz1247107-backport-aarch64-stap-sdt-support-1of2.patch +Patch1028: gdb-rhbz1247107-backport-aarch64-stap-sdt-support-2of2.patch + +# [ppc64le] Use skip_entrypoint for skip_trampoline_code (RH BZ 1260558). +Patch1030: gdb-rhbz1260558-ppc64le-skip_trampoline_code.patch + %if 0%{!?rhel:1} || 0%{?rhel} > 6 # RL_STATE_FEDORA_GDB would not be found for: # Patch642: gdb-readline62-ask-more-rh.patch @@ -737,8 +811,11 @@ BuildRequires: gcc gcc-c++ gcc-gfortran gcc-objc BuildRequires: gcc-java libgcj%{bits_local} libgcj%{bits_other} %endif %if 0%{!?rhel:1} || 0%{?rhel} > 6 +# These Fedoras do not yet have gcc-go built. +%ifnarch ppc64le aarch64 BuildRequires: gcc-go %endif +%endif # archer-sergiodj-stap-patch-split BuildRequires: systemtap-sdt-devel # Copied from prelink-0.4.2-3.fc13. @@ -767,8 +844,11 @@ BuildRequires: libgcc%{bits_local} libgcc%{bits_other} # libstdc++-devel of matching bits is required only for g++ -static. BuildRequires: libstdc++%{bits_local} libstdc++%{bits_other} %if 0%{!?rhel:1} || 0%{?rhel} > 6 +# These Fedoras do not yet have gcc-go built. +%ifnarch ppc64le aarch64 BuildRequires: libgo-devel%{bits_local} libgo-devel%{bits_other} %endif +%endif %if 0%{!?el5:1} BuildRequires: glibc-static%{bits_local} %endif @@ -1044,12 +1124,52 @@ find -name "*.info*"|xargs rm -f %patch968 -p1 %patch972 -p1 %patch976 -p1 +%patch994 -p1 +%patch995 -p1 +%patch996 -p1 +%patch997 -p1 %patch836 -p1 %patch837 -p1 +%patch998 -p1 + +%patch999 -p1 +%patch1000 -p1 +%patch1001 -p1 +%patch1002 -p1 +%patch1003 -p1 +%patch1004 -p1 +%patch1005 -p1 +%patch1006 -p1 +%patch1007 -p1 +%patch1008 -p1 +%patch1009 -p1 +%patch1010 -p1 +%patch1011 -p1 +%patch1012 -p1 +%patch1013 -p1 +%patch1014 -p1 + +%patch1015 -p1 +%patch1016 -p1 +%patch1017 -p1 +%patch1018 -p1 +%patch1019 -p1 +%patch1020 -p1 +%patch1021 -p1 +%patch1022 -p1 +%patch1023 -p1 +%patch1024 -p1 +%patch1025 -p1 +%patch1026 -p1 +%patch1027 -p1 +%patch1028 -p1 +%patch1030 -p1 + %if 0%{?scl:1} %patch836 -p1 -R %patch837 -p1 -R +%patch998 -p1 -R %endif %patch393 -p1 %if 0%{!?el5:1} || 0%{?scl:1} @@ -1062,14 +1182,9 @@ find -name "*.info*"|xargs rm -f %patch642 -p1 %if 0%{?rhel:1} && 0%{?rhel} <= 6 %patch642 -p1 -R -%endif %patch337 -p1 %patch331 -p1 %patch335 -p1 -%if 0%{!?rhel:1} || 0%{?rhel} > 6 -%patch335 -p1 -R -%patch331 -p1 -R -%patch337 -p1 -R %endif find -name "*.orig" | xargs rm -f @@ -1573,6 +1688,74 @@ fi %endif # 0%{!?el5:1} || "%{_target_cpu}" == "noarch" %changelog +* Fri Sep 11 2015 Jan Kratochvil - 7.6.1-80.el7 +- [testsuite] Fix gcc-go BuildRequires for --with testsuite. + +* Thu Sep 10 2015 Jan Kratochvil - 7.6.1-79.el7 +- [ppc64le] Use skip_entrypoint for skip_trampoline_code (RH BZ 1260558). + +* Wed Aug 19 2015 Sergio Durigan Junior - 7.6.1-78.el7 +- Fix 'Backport upstream GDB AArch64 SDT probe support to RHEL GDB' + (Sergio Durigan Junior, RH BZ 1247107). + +* Tue Jul 07 2015 Sergio Durigan Junior - 7.6.1-77.el7 +- Address issues from Coverity Scan related to '[7.2 FEAT] Enable + reverse debugging support for PowerPC on GDB' (RH BZ 1218710). + +* Wed Jul 01 2015 Sergio Durigan Junior - 7.6.1-76.el7 +- Fix '[ppc64] and [s390x] wrong prologue skip on -O2 -g code' (Jan + Kratochvil, RH BZ 1084404). + +* Wed Jul 01 2015 Sergio Durigan Junior - 7.6.1-75.el7 +- Fix typo/thinko on + 'gdb-rhbz1105165-ibm-tdb-support-system-z-3of9.patch', where the + type of the 'hwcap' variable in the 's390_core_read_description' + function should be 'CORE_ADDR', and not 'unsigned log'. This caused + a build breakage on s390 (31-bit) (RH BZ 1105165). + +* Tue Jun 30 2015 Sergio Durigan Junior - 7.6.1-74.el7 +- Fix '[7.2 FEAT] GDB Transactional Diagnostic Block support on System + z' (Andreas Arnez, RH BZ 1105165). + +* Mon Jun 29 2015 Sergio Durigan Junior - 7.6.1-73.el7 +- Remove wrongly backported patches (5of7, 6of7, 7of7) from RH BZ + 1225569 backport. Add new patches necessary to fix failures. + +* Fri Jun 19 2015 Sergio Durigan Junior - 7.6.1-72.el7 +- Fix 'gdb output a internal-error: Assertion `num_lwps (GET_PID + (inferior_ptid)) == 1' failed' (Pedro Alves, RH BZ 1184724). + +* Fri Jun 19 2015 Sergio Durigan Junior - 7.6.1-71.el7 +- Fix 'gdb invoked oom-killer analyzing a vmcore on aarch64' (Pedro + Alves, Tom Tromey, RH BZ 1225569). + +* Tue May 26 2015 Sergio Durigan Junior - 7.6.1-70.el7 +- Implement '[7.2 FEAT] Enable reverse debugging support for PowerPC + on GDB' (Wei-cheng Wang, RH BZ 1218710, thanks to Edjunior Machado + for backporting). + +* Mon May 25 2015 Sergio Durigan Junior - 7.6.1-69.el7 +- Fix 'apply_frame_filter() wrong backport' (Tom Tromey, RH BZ + 1197665). + +* Fri May 08 2015 Sergio Durigan Junior - 7.6.1-68.el7 +- Fix 'ppc64: segv in `gdb -q + /lib/modules/3.10.0-215.el7.ppc64/kernel/fs/nfsd/nfsd.ko`' (Jan + Kratochvil, RH BZ 1190506). + +* Thu May 07 2015 Sergio Durigan Junior - 7.6.1-67.el7 +- Fix '`catch syscall' doesn't work for parent after `fork' is called' + (Philippe Waroquiers, RH BZ 1149207). + +* Wed May 06 2015 Sergio Durigan Junior - 7.6.1-66.el7 +- Fix 'gdb internal error' [Threaded program calls clone, which + crashes GDB] (Pedro Alves, RH BZ 1210889). + +* Wed May 06 2015 Sergio Durigan Junior - 7.6.1-65.el7 +- Fix 'gdb/linux-nat.c:1411: internal-error: + linux_nat_post_attach_wait: Assertion `pid == new_pid' failed.' + (Pedro Alves, RH BZ 1210135). + * Sat Nov 22 2014 Jan Kratochvil - 7.6.1-64.el7 - Fix '[FJ7.0 Bug]: gdb: fail to refer to errno on a core dump file' (RH BZ 1166549, Jan Kratochvil).