From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id +E2MAAN+WWgt1hoAWB0awg (envelope-from ) for ; Mon, 23 Jun 2025 12:17:07 -0400 Received: by simark.ca (Postfix, from userid 112) id F1E611E11C; Mon, 23 Jun 2025 12:17:06 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-9.0 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED, RCVD_IN_VALIDITY_RPBL,RCVD_IN_VALIDITY_SAFE autolearn=ham autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (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 9ACA81E0C2 for ; Mon, 23 Jun 2025 12:17:05 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4BCE03846703 for ; Mon, 23 Jun 2025 16:17:05 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4BCE03846703 Received: from us-smtp-delivery-114.mimecast.com (us-smtp-delivery-114.mimecast.com [170.10.133.114]) by sourceware.org (Postfix) with ESMTP id F33D4384670B for ; Mon, 23 Jun 2025 16:11:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org F33D4384670B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=labware.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=labware.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org F33D4384670B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.114 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750695106; cv=none; b=fk7/53Asljd42DS9wTNMKTMrepLg5ovxE+Oixco1QHYqhO2aeccrwymkc4Jkb3PJJgx9LFcipNTxSTj4BX+ipFqOeNm8pqq1AN119bKrWE1kxAOxLDuFV92NFs+wXVmAJcOVuF1XMhr8/ulpXeMGS4pZoIFArghISbRvWVZkqoA= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1750695106; c=relaxed/simple; bh=vPTvscnkqGiLWMjJoi+naBZGAm9xV6VZJZWr3XcbJy4=; h=From:To:Subject:Date:Message-ID:MIME-Version; b=WpFkzsZLBZF7yhIB5Eu76sbP1z58oJF0yYnMTpb5jIkzoW5220PAQcHRFgL3JoEMI14aBkTjSC2fsSpuhJR7tDyeRfgqdwCYpme7qaSZoeX7QJi4jVXnSuxxHS7yg01agqvI4d8bpPm7ZU12jvPT9rrxmLEry3LaiV+0lzNWi3o= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F33D4384670B Received: from NAM12-DM6-obe.outbound.protection.outlook.com (mail-dm6nam12on2114.outbound.protection.outlook.com [40.107.243.114]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-186-4sCMLYaeM2a14XGmr5nXww-1; Mon, 23 Jun 2025 12:11:44 -0400 X-MC-Unique: 4sCMLYaeM2a14XGmr5nXww-1 X-Mimecast-MFC-AGG-ID: 4sCMLYaeM2a14XGmr5nXww_1750695103 Received: from SA1PR17MB5365.namprd17.prod.outlook.com (2603:10b6:806:1d8::11) by CH3PR17MB6292.namprd17.prod.outlook.com (2603:10b6:610:14b::12) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.8857.27; Mon, 23 Jun 2025 16:11:41 +0000 Received: from SA1PR17MB5365.namprd17.prod.outlook.com ([fe80::6398:7dc0:7d88:5a4d]) by SA1PR17MB5365.namprd17.prod.outlook.com ([fe80::6398:7dc0:7d88:5a4d%5]) with mapi id 15.20.8857.026; Mon, 23 Jun 2025 16:11:41 +0000 From: Jan Vrany To: gdb-patches@sourceware.org CC: Jan Vrany , Eli Zaretskii Subject: [RFC v5 18/18] gdb/python: add section in documentation on implementing JIT interface Date: Mon, 23 Jun 2025 17:10:13 +0100 Message-ID: <20250623161013.650814-19-jan.vrany@labware.com> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250623161013.650814-1-jan.vrany@labware.com> References: <20250623161013.650814-1-jan.vrany@labware.com> X-ClientProxiedBy: LO4P265CA0220.GBRP265.PROD.OUTLOOK.COM (2603:10a6:600:33a::18) To SA1PR17MB5365.namprd17.prod.outlook.com (2603:10b6:806:1d8::11) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SA1PR17MB5365:EE_|CH3PR17MB6292:EE_ X-MS-Office365-Filtering-Correlation-Id: d65f742f-fc2d-4d35-8faa-08ddb270a436 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|376014|366016|1800799024|13003099007 X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?Waz4RiWNyv7WhA6lDDq/oZuT/JiU/gl2j2qD7bbvlzuEnhowXCf6UneISIHG?= =?us-ascii?Q?3YCAPOzX9FMGHDwA8l/w/3Ym4CbRnGyXPEDONrDxzmMGJ6EnNsDyuMgYRBFW?= =?us-ascii?Q?SK/cw4D1sQPYLewstTvzNY3QzjagXsG249xkhGntMkAM3IwLpOpEUWnclBak?= =?us-ascii?Q?fi5hWdp8QHo7tlLfoc/dNHQwO46hON2z1cAfzdsz6oOHb35B6XWSncnZQTxi?= =?us-ascii?Q?sMwv43Ezn2cIasRIpmmRFgl0wZGcGxicbDUQPEnlH6N8FeB1KOrc+Gh9LLFx?= =?us-ascii?Q?8DCCcup3MlgDRiohIp9/EfQvZNHf3ishBxKsP3cgUseyNVT/hKah81pXLHgK?= =?us-ascii?Q?/9Shrb1w/6gqXrjtHOydUWzz1h+8EHxPTf/iFjBU8tC/4UV0OqkFmtVvWvYV?= =?us-ascii?Q?l1ZxhkAt2Qt6D6XchsNvYXCueTCBG2TRw7TBe9nAq8sQyomeRHDnkbB01nb2?= =?us-ascii?Q?nZzAOMySX2FkIc56WbPPJKyCs7hceJ5SJD3K+3HFiG4WdQsShuvXY4Bmt+23?= =?us-ascii?Q?Ms3/tFhHmPdS3IQGdsz1fskzuYYOY1988L49/GoUSo1E6WKG3/tr8BPzFRJb?= =?us-ascii?Q?mqS2uDmDHchgXlbvrcn6/GHXZqdLmzWKsDEW9276u4FDf9CCpptyQyqjBacO?= =?us-ascii?Q?kjFPji5RafT4n6ZIo+wwU7vOgzmaqWO8kTs79DIaVCd0LKB69TXBQDzYPOZh?= =?us-ascii?Q?aIl1KGbxejMTxN3Ecwhkizk79g+y6TMsATjh29NW4E9dWcnwbekpoaz3Bm1S?= =?us-ascii?Q?D2RPJlWYr9rAxUCQ34rJkJUuK/arspsLhTuhnvWp3sVM5k6MexpvIgPAsOKm?= =?us-ascii?Q?DQcuv3nSaGvtOGN+R6Wnxw5lWH+Eib7J0zPTOqLS/BRz5tsve4EJz4y8AG2m?= =?us-ascii?Q?i3NpMqUwZXjFe1VHSsQnJS05QdFlKMhd7vmcy68C4ZVM62Nd4SRtTozPpiKT?= =?us-ascii?Q?rdfrkw6+U26AHZClNzspF4/fNB9P3lTM5fkAf3DTflmuyTNVhwpAB5zF0Wdg?= =?us-ascii?Q?ZgwF1ZTmab4rJlQ0sNlXV+NdbYEOCdQelVoOUF3Blc9HmcopVcKpEjjpGSVV?= =?us-ascii?Q?FA+syLPb6nyMnJGg8Kns8ovPMjb67FIOvYLb67OI7CGpyFXM/DDUW810DT3R?= =?us-ascii?Q?jtRLwDpzcUtt9gnFlt9i7Nmwn7jN5bX/pWnWmiG7/sSBVP8Vp9nAX6ioTR50?= =?us-ascii?Q?/+jPmiS0IXHfO5Lym+ZjEsuqkzEOsTm1ECP1nlbr4iTrSKPjq9n2185SJ542?= =?us-ascii?Q?M61Mwk6k5qOmnF229l7+BQGEAhJp3PI4+ogAV7H8g37YTkQBQ5IjFNT++fF2?= =?us-ascii?Q?2npHJKklLgAPN8aYzqt78d/0vQgsc62fWyPDnrADiCczHc4aKtlr9egbD92y?= =?us-ascii?Q?7kT20G6ymmbyGG/XD/UeyK6NLudsXDlsVS4EIhyY192oPSiBzHTupvf1+RO8?= =?us-ascii?Q?ZgNSrKX8Pkw=3D?= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:SA1PR17MB5365.namprd17.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(376014)(366016)(1800799024)(13003099007); DIR:OUT; SFP:1102 X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?Kojwrb4HbVc6ikiuszE5a9JL/salDpbinTKwLFUVhlVHHB0tHw7xpUZLUKW+?= =?us-ascii?Q?tfSGkJrmzc459hq2F67kMz2ruU5WJiTdlaZv66RXgvwStZodnQdhefiirAJ4?= =?us-ascii?Q?TdTubxkTXp6JLQaOrgtdibc9zlrw/2eZ4IbRgHeiKkAa/aZQcTgg0AscdCH6?= =?us-ascii?Q?pg2hM4oUqy73YVheneNyRaHsasnIjdcHL0VrybnRtQr7eMUVeh40UgrSSBU/?= =?us-ascii?Q?XIn/Oprsnq1sG23fUpNiZ9FJebRZsjWqYRcOIxnF47TVtfCf1s74KgzxMz/G?= =?us-ascii?Q?A5xgHrOz3vDG9m3ottoAODkVbTC3uZmI8NMMzvGoBUZaeyohnOGxgi8ohqCZ?= =?us-ascii?Q?xnGezwfwWK4V688F+btAJkqKzzPfo5YUhreBLCQIqCEqg3VM7zKB0/vMVPyG?= =?us-ascii?Q?l3HzSv4glD4uh9MGlC41Z5ALyrlhskr4MoLa5cW3yHEpNuyowd+ksJbFMqTL?= =?us-ascii?Q?NheS6eHesTzB1FfMJPjENrD8eojGe1zRY9uz3F/cCrdyc4kooZrDc+cO2iSI?= =?us-ascii?Q?3vCpdhxNdVtlc5Xn3j6RNFxVECzbTUwLQp1kzqhFz0Rrxn6ptafqGF0imFZq?= =?us-ascii?Q?Wddr262tMulubQKlz3Bo6KocUZSMFwrbTyejPL+xK2vm8tFCADML1IkQQkBh?= =?us-ascii?Q?cuPBubQcJ51GARhCgFu3uQnjLzsxV9PR2wQcRRnQYOJmOtARwtv57vwJzuSs?= =?us-ascii?Q?UdwYG98DydwwTeqU2Xu6g7R+Ub6+HKpv8n04gLm3rhxqMbgJ4qiE0L+OX+Rh?= =?us-ascii?Q?VMtpSaX1uL4Szihc+urHTzX+x26MJHbo/WeCTdTNiOO37+YzW+osb5m5rfIJ?= =?us-ascii?Q?Zvhq4+sApM1oxStUB51W+D5L2ZFWLHd5YjdvpRaODinK8O0oCJrRu7NX84Cx?= =?us-ascii?Q?aLiM/i3SzOPEDzl1fWw0syN/ad5LWoP7HcME7WRZeAITgFXdYyAPbYhQC4oP?= =?us-ascii?Q?nRnW7w22FaN+/kvczsvImoW7uWAbex14KyP6i3sqrqpYWAb4st8cSI1jtP7g?= =?us-ascii?Q?L9TxKTuw6ysIiZ0dp6XrxlcKx4w7vs/Wg8ZuA+/mnhDWKsS0BtKea6SKzaY3?= =?us-ascii?Q?k52+yqWIpvacF2Z7+e4DtCykO46h1BmwB6IL9BaDbsCYOK6DAPCtaR402lyR?= =?us-ascii?Q?tS0f3YRQ9FK77Tv8N73lwsYEbji+sVUqDYv5jccpDCFLdPeHGRM07pgJfQdB?= =?us-ascii?Q?AdDbQfGBbeEiR4Qr+xk1PG0/xGf/LZeVqq4/DVf3YL+6aHv//iwH2bzxo0po?= =?us-ascii?Q?jHCZBQByyT47Na2YgnzXMZ7w62GXBKAfwb2T1WD9oIUaPreeGQhGByt1DDiw?= =?us-ascii?Q?1CILKzEgxobts1neMxlToSImoyJbTSbt30Ksqydh5U/JNFau9Jq//OKDbj67?= =?us-ascii?Q?KscwB+4zwQwmPpb9H66vTFrExyvjbj0V6Au+me8nY9rT6yHw7qGVkO3d5HDE?= =?us-ascii?Q?1LTx3K3qUBS08gQTNEyviSFDb6EeAzPAwM5peFYkv889+w5pvO36VGk7EQ3f?= =?us-ascii?Q?08TEzojFIIukR9v5GP7BJDUYTGNbNchkW+5WmLeE9uoVv7u8BZMbInYG7eGq?= =?us-ascii?Q?1hZH9ty93ggwd6qaKKPuXC3K9ihVrFUzZGklBMU1?= X-OriginatorOrg: labware.com X-MS-Exchange-CrossTenant-Network-Message-Id: d65f742f-fc2d-4d35-8faa-08ddb270a436 X-MS-Exchange-CrossTenant-AuthSource: SA1PR17MB5365.namprd17.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 23 Jun 2025 16:11:41.8846 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: b5db0322-1aa0-4c0a-859c-ad0f96966f4c X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: gFuof/LD6ybC7fSmac8Bf+Mm0/8SfRorX+Ki6Or7wk4hYFGmGK1FMhQIujZT2YZ644CZasUi7X8T5gRI83PTCQ== X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH3PR17MB6292 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: heCE8N9Aubh3mNMe5vPty9kI0hXXP4uYcftZJ-1c4NI_1750695103 X-Mimecast-Originator: labware.com Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=WINDOWS-1252 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 This commit adds new section - JIT Interface in Python - outlining how to use Python APIs introduced in previous commits to implement simple JIT interface. It also adds new test to make sure the example code is up-to-date. Reviewed-By: Eli Zaretskii --- gdb/NEWS | 4 + gdb/doc/gdb.texinfo | 3 +- gdb/doc/python.texi | 122 ++++++++++++++++++++++++++++ gdb/testsuite/gdb.python/py-jit.c | 61 ++++++++++++++ gdb/testsuite/gdb.python/py-jit.exp | 57 +++++++++++++ gdb/testsuite/gdb.python/py-jit.py | 118 +++++++++++++++++++++++++++ 6 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.python/py-jit.c create mode 100644 gdb/testsuite/gdb.python/py-jit.exp create mode 100644 gdb/testsuite/gdb.python/py-jit.py diff --git a/gdb/NEWS b/gdb/NEWS index 8e381329f9a..187808564ed 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -335,6 +335,10 @@ vFile:stat =20 ** Added class gdb.Compunit. =20 + ** Extended the Python API to allow interfacing with JIT compilers using + Python (as an alternative to JIT reader API). For details, see Secti= on + "JIT Interface in Python" in GDB documentation. + * Debugger Adapter Protocol changes =20 ** The "scopes" request will now return a scope holding global diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 4ef640698bd..b298494cc7c 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -40024,7 +40024,8 @@ If you are using @value{GDBN} to debug a program th= at uses this interface, then it should work transparently so long as you have not stripped the binary. = If you are developing a JIT compiler, then the interface is documented in the= rest of this chapter. At this time, the only known client of this interface is= the -LLVM JIT. +LLVM JIT. An alternative to interface descrived below is to implement JIT +interface in Python (@pxref{JIT Interface in Python}). =20 Broadly speaking, the JIT interface mirrors the dynamic loader interface. = The JIT compiler communicates with @value{GDBN} by writing data into a global diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi index 768ca8ba750..bd0099fd9fb 100644 --- a/gdb/doc/python.texi +++ b/gdb/doc/python.texi @@ -234,6 +234,7 @@ optional arguments while skipping others. Example: * Disassembly In Python:: Instruction Disassembly In Python * Missing Debug Info In Python:: Handle missing debug info from Python. * Missing Objfiles In Python:: Handle objfiles from Python. +* JIT Interface in Python:: Writing JIT compilation interface in Pytho= n @end menu =20 @node Basic Python @@ -8800,6 +8801,127 @@ handlers, all of the matching handlers are enabled.= The @code{enabled} field of each matching handler is set to @code{True}. @end table =20 +@node JIT Interface in Python +@subsubsection Writing JIT compilation interface in Python +@cindex python, just-in-time compilation, JIT compilation interface + +This section provides a high-level overview how to implement a JIT compile= r +interface entirely in Python. For alternative way of interfacing a JIT +@pxref{JIT Interface}. + +A JIT compiler interface usually needs to implement three elements: + +@enumerate +@item +A way how to get notified when the JIT compiler compiles (and installs) ne= w +code and when existing code is discarded. Typical solution is to put a Py= thon +breakpoint (@pxref{Breakpoints In Python}) on some function known to be +called by the JIT compiler once code is installed or discarded. + +@item +When a new code is installed the JIT interface needs to extract (debug) +information for newly installed code from the JIT compiler +(@pxref{Values From Inferior}) and build @value{GDBN}'s internal structure= s. +@xref{Objfiles In Python}, @ref{Compunits In Python}, + @ref{Blocks In Python}, @ref{Symbol Tables In Python}, + @ref{Symbols In Python}, @ref{Line Tables In Python}). + +@item +Finally, when (previously installed) code is discarded the JIT interface +needs to discard @value{GDBN}'s internal structures built in previous step= . +This is done by calling @code{unlink} on an objfile for that code +(which was created in previous step). +@end enumerate + +Here's an example showing how to write a simple JIT interface in Python: + +@c The copy of the code below is also in testsuite/gdb.python/py-jit.py +@c and used by py-jit.exp to make sure it is up to date. If changed the +@c test and py-jit.py should be checked and update accordingly if needed. +@smallexample +import gdb + +class JITRegisterCode(gdb.Breakpoint): + def stop(self): +=09# Extract new code's address, size, name, linetable (and possibly +=09# other useful information). How exactly to do so depends on JIT +=09# compiler in question. +=09# +=09# In this example address, size and name get passed as parameters +=09# to registration function. + +=09frame =3D gdb.newest_frame() +=09addr =3D int(frame.read_var('code')) +=09size =3D int(frame.read_var('size')) +=09name =3D frame.read_var('name').string() +=09linetable_entries =3D get_linetable_entries(addr) + +=09# Create objfile and compunit for allocated "jitted" code +=09objfile =3D gdb.Objfile(name) +=09compunit =3D gdb.Compunit(name, objfile, addr, addr + size) + +=09# Mark the objfile as "jitted" code. This will be used later when +=09# unregistering discarded code to check the objfile was indeed +=09# created for "jitted" code. +=09setattr(objfile, "is_jit_code", True) + +=09# Create block for jitted function +=09block =3D gdb.Block(compunit.static_block(), addr, addr + size) + +=09# Create symbol table holding info about jitted function, ... +=09symtab =3D gdb.Symtab("py-jit.c", compunit) +=09linetable =3D gdb.LineTable(symtab, linetable_entries) + +=09# ...type of the jitted function... +=09void_t =3D gdb.selected_inferior().architecture().void_type() +=09func_t =3D void_t.function() + +=09# ...and symbol representing jitted function. +=09symbol =3D gdb.Symbol(name, symtab, func_t, +=09=09=09 gdb.SYMBOL_FUNCTION_DOMAIN, gdb.SYMBOL_LOC_BLOCK, +=09=09=09 block) + +=09# Finally, register the symbol in static block... +=09compunit.static_block().add_symbol(symbol) + +=09# ..and continue execution +=09return False + +# Create breakpoint to register new code +JITRegisterCode("jit_register_code", internal=3DTrue) + + +class JITUnregisterCode(gdb.Breakpoint): + def stop(self): +=09# Find out which code has been discarded. Again, how exactly to +=09# do so depends on JIT compiler in question. +=09# +=09# In this example address of discarded code is passed as a +=09# parameter. + +=09frame =3D gdb.newest_frame() +=09addr =3D int(frame.read_var('code')) + +=09# Find objfile which was created in JITRegisterCode.stop() for +=09# given jitted code. +=09objfile =3D gdb.current_progspace().objfile_for_address(addr) +=09if objfile is None: +=09 # No objfile for given addr (this should not normally happen) +=09 return False # Continue execution +=09if not getattr(objfile, "is_jit_code", False): +=09 # Not a jitted code (this should not happen either) +=09 return False # Continue execution + +=09# Remove the objfile and all debug info associated with it... +=09objfile.unlink() + +=09# ..and continue execution +=09return False # Continue execution + +# Create breakpoint to discard old code +JITUnregisterCode("jit_unregister_code", internal=3DTrue) +@end smallexample + @node Python Auto-loading @subsection Python Auto-loading @cindex Python auto-loading diff --git a/gdb/testsuite/gdb.python/py-jit.c b/gdb/testsuite/gdb.python/p= y-jit.c new file mode 100644 index 00000000000..fde6d732760 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-jit.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2025-2025 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 +#include +#include +#include +#include + +#include + +/* "JIT-ed" function, with the prototype `long (long, long)`. */ +static const unsigned char jit_function_add_code[] =3D { + 0x48, 0x01, 0xfe,=09=09/* add %rdi,%rsi */ + 0x48, 0x89, 0xf0,=09=09/* mov %rsi,%rax */ + 0xc3,=09=09=09=09/* retq */ +}; + +/* Dummy function to inform the debugger a new code has been installed. *= / +void jit_register_code (char * name, uintptr_t code, size_t size) +{} + +/* Dummy function to inform the debugger that code has been installed. */ +void jit_unregister_code (uintptr_t code) +{} + +int +main (int argc, char **argv) +{ + void *code =3D mmap (NULL, getpagesize (), PROT_WRITE | PROT_EXEC, +=09=09 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + assert (code !=3D MAP_FAILED); + + /* "Compile" jit_function_add. */ + memcpy (code, jit_function_add_code, +=09 sizeof (jit_function_add_code)); + jit_register_code ("jit_function_add", (uintptr_t)code, sizeof (jit_func= tion_add_code)); + + ((long (*)(long, long))code)(1,5); /* breakpoint 1 line */ + + /* "Discard" jit_function_add. */ + memset(code, 0, sizeof(jit_function_add_code)); + jit_unregister_code ((uintptr_t)code); + + return 0; /* breakpoint 2 line */ +} diff --git a/gdb/testsuite/gdb.python/py-jit.exp b/gdb/testsuite/gdb.python= /py-jit.exp new file mode 100644 index 00000000000..09b550bbf36 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-jit.exp @@ -0,0 +1,57 @@ +# Copyright (C) 2025-2025 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 test the Python API to +# create symbol tables for dynamic (JIT) code and follows the example +# code given in documentation (see section JIT Interface in Python) + +load_lib gdb-python.exp + +require allow_python_tests +require is_x86_64_m64_target + +standard_testfile + +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { + return -1 +} + +if ![runto_main] { + return 0 +} + +set remote_python_file [gdb_remote_download host \ +=09=09=09=09${srcdir}/${subdir}/${testfile}.py] +gdb_test_no_output "source ${remote_python_file}" "load python file" + +gdb_breakpoint [gdb_get_line_number "breakpoint 1 line" ${testfile}.c] +gdb_continue_to_breakpoint "continue to breakpoint 1 line" +gdb_test "disassemble /s jit_function_add" \ +=09"Dump of assembler code for function jit_function_add:.*End of assemble= r dump." \ +=09"disassemble jit_function_add" + +gdb_breakpoint "jit_function_add" +gdb_continue_to_breakpoint "continue to jit_function_add" + +gdb_test "bt 1" \ +=09"#0 jit_function_add \\(\\) at py-jit.c:.*" \ +=09"bt 1" + +gdb_breakpoint [gdb_get_line_number "breakpoint 2 line" ${testfile}.c] +gdb_continue_to_breakpoint "continue to breakpoint 2 line" + +gdb_test "disassemble jit_function_add" \ +=09"No symbol \"jit_function_add\" in current context." \ +=09"disassemble jit_function_add after code has been unregistered" diff --git a/gdb/testsuite/gdb.python/py-jit.py b/gdb/testsuite/gdb.python/= py-jit.py new file mode 100644 index 00000000000..efef3e9c19a --- /dev/null +++ b/gdb/testsuite/gdb.python/py-jit.py @@ -0,0 +1,118 @@ +# Copyright (C) 2025-2025 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 . = */ + +# This code is same (modulo small tweaks) as the code in documentation, +# section "JIT Interface in Python". If changed the documentation should +# be checked and updated accordingly if necessary. +import gdb + +objfile =3D None +compunit =3D None +block =3D None +symtab =3D None +symbol =3D None + + +def get_linetable_entries(addr): + # Entries are not in increasing order to test that + # gdb.LineTable.__init__() sorts them properly. + return [ + gdb.LineTableEntry(31, addr + 6, True), + gdb.LineTableEntry(29, addr, True), + gdb.LineTableEntry(30, addr + 3, True), + ] + + +class JITRegisterCode(gdb.Breakpoint): + def stop(self): + + global objfile + global compunit + global block + global symtab + global symbol + + frame =3D gdb.newest_frame() + name =3D frame.read_var("name").string() + addr =3D int(frame.read_var("code")) + size =3D int(frame.read_var("size")) + linetable_entries =3D get_linetable_entries(addr) + + # Create objfile and compunit for allocated "jit" code + objfile =3D gdb.Objfile(name) + compunit =3D gdb.Compunit(name, objfile, addr, addr + size) + + # Mark the objfile as "jitted code". This will be used later when + # unregistering discarded code to check the objfile was indeed + # created for jitted code. + setattr(objfile, "is_jit_code", True) + + # Create block for jitted function + block =3D gdb.Block(compunit.static_block(), addr, addr + size) + + # Create symbol table holding info about jitted function, ... + symtab =3D gdb.Symtab("py-jit.c", compunit) + linetable =3D gdb.LineTable(symtab, linetable_entries) + + # ...type of the jitted function... + int64_t =3D gdb.selected_inferior().architecture().integer_type(64= ) + func_t =3D int64_t.function(int64_t, int64_t) + + # ...and symbol representing jitted function. + symbol =3D gdb.Symbol( + name, + symtab, + func_t, + gdb.SYMBOL_FUNCTION_DOMAIN, + gdb.SYMBOL_LOC_BLOCK, + block, + ) + + # Finally, register the symbol in static block + compunit.static_block().add_symbol(symbol) + + return False # Continue execution + + +# Create breakpoint to register new code +JITRegisterCode("jit_register_code", internal=3DTrue) + + +class JITUnregisterCode(gdb.Breakpoint): + def stop(self): + frame =3D gdb.newest_frame() + addr =3D int(frame.read_var("code")) + + objfile =3D gdb.current_progspace().objfile_for_address(addr) + if objfile is None: + # No objfile for given addr - bail out (this should not happen= ) + assert False + return False # Continue execution + + if not getattr(objfile, "is_jit_code", False): + # Not a jitted addr - bail out (this should not happen either) + assert False + return False # Continue execution + + # Remove the objfile and all debug info associated with it. + objfile.unlink() + + return False # Continue execution + + +# Create breakpoint to discard old code +JITUnregisterCode("jit_unregister_code", internal=3DTrue) --=20 2.47.2