@@ -125,7 +125,8 @@ class sarif_tool_component : public sarif_object {};
class sarif_invocation : public sarif_object
{
public:
- sarif_invocation (sarif_builder &builder);
+ sarif_invocation (sarif_builder &builder,
+ const char * const *original_argv);
void add_notification_for_ice (diagnostic_context &context,
const diagnostic_info &diagnostic,
@@ -329,10 +330,8 @@ public:
- GCC supports one-deep nesting of diagnostics (via auto_diagnostic_group),
but we only capture location and message information from such nested
diagnostics (e.g. we ignore fix-it hints on them)
- - doesn't yet capture command-line arguments: would be run.invocations
- property (SARIF v2.1.0 section 3.14.11), as invocation objects
- (SARIF v2.1.0 section 3.20), but we'd want to capture the arguments to
- toplev::main, and the response files.
+ - although we capture command-line arguments (section 3.20.2), we don't
+ yet capture response files.
- doesn't capture secondary locations within a rich_location
(perhaps we should use the "relatedLocations" property: SARIF v2.1.0
section 3.27.22)
@@ -513,10 +512,20 @@ sarif_object::get_or_create_properties ()
/* class sarif_invocation : public sarif_object. */
-sarif_invocation::sarif_invocation (sarif_builder &builder)
+sarif_invocation::sarif_invocation (sarif_builder &builder,
+ const char * const *original_argv)
: m_notifications_arr (::make_unique<json::array> ()),
m_success (true)
{
+ // "arguments" property (SARIF v2.1.0 section 3.20.2)
+ if (original_argv)
+ {
+ auto arguments_arr = ::make_unique<json::array> ();
+ for (size_t i = 0; original_argv[i]; ++i)
+ arguments_arr->append_string (original_argv[i]);
+ set<json::array> ("arguments", std::move (arguments_arr));
+ }
+
// "workingDirectory" property (SARIF v2.1.0 section 3.20.19)
if (const char *pwd = getpwd ())
set<sarif_artifact_location> ("workingDirectory",
@@ -752,7 +761,9 @@ sarif_builder::sarif_builder (diagnostic_context &context,
const char *main_input_filename_,
bool formatted)
: m_context (context),
- m_invocation_obj (::make_unique<sarif_invocation> (*this)),
+ m_invocation_obj
+ (::make_unique<sarif_invocation> (*this,
+ context.get_original_argv ())),
m_results_array (new json::array ()),
m_cur_group_result (nullptr),
m_seen_any_relative_paths (false),
@@ -261,6 +261,7 @@ diagnostic_context::initialize (int n_opts)
m_includes_seen = nullptr;
m_client_data_hooks = nullptr;
m_diagrams.m_theme = nullptr;
+ m_original_argv = nullptr;
enum diagnostic_text_art_charset text_art_charset
= DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI;
@@ -385,6 +386,9 @@ diagnostic_context::finish ()
delete m_urlifier;
m_urlifier = nullptr;
+
+ freeargv (m_original_argv);
+ m_original_argv = nullptr;
}
void
@@ -403,6 +407,19 @@ diagnostic_context::set_client_data_hooks (diagnostic_client_data_hooks *hooks)
m_client_data_hooks = hooks;
}
+void
+diagnostic_context::set_original_argv (unique_argv original_argv)
+{
+ /* Ideally we'd use a unique_argv for m_original_argv, but
+ diagnostic_context doesn't yet have a ctor/dtor pair. */
+
+ // Ensure any old value is freed
+ freeargv (m_original_argv);
+
+ // Take ownership of the new value
+ m_original_argv = original_argv.release ();
+}
+
void
diagnostic_context::
set_option_hooks (diagnostic_option_enabled_cb option_enabled_cb,
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_DIAGNOSTIC_H
#define GCC_DIAGNOSTIC_H
+#include "unique-argv.h"
#include "rich-location.h"
#include "pretty-print.h"
#include "diagnostic-core.h"
@@ -391,6 +392,12 @@ public:
void finish ();
+ void set_original_argv (unique_argv original_argv);
+ const char * const *get_original_argv ()
+ {
+ return const_cast<const char * const *> (m_original_argv);
+ }
+
void set_set_locations_callback (set_locations_callback_t cb)
{
m_set_locations_cb = cb;
@@ -813,6 +820,9 @@ private:
text_art::theme *m_theme;
} m_diagrams;
+
+ /* Owned by the context. */
+ char **m_original_argv;
};
inline void
@@ -2568,7 +2568,11 @@ compile ()
if (get_logger ())
for (unsigned i = 0; i < fake_args.length (); i++)
get_logger ()->log ("argv[%i]: %s", i, fake_args[i]);
- toplev.main (fake_args.length (),
+
+ /* Add a trailing null to argvec; this is not counted in argc. */
+ fake_args.safe_push (nullptr);
+ toplev.main (/* The trailing null is not counted in argv. */
+ fake_args.length () - 1,
const_cast <char **> (fake_args.address ()));
exit_scope ("toplev::main");
@@ -32,6 +32,11 @@
{ dg-final { scan-sarif-file "\"informationUri\": \"" } }
{ dg-final { scan-sarif-file "\"invocations\": \\\[" } }
+ 3.20: "invocation" object:
+
+ 3.20.2 invocation "arguments" property:
+ { dg-final { scan-sarif-file {"arguments": \[} } }
+
{ dg-final { scan-sarif-file {"workingDirectory": } } }
{ dg-final { scan-sarif-file "\"toolExecutionNotifications\": \\\[\\\]" } }
{ dg-final { scan-sarif-file "\"executionSuccessful\": true" } }
@@ -93,6 +93,7 @@ along with GCC; see the file COPYING3. If not see
#include "ipa-param-manipulation.h"
#include "dbgcnt.h"
#include "gcc-urlifier.h"
+#include "unique-argv.h"
#include "selftest.h"
@@ -100,7 +101,7 @@ along with GCC; see the file COPYING3. If not see
#include <isl/version.h>
#endif
-static void general_init (const char *, bool);
+static void general_init (const char *, bool, unique_argv original_argv);
static void backend_init (void);
static int lang_dependent_init (const char *);
static void init_asm_output (const char *);
@@ -1000,7 +1001,7 @@ internal_error_function (diagnostic_context *, const char *, va_list *)
options are parsed. Signal handlers, internationalization etc.
ARGV0 is main's argv[0]. */
static void
-general_init (const char *argv0, bool init_signals)
+general_init (const char *argv0, bool init_signals, unique_argv original_argv)
{
const char *p;
@@ -1028,6 +1029,8 @@ general_init (const char *argv0, bool init_signals)
override it later. */
tree_diagnostics_defaults (global_dc);
+ global_dc->set_original_argv (std::move (original_argv));
+
global_dc->m_source_printing.enabled
= global_options_init.x_flag_diagnostics_show_caret;
global_dc->m_source_printing.show_event_links_p
@@ -2241,10 +2244,14 @@ toplev::main (int argc, char **argv)
Increase stack size limits if possible. */
stack_limit_increase (64 * 1024 * 1024);
+ /* Stash a copy of the original argv before expansion
+ for use by SARIF output. */
+ unique_argv original_argv (dupargv (argv));
+
expandargv (&argc, &argv);
/* Initialization of GCC's environment, and diagnostics. */
- general_init (argv[0], m_init_signals);
+ general_init (argv[0], m_init_signals, std::move (original_argv));
/* One-off initialization of options that does not need to be
repeated when options are added for particular functions. */
new file mode 100644
@@ -0,0 +1,67 @@
+/* C++11 wrapper around libiberty's argv.c
+ Copyright (C) 2024 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_UNIQUE_ARGV_H
+#define GCC_UNIQUE_ARGV_H
+
+/* C++11 wrapper around libiberty's argv.c, with
+ ownership of the underlying array and strings. */
+
+struct unique_argv
+{
+ /* Take ownership of argv. */
+ unique_argv (char **argv)
+ : m_argv (argv)
+ {
+ }
+
+ ~unique_argv ()
+ {
+ freeargv (m_argv);
+ }
+
+ unique_argv (const unique_argv &other) = delete;
+ unique_argv &operator= (const unique_argv &other) = delete;
+
+ unique_argv (unique_argv &&other)
+ : m_argv (other.m_argv)
+ {
+ other.m_argv = nullptr;
+ }
+
+ unique_argv &operator= (unique_argv &&other)
+ {
+ freeargv (m_argv);
+ m_argv = other.m_argv;
+ other.m_argv = nullptr;
+ return *this;
+ }
+
+ char **release ()
+ {
+ char **result = m_argv;
+ m_argv = nullptr;
+ return result;
+ }
+
+ char **m_argv;
+};
+
+#endif /* ! GCC_UNIQUE_ARGV_H */
gcc/ChangeLog: * diagnostic-format-sarif.cc (sarif_invocation::sarif_invocation): Add "original_argv" param and use it to populate "arguments" property (§3.20.2). (sarif_builder::sarif_builder): Pass argv to m_invocation_obj's ctor. * diagnostic.cc (diagnostic_context::initialize): Initialize m_original_argv. (diagnostic_context::finish): Clean up m_original_argv. (diagnostic_context::set_original_argv): New. * diagnostic.h: Include "unique-argv.h". (diagnostic_context::set_original_argv): New decl. (diagnostic_context::get_original_argv): New decl. (diagnostic_context::m_original_argv): New field. * toplev.cc: Include "unique-argv.h". (general_init): Add "original_argv" param and move it to global_dc. (toplev::main): Stash a copy of the original argv before expansion, and pass it to general_init for use by SARIF output. * unique-argv.h: New file. gcc/jit/ChangeLog: * jit-playback.cc (jit::playback_context::compile) Add a trailing null to argvec. gcc/testsuite/ChangeLog: * c-c++-common/diagnostic-format-sarif-file-1.c: Verify that we have an "arguments" property (§3.20.2). Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- gcc/diagnostic-format-sarif.cc | 25 +++++-- gcc/diagnostic.cc | 17 +++++ gcc/diagnostic.h | 10 +++ gcc/jit/jit-playback.cc | 6 +- .../diagnostic-format-sarif-file-1.c | 5 ++ gcc/toplev.cc | 13 +++- gcc/unique-argv.h | 67 +++++++++++++++++++ 7 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 gcc/unique-argv.h