From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id iT86A3KOfWp80CIAWB0awg (envelope-from ) for ; Thu, 13 Aug 2026 05:29:22 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=UjP/Ti3H; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 082B21E166; Thu, 13 Aug 2026 05:29:22 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-5.3 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 0F7801E033 for ; Thu, 13 Aug 2026 05:29:20 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 896B64BA799A for ; Thu, 13 Aug 2026 09:29:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 896B64BA799A Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=UjP/Ti3H Received: from mx0b-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) by sourceware.org (Postfix) with ESMTPS id 4F1774BA23C7 for ; Thu, 13 Aug 2026 09:28:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 4F1774BA23C7 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=linux.ibm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 4F1774BA23C7 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=148.163.158.5 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1786613331; cv=none; b=NljCKajRQ0WviPMX84cXgCExVTCOpBgOOcqRJdBPq6q//mB4artmNJqhZ4SswiD3w8Q8Cz3mem/gGObgArSgjTga2VfYLC24MLdW5cQo8fFCuueppRQCKSJQW2pC4HHhtx+HusgjPFTRO24rspnMaO261Aq69SaP3J2DcYh2g4g= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1786613331; c=relaxed/simple; bh=6ioFaa/1wGQZUn37G3H8XMXKTyedRBLgi3toYYKJn3M=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=dUq+s8w5KNRmlfyrBaqgtnpOKwnB58rTueJ+zZ0p8ghO/8a3Q+lYCpSBKZeOjCGWZUqFhtVG7UnIJ8WjdnSXGyQfmQHH/lMXsra7szu0CAfdJdsVK7Qmzm6kxCoj3t6w+zTCXm+1agpZ/ggF7VgxuTTpNQbtIxTkZtL+o1CS7WI= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=ibm.com header.i=@ibm.com header.a=rsa-sha256 header.s=pp1 header.b=UjP/Ti3H DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4F1774BA23C7 Received: from pps.filterd (m0353725.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 67D99HX9811684 for ; Thu, 13 Aug 2026 09:28:50 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:message-id:mime-version :subject:to; s=pp1; bh=3ng1Qo/Dy/8FoxZCvm3/JwSfFKzpG5CPegZa/zefB vI=; b=UjP/Ti3HF84VzRdiLwsDajz7PZZk34TI+S9ZmNG9rIq7Vy140wouzIIa+ ARX1ilcysuLR/Ta4LY/um9ehpQPG3Q4d1BtgFLXFQccS979vyYQ1Gx8tLSh7iwli uRjV50PVhjA0xyt8kt2tzPAPP5DdQf8ok+4E0/u2OfYbgKShBFw2uQ8Q9aOlGxMW jgaEshTkDiLaX193DALV6+HhL1OeAPfySTuGgdFMs+Xy/LGl/WIieyNx75kn1yqh ubyVeNaF7B0F9OmcKpkb41VAlpgBJA39l/P7qrgsoJT1xwJ8fFkt4xIRaCWvRcAT Si5VJyfxivXl4PY9KEJD9vGTcMMkw== Received: from ppma11.dal12v.mail.ibm.com (db.9e.1632.ip4.static.sl-reverse.com [50.22.158.219]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4fyb23yk23-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 13 Aug 2026 09:28:50 +0000 (GMT) Received: from pps.filterd (ppma11.dal12v.mail.ibm.com [127.0.0.1]) by ppma11.dal12v.mail.ibm.com (8.18.1.7/8.18.1.7) with ESMTP id 67D9QJrI030170 for ; Thu, 13 Aug 2026 09:28:49 GMT Received: from smtprelay07.fra02v.mail.ibm.com ([9.218.2.229]) by ppma11.dal12v.mail.ibm.com (PPS) with ESMTPS id 4fxhfya730-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Thu, 13 Aug 2026 09:28:49 +0000 (GMT) Received: from smtpav06.fra02v.mail.ibm.com (smtpav06.fra02v.mail.ibm.com [10.20.54.105]) by smtprelay07.fra02v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 67D9SeO248496938 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Thu, 13 Aug 2026 09:28:41 GMT Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C784220049; Thu, 13 Aug 2026 09:28:40 +0000 (GMT) Received: from smtpav06.fra02v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F042720040; Thu, 13 Aug 2026 09:28:39 +0000 (GMT) Received: from kubota.pok.stglabs.ibm.com (unknown [9.114.39.181]) by smtpav06.fra02v.mail.ibm.com (Postfix) with ESMTP; Thu, 13 Aug 2026 09:28:39 +0000 (GMT) From: Abhay Kandpal To: gdb-patches@sourceware.org Cc: Ulrich.Weigand@de.ibm.com, cel@linux.ibm.com, abhay.k@ibm.com, Abhay Kandpal Subject: [PATCHi v1] PowerPC: Create call stubs for compiled modules Date: Thu, 13 Aug 2026 04:28:29 -0500 Message-ID: <20260813092829.262470-1-abhay@linux.ibm.com> X-Mailer: git-send-email 2.52.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=XqfK/1F9 c=1 sm=1 tr=0 ts=6a7d8e52 cx=c_pps a=aDMHemPKRhS1OARIsFnwRA==:117 a=aDMHemPKRhS1OARIsFnwRA==:17 a=Sv0fKeRqtYgA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=V8glGbnc2Ofi9Qvn3v5h:22 a=zAMy_g7hTY2brhV4zAUA:9 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwODEzMDA2MiBTYWx0ZWRfXzHCwUi7bjX0w pjZsErpWUjiapd0UM0iwXmefaPGoP8TVTG8j+eA+lMnXrA/vJWeCVZwUkewByE0wSfyQAHynBdS VGvHdHU9WFNp7VF6DRzC1HZl6vPwCvddMqw4l6+DHBUviyfGcpFL3KvU9iDWwFO36MZr939CNfX konV0mCbXMjtrSac47JiRJW5tTec/f1FjP/ySf5L14Yv5czBDF4r1gv6AQVqw3RwwugxMptq7U5 EkIph+nDQldppbGDqX8Y8bkGzIi+ZqYdKBJDmiltNHx+Kw1ns9kQaKqW/ICN30NMsQmwwl8rlmQ /uHNnuw3AIPHhAso6BiX27KO2NGYZEqMpbyM7qS/on/k1CMzX54y2cE7J+aBG7JyJSrgd72qbZJ K6BkmBKuRKG1ibrIuOwmer36fHO7NGUZcSU5PtcOoleh5jDKTlntKvjbvR1r1Euh56GqrgQ4rdH 9VOCR9PzEWZOFJH0RGA== X-Proofpoint-ORIG-GUID: Tevf1gPRhRT0D_y6y-gyF-wmMDvJNaTa X-Proofpoint-GUID: Tevf1gPRhRT0D_y6y-gyF-wmMDvJNaTa X-Proofpoint-Spam-Info: AW1haW4tMjYwODEzMDA2MiBTYWx0ZWRfX8oqHYWcrGFA3 +S9fSGGwXypgbxc6+17iCO+6Q1M7NK9ARM2xXBzdqv1rAFUcEUEpfeNbs1PHnyZF64cipt2CYkh MLHQ+VQjEWg8a2Pcyq1kkHHxRBIk1cA= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-08-13_03,2026-08-12_01,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 spamscore=0 adultscore=0 malwarescore=0 clxscore=1015 suspectscore=0 priorityscore=1501 impostorscore=0 phishscore=0 bulkscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2606150000 definitions=main-2608130062 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org The compile command loads a module into inferior memory and relocates it itself, without a linker. For R_PPC64_REL24 it patches the branch to point directly at the target. On ELFv2 that is not a valid call to another module: the callee derives its TOC pointer from r12, which only a PLT-style call stub sets up, and the caller's TOC pointer is never restored because the nop following the bl is left alone. Any call leaving a compiled module therefore runs with a wrong TOC pointer. gdb.compile/compile-setjmp.exp is where this shows up: the injected code calls setjmp, whose global entry point computes r2 from a stale r12, and the first TOC-relative load segfaults. Add two gdbarch hooks. compile_stub_area_size tells the loader how much executable inferior memory to reserve for stubs; compile_fixup_section lets the architecture rewrite the relocated section contents before they are written to the inferior. Both are installed only for ELFv2. ppc64_compile_fixup_section redirects each call to an external symbol through a stub which saves r2, loads the target into r12 and branches to it, and rewrites the following nop to ld r2,24(r1). Symbol values are left untouched, so a function address used as data stays correct. The symbol table is passed through the hook rather than re-read by the architecture code, so the arch sees the same symbols compile_object_load resolved. Tested on powerpc64le-linux; the two compile-setjmp.exp failures now pass with no regressions in gdb.compile. --- This patch is reg tested. gdb/compile/compile-object-load.c | 40 +++++++++- gdb/gdbarch-gen.c | 54 +++++++++++++ gdb/gdbarch-gen.h | 18 +++++ gdb/gdbarch_components.py | 33 ++++++++ gdb/ppc-linux-tdep.c | 3 + gdb/ppc64-tdep.c | 123 ++++++++++++++++++++++++++++++ gdb/ppc64-tdep.h | 13 ++++ 7 files changed, 282 insertions(+), 2 deletions(-) diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c index a70282c4e0c..4ed9ebdf25f 100644 --- a/gdb/compile/compile-object-load.c +++ b/gdb/compile/compile-object-load.c @@ -333,7 +333,9 @@ struct link_hash_table_cleanup_data static void copy_section (bfd *abfd, asection *sect, - gdb::array_view symbol_table) + gdb::array_view symbol_table, + CORE_ADDR stub_area, CORE_ADDR stub_area_size, + CORE_ADDR *stub_next) { bfd_byte *sect_data_got; struct bfd_link_info link_info; @@ -382,6 +384,15 @@ copy_section (bfd *abfd, asection *sect, bfd_errmsg (bfd_get_error ())); gdb_assert (sect_data_got == sect_data.get ()); + /* Some architectures cannot express a call to another module in the + relocated contents alone; give the architecture a chance to rewrite + the calls before the section reaches inferior memory. */ + gdbarch *gdbarch = current_inferior ()->arch (); + if (gdbarch_compile_fixup_section_p (gdbarch)) + gdbarch_compile_fixup_section (gdbarch, abfd, sect, sect_data.get (), + symbol_table.data (), stub_area, + stub_area_size, stub_next); + inferior_addr = bfd_section_vma (sect); if (0 != target_write_memory (inferior_addr, sect_data.get (), bfd_section_size (sect))) @@ -635,6 +646,30 @@ compile_object_load (const compile_file_names &file_names, setup_sections_data.setup_one_section (sect); setup_sections_data.setup_one_section (nullptr); + /* Executable inferior memory the architecture may need for call stubs, + and the next unused address within it. */ + CORE_ADDR stub_area = 0, stub_next = 0; + CORE_ADDR stub_area_size = 0; + + if (gdbarch_compile_fixup_section_p (current_inferior ()->arch ())) + stub_area_size + = gdbarch_compile_stub_area_size (current_inferior ()->arch ()); + + if (stub_area_size != 0) + { + stub_area = gdbarch_infcall_mmap (current_inferior ()->arch (), + stub_area_size, + GDB_MMAP_PROT_READ | GDB_MMAP_PROT_EXEC); + setup_sections_data.munmap_list.add (stub_area, stub_area_size); + stub_next = stub_area; + + if (compile_debug) + gdb_printf (gdb_stdlog, + "allocated %s bytes at %s for call stubs\n", + paddress (current_inferior ()->arch (), stub_area_size), + paddress (current_inferior ()->arch (), stub_area)); + } + /* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in "Reading symbols from ..." message for automatically generated file. */ scoped_objfile_unlinker objfile_holder (symbol_file_add_from_bfd @@ -789,7 +824,8 @@ compile_object_load (const compile_file_names &file_names, error (_("%ld symbols were missing, cannot continue."), missing_symbols); for (asection *sect : gdb_bfd_sections (abfd.get ())) - copy_section (abfd.get (), sect, symbol_table); + copy_section (abfd.get (), sect, symbol_table, stub_area, + stub_area_size, &stub_next); regs_type = get_regs_type (func_sym, objfile); if (regs_type == NULL) diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index 6008003466c..042c4f308c6 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -241,6 +241,8 @@ struct gdbarch gdbarch_infcall_mmap_ftype *infcall_mmap = default_infcall_mmap; gdbarch_infcall_munmap_ftype *infcall_munmap = default_infcall_munmap; gdbarch_gcc_target_options_ftype *gcc_target_options = default_gcc_target_options; + ULONGEST compile_stub_area_size = 0; + gdbarch_compile_fixup_section_ftype *compile_fixup_section = nullptr; gdbarch_gnu_triplet_regexp_ftype *gnu_triplet_regexp = default_gnu_triplet_regexp; gdbarch_addressable_memory_unit_size_ftype *addressable_memory_unit_size = default_addressable_memory_unit_size; const char *disassembler_options_implicit = nullptr; @@ -501,6 +503,8 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of infcall_mmap, invalid_p == 0. */ /* Skip verify of infcall_munmap, invalid_p == 0. */ /* Skip verify of gcc_target_options, invalid_p == 0. */ + /* Skip verify of compile_stub_area_size, invalid_p == 0. */ + /* Skip verify of compile_fixup_section, has predicate. */ /* Skip verify of gnu_triplet_regexp, invalid_p == 0. */ /* Skip verify of addressable_memory_unit_size, invalid_p == 0. */ /* Skip verify of disassembler_options_implicit, invalid_p == 0. */ @@ -1300,6 +1304,15 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: gcc_target_options = <%s>\n", host_address_to_string (gdbarch->gcc_target_options)); + gdb_printf (file, + "gdbarch_dump: compile_stub_area_size = %s\n", + plongest (gdbarch->compile_stub_area_size)); + gdb_printf (file, + "gdbarch_dump: gdbarch_compile_fixup_section_p() = %d\n", + gdbarch_compile_fixup_section_p (gdbarch)); + gdb_printf (file, + "gdbarch_dump: compile_fixup_section = <%s>\n", + host_address_to_string (gdbarch->compile_fixup_section)); gdb_printf (file, "gdbarch_dump: gnu_triplet_regexp = <%s>\n", host_address_to_string (gdbarch->gnu_triplet_regexp)); @@ -5076,6 +5089,47 @@ set_gdbarch_gcc_target_options (struct gdbarch *gdbarch, gdbarch->gcc_target_options = gcc_target_options; } +ULONGEST +gdbarch_compile_stub_area_size (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != nullptr); + /* Skip verify of compile_stub_area_size, invalid_p == 0. */ + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_compile_stub_area_size called\n"); + return gdbarch->compile_stub_area_size; +} + +void +set_gdbarch_compile_stub_area_size (struct gdbarch *gdbarch, + ULONGEST compile_stub_area_size) +{ + gdbarch->compile_stub_area_size = compile_stub_area_size; +} + +bool +gdbarch_compile_fixup_section_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != nullptr); + return gdbarch->compile_fixup_section != nullptr; +} + +void +gdbarch_compile_fixup_section (struct gdbarch *gdbarch, bfd *abfd, asection *sect, gdb_byte *sect_data, asymbol **symbol_table, CORE_ADDR stub_area, CORE_ADDR stub_area_size, CORE_ADDR *stub_next) +{ + gdb_assert (gdbarch != nullptr); + gdb_assert (gdbarch->compile_fixup_section != nullptr); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_compile_fixup_section called\n"); + gdbarch->compile_fixup_section (gdbarch, abfd, sect, sect_data, symbol_table, stub_area, stub_area_size, stub_next); +} + +void +set_gdbarch_compile_fixup_section (struct gdbarch *gdbarch, + gdbarch_compile_fixup_section_ftype compile_fixup_section) +{ + gdbarch->compile_fixup_section = compile_fixup_section; +} + const char * gdbarch_gnu_triplet_regexp (struct gdbarch *gdbarch) { diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index 6eda8693d58..d88b167a489 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1656,6 +1656,24 @@ using gdbarch_gcc_target_options_ftype = std::string (struct gdbarch *gdbarch); std::string gdbarch_gcc_target_options (struct gdbarch *gdbarch); void set_gdbarch_gcc_target_options (struct gdbarch *gdbarch, gdbarch_gcc_target_options_ftype *gcc_target_options); +/* Size in bytes of executable inferior memory to reserve for call stubs + when loading a module for the 'compile' command, or 0 if none is needed. */ + +ULONGEST gdbarch_compile_stub_area_size (struct gdbarch *gdbarch); +void set_gdbarch_compile_stub_area_size (struct gdbarch *gdbarch, ULONGEST compile_stub_area_size); + +/* Rewrite the relocated contents SECT_DATA of section SECT of the compiled + module ABFD before it is written to inferior memory. Used on targets + where a call to another module needs a linkage stub. STUB_AREA and + STUB_AREA_SIZE describe the reserved stub memory; *STUB_NEXT is the next + free address within it and is updated as stubs are written. */ + +bool gdbarch_compile_fixup_section_p (struct gdbarch *gdbarch); + +using gdbarch_compile_fixup_section_ftype = void (struct gdbarch *gdbarch, bfd *abfd, asection *sect, gdb_byte *sect_data, asymbol **symbol_table, CORE_ADDR stub_area, CORE_ADDR stub_area_size, CORE_ADDR *stub_next); +void gdbarch_compile_fixup_section (struct gdbarch *gdbarch, bfd *abfd, asection *sect, gdb_byte *sect_data, asymbol **symbol_table, CORE_ADDR stub_area, CORE_ADDR stub_area_size, CORE_ADDR *stub_next); +void set_gdbarch_compile_fixup_section (struct gdbarch *gdbarch, gdbarch_compile_fixup_section_ftype *compile_fixup_section); + /* Return a regular expression that matches names used by this architecture in GNU configury triplets. The result is statically allocated and must not be freed. The default implementation simply diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index d8b2d114909..b2a717aef0d 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2627,6 +2627,39 @@ they can override it. invalid=False, ) +Value( + comment=""" +Size in bytes of executable inferior memory to reserve for call stubs +when loading a module for the 'compile' command, or 0 if none is needed. +""", + type="ULONGEST", + name="compile_stub_area_size", + predefault="0", + invalid=False, +) + +Method( + comment=""" +Rewrite the relocated contents SECT_DATA of section SECT of the compiled +module ABFD before it is written to inferior memory. Used on targets +where a call to another module needs a linkage stub. STUB_AREA and +STUB_AREA_SIZE describe the reserved stub memory; *STUB_NEXT is the next +free address within it and is updated as stubs are written. +""", + type="void", + name="compile_fixup_section", + params=[ + ("bfd *", "abfd"), + ("asection *", "sect"), + ("gdb_byte *", "sect_data"), + ("asymbol **", "symbol_table"), + ("CORE_ADDR", "stub_area"), + ("CORE_ADDR", "stub_area_size"), + ("CORE_ADDR *", "stub_next"), + ], + predicate=True, +) + Method( comment=""" Return a regular expression that matches names used by this diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c index 8a55ff5d4af..de0e1d79b2b 100644 --- a/gdb/ppc-linux-tdep.c +++ b/gdb/ppc-linux-tdep.c @@ -2304,6 +2304,9 @@ ppc_linux_init_abi (struct gdbarch_info info, (gdbarch, ppc_elfv2_elf_make_msymbol_special); set_gdbarch_skip_entrypoint (gdbarch, ppc_elfv2_skip_entrypoint); + set_gdbarch_compile_stub_area_size (gdbarch, PPC64_STUB_AREA_SIZE); + set_gdbarch_compile_fixup_section (gdbarch, + ppc64_compile_fixup_section); } /* Shared library handling. */ diff --git a/gdb/ppc64-tdep.c b/gdb/ppc64-tdep.c index 9011a354612..5f5e48db641 100644 --- a/gdb/ppc64-tdep.c +++ b/gdb/ppc64-tdep.c @@ -24,6 +24,8 @@ #include "ppc-tdep.h" #include "ppc64-tdep.h" #include "elf-bfd.h" +#include "elf/ppc64.h" +#include /* Macros for matching instructions. Note that, since all the operands are masked off before they're or-ed into the instruction, @@ -788,6 +790,127 @@ ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, return addr; } +/* Size of one call stub written by ppc64_write_call_stub. */ + +#define PPC64_STUB_SIZE (8 * 4) + +/* Write a PLT-style call stub at STUB_ADDR in inferior memory which + transfers control to TARGET. ELFv2 requires the caller to save its + own TOC pointer in the ABI-reserved stack slot, and to pass TARGET in + r12 so that TARGET's global entry point sequence can derive its own + TOC pointer from it. A direct branch can do neither, hence this stub. + Returns STUB_ADDR. */ + +static CORE_ADDR +ppc64_write_call_stub (struct gdbarch *gdbarch, CORE_ADDR stub_addr, + CORE_ADDR target) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[PPC64_STUB_SIZE]; + uint32_t insns[8] = { + /* std r2,24(r1) */ + 0xf8410018, + /* lis r12,target@highest */ + (uint32_t) (0x3d800000 | ((target >> 48) & 0xffff)), + /* ori r12,r12,target@higher */ + (uint32_t) (0x618c0000 | ((target >> 32) & 0xffff)), + /* rldicr r12,r12,32,31 */ + 0x798c07c6, + /* oris r12,r12,target@h */ + (uint32_t) (0x658c0000 | ((target >> 16) & 0xffff)), + /* ori r12,r12,target@l */ + (uint32_t) (0x618c0000 | (target & 0xffff)), + /* mtctr r12 */ + 0x7d8903a6, + /* bctr */ + 0x4e800420 + }; + + for (int i = 0; i < 8; i++) + store_unsigned_integer (buf + i * 4, 4, byte_order, insns[i]); + + write_memory (stub_addr, buf, sizeof (buf)); + return stub_addr; +} + +/* See ppc64-tdep.h. */ + +void +ppc64_compile_fixup_section (struct gdbarch *gdbarch, bfd *abfd, + asection *sect, gdb_byte *sect_data, + asymbol **symbol_table, CORE_ADDR stub_area, + CORE_ADDR stub_area_size, CORE_ADDR *stub_next) +{ + long relsize = bfd_get_reloc_upper_bound (abfd, sect); + + if (relsize <= 0) + return; + + gdb::unique_xmalloc_ptr relocs ((arelent **) xmalloc (relsize)); + long relcount = bfd_canonicalize_reloc (abfd, sect, relocs.get (), + symbol_table); + + /* Stubs already written for this section, keyed by target address, so + that repeated calls to one function share a single stub. */ + std::unordered_map stubs; + + for (long i = 0; i < relcount; i++) + { + arelent *rel = relocs.get ()[i]; + + if (rel->howto == NULL || rel->howto->type != R_PPC64_REL24) + continue; + + /* Symbols resolved outside this module were parked in the absolute + section by compile_object_load; those are the calls needing a + stub. Calls staying within the module are left alone. They are + relocated to the global entry point, so the callee recomputes r2 + from r12, which still holds the address of the function GDB + called; resolving them to the local entry point instead would be + more correct. A compiled module reaches its data through + absolute addresses rather than its TOC, so this has no effect in + practice. */ + asymbol *sym = *rel->sym_ptr_ptr; + if (!bfd_is_abs_section (sym->section)) + continue; + + CORE_ADDR target = sym->value + rel->addend; + CORE_ADDR stub; + + auto iter = stubs.find (target); + if (iter != stubs.end ()) + stub = iter->second; + else + { + if (*stub_next + PPC64_STUB_SIZE > stub_area + stub_area_size) + error (_("No room left for compiled module call stubs.")); + + stub = ppc64_write_call_stub (gdbarch, *stub_next, target); + *stub_next += PPC64_STUB_SIZE; + stubs[target] = stub; + } + + CORE_ADDR at = bfd_section_vma (sect) + rel->address; + LONGEST disp = (LONGEST) stub - (LONGEST) at; + + if (disp < -(1 << 25) || disp >= (1 << 25) || (disp & 3) != 0) + error (_("Compiled module call stub at %s is out of reach of the " + "call at %s."), + paddress (gdbarch, stub), paddress (gdbarch, at)); + + /* Branch to the stub rather than to the target. */ + uint32_t insn = bfd_get_32 (abfd, sect_data + rel->address); + insn = (insn & ~0x03fffffc) | (((uint32_t) disp) & 0x03fffffc); + bfd_put_32 (abfd, insn, sect_data + rel->address); + + /* The compiler left a nop after the call for the TOC pointer + reload; fill it in, as a linker would. */ + if (rel->address + 8 <= bfd_section_size (sect) + && bfd_get_32 (abfd, sect_data + rel->address + 4) == 0x60000000) + bfd_put_32 (abfd, 0xe8410018, sect_data + rel->address + 4); + } +} + /* A synthetic 'dot' symbols on ppc64 has the udata.p entry pointing back to the original ELF symbol it was derived from. Get the size from that symbol. */ diff --git a/gdb/ppc64-tdep.h b/gdb/ppc64-tdep.h index ae12a70d053..2b8498a4989 100644 --- a/gdb/ppc64-tdep.h +++ b/gdb/ppc64-tdep.h @@ -24,6 +24,11 @@ struct gdbarch; class frame_info_ptr; struct target_ops; +/* Inferior memory reserved for the call stubs of one module loaded by + the "compile" command; enough for 128 stubs. */ + +#define PPC64_STUB_AREA_SIZE 4096 + extern CORE_ADDR ppc64_skip_trampoline_code (const frame_info_ptr &frame, CORE_ADDR pc); @@ -33,4 +38,12 @@ extern CORE_ADDR ppc64_convert_from_func_ptr_addr (struct gdbarch *gdbarch, extern void ppc64_elf_make_msymbol_special (const asymbol *, struct minimal_symbol *); + +extern void ppc64_compile_fixup_section (struct gdbarch *gdbarch, bfd *abfd, + asection *sect, gdb_byte *sect_data, + asymbol **symbol_table, + CORE_ADDR stub_area, + CORE_ADDR stub_area_size, + CORE_ADDR *stub_next); + #endif /* GDB_PPC64_TDEP_H */ -- 2.52.0