From patchwork Fri Feb 2 22:12:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: ia64: fix ptrace(PTRACE_GETREGS) (unbreaks strace, gdb) From: Sergei Trofimovich X-Patchwork-Id: 10198159 Message-Id: <20180202221224.16597-1-slyfox@gentoo.org> To: Tony Luck , Fenghua Yu , linux-ia64@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Sergei Trofimovich Date: Fri, 2 Feb 2018 22:12:24 +0000 The strace breakage looks like that: ./strace: get_regs: get_regs_error: Input/output error It happens because ia64 needs to load unwind tables to read certain registers. Unwind tables fail to load due to GCC quirk on the following code: extern char __end_unwind[]; const struct unw_table_entry *end = (struct unw_table_entry *)table_end; table->end = segment_base + end[-1].end_offset; GCC does not generate correct code for this single memory reference after constant propagation (see https://gcc.gnu.org/PR84184). Two triggers are required for bad code generation: - '__end_unwind' has alignment lower (char), than 'struct unw_table_entry' (8). - symbol offset is negative. This commit workarounds it by fixing alignment of '__end_unwind'. While at it use hidden symbols to generate shorter gp-relative relocations. CC: Tony Luck CC: Fenghua Yu CC: linux-ia64@vger.kernel.org CC: linux-kernel@vger.kernel.org Bug: https://github.com/strace/strace/issues/33 Bug: https://gcc.gnu.org/PR84184 Reported-by: Émeric Maschino Signed-off-by: Sergei Trofimovich Tested-by: stanton_arch@mail.com --- arch/ia64/include/asm/sections.h | 1 - arch/ia64/kernel/unwind.c | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/ia64/include/asm/sections.h b/arch/ia64/include/asm/sections.h index f3481408594e..0fc4f1757a44 100644 --- a/arch/ia64/include/asm/sections.h +++ b/arch/ia64/include/asm/sections.h @@ -24,7 +24,6 @@ extern char __start_gate_mckinley_e9_patchlist[], __end_gate_mckinley_e9_patchli extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[]; extern char __start_gate_fsyscall_patchlist[], __end_gate_fsyscall_patchlist[]; extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_bubble_down_patchlist[]; -extern char __start_unwind[], __end_unwind[]; extern char __start_ivt_text[], __end_ivt_text[]; #undef dereference_function_descriptor diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index e04efa088902..025ba6700790 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -2243,7 +2243,20 @@ __initcall(create_gate_table); void __init unw_init (void) { - extern char __gp[]; + #define __ia64_hidden __attribute__((visibility("hidden"))) + /* + * We use hidden symbols to generate more efficient code using + * gp-relative addressing. + */ + extern char __gp[] __ia64_hidden; + /* + * Unwind tables need to have proper alignment as init_unwind_table() + * uses negative offsets against '__end_unwind'. + * See https://gcc.gnu.org/PR84184 + */ + extern const struct unw_table_entry __start_unwind[] __ia64_hidden; + extern const struct unw_table_entry __end_unwind[] __ia64_hidden; + #undef __ia64_hidden extern void unw_hash_index_t_is_too_narrow (void); long i, off;