From patchwork Wed Oct 16 17:18:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Malcolm X-Patchwork-Id: 1998176 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=aA1xjg3G; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XTHkf33cvz1xth for ; Thu, 17 Oct 2024 04:19:06 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 64E233857C4F for ; Wed, 16 Oct 2024 17:19:04 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTP id 0BA0B3858D33 for ; Wed, 16 Oct 2024 17:18:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0BA0B3858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 0BA0B3858D33 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729099119; cv=none; b=gUZDTccTqwKE2Y7PPHwGWqAsFtAqwNraUXSAnO/kYARka2HPPLWU054XMK+4hPtLjIaDScIntrJEWALS6OWQwT4fvAsuBbJpvUPHUKiaCYcKc4oWu7rPX9NZjgw/Lxxj+gOJ+n30SbbpawI1HdcAR+7pdzbdGD7wzkyRZS0ftNk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1729099119; c=relaxed/simple; bh=KhncHZxcqnTmp1DNO3aSGEdPUkKOx9ABgHTK6J9JmXM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=o6P7oxKVpC0ElCyoK072NoYT1hn9EQZex15vGp1bHnHR350Pvi+7F0U/1FmxJp1gJPOJx+uLwd4+torG+8MP7i4QeV6hub26iV5Ta4DswQrtZM94cztb3I1ufPcje/m4hOYZMY8ov6b217XIp2K8S/xkXzT+8dZu6Y+E38Xxpa0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1729099115; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BRRAQxzGtrmPCyfpAdEpWwuRhmv35NiWyyUJ1n/AvXg=; b=aA1xjg3GIFUQcC++uADK6fc6aAEVBhrYz47G4rv0sIQaB9FGK3dyVOUUVFUBI0xcQ+rVVX Zs1jNHjPx/TXOEGWa07iYf8nmH4dIRDrK/dwO1SJ6X07jDz1dawcgT5fLFIsNVHRbwUXCj BK9GwCYAWfniwxTFb73v6ahq4b0VsLo= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-586-Rwdq0dG4MLGuUaUz2XmveA-1; Wed, 16 Oct 2024 13:18:34 -0400 X-MC-Unique: Rwdq0dG4MLGuUaUz2XmveA-1 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 951D21956080 for ; Wed, 16 Oct 2024 17:18:33 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.22.64.110]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id D482619560AE; Wed, 16 Oct 2024 17:18:32 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Cc: David Malcolm Subject: [pushed: r15-4393] diagnostics: capture backtraces in SARIF notifications [PR116602] Date: Wed, 16 Oct 2024 13:18:30 -0400 Message-ID: <20241016171830.733634-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_SBL_CSS, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This patch makes the SARIF output's crash handler attempt to capture a backtrace in JSON form within the notification's property bag. The precise format of the property is subject to change, but, for example, in one of the test cases I got output like this: "properties": {"gcc/backtrace": {"frames": [{"pc": "0x7f39c610a32d", "function": "pass_crash_test::execute(function*)", "filename": "/home/david/gcc-newgit/src/gcc/testsuite/gcc.dg/plugin/crash_test_plugin.c", "lineno": 98}]}}}], The backtrace code is based on that in diagnostic.cc. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r15-4393-g69b2d523b10696. gcc/ChangeLog: PR other/116602 * diagnostic-format-sarif.cc: Include "demangle.h" and "backtrace.h". (sarif_invocation::add_notification_for_ice): Add "backtrace" param and pass it to ctor. (sarif_ice_notification::sarif_ice_notification): Add "backtrace" param and add it to property bag. (bt_stop): New, taken from diagnostic.cc. (struct bt_closure): New. (bt_callback): New, adapted from diagnostic.cc. (sarif_builder::make_stack_from_backtrace): New. (sarif_builder::on_report_diagnostic): Attempt to get backtrace and pass it to add_notification_for_ice. gcc/testsuite/ChangeLog: PR other/116602 * gcc.dg/plugin/crash-test-ice-in-header-sarif-2_1.py: Add check for backtrace. * gcc.dg/plugin/crash-test-ice-in-header-sarif-2_2.py: Likewise. Signed-off-by: David Malcolm --- gcc/diagnostic-format-sarif.cc | 155 +++++++++++++++++- .../crash-test-ice-in-header-sarif-2_1.py | 7 + .../crash-test-ice-in-header-sarif-2_2.py | 7 + 3 files changed, 163 insertions(+), 6 deletions(-) diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index 0ab2b83bff9a..89ac9a5424c9 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -47,6 +47,8 @@ along with GCC; see the file COPYING3. If not see #include "text-range-label.h" #include "pretty-print-format-impl.h" #include "pretty-print-urlifier.h" +#include "demangle.h" +#include "backtrace.h" /* Forward decls. */ class sarif_builder; @@ -167,7 +169,8 @@ public: const char * const *original_argv); void add_notification_for_ice (const diagnostic_info &diagnostic, - sarif_builder &builder); + sarif_builder &builder, + std::unique_ptr backtrace); void prepare_to_flush (sarif_builder &builder); private: @@ -578,7 +581,8 @@ class sarif_ice_notification : public sarif_location_manager { public: sarif_ice_notification (const diagnostic_info &diagnostic, - sarif_builder &builder); + sarif_builder &builder, + std::unique_ptr backtrace); void add_related_location (std::unique_ptr location_obj, @@ -801,6 +805,9 @@ private: make_artifact_content_object (const char *text) const; int get_sarif_column (expanded_location exploc) const; + std::unique_ptr + make_stack_from_backtrace (); + diagnostic_context &m_context; pretty_printer *m_printer; const line_maps *m_line_maps; @@ -885,12 +892,15 @@ sarif_invocation::sarif_invocation (sarif_builder &builder, void sarif_invocation::add_notification_for_ice (const diagnostic_info &diagnostic, - sarif_builder &builder) + sarif_builder &builder, + std::unique_ptr backtrace) { m_success = false; auto notification - = ::make_unique (diagnostic, builder); + = ::make_unique (diagnostic, + builder, + std::move (backtrace)); /* Support for related locations within a notification was added in SARIF 2.2; see https://github.com/oasis-tcs/sarif-spec/issues/540 */ @@ -1310,7 +1320,8 @@ sarif_location::lazily_add_relationships_array () sarif_ice_notification:: sarif_ice_notification (const diagnostic_info &diagnostic, - sarif_builder &builder) + sarif_builder &builder, + std::unique_ptr backtrace) { /* "locations" property (SARIF v2.1.0 section 3.58.4). */ auto locations_arr @@ -1327,6 +1338,13 @@ sarif_ice_notification (const diagnostic_info &diagnostic, /* "level" property (SARIF v2.1.0 section 3.58.6). */ set_string ("level", "error"); + + /* If we have backtrace information, add it as part of a property bag. */ + if (backtrace) + { + sarif_property_bag &bag = get_or_create_properties (); + bag.set ("gcc/backtrace", std::move (backtrace)); + } } /* Implementation of sarif_location_manager::add_related_location vfunc @@ -1528,6 +1546,129 @@ sarif_builder::~sarif_builder () } } +/* Functions at which to stop the backtrace print. It's not + particularly helpful to print the callers of these functions. */ + +static const char * const bt_stop[] = +{ + "main", + "toplev::main", + "execute_one_pass", + "compile_file", +}; + +struct bt_closure +{ + bt_closure (sarif_builder &builder, + json::array *frames_arr) + : m_builder (builder), + m_frames_arr (frames_arr) + { + } + + sarif_builder &m_builder; + json::array *m_frames_arr; +}; + +/* A callback function passed to the backtrace_full function. */ + +static int +bt_callback (void *data, uintptr_t pc, const char *filename, int lineno, + const char *function) +{ + bt_closure *closure = (bt_closure *)data; + + /* If we don't have any useful information, don't print + anything. */ + if (filename == NULL && function == NULL) + return 0; + + /* Skip functions in diagnostic.cc or diagnostic-global-context.cc. */ + if (closure->m_frames_arr->size () == 0 + && filename != NULL + && (strcmp (lbasename (filename), "diagnostic.cc") == 0 + || strcmp (lbasename (filename), + "diagnostic-global-context.cc") == 0)) + return 0; + + /* Print up to 20 functions. We could make this a --param, but + since this is only for debugging just use a constant for now. */ + if (closure->m_frames_arr->size () >= 20) + { + /* Returning a non-zero value stops the backtrace. */ + return 1; + } + + char *alc = NULL; + if (function != NULL) + { + char *str = cplus_demangle_v3 (function, + (DMGL_VERBOSE | DMGL_ANSI + | DMGL_GNU_V3 | DMGL_PARAMS)); + if (str != NULL) + { + alc = str; + function = str; + } + + for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i) + { + size_t len = strlen (bt_stop[i]); + if (strncmp (function, bt_stop[i], len) == 0 + && (function[len] == '\0' || function[len] == '(')) + { + if (alc != NULL) + free (alc); + /* Returning a non-zero value stops the backtrace. */ + return 1; + } + } + } + + auto frame_obj = ::make_unique (); + + /* I tried using sarifStack and sarifStackFrame for this + but it's not a good fit e.g. PC information. */ + char buf[128]; + snprintf (buf, sizeof (buf) - 1, "0x%lx", (unsigned long)pc); + frame_obj->set_string ("pc", buf); + if (function) + frame_obj->set_string ("function", function); + if (filename) + frame_obj->set_string ("filename", filename); + frame_obj->set_integer ("lineno", lineno); + closure->m_frames_arr->append (std::move (frame_obj)); + + if (alc != NULL) + free (alc); + + return 0; +} + +/* Attempt to generate a JSON object representing a backtrace, + for adding to ICE notifications. */ + +std::unique_ptr +sarif_builder::make_stack_from_backtrace () +{ + auto frames_arr = ::make_unique (); + + backtrace_state *state = nullptr; + state = backtrace_create_state (nullptr, 0, nullptr, nullptr); + bt_closure closure (*this, frames_arr.get ()); + const int frames_to_skip = 5; + if (state != nullptr) + backtrace_full (state, frames_to_skip, bt_callback, nullptr, + (void *) &closure); + + if (frames_arr->size () == 0) + return nullptr; + + auto stack = ::make_unique (); + stack->set ("frames", std::move (frames_arr)); + return stack; +} + /* Implementation of "on_report_diagnostic" for SARIF output. */ void @@ -1538,7 +1679,9 @@ sarif_builder::on_report_diagnostic (const diagnostic_info &diagnostic, if (diagnostic.kind == DK_ICE || diagnostic.kind == DK_ICE_NOBT) { - m_invocation_obj->add_notification_for_ice (diagnostic, *this); + std::unique_ptr stack = make_stack_from_backtrace (); + m_invocation_obj->add_notification_for_ice (diagnostic, *this, + std::move (stack)); /* Print a header for the remaining output to stderr, and return, attempting to print the usual ICE messages to diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_1.py b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_1.py index 223e9a0c6132..c7dee92618ac 100644 --- a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_1.py +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_1.py @@ -55,6 +55,13 @@ def test_notification(sarif): assert get_location_artifact_uri(loc0).endswith('crash-test-ice-in-header.h') assert 'inject_ice ();' in get_location_snippet_text(loc0) + # We may have backtrace information + if 'properties' in notification: + backtrace = notification['properties']['gcc/backtrace'] + assert 'frames' in backtrace + # Ideally we should have a frame for pass_crash_test::execute(function*) + # but we can't rely on this. + # In SARIF 2.1 and earlier we aren't able to capture the include path # as a related location within the notification assert 'relationships' not in loc0 diff --git a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_2.py b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_2.py index 27c6da9e1f59..d3e4d5403fed 100644 --- a/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_2.py +++ b/gcc/testsuite/gcc.dg/plugin/crash-test-ice-in-header-sarif-2_2.py @@ -55,6 +55,13 @@ def test_notification(sarif): assert get_location_artifact_uri(loc0).endswith('crash-test-ice-in-header.h') assert 'inject_ice ();' in get_location_snippet_text(loc0) + # We may have backtrace information + if 'properties' in notification: + backtrace = notification['properties']['gcc/backtrace'] + assert 'frames' in backtrace + # Ideally we should have a frame for pass_crash_test::execute(function*) + # but we can't rely on this. + # In SARIF 2.2 onwards we should be able to capture the include path # as a related location within the notification assert len(loc0['relationships']) == 1