public inbox for libabigail@sourceware.org
 help / color / mirror / Atom feed
From: Matthias Maennich <maennich@google.com>
To: libabigail@sourceware.org
Cc: dodji@seketeli.org, gprocida@google.com, kernel-team@android.com,
	 maennich@google.com
Subject: [PATCH 08/20] corpus: make get_unreferenced_(function|variable)_symbols use the new symtab
Date: Wed, 27 Jan 2021 12:58:41 +0000	[thread overview]
Message-ID: <20210127125853.886677-9-maennich@google.com> (raw)
In-Reply-To: <20210127125853.886677-1-maennich@google.com>

Make the corresponding members an implementation detail of corpus::priv.
They get computed based on the new symtab whenever they are accessed
first with an atomic instantiation. That simplifies the implementation
and homogenizes the access to functions and variables. Sorting does not
need to be done as the symtab already gives a guarantee for that.

        * src/abg-corpus-priv.h (corpus::priv::unrefed_var_symbols): make
          private, mutable and optional.
          (corpus::unrefed_fun_symbols): Likewise.
          (corpus::priv::get_unreferenced_function_symbols): New method declaration.
          (corpus::priv::get_unreferenced_variable_symbols): Likewise.
        * src/abg-corpus.cc
          (corpus::priv::build_unreferenced_symbols_tables): Delete method.
          (corpus::priv::get_unreferenced_function_symbols): New method implementation.
          (corpus::priv::get_unreferenced_variable_symbols): Likewise.
          (corpus::get_unreferenced_function_symbols): Proxy call to corpus::priv.
          (corpus::get_unreferenced_variable_symbols): Likewise.

Reviewed-by: Giuliano Procida <gprocida@google.com>
Signed-off-by: Matthias Maennich <maennich@google.com>
---
 src/abg-corpus-priv.h |  13 ++-
 src/abg-corpus.cc     | 246 +++++++++++++++++++-----------------------
 2 files changed, 116 insertions(+), 143 deletions(-)

diff --git a/src/abg-corpus-priv.h b/src/abg-corpus-priv.h
index 282796e1b685..c8bf7f9d4cf6 100644
--- a/src/abg-corpus-priv.h
+++ b/src/abg-corpus-priv.h
@@ -686,8 +686,6 @@ struct corpus::priv
   symtab_reader::symtab_sptr			symtab_;
   string_elf_symbols_map_sptr			fun_symbol_map;
   string_elf_symbols_map_sptr			undefined_fun_symbol_map;
-  elf_symbols					unrefed_fun_symbols;
-  elf_symbols					unrefed_var_symbols;
   // The type maps contained in this data member are populated if the
   // corpus follows the One Definition Rule and thus if there is only
   // one copy of a type with a given name, per corpus. Otherwise, if
@@ -709,8 +707,10 @@ private:
 
   mutable abg_compat::optional<elf_symbols> sorted_var_symbols;
   mutable abg_compat::optional<elf_symbols> sorted_undefined_var_symbols;
+  mutable abg_compat::optional<elf_symbols> unrefed_var_symbols;
   mutable abg_compat::optional<elf_symbols> sorted_fun_symbols;
   mutable abg_compat::optional<elf_symbols> sorted_undefined_fun_symbols;
+  mutable abg_compat::optional<elf_symbols> unrefed_fun_symbols;
 
 public:
   priv(const string &	p,
@@ -722,9 +722,6 @@ public:
       pub_type_pretty_reprs_()
   {}
 
-  void
-  build_unreferenced_symbols_tables();
-
   type_maps&
   get_types();
 
@@ -737,12 +734,18 @@ public:
   const elf_symbols&
   get_sorted_undefined_fun_symbols() const;
 
+  const elf_symbols&
+  get_unreferenced_function_symbols() const;
+
   const elf_symbols&
   get_sorted_var_symbols() const;
 
   const elf_symbols&
   get_sorted_undefined_var_symbols() const;
 
+  const elf_symbols&
+  get_unreferenced_variable_symbols() const;
+
   unordered_set<interned_string, hash_interned_string>*
   get_public_types_pretty_representations();
 
diff --git a/src/abg-corpus.cc b/src/abg-corpus.cc
index 75f897eb72a8..f9f51a360707 100644
--- a/src/abg-corpus.cc
+++ b/src/abg-corpus.cc
@@ -302,132 +302,6 @@ struct comp_elf_symbols_functor
 
 // <corpus stuff>
 
-
-/// Build the tables of symbols that are not referenced by any
-/// function or variables of corpus::get_functions() or
-/// corpus::get_variables().
-///
-/// Note that this function considers the list of function and
-/// variable symbols to keep, that is provided by
-/// corpus::get_sym_ids_of_fns_to_keep() and
-/// corpus::get_sym_ids_of_vars_to_keep().  If a given unreferenced
-/// function or variable symbol is not in the list of variable and
-/// function symbols to keep, then that symbol is dropped and will not
-/// be part of the resulting table of unreferenced symbol that is
-/// built.
-///
-/// The built tables are accessible from
-/// corpus::get_unreferenced_function_symbols() and
-/// corpus::get_unreferenced_variable_symbols().
-void
-corpus::priv::build_unreferenced_symbols_tables()
-{
-  unordered_map<string, bool> refed_funs, refed_vars;
-  elf_symbol_sptr sym;
-
-  for (vector<function_decl*>::const_iterator f = fns.begin();
-       f != fns.end();
-       ++f)
-    if ((sym = (*f)->get_symbol()))
-      {
-	refed_funs[sym->get_id_string()] = true;
-	for (elf_symbol_sptr a = sym->get_next_alias();
-	     a && !a->is_main_symbol();
-	     a = a->get_next_alias())
-	  refed_funs[a->get_id_string()] = true;
-      }
-
-  for (vector<var_decl*>::const_iterator v = vars.begin();
-       v != vars.end();
-       ++v)
-    if ((sym = (*v)->get_symbol()))
-      {
-	refed_vars[sym->get_id_string()] = true;
-	for (elf_symbol_sptr a = sym->get_next_alias();
-	     a && !a->is_main_symbol();
-	     a = a->get_next_alias())
-	  refed_vars[a->get_id_string()] = true;
-      }
-
-  if (fun_symbol_map)
-    {
-      // Let's assume that the size of the unreferenced symbols vector
-      // is roughly smaller than the size of the symbol table.
-      unrefed_fun_symbols.reserve(fun_symbol_map->size());
-      for (string_elf_symbols_map_type::const_iterator i
-	     = fun_symbol_map->begin();
-	   i != fun_symbol_map->end();
-	   ++i)
-	for (elf_symbols::const_iterator s = i->second.begin();
-	     s != i->second.end();
-	     ++s)
-	  {
-	    string sym_id = (*s)->get_id_string();
-	    if (refed_funs.find(sym_id) == refed_funs.end())
-	      {
-		bool keep = sym_id_fns_to_keep.empty();
-		for (vector<string>::const_iterator i =
-		       sym_id_fns_to_keep.begin();
-		     i != sym_id_fns_to_keep.end();
-		     ++i)
-		  {
-		    if (*i == sym_id)
-		      {
-			keep = true;
-			break;
-		      }
-		  }
-		if (keep)
-		  unrefed_fun_symbols.push_back(*s);
-	      }
-	  }
-
-      comp_elf_symbols_functor comp;
-      std::sort(unrefed_fun_symbols.begin(),
-		unrefed_fun_symbols.end(),
-		comp);
-    }
-
-  if (var_symbol_map)
-    {
-      // Let's assume that the size of the unreferenced symbols vector
-      // is roughly smaller than the size of the symbol table.
-      unrefed_var_symbols.reserve(var_symbol_map->size());
-      for (string_elf_symbols_map_type::const_iterator i
-	     = var_symbol_map->begin();
-	   i != var_symbol_map->end();
-	   ++i)
-	for (elf_symbols::const_iterator s = i->second.begin();
-	     s != i->second.end();
-	     ++s)
-	  {
-	    string sym_id = (*s)->get_id_string();
-	    if (refed_vars.find(sym_id) == refed_vars.end())
-	      {
-		bool keep = sym_id_vars_to_keep.empty();
-		for (vector<string>::const_iterator i =
-		       sym_id_vars_to_keep.begin();
-		     i != sym_id_vars_to_keep.end();
-		     ++i)
-		  {
-		    if (*i == sym_id)
-		      {
-			keep = true;
-			break;
-		      }
-		  }
-		if (keep)
-		  unrefed_var_symbols.push_back(*s);
-	      }
-	  }
-
-      comp_elf_symbols_functor comp;
-      std::sort(unrefed_var_symbols.begin(),
-		unrefed_var_symbols.end(),
-		comp);
-    }
-}
-
 /// Get the maps that associate a name to a certain kind of type.
 type_maps&
 corpus::priv::get_types()
@@ -478,6 +352,59 @@ corpus::priv::get_sorted_undefined_fun_symbols() const
   return *sorted_undefined_fun_symbols;
 }
 
+/// Return a list of symbols that are not referenced by any function of
+/// corpus::get_functions().
+///
+/// Note that this function considers the list of function symbols to keep,
+/// that is provided by corpus::get_sym_ids_of_fns_to_keep(). If a given
+/// unreferenced function symbol is not in the list of functions to keep, then
+/// that symbol is dropped and will not be part of the resulting table of
+/// unreferenced symbol that is built.
+const elf_symbols&
+corpus::priv::get_unreferenced_function_symbols() const
+{
+  if (!unrefed_fun_symbols)
+    {
+      unrefed_fun_symbols = elf_symbols();
+      if (symtab_)
+	{
+	  unordered_map<string, bool> refed_funs;
+
+	  for (const auto& function : fns)
+	    if (elf_symbol_sptr sym = function->get_symbol())
+	      {
+		refed_funs[sym->get_id_string()] = true;
+		for (elf_symbol_sptr a = sym->get_next_alias();
+		     a && !a->is_main_symbol(); a = a->get_next_alias())
+		  refed_funs[a->get_id_string()] = true;
+	      }
+
+	  auto filter = symtab_->make_filter();
+	  filter.set_functions();
+	  for (const auto& symbol :
+	       symtab_reader::filtered_symtab(*symtab_, filter))
+	    {
+	      const std::string sym_id = symbol->get_id_string();
+	      if (refed_funs.find(sym_id) == refed_funs.end())
+		{
+		  bool keep = sym_id_fns_to_keep.empty();
+		  for (const auto& id : sym_id_fns_to_keep)
+		    {
+		      if (id == sym_id)
+			{
+			  keep = true;
+			  break;
+			}
+		    }
+		  if (keep)
+		    unrefed_fun_symbols->push_back(symbol);
+		}
+	    }
+	}
+    }
+  return *unrefed_fun_symbols;
+}
+
 /// Getter for the sorted vector of variable symbols for this corpus.
 ///
 /// Note that the first time this function is called, it computes the
@@ -519,6 +446,59 @@ corpus::priv::get_sorted_undefined_var_symbols() const
   return *sorted_undefined_var_symbols;
 }
 
+/// Return a list of symbols that are not referenced by any variable of
+/// corpus::get_variables().
+///
+/// Note that this function considers the list of variable symbols to keep,
+/// that is provided by corpus::get_sym_ids_of_vars_to_keep(). If a given
+/// unreferenced variable symbol is not in the list of variable to keep, then
+/// that symbol is dropped and will not be part of the resulting table of
+/// unreferenced symbol that is built.
+const elf_symbols&
+corpus::priv::get_unreferenced_variable_symbols() const
+{
+  if (!unrefed_var_symbols)
+    {
+      unrefed_var_symbols = elf_symbols();
+      if (symtab_)
+	{
+	  unordered_map<string, bool> refed_vars;
+	  for (const auto& variable : vars)
+	    if (elf_symbol_sptr sym = variable->get_symbol())
+	      {
+		refed_vars[sym->get_id_string()] = true;
+		for (elf_symbol_sptr a = sym->get_next_alias();
+		     a && !a->is_main_symbol(); a = a->get_next_alias())
+		  refed_vars[a->get_id_string()] = true;
+	      }
+
+	  auto filter = symtab_->make_filter();
+	  filter.set_variables();
+	  for (const auto& symbol :
+	       symtab_reader::filtered_symtab(*symtab_, filter))
+	    {
+	      const std::string sym_id = symbol->get_id_string();
+	      if (refed_vars.find(sym_id) == refed_vars.end())
+		{
+		  bool keep = sym_id_vars_to_keep.empty();
+		  for (const auto& id : sym_id_vars_to_keep)
+		    {
+		      if (id == sym_id)
+			{
+			  keep = true;
+			  break;
+			}
+		    }
+		  if (keep)
+		    unrefed_var_symbols->push_back(symbol);
+		}
+	    }
+	}
+    }
+  return *unrefed_var_symbols;
+}
+
+
 /// Getter of the set of pretty representation of types that are
 /// reachable from public interfaces (global functions and variables).
 ///
@@ -1310,12 +1290,7 @@ corpus::sort_variables()
 /// function exported by the current corpus.
 const elf_symbols&
 corpus::get_unreferenced_function_symbols() const
-{
-  if (priv_->unrefed_fun_symbols.empty()
-      && priv_->unrefed_var_symbols.empty())
-    priv_->build_unreferenced_symbols_tables();
-  return priv_->unrefed_fun_symbols;
-}
+{ return priv_->get_unreferenced_function_symbols(); }
 
 /// Getter of the set of variable symbols that are not referenced by
 /// any variable exported by the current corpus.
@@ -1328,12 +1303,7 @@ corpus::get_unreferenced_function_symbols() const
 /// variable exported by the current corpus.
 const elf_symbols&
 corpus::get_unreferenced_variable_symbols() const
-{
-    if (priv_->unrefed_fun_symbols.empty()
-      && priv_->unrefed_var_symbols.empty())
-    priv_->build_unreferenced_symbols_tables();
-  return priv_->unrefed_var_symbols;
-}
+{ return priv_->get_unreferenced_variable_symbols(); }
 
 /// Accessor for the regex patterns describing the functions to drop
 /// from the public decl table.
-- 
2.30.0.280.ga3ce27912f-goog


  parent reply	other threads:[~2021-01-27 12:59 UTC|newest]

Thread overview: 91+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-06-19 21:42 [PATCH v1 00/16] Refactor (k)symtab reader Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 01/16] abg-cxx-compat: add simplified version of std::optional Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 02/16] abg-cxx-compat: more <functional> support: std::bind and friends Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 03/16] abg-ir: elf_symbol: add is_in_ksymtab field Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 04/16] abg-ir: elf_symbol: add is_suppressed field Matthias Maennich
2020-06-22  9:46   ` Giuliano Procida
2020-06-19 21:42 ` [PATCH v1 05/16] dwarf-reader split: create abg-symtab-reader.{h, cc} and test case Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 06/16] Refactor ELF symbol table reading by adding a new symtab reader Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 07/16] Integrate new symtab reader into corpus and read_context Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 08/16] corpus: make get_(undefined_)?_(var|fun)_symbols use the new symtab Matthias Maennich
2020-06-22  9:53   ` Giuliano Procida
2020-06-19 21:42 ` [PATCH v1 09/16] corpus: make get_unreferenced_(function|variable)_symbols " Matthias Maennich
2020-06-19 21:42 ` [PATCH v1 10/16] abg-reader: avoid using the (var|function)_symbol_map Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 11/16] dwarf-reader: read_context: use new symtab in *_symbols_is_exported Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 12/16] Switch kernel stuff over to new symtab and drop unused code Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 13/16] abg-elf-helpers: migrate ppc64 specific helpers Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 14/16] symtab_reader: add support for ppc64 ELFv1 binaries Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 15/16] abg-corpus: remove symbol maps and their setters Matthias Maennich
2020-06-19 21:43 ` [PATCH v1 16/16] dwarf reader: drop (now) unused code related symbol table reading Matthias Maennich
2020-06-22  9:56   ` Giuliano Procida
2020-07-03 16:46 ` [PATCH v2 00/21] Refactor (k)symtab reader Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 01/21] abg-cxx-compat: add simplified version of std::optional Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 02/21] abg-cxx-compat: more <functional> support: std::bind and friends Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 03/21] abg-ir: elf_symbol: add is_in_ksymtab field Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 04/21] abg-ir: elf_symbol: add is_suppressed field Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 05/21] dwarf-reader split: create abg-symtab-reader.{h, cc} and test case Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 06/21] Refactor ELF symbol table reading by adding a new symtab reader Matthias Maennich
2020-07-20 15:39     ` Dodji Seketeli
2020-07-03 16:46   ` [PATCH v2 07/21] Integrate new symtab reader into corpus and read_context Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 08/21] corpus: make get_(undefined_)?_(var|fun)_symbols use the new symtab Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 09/21] corpus: make get_unreferenced_(function|variable)_symbols " Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 10/21] abg-reader: avoid using the (var|function)_symbol_map Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 11/21] dwarf-reader: read_context: use new symtab in *_symbols_is_exported Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 12/21] Switch kernel stuff over to new symtab and drop unused code Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 13/21] abg-elf-helpers: migrate ppc64 specific helpers Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 14/21] symtab_reader: add support for ppc64 ELFv1 binaries Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 15/21] abg-corpus: remove symbol maps and their setters Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 16/21] dwarf reader: drop now-unused code related to symbol table reading Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 17/21] test-symtab: add tests for whitelisted functions Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 18/21] symtab/dwarf-reader: allow hinting of main symbols for aliases Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 19/21] dwarf-reader/writer: consider aliases when dealing with suppressions Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 20/21] symtab: Add support for MODVERSIONS (CRC checksums) Matthias Maennich
2020-07-03 16:46   ` [PATCH v2 21/21] reader/symtab: Improve handling for suppressed aliases Matthias Maennich
2020-07-20 14:27   ` [PATCH v2 00/21] Refactor (k)symtab reader Dodji Seketeli
2021-01-27 12:58 ` [PATCH 00/20] " Matthias Maennich
2021-01-27 12:58   ` [PATCH 01/20] abg-cxx-compat: add simplified version of std::optional Matthias Maennich
2021-03-09  9:43     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 02/20] abg-ir: elf_symbol: add is_in_ksymtab field Matthias Maennich
2021-03-09 14:05     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 03/20] abg-ir: elf_symbol: add is_suppressed field Matthias Maennich
2021-03-09 18:03     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 04/20] dwarf-reader split: create abg-symtab-reader.{h, cc} and test case Matthias Maennich
2021-03-10 18:00     ` [PATCH 04/20] dwarf-reader split: create abg-symtab-reader.{h,cc} " Dodji Seketeli
2021-01-27 12:58   ` [PATCH 05/20] Refactor ELF symbol table reading by adding a new symtab reader Matthias Maennich
2021-03-12 11:18     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 06/20] Integrate new symtab reader into corpus and read_context Matthias Maennich
2021-03-12 15:04     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 07/20] corpus: make get_(undefined_)?_(var|fun)_symbols use the new symtab Matthias Maennich
2021-03-15 10:05     ` Dodji Seketeli
2021-01-27 12:58   ` Matthias Maennich [this message]
2021-03-15 12:06     ` [PATCH 08/20] corpus: make get_unreferenced_(function|variable)_symbols " Dodji Seketeli
2021-01-27 12:58   ` [PATCH 09/20] abg-reader: avoid using the (var|function)_symbol_map Matthias Maennich
2021-03-15 14:23     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 10/20] dwarf-reader: read_context: use new symtab in *_symbols_is_exported Matthias Maennich
2021-03-15 18:13     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 11/20] Switch kernel stuff over to new symtab and drop unused code Matthias Maennich
2021-03-16 10:38     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 12/20] abg-elf-helpers: migrate ppc64 specific helpers Matthias Maennich
2021-03-16 10:59     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 13/20] symtab_reader: add support for ppc64 ELFv1 binaries Matthias Maennich
2021-03-16 11:39     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 14/20] abg-corpus: remove symbol maps and their setters Matthias Maennich
2021-03-16 18:08     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 15/20] dwarf reader: drop (now) unused code related to symbol table reading Matthias Maennich
2021-03-16 18:42     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 16/20] test-symtab: add tests for whitelisted functions Matthias Maennich
2021-03-17 11:07     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 17/20] symtab/dwarf-reader: allow hinting of main symbols for aliases Matthias Maennich
2021-03-17 13:40     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 18/20] dwarf-reader/writer: consider aliases when dealing with suppressions Matthias Maennich
2021-03-17 15:44     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 19/20] abg-writer.cc: fix write_elf_symbol_reference loop Matthias Maennich
2021-03-17 16:11     ` Dodji Seketeli
2021-01-27 12:58   ` [PATCH 20/20] symtab: Add support for MODVERSIONS (CRC checksums) Matthias Maennich
2021-03-17 17:13     ` Dodji Seketeli
2021-03-17 23:29       ` Giuliano Procida
2021-03-18 22:10         ` Matthias Maennich
2021-03-19 16:55           ` Dodji Seketeli
2021-03-19 18:15     ` Dodji Seketeli
2021-03-29 13:19   ` [GIT PULL] Refactor (k)symtab reader Matthias Maennich
2021-04-02 14:28     ` Dodji Seketeli

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=20210127125853.886677-9-maennich@google.com \
    --to=maennich@google.com \
    --cc=dodji@seketeli.org \
    --cc=gprocida@google.com \
    --cc=kernel-team@android.com \
    --cc=libabigail@sourceware.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).