From patchwork Fri Aug 28 12:50:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Gerlicher, Klaus" X-Patchwork-Id: 142396 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 5522F4BA23F8 for ; Fri, 28 Aug 2026 12:50:53 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5522F4BA23F8 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=aOj9lyg7 X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.12]) by sourceware.org (Postfix) with ESMTPS id 27D4F4BA2E07 for ; Fri, 28 Aug 2026 12:50:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 27D4F4BA2E07 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 27D4F4BA2E07 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=198.175.65.12 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787921420; cv=none; b=gXcE2JjZr8CujBNOF1nznVft7V8uS27B6KqEEMou8OkZ9MzwhLmhtd9QXCh8OwAMmUTGy8y+XgXoHpWcek6TiQQD9TQEUU/f/C/E4mXOYXjK6Xr4JRy4HeBeokORuncW40v1r7/KG49y2PgxuDk2Xk5rRFmvMEa0JT/0YepDBw8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1787921420; c=relaxed/simple; bh=HfBl+kWyuzvt9H8IQAOIJIztkOMGZ2BkeUkEN8iObDY=; h=DKIM-Signature:From:To:Subject:Date:Message-Id:MIME-Version; b=JZzsmbH5lDUazy4bmGnxP1HMIhhTq1SF5obHhnn0z3gJCs2B5Z7gJfRMkFFuvdAvYPqpjIGflXri/+ZT6pz2cVsCW/iwH+g72yb5Biwhi8+wdgjVeHVMBs6FPy9z3g8x7jn3ht4oAoPMYc1eiQqbkI4SEF3Q/RgfdG+69stxYRM= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=aOj9lyg7 DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 27D4F4BA2E07 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1787921421; x=1819457421; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=HfBl+kWyuzvt9H8IQAOIJIztkOMGZ2BkeUkEN8iObDY=; b=aOj9lyg7m3VvqyBn1sgPvhFCJF6w7iyOPAPc94lwckM8zT44IzNuYr49 mn+PJLF/skmIsSp6yGwf3ShKCi9yH+tksy946mzR2etIA/FKy2gLFNq1H 5AihDaFXPUrnlJgOfv3oW2+eWO1urGepR0lYMqEa9AbN0RvPsTjsDoD86 vi4izJjaw5T9GtylH/W9jKCTs5B+pRU9qqZrxMs6hbe+3Jq9VnDRuZ4e5 +W30yLBB9lWO7WE4OI0qvd5Q7bac2inbiyZP/EZzL+AaskYFeQhy51cco Y3Vq9sOeSNNhd3F97EjqBP4J0HZ7U0/vK6LijCUlOY+TgoMRddD39Rbz5 g==; X-CSE-ConnectionGUID: El0vqTFdQZ+5yxLiz2voSA== X-CSE-MsgGUID: jYjVmo4cSs22Ff3wfIlvAw== X-IronPort-AV: E=McAfee;i="6800,10657,11888"; a="99943167" X-IronPort-AV: E=Sophos;i="6.25,248,1779174000"; d="scan'208";a="99943167" Received: from orviesa006.jf.intel.com ([10.64.159.146]) by orvoesa104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Aug 2026 05:50:19 -0700 X-CSE-ConnectionGUID: +EEi3y6US2OfCRR14Erl6w== X-CSE-MsgGUID: m6ZogYm6R7uncOMb2eFpPQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.25,248,1779174000"; d="scan'208";a="266341604" Received: from dut1583dg2frd.igk.intel.com (HELO localhost) ([10.211.179.243]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 28 Aug 2026 05:50:18 -0700 From: Klaus Gerlicher To: gdb-patches@sourceware.org Cc: TankutBaris.Aktemur@amd.com, aburgess@redhat.com, simark@simark.ca Subject: [PATCH v5 1/1] gdb: avoid conversion of SIGSEGV to SIGTRAP on user breakpoints Date: Fri, 28 Aug 2026 12:50:03 +0000 Message-Id: <20260828125003.253648-1-klaus.gerlicher@intel.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, TXREP, T_SPF_TEMPERROR shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org 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~patchwork=sourceware.org@sourceware.org From: "Gerlicher, Klaus" GDB converts signals GDB_SIGNAL_ILL, GDB_SIGNAL_SEGV and GDB_SIGNAL_EMT to GDB_SIGNAL_TRAP if a breakpoint is inserted at the fault location. This conversion logic assumes that when these signals occur at a breakpoint location, the signal was actually caused by hitting the breakpoint rather than a genuine fault. However, some architectures have "imprecise page fault reporting," where a memory access violation can be reported several instructions after the faulting instruction. For example: INSN1 <-- generates a SIGSEGV INSN2 INSN3 <-- breakpoint installed here If INSN1 causes a memory access violation, the backend may report the stop at INSN3, where a breakpoint happens to be installed. GDB's logic then incorrectly assumes "there is a breakpoint at INSN3, so this SIGSEGV must mean we hit the breakpoint" and converts it to SIGTRAP. On architectures with imprecise fault reporting, this is wrong: if a breakpoint is never reported via SIGSEGV, then receiving a SIGSEGV at a breakpoint location means we have a genuine SIGSEGV, not a breakpoint hit. Add a new gdbarch function, imprecise_pagefault_reporting, that allows the signal conversion from GDB_SIGNAL_SEGV to GDB_SIGNAL_TRAP to be skipped for an architecture. The default is false (conversion enabled), preserving existing behavior. Architectures with imprecise fault reporting should override this to return true. Reviewed-By: Tankut Baris Aktemur --- gdb/gdbarch-gen.c | 22 ++++++++++++++++++++++ gdb/gdbarch-gen.h | 24 ++++++++++++++++++++++++ gdb/gdbarch_components.py | 29 +++++++++++++++++++++++++++++ gdb/infrun.c | 4 +++- 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/gdb/gdbarch-gen.c b/gdb/gdbarch-gen.c index 6008003466c..b3a699598f9 100644 --- a/gdb/gdbarch-gen.c +++ b/gdb/gdbarch-gen.c @@ -253,6 +253,7 @@ struct gdbarch gdbarch_core_parse_exec_context_ftype *core_parse_exec_context = default_core_parse_exec_context; gdbarch_shadow_stack_push_ftype *shadow_stack_push = nullptr; gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer = default_get_shadow_stack_pointer; + gdbarch_imprecise_pagefault_reporting_ftype *imprecise_pagefault_reporting = [] () -> bool {return false;}; }; /* Create a new ``struct gdbarch'' based on information provided by @@ -513,6 +514,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of core_parse_exec_context, invalid_p == 0. */ /* Skip verify of shadow_stack_push, has predicate. */ /* Skip verify of get_shadow_stack_pointer, invalid_p == 0. */ + /* Skip verify of imprecise_pagefault_reporting, invalid_p == 0. */ if (!log.empty ()) internal_error (_("verify_gdbarch: the following are invalid ...%s"), log.c_str ()); @@ -1339,6 +1341,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file) gdb_printf (file, "gdbarch_dump: get_shadow_stack_pointer = <%s>\n", host_address_to_string (gdbarch->get_shadow_stack_pointer)); + gdb_printf (file, + "gdbarch_dump: imprecise_pagefault_reporting = <%s>\n", + host_address_to_string (gdbarch->imprecise_pagefault_reporting)); if (gdbarch->dump_tdep != nullptr) gdbarch->dump_tdep (gdbarch, file); } @@ -5286,3 +5291,20 @@ set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, { gdbarch->get_shadow_stack_pointer = get_shadow_stack_pointer; } + +bool +gdbarch_imprecise_pagefault_reporting (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != nullptr); + gdb_assert (gdbarch->imprecise_pagefault_reporting != nullptr); + if (gdbarch_debug >= 2) + gdb_printf (gdb_stdlog, "gdbarch_imprecise_pagefault_reporting called\n"); + return gdbarch->imprecise_pagefault_reporting (); +} + +void +set_gdbarch_imprecise_pagefault_reporting (struct gdbarch *gdbarch, + gdbarch_imprecise_pagefault_reporting_ftype imprecise_pagefault_reporting) +{ + gdbarch->imprecise_pagefault_reporting = imprecise_pagefault_reporting; +} diff --git a/gdb/gdbarch-gen.h b/gdb/gdbarch-gen.h index 6eda8693d58..3175e712c55 100644 --- a/gdb/gdbarch-gen.h +++ b/gdb/gdbarch-gen.h @@ -1758,3 +1758,27 @@ void set_gdbarch_shadow_stack_push (struct gdbarch *gdbarch, gdbarch_shadow_stac using gdbarch_get_shadow_stack_pointer_ftype = std::optional (struct gdbarch *gdbarch, regcache *regcache, bool &shadow_stack_enabled); std::optional gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, regcache *regcache, bool &shadow_stack_enabled); void set_gdbarch_get_shadow_stack_pointer (struct gdbarch *gdbarch, gdbarch_get_shadow_stack_pointer_ftype *get_shadow_stack_pointer); + +/* Returns true if architecture has imprecise page fault reporting, where a + memory access violation may be reported several instructions after the + faulting instruction. + + On such architectures, if an instruction causes a memory access violation, + the backend may report the stop at a later instruction where a breakpoint + happens to be installed. GDB's normal logic would incorrectly assume that + the SIGSEGV was caused by hitting the breakpoint and convert it to SIGTRAP. + + However, if an architecture never reports breakpoints via SIGSEGV (e.g., + breakpoints are always reported via a dedicated mechanism), then receiving + a SIGSEGV at a breakpoint location means we have a genuine SIGSEGV, not a + breakpoint hit. + + Return true for architectures with imprecise fault reporting to disable the + SIGSEGV-to-SIGTRAP conversion. The default is false (conversion enabled) + to preserve existing behavior for architectures where breakpoints may be + reported as SIGSEGV (e.g., executing a breakpoint instruction on a + non-executable stack). */ + +using gdbarch_imprecise_pagefault_reporting_ftype = bool (); +bool gdbarch_imprecise_pagefault_reporting (struct gdbarch *gdbarch); +void set_gdbarch_imprecise_pagefault_reporting (struct gdbarch *gdbarch, gdbarch_imprecise_pagefault_reporting_ftype *imprecise_pagefault_reporting); diff --git a/gdb/gdbarch_components.py b/gdb/gdbarch_components.py index d8b2d114909..09d3130e753 100644 --- a/gdb/gdbarch_components.py +++ b/gdb/gdbarch_components.py @@ -2789,3 +2789,32 @@ SHADOW_STACK_ENABLED to false. predefault="default_get_shadow_stack_pointer", invalid=False, ) + +Function( + comment=""" +Returns true if architecture has imprecise page fault reporting, where a +memory access violation may be reported several instructions after the +faulting instruction. + +On such architectures, if an instruction causes a memory access violation, +the backend may report the stop at a later instruction where a breakpoint +happens to be installed. GDB's normal logic would incorrectly assume that +the SIGSEGV was caused by hitting the breakpoint and convert it to SIGTRAP. + +However, if an architecture never reports breakpoints via SIGSEGV (e.g., +breakpoints are always reported via a dedicated mechanism), then receiving +a SIGSEGV at a breakpoint location means we have a genuine SIGSEGV, not a +breakpoint hit. + +Return true for architectures with imprecise fault reporting to disable the +SIGSEGV-to-SIGTRAP conversion. The default is false (conversion enabled) +to preserve existing behavior for architectures where breakpoints may be +reported as SIGSEGV (e.g., executing a breakpoint instruction on a +non-executable stack). +""", + type="bool", + name="imprecise_pagefault_reporting", + params=[], + predefault="[] () -> bool {return false;}", + invalid=False, +) diff --git a/gdb/infrun.c b/gdb/infrun.c index c0767e7f764..25ed7e7523f 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -6331,7 +6331,9 @@ handle_inferior_event (struct execution_control_state *ecs) stack. */ if (ecs->ws.kind () == TARGET_WAITKIND_STOPPED && (ecs->ws.sig () == GDB_SIGNAL_ILL - || ecs->ws.sig () == GDB_SIGNAL_SEGV + || (ecs->ws.sig () == GDB_SIGNAL_SEGV + && !gdbarch_imprecise_pagefault_reporting + (target_thread_architecture (ecs->event_thread->ptid))) || ecs->ws.sig () == GDB_SIGNAL_EMT)) { struct regcache *regcache = get_thread_regcache (ecs->event_thread);