public inbox for dwz@sourceware.org
 help / color / mirror / Atom feed
From: Tom de Vries <tdevries@suse.de>
To: dwz@sourceware.org, jakub@redhat.com, mark@klomp.org
Subject: [PATCH] Factor out args.c and args.h
Date: Wed, 17 Mar 2021 11:37:55 +0100	[thread overview]
Message-ID: <20210317103754.GA13562@delia> (raw)

Hi,

Reduces dwz.c from 17079 to 16450 lines, a reduction of 629 lines or ~3.7%.

Tested performance, no regression found.

Any comments?

Thanks,
- Tom

Factor out args.c and args.h

2021-03-17  Tom de Vries  <tdevries@suse.de>

	* Makefile (OBJECTS): Add args.o.
	* dwz.c	(skip_producer, add_skip_producer, do_indent, wrap)
	(print_options_help, usage, version, parse_args): Move ...
	* args.c: ... here.  New file.
	* args.h: New file.
	(parse_args, skip_producer): Declare.

---
 Makefile |   2 +-
 args.c   | 637 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 args.h   |  94 ++++++++++
 dwz.c    | 631 +-------------------------------------------------------------
 4 files changed, 733 insertions(+), 631 deletions(-)

diff --git a/Makefile b/Makefile
index 2f7c76a..e09d31a 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ exec_prefix = $(prefix)
 bindir = $(exec_prefix)/bin
 datarootdir = $(prefix)/share
 mandir = $(datarootdir)/man
-OBJECTS = dwz.o hashtab.o sha1.o dwarfnames.o
+OBJECTS = args.o dwz.o hashtab.o sha1.o dwarfnames.o
 dwz: $(OBJECTS)
 	$(CC) $(LDFLAGS) -o $@ $^ -lelf
 install: dwz
diff --git a/args.c b/args.c
new file mode 100644
index 0000000..cc8c717
--- /dev/null
+++ b/args.c
@@ -0,0 +1,637 @@
+/* Copyright (C) 2001-2021 Red Hat, Inc.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2019-2021 SUSE LLC.
+   Written by Jakub Jelinek <jakub@redhat.com>, 2012.
+
+   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 2, 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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#include <getopt.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <error.h>
+
+#include "args.h"
+
+#if DEVEL
+int tracing;
+int ignore_size;
+int ignore_locus;
+int dump_checksum_p;
+int dump_dies_p;
+int dump_dups_p;
+int dump_pus_p;
+int verify_dups_p;
+int verify_edge_freelist;
+int stats_p;
+int checksum_cycle_opt = 1;
+int skip_producers_p;
+#endif
+
+int unoptimized_multifile;
+int save_temps;
+int verify_edges_p;
+int dump_edges_p;
+int partition_dups_opt;
+int progress_p;
+int progress_mem_p;
+int import_opt_p = 1;
+int force_p;
+
+enum deduplication_mode deduplication_mode = dm_inter_cu;
+
+int uni_lang_p = 0;
+int gen_cu_p = 0;
+
+enum die_count_methods die_count_method = estimate;
+
+int odr = 0;
+enum odr_mode odr_mode = ODR_LINK;
+
+/* Filename if inter-file size optimization should be performed.  */
+const char *multifile;
+
+/* Argument of -M option, i.e. preferred name that should be stored
+   into the .gnu_debugaltlink or .debug_sup section.  */
+const char *multifile_name;
+
+/* True if -r option is present, i.e. .gnu_debugaltlink or .debug_sup section
+   should contain a filename relative to the directory in which
+   the particular file is present.  */
+bool multifile_relative;
+
+/* True if DWARF 5 .debug_sup and DW_FORM_ref_sup4 / DW_FORM_strp_sup
+   should be used instead of the GNU extensions .gnu_debugaltlink
+   and DW_FORM_GNU_ref_alt / DW_FORM_GNU_strp_alt etc.  */
+bool dwarf_5;
+
+/* True if -q option has been passed.  */
+bool quiet;
+
+/* Number of DIEs, above which dwz retries processing
+   in low_mem mode (and give up on multifile optimizing
+   the file in question).  */
+unsigned int low_mem_die_limit = 10000000;
+
+/* Number of DIEs, above which dwz gives up processing
+   input altogether.  */
+unsigned int max_die_limit = 50000000;
+
+/* Phase of multifile handling.  */
+unsigned char multifile_mode;
+
+static int die_count_method_parsed;
+static int deduplication_mode_parsed;
+static int odr_mode_parsed;
+static int skip_producer_parsed;
+
+/* Options for getopt_long.  */
+static struct option dwz_options[] =
+{
+  { "help",		 no_argument,	    0, '?' },
+  { "output",		 required_argument, 0, 'o' },
+  { "multifile",	 required_argument, 0, 'm' },
+  { "quiet",		 no_argument,	    0, 'q' },
+  { "hardlink",		 no_argument,	    0, 'h' },
+  { "low-mem-die-limit", required_argument, 0, 'l' },
+  { "max-die-limit",	 required_argument, 0, 'L' },
+  { "multifile-name",	 required_argument, 0, 'M' },
+  { "relative",		 no_argument,	    0, 'r' },
+  { "version",		 no_argument,	    0, 'v' },
+  { "import-optimize",
+			 no_argument,	    &import_opt_p, 1 },
+  { "no-import-optimize",
+			 no_argument,	    &import_opt_p, 0 },
+  { "dwarf-5",		 no_argument,	    0, '5' },
+#if DEVEL
+  { "devel-trace",	 no_argument,	    &tracing, 1 },
+  { "devel-progress",	 no_argument,	    &progress_p, 1 },
+  { "devel-progress-mem",no_argument,	    &progress_mem_p, 1 },
+  { "devel-ignore-size", no_argument,	    &ignore_size, 1 },
+  { "devel-ignore-locus",no_argument,	    &ignore_locus, 1 },
+  { "devel-force",	 no_argument,	    &force_p, 1 },
+  { "devel-save-temps",  no_argument,	    &save_temps, 1 },
+  { "devel-dump-checksum",
+			 no_argument,	    &dump_checksum_p, 1 },
+  { "devel-dump-dies",  no_argument,	    &dump_dies_p, 1 },
+  { "devel-dump-dups",  no_argument,	    &dump_dups_p, 1 },
+  { "devel-dump-pus",  no_argument,	    &dump_pus_p, 1 },
+  { "devel-unoptimized-multifile",
+			 no_argument,	    &unoptimized_multifile, 1 },
+  { "devel-verify-edges",no_argument,	    &verify_edges_p, 1 },
+  { "devel-verify-dups", no_argument,	    &verify_dups_p, 1 },
+  { "devel-dump-edges",  no_argument,	    &dump_edges_p, 1 },
+  { "devel-partition-dups-opt",
+			 no_argument,	    &partition_dups_opt, 1 },
+  { "devel-die-count-method",
+			 required_argument, &die_count_method_parsed, 1 },
+  { "devel-stats",	 no_argument,	    &stats_p, 1 },
+  { "devel-deduplication-mode",
+			 required_argument, &deduplication_mode_parsed, 1 },
+  { "devel-uni-lang",
+			 no_argument,	    &uni_lang_p, 1 },
+  { "devel-no-uni-lang",
+			 no_argument,	    &uni_lang_p, 0 },
+  { "devel-gen-cu",
+			 no_argument,	    &gen_cu_p, 1 },
+  { "devel-no-gen-cu",
+			 no_argument,	    &gen_cu_p, 0 },
+  { "devel-checksum-cycle-opt",
+			 no_argument,	    &checksum_cycle_opt, 1 },
+  { "devel-no-checksum-cycle-opt",
+			 no_argument,	    &checksum_cycle_opt, 0 },
+  { "devel-skip-producer",
+			 required_argument, &skip_producer_parsed, 1},
+#endif
+  { "odr",		 no_argument,	    &odr, 1 },
+  { "no-odr",		 no_argument,	    &odr, 0 },
+  { "odr-mode",		 required_argument, &odr_mode_parsed, 1 },
+  { NULL,		 no_argument,	    0, 0 }
+};
+
+/* Struct describing various usage aspects of a command line option.  */
+struct option_help
+{
+  const char *short_name;
+  const char *long_name;
+  const char *argument;
+  const char *default_value;
+  const char *msg;
+};
+
+/* Describe common command line options.  */
+static struct option_help dwz_common_options_help[] =
+{
+  { "q", "quiet", NULL, NULL,
+    "Silence up the most common messages." },
+  { "l", "low-mem-die-limit", "<COUNT|none>", "10 million DIEs",
+    "Handle files larger than this limit using a slower and more memory"
+    " usage friendly mode and don't optimize those files in multifile mode." },
+  { "L", "max-die-limit", "<COUNT|none>", "50 million DIEs",
+    "Don't optimize files larger than this limit." },
+  { NULL, "odr", NULL, NULL,
+    NULL },
+  { NULL, "no-odr", NULL, "Disabled",
+    "Enable/disable one definition rule optimization." },
+  { NULL, "odr-mode", "<basic|link>", "link",
+    "Set aggressiveness level of one definition rule optimization." },
+  { NULL, "import-optimize", NULL, NULL,
+    NULL },
+  { NULL, "no-import-optimize", NULL, "Enabled",
+    "Enable/disable optimization that reduces the number of"
+    " DW_TAG_imported_unit DIEs." }
+};
+
+/* Describe single-file command line options.  */
+static struct option_help dwz_single_file_options_help[] =
+{
+  { "o", "output", "OUTFILE", NULL,
+    "Place the output in OUTFILE." }
+};
+
+/* Describe mult-file command line options.  */
+static struct option_help dwz_multi_file_options_help[] =
+{
+  { "h", "hardlink", NULL, NULL,
+    "Handle hardlinked files as one file." },
+  { "m", "multifile", "COMMONFILE", NULL,
+    "Enable multifile optimization, placing common DIEs in multifile"
+    " COMMONFILE." },
+  { "M", "multifile-name", "NAME", NULL,
+    "Set .gnu_debugaltlink or .debug_sup in files to NAME." },
+  { "r", "relative", NULL, NULL,
+    "Set .gnu_debugaltlink in files to relative path from file directory"
+    " to multifile." },
+  { "5", "dwarf-5", NULL, NULL,
+    "Emit DWARF 5 standardized supplementary object files instead of"
+    " GNU extension .debug_altlink." }
+};
+
+/* Describe misc command line options.  */
+static struct option_help dwz_misc_options_help[] =
+{
+  { "v", "version", NULL, NULL,
+    "Display dwz version information." },
+  { "?", "help", NULL, NULL,
+    "Display this information." }
+};
+
+/* Print LEN spaces to STREAM.  */
+static void
+do_indent (FILE *stream, unsigned int len)
+{
+  unsigned int i;
+
+  for (i = 0; i < len; i++)
+    fprintf (stream, " ");
+}
+
+/* Print MSG to STREAM, indenting to INDENT and wrapping at LIMIT.
+   Assume starting position is at INDENT.  */
+static void
+wrap (FILE *stream, unsigned int indent, unsigned int limit, const char *msg)
+{
+  unsigned int len = indent;
+  const char *s = msg;
+  while (true)
+    {
+      const char *e = strchr (s, ' ');
+      unsigned int word_len;
+      if (e == NULL)
+	word_len = strlen (s);
+      else
+	word_len = e - s;
+      if (word_len == 0)
+	return;
+
+      if (len + 1 /* space */ + word_len > limit)
+	{
+	  fprintf (stream, "\n");
+	  do_indent (stream ,indent);
+	  len = indent;
+	}
+      else if (len > indent)
+	{
+	  fprintf (stream, " ");
+	  len += 1;
+	}
+
+      if (e != NULL)
+	{
+	  const char *i;
+	  for (i = s; i < e; ++i)
+	    fprintf (stream, "%c", *i);
+	}
+      else
+	fprintf (stream, "%s", s);
+      len += word_len;
+
+      if (e == NULL)
+	break;
+
+      s = e + 1;
+    }
+}
+
+/* Print OPTIONS_HELP of length H to STREAM, indenting to help message to
+   INDENT an wrapping at LIMIT.  */
+static void
+print_options_help (FILE *stream, struct option_help *options_help, unsigned int n,
+		    unsigned int indent, unsigned int limit)
+{
+  unsigned len;
+  const char *s;
+  unsigned int i;
+
+  for (i = 0; i <  n; ++i)
+    {
+      len = 0;
+
+      fprintf (stream, "  ");
+      len += 2;
+
+      s = options_help[i].short_name;
+      if (s)
+	{
+	  fprintf (stream, "-%s", s);
+	  len += 2;
+	}
+
+      s = options_help[i].long_name;
+      if (len == 4)
+	{
+	  fprintf (stream, ", ");
+	  len += 2;
+	}
+      fprintf (stream, "--%s", s);
+      len += 2 + strlen (s);
+
+      s = options_help[i].argument;
+      if (s)
+	{
+	  fprintf (stream, " %s", s);
+	  len += 1 + strlen (s);
+	}
+
+      s = options_help[i].msg;
+      if (s)
+	{
+	  if (len > indent)
+	    {
+	      fprintf (stream, "\n");
+	      do_indent (stream, indent);
+	    }
+	  else
+	    do_indent (stream, indent - len);
+	  len = indent;
+
+	  wrap (stream, indent, limit, s);
+	}
+      fprintf (stream, "\n");
+
+      s = options_help[i].default_value;
+      if (s)
+	{
+	  do_indent (stream, indent);
+	  fprintf (stream, "Default value: %s.\n", s);
+	}
+    }
+}
+
+/* Print usage and exit.  */
+static void
+usage (const char *progname, int failing)
+{
+  unsigned int n;
+  unsigned int indent, limit;
+  FILE *stream = failing ? stderr : stdout;
+
+  fprintf (stream,
+	   ("Usage:\n"
+	    "  %s [common options] [-h] [-m COMMONFILE] [-M NAME | -r] [FILES]\n"
+	    "  %s [common options] -o OUTFILE FILE\n"
+	    "  %s [ -v | -? ]\n"),
+	   progname, progname, progname);
+
+  indent = 30;
+  limit = 80;
+  fprintf (stream, "Common options:\n");
+  n = (sizeof (dwz_common_options_help)
+       / sizeof (dwz_common_options_help[0]));
+  print_options_help (stream, dwz_common_options_help, n, indent, limit);
+
+  fprintf (stream, "Single-file options:\n");
+  n = (sizeof (dwz_single_file_options_help)
+       / sizeof (dwz_single_file_options_help[0]));
+  print_options_help (stream, dwz_single_file_options_help, n, indent, limit);
+
+  fprintf (stream, "Multi-file options:\n");
+  n = (sizeof (dwz_multi_file_options_help)
+       / sizeof (dwz_multi_file_options_help[0]));
+  print_options_help (stream, dwz_multi_file_options_help, n, indent, limit);
+
+  fprintf (stream, "Miscellaneous options:\n");
+  n = (sizeof (dwz_misc_options_help)
+       / sizeof (dwz_misc_options_help[0]));
+  print_options_help (stream, dwz_misc_options_help, n, indent, limit);
+
+#if DEVEL
+  fprintf (stream, "Development options:\n");
+  fprintf (stream, "%s",
+	   ("  --devel-trace\n"
+	    "  --devel-progress\n"
+	    "  --devel-progress-mem\n"
+	    "  --devel-stats\n"
+	    "  --devel-ignore-size\n"
+	    "  --devel-ignore-locus\n"
+	    "  --devel-force\n"
+	    "  --devel-save-temps\n"
+	    "  --devel-dump-checksum\n"
+	    "  --devel-dump-dies\n"
+	    "  --devel-dump-dups\n"
+	    "  --devel-dump-pus\n"
+	    "  --devel-unoptimized-multifile\n"
+	    "  --devel-verify-dups\n"
+	    "  --devel-verify-edges\n"
+	    "  --devel-dump-edges\n"
+	    "  --devel-partition-dups-opt\n"
+	    "  --devel-die-count-method\n"
+	    "  --devel-deduplication-mode={none,intra-cu,inter-cu}\n"
+	    "  --devel-uni-lang / --devel-no-uni-lang\n"
+	    "  --devel-gen-cu / --devel-no-gen-cu\n"
+	    "  --devel-skip-producer <producer>\n"));
+#endif
+
+  exit (failing);
+}
+
+/* Print version and exit.  */
+static void
+version (void)
+{
+  printf ("dwz version " DWZ_VERSION "\n"
+	  "Copyright (C) " RH_YEARS " Red Hat, Inc.\n"
+	  "Copyright (C) " FSF_YEARS " Free Software Foundation, Inc.\n"
+	  "Copyright (C) " SUSE_YEARS " SUSE LLC.\n"
+	  "This program is free software; you may redistribute it under the terms of\n"
+	  "the GNU General Public License version 3 or (at your option) any later version.\n"
+	  "This program has absolutely no warranty.\n");
+  exit (0);
+}
+
+static const char **skip_producers;
+static size_t skip_producers_size;
+static size_t nr_skip_producers;
+
+static void
+add_skip_producer (const char *producer)
+{
+  size_t alloc_size;
+  if (skip_producers == NULL)
+    {
+      skip_producers_size = 10;
+      alloc_size = skip_producers_size * sizeof (const char *);
+      skip_producers = malloc (alloc_size);
+    }
+  else if (nr_skip_producers == skip_producers_size)
+    {
+      skip_producers_size += 10;
+      alloc_size = skip_producers_size * sizeof (const char *);
+      skip_producers = realloc (skip_producers, alloc_size);
+    }
+
+  skip_producers[nr_skip_producers] = producer;
+  nr_skip_producers++;
+}
+
+bool
+skip_producer (const char *producer)
+{
+  size_t i;
+
+  if (producer == NULL)
+    return false;
+
+  for (i = 0; i < nr_skip_producers; ++i)
+    {
+      const char *skip = skip_producers[i];
+      if (strncmp (skip, producer, strlen (skip)) == 0)
+	return true;
+    }
+
+  return false;
+}
+
+/* Parse command line arguments in ARGV.  */
+void
+parse_args (int argc, char *argv[], bool *hardlink, const char **outfile)
+{
+  unsigned long l;
+  char *end;
+
+  while (1)
+    {
+      int option_index = -1;
+      int c = getopt_long (argc, argv, "m:o:qhl:L:M:r?v5", dwz_options,
+			   &option_index);
+      if (c == -1)
+	break;
+      switch (c)
+	{
+	default:
+	case '?':
+	  usage (argv[0], option_index == -1);
+	  break;
+
+	case 0:
+	  /* Option handled by getopt_long.  */
+	  if (die_count_method_parsed)
+	    {
+	      die_count_method_parsed = 0;
+	      if (strcmp (optarg, "none") == 0)
+		{
+		  die_count_method = none;
+		  break;
+		}
+	      if (strcmp (optarg, "estimate") == 0)
+		{
+		  die_count_method = estimate;
+		  break;
+		}
+	      error (1, 0, "invalid argument --devel-die-count-method %s",
+		     optarg);
+	    }
+	  if (deduplication_mode_parsed)
+	    {
+	      deduplication_mode_parsed = 0;
+	      if (strcmp (optarg, "none") == 0)
+		{
+		  deduplication_mode = dm_none;
+		  break;
+		}
+	      if (strcmp (optarg, "intra-cu") == 0)
+		{
+		  deduplication_mode = dm_intra_cu;
+		  break;
+		}
+	      if (strcmp (optarg, "inter-cu") == 0)
+		{
+		  deduplication_mode = dm_inter_cu;
+		  break;
+		}
+	      error (1, 0, "invalid argument --devel-deduplication-mode %s",
+		     optarg);
+	    }
+	  if (odr_mode_parsed)
+	    {
+	      odr_mode_parsed = 0;
+	      if (strcmp (optarg, "basic") == 0)
+		{
+		  odr_mode = ODR_BASIC;
+		  break;
+		}
+	      if (strcmp (optarg, "link") == 0)
+		{
+		  odr_mode = ODR_LINK;
+		  break;
+		}
+	      error (1, 0, "invalid argument --odr-mode %s",
+		     optarg);
+	    }
+	  if (skip_producer_parsed)
+	    {
+	      skip_producer_parsed = 0;
+	      add_skip_producer (optarg);
+
+#if DEVEL
+	      skip_producers_p = 1;
+#endif
+	    }
+	  break;
+
+	case 'o':
+	  *outfile = optarg;
+	  break;
+
+	case 'm':
+	  multifile = optarg;
+	  break;
+
+	case 'q':
+	  quiet = true;
+	  break;
+
+	case 'h':
+	  *hardlink = true;
+	  break;
+
+	case 'M':
+	  multifile_name = optarg;
+	  break;
+
+	case 'r':
+	  multifile_relative = true;
+	  break;
+
+	case 'l':
+	  if (strcmp (optarg, "none") == 0)
+	    {
+	      low_mem_die_limit = -1U;
+	      break;
+	    }
+	  l = strtoul (optarg, &end, 0);
+	  if (*end != '\0' || optarg == end || (unsigned int) l != l)
+	    error (1, 0, "invalid argument -l %s", optarg);
+	  low_mem_die_limit = l;
+	  break;
+
+	case 'L':
+	  if (strcmp (optarg, "none") == 0)
+	    {
+	      max_die_limit = -1U;
+	      break;
+	    }
+	  l = strtoul (optarg, &end, 0);
+	  if (*end != '\0' || optarg == end || (unsigned int) l != l)
+	    error (1, 0, "invalid argument -L %s", optarg);
+	  max_die_limit = l;
+	  break;
+
+	case '5':
+	  dwarf_5 = true;
+	  break;
+
+	case 'v':
+	  version ();
+	  break;
+	}
+    }
+
+  if (progress_mem_p)
+    progress_p = 1;
+
+  /* Specifying a low-mem die-limit that is larger than or equal to the
+     max die-limit has the effect of disabling low-mem mode.  Make this
+     explicit by setting it to the 'none' value.  */
+  if (low_mem_die_limit != -1U
+      && low_mem_die_limit >= max_die_limit)
+    low_mem_die_limit = -1U;
+
+  if (multifile_relative && multifile_name)
+    error (1, 0, "-M and -r options can't be specified together");
+}
diff --git a/args.h b/args.h
new file mode 100644
index 0000000..c899003
--- /dev/null
+++ b/args.h
@@ -0,0 +1,94 @@
+/* Copyright (C) 2001-2021 Red Hat, Inc.
+   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2019-2021 SUSE LLC.
+   Written by Jakub Jelinek <jakub@redhat.com>, 2012.
+
+   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 2, 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; see the file COPYING.  If not, write to
+   the Free Software Foundation, 51 Franklin Street - Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
+
+#if DEVEL
+extern int tracing;
+extern int ignore_size;
+extern int ignore_locus;
+extern int dump_checksum_p;
+extern int dump_dies_p;
+extern int dump_dups_p;
+extern int dump_pus_p;
+extern int verify_dups_p;
+extern int verify_edge_freelist;
+extern int stats_p;
+extern int checksum_cycle_opt;
+extern int skip_producers_p;
+#else
+#define tracing 0
+#define ignore_size 0
+#define ignore_locus 0
+#define dump_checksum_p 0
+#define dump_dies_p 0
+#define dump_dups_p 0
+#define dump_pus_p 0
+#define verify_dups_p 0
+#define stats_p 0
+#define checksum_cycle_opt 1
+#define skip_producers_p 0
+#endif
+
+extern int unoptimized_multifile;
+extern int save_temps;
+extern int verify_edges_p;
+extern int dump_edges_p;
+extern int partition_dups_opt;
+extern int progress_p;
+extern int progress_mem_p;
+extern int import_opt_p;
+extern int force_p;
+
+enum deduplication_mode
+{
+  dm_none,
+  dm_intra_cu,
+  dm_inter_cu
+};
+extern enum deduplication_mode deduplication_mode;
+
+extern int uni_lang_p;
+extern int gen_cu_p;
+
+enum die_count_methods
+{
+  none,
+  estimate
+};
+extern enum die_count_methods die_count_method;
+
+extern int odr;
+enum odr_mode { ODR_BASIC, ODR_LINK };
+extern enum odr_mode odr_mode;
+
+extern const char *multifile;
+extern const char *multifile_name;
+extern bool multifile_relative;
+
+extern unsigned char multifile_mode;
+
+extern bool dwarf_5;
+
+extern bool quiet;
+
+extern unsigned int low_mem_die_limit;
+extern unsigned int max_die_limit;
+
+extern void parse_args (int, char *[], bool *, const char **);
+extern bool skip_producer (const char *producer);
diff --git a/dwz.c b/dwz.c
index 8f64a34..31a0dd3 100644
--- a/dwz.c
+++ b/dwz.c
@@ -22,7 +22,6 @@
 #include <errno.h>
 #include <error.h>
 #include <fcntl.h>
-#include <getopt.h>
 #include <setjmp.h>
 #include <string.h>
 #include <stdbool.h>
@@ -42,6 +41,7 @@
 #include "dwarf2.h"
 #include "hashtab.h"
 #include "sha1.h"
+#include "args.h"
 
 #ifndef SHF_COMPRESSED
  /* Glibc elf.h contains SHF_COMPRESSED starting v2.22.  Libelf libelf.h has
@@ -148,8 +148,6 @@ print_mem (long m)
   fprintf (stderr, "%ld (%.1f%s)\n", m, h, unit[level]);
 }
 
-static int progress_mem_p;
-
 static void
 report_progress (void)
 {
@@ -235,64 +233,8 @@ static struct obstack ob2;
    and restored during final cleanup.  */
 static struct obstack alt_ob, alt_ob2;
 
-#if DEVEL
-static int tracing;
-static int ignore_size;
-static int ignore_locus;
-static int dump_checksum_p;
-static int dump_dies_p;
-static int dump_dups_p;
-static int dump_pus_p;
-static int verify_dups_p;
-static int verify_edge_freelist;
-static int stats_p;
-static int checksum_cycle_opt = 1;
-static int skip_producers_p;
-#else
-#define tracing 0
-#define ignore_size 0
-#define ignore_locus 0
-#define dump_checksum_p 0
-#define dump_dies_p 0
-#define dump_dups_p 0
-#define dump_pus_p 0
-#define verify_dups_p 0
-#define stats_p 0
-#define checksum_cycle_opt 1
-#define skip_producers_p 0
-#endif
-static int unoptimized_multifile;
-static int save_temps = 0;
-static int verify_edges_p = 0;
-static int dump_edges_p = 0;
-static int partition_dups_opt;
-static int progress_p;
-static int import_opt_p = 1;
-static int force_p = 0;
-enum deduplication_mode
-{
-  dm_none,
-  dm_intra_cu,
-  dm_inter_cu
-};
-static enum deduplication_mode deduplication_mode = dm_inter_cu;
-static int uni_lang_p = 0;
-static int gen_cu_p = 0;
-enum die_count_methods
-{
-  none,
-  estimate
-};
-static enum die_count_methods die_count_method = estimate;
-
-static int odr = 0;
-enum odr_mode { ODR_BASIC, ODR_LINK };
-static enum odr_mode odr_mode = ODR_LINK;
-static int odr_mode_parsed = 0;
 static bool odr_active_p = false;
 
-static int skip_producer_parsed = 0;
-
 /* Struct to gather statistics.  */
 struct stats
 {
@@ -887,18 +829,6 @@ static int multi_endian;
 /* Highest .gdb_index version seen.  */
 static unsigned int multi_gdb_index_ver;
 
-/* Number of DIEs, above which dwz retries processing
-   in low_mem mode (and give up on multifile optimizing
-   the file in question).  */
-static unsigned int low_mem_die_limit = 10000000;
-
-/* Number of DIEs, above which dwz gives up processing
-   input altogether.  */
-static unsigned int max_die_limit = 50000000;
-
-/* Phase of multifile handling.  */
-static unsigned char multifile_mode;
-
 enum multifile_mode_kind
 {
   MULTIFILE_MODE_WR = 1,
@@ -923,29 +853,9 @@ enum multifile_mode_kind
 /* True if running in low_mem mode.  */
 #define low_mem (multifile_mode & MULTIFILE_MODE_LOW_MEM)
 
-/* Filename if inter-file size optimization should be performed.  */
-static const char *multifile;
-
-/* Argument of -M option, i.e. preferred name that should be stored
-   into the .gnu_debugaltlink or .debug_sup section.  */
-static const char *multifile_name;
-
-/* True if -r option is present, i.e. .gnu_debugaltlink or .debug_sup section
-   should contain a filename relative to the directory in which
-   the particular file is present.  */
-static bool multifile_relative;
-
 /* SHA1 checksum (build-id) of the common file.  */
 static unsigned char multifile_sha1[0x14];
 
-/* True if DWARF 5 .debug_sup and DW_FORM_ref_sup4 / DW_FORM_strp_sup
-   should be used instead of the GNU extensions .gnu_debugaltlink
-   and DW_FORM_GNU_ref_alt / DW_FORM_GNU_strp_alt etc.  */
-static bool dwarf_5;
-
-/* True if -q option has been passed.  */
-static bool quiet;
-
 /* A single attribute in abbreviations.  */
 struct abbrev_attr
 {
@@ -6652,49 +6562,6 @@ read_lang (unsigned char *ptr, enum dwarf_form form,
   return ptr;
 }
 
-static const char **skip_producers;
-static size_t skip_producers_size;
-static size_t nr_skip_producers;
-
-static void
-add_skip_producer (const char *producer)
-{
-  size_t alloc_size;
-  if (skip_producers == NULL)
-    {
-      skip_producers_size = 10;
-      alloc_size = skip_producers_size * sizeof (const char *);
-      skip_producers = malloc (alloc_size);
-    }
-  else if (nr_skip_producers == skip_producers_size)
-    {
-      skip_producers_size += 10;
-      alloc_size = skip_producers_size * sizeof (const char *);
-      skip_producers = realloc (skip_producers, alloc_size);
-    }
-
-  skip_producers[nr_skip_producers] = producer;
-  nr_skip_producers++;
-}
-
-static bool
-skip_producer (const char *producer)
-{
-  size_t i;
-
-  if (producer == NULL)
-    return false;
-
-  for (i = 0; i < nr_skip_producers; ++i)
-    {
-      const char *skip = skip_producers[i];
-      if (strncmp (skip, producer, strlen (skip)) == 0)
-	return true;
-    }
-
-  return false;
-}
-
 /* First phase of the DWARF compression.  Parse .debug_info section
    (for kind == DEBUG_INFO) or .debug_types section (for kind == DEBUG_TYPES)
    for each CU in it construct internal representation for the CU
@@ -16389,502 +16256,6 @@ make_temp_file (const char *name)
   return fd;
 }
 
-static int die_count_method_parsed;
-static int deduplication_mode_parsed;
-
-/* Options for getopt_long.  */
-static struct option dwz_options[] =
-{
-  { "help",		 no_argument,	    0, '?' },
-  { "output",		 required_argument, 0, 'o' },
-  { "multifile",	 required_argument, 0, 'm' },
-  { "quiet",		 no_argument,	    0, 'q' },
-  { "hardlink",		 no_argument,	    0, 'h' },
-  { "low-mem-die-limit", required_argument, 0, 'l' },
-  { "max-die-limit",	 required_argument, 0, 'L' },
-  { "multifile-name",	 required_argument, 0, 'M' },
-  { "relative",		 no_argument,	    0, 'r' },
-  { "version",		 no_argument,	    0, 'v' },
-  { "import-optimize",
-			 no_argument,	    &import_opt_p, 1 },
-  { "no-import-optimize",
-			 no_argument,	    &import_opt_p, 0 },
-  { "dwarf-5",		 no_argument,	    0, '5' },
-#if DEVEL
-  { "devel-trace",	 no_argument,	    &tracing, 1 },
-  { "devel-progress",	 no_argument,	    &progress_p, 1 },
-  { "devel-progress-mem",no_argument,	    &progress_mem_p, 1 },
-  { "devel-ignore-size", no_argument,	    &ignore_size, 1 },
-  { "devel-ignore-locus",no_argument,	    &ignore_locus, 1 },
-  { "devel-force",	 no_argument,	    &force_p, 1 },
-  { "devel-save-temps",  no_argument,	    &save_temps, 1 },
-  { "devel-dump-checksum",
-			 no_argument,	    &dump_checksum_p, 1 },
-  { "devel-dump-dies",  no_argument,	    &dump_dies_p, 1 },
-  { "devel-dump-dups",  no_argument,	    &dump_dups_p, 1 },
-  { "devel-dump-pus",  no_argument,	    &dump_pus_p, 1 },
-  { "devel-unoptimized-multifile",
-			 no_argument,	    &unoptimized_multifile, 1 },
-  { "devel-verify-edges",no_argument,	    &verify_edges_p, 1 },
-  { "devel-verify-dups", no_argument,	    &verify_dups_p, 1 },
-  { "devel-dump-edges",  no_argument,	    &dump_edges_p, 1 },
-  { "devel-partition-dups-opt",
-			 no_argument,	    &partition_dups_opt, 1 },
-  { "devel-die-count-method",
-			 required_argument, &die_count_method_parsed, 1 },
-  { "devel-stats",	 no_argument,	    &stats_p, 1 },
-  { "devel-deduplication-mode",
-			 required_argument, &deduplication_mode_parsed, 1 },
-  { "devel-uni-lang",
-			 no_argument,	    &uni_lang_p, 1 },
-  { "devel-no-uni-lang",
-			 no_argument,	    &uni_lang_p, 0 },
-  { "devel-gen-cu",
-			 no_argument,	    &gen_cu_p, 1 },
-  { "devel-no-gen-cu",
-			 no_argument,	    &gen_cu_p, 0 },
-  { "devel-checksum-cycle-opt",
-			 no_argument,	    &checksum_cycle_opt, 1 },
-  { "devel-no-checksum-cycle-opt",
-			 no_argument,	    &checksum_cycle_opt, 0 },
-  { "devel-skip-producer",
-			 required_argument, &skip_producer_parsed, 1},
-#endif
-  { "odr",		 no_argument,	    &odr, 1 },
-  { "no-odr",		 no_argument,	    &odr, 0 },
-  { "odr-mode",		 required_argument, &odr_mode_parsed, 1 },
-  { NULL,		 no_argument,	    0, 0 }
-};
-
-/* Struct describing various usage aspects of a command line option.  */
-struct option_help
-{
-  const char *short_name;
-  const char *long_name;
-  const char *argument;
-  const char *default_value;
-  const char *msg;
-};
-
-/* Describe common command line options.  */
-static struct option_help dwz_common_options_help[] =
-{
-  { "q", "quiet", NULL, NULL,
-    "Silence up the most common messages." },
-  { "l", "low-mem-die-limit", "<COUNT|none>", "10 million DIEs",
-    "Handle files larger than this limit using a slower and more memory"
-    " usage friendly mode and don't optimize those files in multifile mode." },
-  { "L", "max-die-limit", "<COUNT|none>", "50 million DIEs",
-    "Don't optimize files larger than this limit." },
-  { NULL, "odr", NULL, NULL,
-    NULL },
-  { NULL, "no-odr", NULL, "Disabled",
-    "Enable/disable one definition rule optimization." },
-  { NULL, "odr-mode", "<basic|link>", "link",
-    "Set aggressiveness level of one definition rule optimization." },
-  { NULL, "import-optimize", NULL, NULL,
-    NULL },
-  { NULL, "no-import-optimize", NULL, "Enabled",
-    "Enable/disable optimization that reduces the number of"
-    " DW_TAG_imported_unit DIEs." }
-};
-
-/* Describe single-file command line options.  */
-static struct option_help dwz_single_file_options_help[] =
-{
-  { "o", "output", "OUTFILE", NULL,
-    "Place the output in OUTFILE." }
-};
-
-/* Describe mult-file command line options.  */
-static struct option_help dwz_multi_file_options_help[] =
-{
-  { "h", "hardlink", NULL, NULL,
-    "Handle hardlinked files as one file." },
-  { "m", "multifile", "COMMONFILE", NULL,
-    "Enable multifile optimization, placing common DIEs in multifile"
-    " COMMONFILE." },
-  { "M", "multifile-name", "NAME", NULL,
-    "Set .gnu_debugaltlink or .debug_sup in files to NAME." },
-  { "r", "relative", NULL, NULL,
-    "Set .gnu_debugaltlink in files to relative path from file directory"
-    " to multifile." },
-  { "5", "dwarf-5", NULL, NULL,
-    "Emit DWARF 5 standardized supplementary object files instead of"
-    " GNU extension .debug_altlink." }
-};
-
-/* Describe misc command line options.  */
-static struct option_help dwz_misc_options_help[] =
-{
-  { "v", "version", NULL, NULL,
-    "Display dwz version information." },
-  { "?", "help", NULL, NULL,
-    "Display this information." }
-};
-
-/* Print LEN spaces to STREAM.  */
-static void
-do_indent (FILE *stream, unsigned int len)
-{
-  unsigned int i;
-
-  for (i = 0; i < len; i++)
-    fprintf (stream, " ");
-}
-
-/* Print MSG to STREAM, indenting to INDENT and wrapping at LIMIT.
-   Assume starting position is at INDENT.  */
-static void
-wrap (FILE *stream, unsigned int indent, unsigned int limit, const char *msg)
-{
-  unsigned int len = indent;
-  const char *s = msg;
-  while (true)
-    {
-      const char *e = strchr (s, ' ');
-      unsigned int word_len;
-      if (e == NULL)
-	word_len = strlen (s);
-      else
-	word_len = e - s;
-      if (word_len == 0)
-	return;
-
-      if (len + 1 /* space */ + word_len > limit)
-	{
-	  fprintf (stream, "\n");
-	  do_indent (stream ,indent);
-	  len = indent;
-	}
-      else if (len > indent)
-	{
-	  fprintf (stream, " ");
-	  len += 1;
-	}
-
-      if (e != NULL)
-	{
-	  const char *i;
-	  for (i = s; i < e; ++i)
-	    fprintf (stream, "%c", *i);
-	}
-      else
-	fprintf (stream, "%s", s);
-      len += word_len;
-
-      if (e == NULL)
-	break;
-
-      s = e + 1;
-    }
-}
-
-/* Print OPTIONS_HELP of length H to STREAM, indenting to help message to
-   INDENT an wrapping at LIMIT.  */
-static void
-print_options_help (FILE *stream, struct option_help *options_help, unsigned int n,
-		    unsigned int indent, unsigned int limit)
-{
-  unsigned len;
-  const char *s;
-  unsigned int i;
-
-  for (i = 0; i <  n; ++i)
-    {
-      len = 0;
-
-      fprintf (stream, "  ");
-      len += 2;
-
-      s = options_help[i].short_name;
-      if (s)
-	{
-	  fprintf (stream, "-%s", s);
-	  len += 2;
-	}
-
-      s = options_help[i].long_name;
-      if (len == 4)
-	{
-	  fprintf (stream, ", ");
-	  len += 2;
-	}
-      fprintf (stream, "--%s", s);
-      len += 2 + strlen (s);
-
-      s = options_help[i].argument;
-      if (s)
-	{
-	  fprintf (stream, " %s", s);
-	  len += 1 + strlen (s);
-	}
-
-      s = options_help[i].msg;
-      if (s)
-	{
-	  if (len > indent)
-	    {
-	      fprintf (stream, "\n");
-	      do_indent (stream, indent);
-	    }
-	  else
-	    do_indent (stream, indent - len);
-	  len = indent;
-
-	  wrap (stream, indent, limit, s);
-	}
-      fprintf (stream, "\n");
-
-      s = options_help[i].default_value;
-      if (s)
-	{
-	  do_indent (stream, indent);
-	  fprintf (stream, "Default value: %s.\n", s);
-	}
-    }
-}
-
-/* Print usage and exit.  */
-static void
-usage (const char *progname, int failing)
-{
-  unsigned int n;
-  unsigned int indent, limit;
-  FILE *stream = failing ? stderr : stdout;
-
-  fprintf (stream,
-	   ("Usage:\n"
-	    "  %s [common options] [-h] [-m COMMONFILE] [-M NAME | -r] [FILES]\n"
-	    "  %s [common options] -o OUTFILE FILE\n"
-	    "  %s [ -v | -? ]\n"),
-	   progname, progname, progname);
-
-  indent = 30;
-  limit = 80;
-  fprintf (stream, "Common options:\n");
-  n = (sizeof (dwz_common_options_help)
-       / sizeof (dwz_common_options_help[0]));
-  print_options_help (stream, dwz_common_options_help, n, indent, limit);
-
-  fprintf (stream, "Single-file options:\n");
-  n = (sizeof (dwz_single_file_options_help)
-       / sizeof (dwz_single_file_options_help[0]));
-  print_options_help (stream, dwz_single_file_options_help, n, indent, limit);
-
-  fprintf (stream, "Multi-file options:\n");
-  n = (sizeof (dwz_multi_file_options_help)
-       / sizeof (dwz_multi_file_options_help[0]));
-  print_options_help (stream, dwz_multi_file_options_help, n, indent, limit);
-
-  fprintf (stream, "Miscellaneous options:\n");
-  n = (sizeof (dwz_misc_options_help)
-       / sizeof (dwz_misc_options_help[0]));
-  print_options_help (stream, dwz_misc_options_help, n, indent, limit);
-
-#if DEVEL
-  fprintf (stream, "Development options:\n");
-  fprintf (stream, "%s",
-	   ("  --devel-trace\n"
-	    "  --devel-progress\n"
-	    "  --devel-progress-mem\n"
-	    "  --devel-stats\n"
-	    "  --devel-ignore-size\n"
-	    "  --devel-ignore-locus\n"
-	    "  --devel-force\n"
-	    "  --devel-save-temps\n"
-	    "  --devel-dump-checksum\n"
-	    "  --devel-dump-dies\n"
-	    "  --devel-dump-dups\n"
-	    "  --devel-dump-pus\n"
-	    "  --devel-unoptimized-multifile\n"
-	    "  --devel-verify-dups\n"
-	    "  --devel-verify-edges\n"
-	    "  --devel-dump-edges\n"
-	    "  --devel-partition-dups-opt\n"
-	    "  --devel-die-count-method\n"
-	    "  --devel-deduplication-mode={none,intra-cu,inter-cu}\n"
-	    "  --devel-uni-lang / --devel-no-uni-lang\n"
-	    "  --devel-gen-cu / --devel-no-gen-cu\n"
-	    "  --devel-skip-producer <producer>\n"));
-#endif
-
-  exit (failing);
-}
-
-/* Print version and exit.  */
-static void
-version (void)
-{
-  printf ("dwz version " DWZ_VERSION "\n"
-	  "Copyright (C) " RH_YEARS " Red Hat, Inc.\n"
-	  "Copyright (C) " FSF_YEARS " Free Software Foundation, Inc.\n"
-	  "Copyright (C) " SUSE_YEARS " SUSE LLC.\n"
-	  "This program is free software; you may redistribute it under the terms of\n"
-	  "the GNU General Public License version 3 or (at your option) any later version.\n"
-	  "This program has absolutely no warranty.\n");
-  exit (0);
-}
-
-/* Parse command line arguments in ARGV.  */
-static void
-parse_args (int argc, char *argv[], bool *hardlink, const char **outfile)
-{
-  unsigned long l;
-  char *end;
-
-  while (1)
-    {
-      int option_index = -1;
-      int c = getopt_long (argc, argv, "m:o:qhl:L:M:r?v5", dwz_options,
-			   &option_index);
-      if (c == -1)
-	break;
-      switch (c)
-	{
-	default:
-	case '?':
-	  usage (argv[0], option_index == -1);
-	  break;
-
-	case 0:
-	  /* Option handled by getopt_long.  */
-	  if (die_count_method_parsed)
-	    {
-	      die_count_method_parsed = 0;
-	      if (strcmp (optarg, "none") == 0)
-		{
-		  die_count_method = none;
-		  break;
-		}
-	      if (strcmp (optarg, "estimate") == 0)
-		{
-		  die_count_method = estimate;
-		  break;
-		}
-	      error (1, 0, "invalid argument --devel-die-count-method %s",
-		     optarg);
-	    }
-	  if (deduplication_mode_parsed)
-	    {
-	      deduplication_mode_parsed = 0;
-	      if (strcmp (optarg, "none") == 0)
-		{
-		  deduplication_mode = dm_none;
-		  break;
-		}
-	      if (strcmp (optarg, "intra-cu") == 0)
-		{
-		  deduplication_mode = dm_intra_cu;
-		  break;
-		}
-	      if (strcmp (optarg, "inter-cu") == 0)
-		{
-		  deduplication_mode = dm_inter_cu;
-		  break;
-		}
-	      error (1, 0, "invalid argument --devel-deduplication-mode %s",
-		     optarg);
-	    }
-	  if (odr_mode_parsed)
-	    {
-	      odr_mode_parsed = 0;
-	      if (strcmp (optarg, "basic") == 0)
-		{
-		  odr_mode = ODR_BASIC;
-		  break;
-		}
-	      if (strcmp (optarg, "link") == 0)
-		{
-		  odr_mode = ODR_LINK;
-		  break;
-		}
-	      error (1, 0, "invalid argument --odr-mode %s",
-		     optarg);
-	    }
-	  if (skip_producer_parsed)
-	    {
-	      skip_producer_parsed = 0;
-	      add_skip_producer (optarg);
-
-#if DEVEL
-	      skip_producers_p = 1;
-#endif
-	    }
-	  break;
-
-	case 'o':
-	  *outfile = optarg;
-	  break;
-
-	case 'm':
-	  multifile = optarg;
-	  break;
-
-	case 'q':
-	  quiet = true;
-	  break;
-
-	case 'h':
-	  *hardlink = true;
-	  break;
-
-	case 'M':
-	  multifile_name = optarg;
-	  break;
-
-	case 'r':
-	  multifile_relative = true;
-	  break;
-
-	case 'l':
-	  if (strcmp (optarg, "none") == 0)
-	    {
-	      low_mem_die_limit = -1U;
-	      break;
-	    }
-	  l = strtoul (optarg, &end, 0);
-	  if (*end != '\0' || optarg == end || (unsigned int) l != l)
-	    error (1, 0, "invalid argument -l %s", optarg);
-	  low_mem_die_limit = l;
-	  break;
-
-	case 'L':
-	  if (strcmp (optarg, "none") == 0)
-	    {
-	      max_die_limit = -1U;
-	      break;
-	    }
-	  l = strtoul (optarg, &end, 0);
-	  if (*end != '\0' || optarg == end || (unsigned int) l != l)
-	    error (1, 0, "invalid argument -L %s", optarg);
-	  max_die_limit = l;
-	  break;
-
-	case '5':
-	  dwarf_5 = true;
-	  break;
-
-	case 'v':
-	  version ();
-	  break;
-	}
-    }
-
-  if (progress_mem_p)
-    progress_p = 1;
-
-  /* Specifying a low-mem die-limit that is larger than or equal to the
-     max die-limit has the effect of disabling low-mem mode.  Make this
-     explicit by setting it to the 'none' value.  */
-  if (low_mem_die_limit != -1U
-      && low_mem_die_limit >= max_die_limit)
-    low_mem_die_limit = -1U;
-
-  if (multifile_relative && multifile_name)
-    error (1, 0, "-M and -r options can't be specified together");
-}
-
 /* Dwarf-compress FILE.  If OUTFILE, write to result to OUTFILE, otherwise
    modify FILE.  */
 static int

                 reply	other threads:[~2021-03-17 10:37 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210317103754.GA13562@delia \
    --to=tdevries@suse.de \
    --cc=dwz@sourceware.org \
    --cc=jakub@redhat.com \
    --cc=mark@klomp.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).