public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [google gcc-4.9] FDO build for linux kernel
@ 2014-11-13 18:57 Rong Xu
  2014-11-13 20:34 ` Xinliang David Li
  0 siblings, 1 reply; 2+ messages in thread
From: Rong Xu @ 2014-11-13 18:57 UTC (permalink / raw)
  To: GCC Patches; +Cc: David Li

[-- Attachment #1: Type: text/plain, Size: 376 bytes --]

Here is patch that ports our work on FDO linux kernel build support to
gcc-4_9. With this patch, kernel will use the libgcov functions to
dump the gcda files.

This patch also enables LIPO build. But the module grouping is not
computed online. We will use gcov-tool to do this offline.

Tested with kernel FDO build, regression and google internal benchmarks.

Thanks,

-Rong

[-- Attachment #2: kfdo_patch --]
[-- Type: application/octet-stream, Size: 41777 bytes --]

2014-11-12  Rong Xu  <xur@google.com>

	* gcc/coverage.c (is_kernel_build): New decls.
	(coverage_note_define): Set is_kernel_build
	* gcc/gcov-io.c (struct gcov_var): Repalce file operatons
        with macros, and support kernel build.
	(gcov_rewrite): Ditto.
	(gcov_open): Ditto.
	(gcov_close): Ditto.
	(gcov_write_block): Ditto.
	(gcov_write_string_array): Ditto.
	(gcov_read_words): Ditto.
	(gcov_sync): Ditto.
	(gcov_seek): Ditto.
	(gcov_truncate): Ditto.
	(k_popcountll): New function.
	(gcov_read_summary): Support kernel build.
	(gcov_read_comdat_zero_fixup): Ditto.
	* gcc/gcov-io.h: Provide macro defineitons for file operations.
	* gcc/tree-profile.c (is_kernel_build): New global var.
	(init_ic_make_global_vars): Don't emit tls for kernel
        build.
	(tree_init_instrumentation_sampling): Ditto.
	(direct_call_profiling): Ditto.
	* libgcc/Makefile.in : Install new files to gcov-src.
	* libgcc/dyn-ipa.c (gcov_write_module_info): Move to libgcov-driver.c
	and make it public.
	(gcov_write_module_infos): Move the flag setting code from 
	gcov_write_module_info().
	* libgcc/libgcov-driver-kernel.c (gcov_error): New kernel support.
	(allocate_filename_struct): Ditto.
	(gcov_open_by_filename): Ditto.
	(gcov_strip_leading_dirs): Ditto.
	(gcov_set_vfile): Ditto.
	(kernel_file_fclose): Ditto.
	(kernel_file_ftell): Ditto.
	(kernel_file_fseek): Ditto.
	(kernel_file_ftruncate): Ditto.
	(kernel_file_fread): Ditto.
	(kernel_file_fwrite): Ditto.
	(kernel_file_fileno): Ditto.
	* libgcc/libgcov-driver-system.c (gcov_exit_open_gcda_file): Move
	to libgcov-driver.c.
	* libgcc/libgcov-driver.c (free_fn_data): Kernel build support.
	(libgcov-driver-kernel.c): New include to support kernel build.
	(scan_build_info): Reformat to avoid c compiler warning.
	(gcov_exit_merge_gcda): Ditto.
	(gcov_scan_to_function_data): Aviod in kernel build
	(gcov_write_comdat_zero_fixup) : Ditto.
	(gcov_write_import_file): Ditto.
	(gcov_dump_module_info): Ditto.
	(gcov_exit): Ditto.
	(__gcov_init): Ditto.
	(gcov_write_func_counters): Kernel build support.
	(gcov_exit_write_gcda): Ditto.
	(gcov_exit_open_gcda_file): Moved from libgcov-driver.system.c.
	(gcov_exit_dump_gcov): Kernel support (never merge), and
	output modu_info for kernel lipo build.
	(gcov_kernel_dump_gcov_init): New kernel support.
	(gcov_kernel_dump_one_gcov): Ditto.
	(gcov_write_module_info): Move from dyn-ipa.c.
	* libgcc/libgcov-kernel.h: New.
	* libgcc/libgcov.h: Kernel build support.

Index: gcc/coverage.c
===================================================================
--- gcc/coverage.c	(revision 217448)
+++ gcc/coverage.c	(working copy)
@@ -2986,6 +2986,10 @@ coverage_finish (void)
   da_file_name = NULL;
 }
 
+extern bool is_kernel_build;
+
+#define KERNEL_BUILD_PREDEF_STRING "__KERNEL__"
+
 /* Copies the macro def or undef CPP_DEF and saves the copy
    in a list. IS_DEF is a flag indicating if CPP_DEF represents
    a -D or -U.  */
@@ -2998,6 +3002,11 @@ coverage_note_define (const char *cpp_def, bool is
   strcpy (s + 1, cpp_def);
   str_list_append (&cpp_defines_head, &cpp_defines_tail, s);
   num_cpp_defines++;
+
+  /* When -D__KERNEL__ is in the option list, we assume this is
+     compilation for Linux Kernel.  */
+  if (!strcmp(cpp_def, KERNEL_BUILD_PREDEF_STRING))
+    is_kernel_build = is_def;
 }
 
 /* Copies the -imacro/-include FILENAME and saves the copy in a list.  */
Index: gcc/gcov-io.c
===================================================================
--- gcc/gcov-io.c	(revision 217448)
+++ gcc/gcov-io.c	(working copy)
@@ -41,7 +41,7 @@ static void gcov_allocate (unsigned);
 
 GCOV_LINKAGE struct gcov_var
 {
-  FILE *file;
+  _GCOV_FILE *file;
   gcov_position_t start;	/* Position of first byte of block */
   unsigned offset;		/* Read/write position within the block.  */
   unsigned length;		/* Read limit in the block.  */
@@ -94,7 +94,7 @@ gcov_rewrite (void)
   gcov_var.mode = -1; 
   gcov_var.start = 0;
   gcov_var.offset = 0;
-  fseek (gcov_var.file, 0L, SEEK_SET);
+  _GCOV_fseek (gcov_var.file, 0L, SEEK_SET);
 }
 #endif
 
@@ -120,6 +120,7 @@ static inline gcov_unsigned_t from_file (gcov_unsi
    Return zero on failure, >0 on opening an existing file and <0 on
    creating a new one.  */
 
+#ifndef __KERNEL__
 GCOV_LINKAGE int
 #if IN_LIBGCOV
 gcov_open (const char *name)
@@ -190,7 +191,7 @@ gcov_open (const char *name, int mode)
 
       if (fstat (fd, &st) < 0)
 	{
-	  fclose (gcov_var.file);
+	  _GCOV_fclose (gcov_var.file);
 	  gcov_var.file = 0;
 	  return 0;
 	}
@@ -203,13 +204,13 @@ gcov_open (const char *name, int mode)
     gcov_var.mode = mode * 2 + 1;
 #else
   if (mode >= 0)
-    gcov_var.file = fopen (name, (mode > 0) ? "rb" : "r+b");
+    gcov_var.file = _GCOV_fopen (name, (mode > 0) ? "rb" : "r+b");
 
   if (gcov_var.file)
     gcov_var.mode = 1;
   else if (mode <= 0)
     {
-      gcov_var.file = fopen (name, "w+b");
+      gcov_var.file = _GCOV_fopen (name, "w+b");
       if (gcov_var.file)
 	gcov_var.mode = mode * 2 + 1;
     }
@@ -221,7 +222,25 @@ gcov_open (const char *name, int mode)
 
   return 1;
 }
+#else /* __KERNEL__ */
 
+extern _GCOV_FILE *gcov_current_file;
+
+GCOV_LINKAGE int
+gcov_open (const char *name)
+{
+  gcov_var.start = 0; 
+  gcov_var.offset = gcov_var.length = 0; 
+  gcov_var.overread = -1u; 
+  gcov_var.error = 0; 
+  gcov_var.file = gcov_current_file;
+  gcov_var.mode = 1; 
+
+  return 1;
+}
+#endif /* __KERNEL__ */
+
+
 /* Close the current gcov file. Flushes data to disk. Returns nonzero
    on failure or error flag set.  */
 
@@ -234,7 +253,7 @@ gcov_close (void)
       if (gcov_var.offset && gcov_var.mode < 0)
 	gcov_write_block (gcov_var.offset);
 #endif
-      fclose (gcov_var.file);
+      _GCOV_fclose (gcov_var.file);
       gcov_var.file = 0;
       gcov_var.length = 0;
     }
@@ -290,7 +309,7 @@ gcov_allocate (unsigned length)
 static void
 gcov_write_block (unsigned size)
 {
-  if (fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
+  if (_GCOV_fwrite (gcov_var.buffer, size << 2, 1, gcov_var.file) != 1)
     gcov_var.error = 1;
   gcov_var.start += size;
   gcov_var.offset -= size;
@@ -368,7 +387,7 @@ gcov_write_string_array (char **string_array, gcov
 	(strlen (string_array[j]) + sizeof (gcov_unsigned_t)) /
 	sizeof (gcov_unsigned_t);
       aligned_string = (gcov_unsigned_t *)
-	alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
+	__builtin_alloca ((string_len + 1) * sizeof (gcov_unsigned_t));
       memset (aligned_string, 0, (string_len + 1) * sizeof (gcov_unsigned_t));
       aligned_string[0] = string_len;
       strcpy ((char*) (aligned_string + 1), string_array[j]);
@@ -558,7 +577,7 @@ gcov_read_words (unsigned words)
 	gcov_allocate (gcov_var.length + words);
       excess = gcov_var.alloc - gcov_var.length;
 #endif
-      excess = fread (gcov_var.buffer + gcov_var.length,
+      excess = _GCOV_fread (gcov_var.buffer + gcov_var.length,
 		      1, excess << 2, gcov_var.file) >> 2;
       gcov_var.length += excess;
       if (gcov_var.length < words)
@@ -627,6 +646,20 @@ gcov_read_string (void)
 }
 #endif
 
+#ifdef __KERNEL__
+static int
+k_popcountll (long long x)
+{
+  int c = 0;
+  while (x)
+    {
+      c++;
+      x &= (x-1);
+    }
+  return c;
+}
+#endif
+
 GCOV_LINKAGE void
 gcov_read_summary (struct gcov_summary *summary)
 {
@@ -653,8 +686,12 @@ gcov_read_summary (struct gcov_summary *summary)
              hwint.h (where popcount_hwi is declared). However, libgcov.a
              is built by the bootstrapped compiler and therefore the builtins
              are always available.  */
+#ifndef __KERNEL__
           h_cnt += __builtin_popcount (histo_bitvector[bv_ix]);
 #else
+          h_cnt += k_popcountll (histo_bitvector[bv_ix]);
+#endif
+#else
           h_cnt += popcount_hwi (histo_bitvector[bv_ix]);
 #endif
         }
@@ -699,6 +736,7 @@ GCOV_LINKAGE int *
 gcov_read_comdat_zero_fixup (gcov_unsigned_t length,
                              gcov_unsigned_t *num_fns)
 {
+#ifndef __KERNEL__
   unsigned ix, f_ix;
   gcov_unsigned_t num = gcov_read_unsigned ();
   /* The length consists of 1 word to hold the number of functions,
@@ -719,6 +757,9 @@ gcov_read_comdat_zero_fixup (gcov_unsigned_t lengt
     }
   *num_fns = num;
   return zero_fixup_flags;
+#else
+  return NULL;
+#endif
 }
 
 /* Read NUM_STRINGS strings (as an unsigned array) in STRING_ARRAY, and return
@@ -819,8 +860,8 @@ gcov_sync (gcov_position_t base, gcov_unsigned_t l
   else
     {
       gcov_var.offset = gcov_var.length = 0;
-      fseek (gcov_var.file, base << 2, SEEK_SET);
-      gcov_var.start = ftell (gcov_var.file) >> 2;
+      _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET);
+      gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2;
     }
 }
 #endif
@@ -834,8 +875,8 @@ gcov_seek (gcov_position_t base)
   gcc_assert (gcov_var.mode < 0);
   if (gcov_var.offset)
     gcov_write_block (gcov_var.offset);
-  fseek (gcov_var.file, base << 2, SEEK_SET);
-  gcov_var.start = ftell (gcov_var.file) >> 2;
+  _GCOV_fseek (gcov_var.file, base << 2, SEEK_SET);
+  gcov_var.start = _GCOV_ftell (gcov_var.file) >> 2;
 }
 
 /* Truncate the gcov file at the current position.  */
@@ -843,15 +884,19 @@ gcov_seek (gcov_position_t base)
 GCOV_LINKAGE void
 gcov_truncate (void)
 {
+#ifdef __KERNEL__
+  gcc_assert (0);
+#else /* __KERNEL__ */
   long offs;
   int filenum;
   gcc_assert (gcov_var.mode < 0);
   if (gcov_var.offset)
     gcov_write_block (gcov_var.offset);
-  offs = ftell (gcov_var.file);
+  offs = _GCOV_ftell (gcov_var.file);
   filenum = fileno (gcov_var.file);
-  if (offs == -1 || filenum == -1 || ftruncate (filenum, offs))
+  if (offs == -1 || filenum == -1 || _GCOV_ftruncate (filenum, offs))
     gcov_var.error = 1;
+#endif
 }
 #endif
 
Index: gcc/gcov-io.h
===================================================================
--- gcc/gcov-io.h	(revision 217448)
+++ gcc/gcov-io.h	(working copy)
@@ -177,6 +177,18 @@ see the files COPYING3 and COPYING.RUNTIME respect
 #ifndef GCC_GCOV_IO_H
 #define GCC_GCOV_IO_H
 
+#ifndef __KERNEL__
+# define _GCOV_FILE      FILE
+# define _GCOV_fclose    fclose
+# define _GCOV_ftell     ftell
+# define _GCOV_fseek     fseek
+# define _GCOV_ftruncate ftruncate
+# define _GCOV_fread     fread
+# define _GCOV_fwrite    fwrite
+# define _GCOV_fread     fread
+# define _GCOV_fileno    fileno
+#endif
+
 #ifndef IN_LIBGCOV
 /* About the host */
 
Index: gcc/tree-profile.c
===================================================================
--- gcc/tree-profile.c	(revision 217448)
+++ gcc/tree-profile.c	(working copy)
@@ -96,6 +96,11 @@ static GTY(()) tree dc_gcov_type_ptr_var;
 static GTY(()) tree ptr_void;
 static GTY(()) tree gcov_info_decl;
 
+/* When -D__KERNEL__ is in the option list, we assume this is a
+   compilation for Linux Kernel. This is checked and set in
+   coverage.c.  */ 
+bool is_kernel_build;
+
 /* Do initialization work for the edge profiler.  */
 
 /* Add code:
@@ -123,7 +128,7 @@ init_ic_make_global_vars (void)
 		      ptr_void);
       TREE_PUBLIC (ic_void_ptr_var) = 1;
       DECL_EXTERNAL (ic_void_ptr_var) = 1;
-      if (targetm.have_tls)
+      if (targetm.have_tls && !is_kernel_build)
         DECL_TLS_MODEL (ic_void_ptr_var) =
           decl_default_tls_model (ic_void_ptr_var);
       gcov_type_ptr = build_pointer_type (get_gcov_type ());
@@ -133,7 +138,7 @@ init_ic_make_global_vars (void)
 		      gcov_type_ptr);
       TREE_PUBLIC (ic_gcov_type_ptr_var) = 1;
       DECL_EXTERNAL (ic_gcov_type_ptr_var) = 1;
-      if (targetm.have_tls)
+      if (targetm.have_tls && !is_kernel_build)
         DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
           decl_default_tls_model (ic_gcov_type_ptr_var);
     }
@@ -164,7 +169,7 @@ init_ic_make_global_vars (void)
   TREE_STATIC (ic_void_ptr_var) = 1;
   DECL_ARTIFICIAL (ic_void_ptr_var) = 1;
   DECL_INITIAL (ic_void_ptr_var) = NULL;
-  if (targetm.have_tls)
+  if (targetm.have_tls && !is_kernel_build)
     DECL_TLS_MODEL (ic_void_ptr_var) =
       decl_default_tls_model (ic_void_ptr_var);
 
@@ -195,7 +200,7 @@ init_ic_make_global_vars (void)
   TREE_STATIC (ic_gcov_type_ptr_var) = 1;
   DECL_ARTIFICIAL (ic_gcov_type_ptr_var) = 1;
   DECL_INITIAL (ic_gcov_type_ptr_var) = NULL;
-  if (targetm.have_tls)
+  if (targetm.have_tls && !is_kernel_build)
     DECL_TLS_MODEL (ic_gcov_type_ptr_var) =
       decl_default_tls_model (ic_gcov_type_ptr_var);
 
@@ -639,7 +644,7 @@ tree_init_instrumentation_sampling (void)
       TREE_PUBLIC (gcov_sample_counter_decl) = 1;
       DECL_EXTERNAL (gcov_sample_counter_decl) = 1;
       DECL_ARTIFICIAL (gcov_sample_counter_decl) = 1;
-      if (targetm.have_tls)
+      if (targetm.have_tls && !is_kernel_build)
         DECL_TLS_MODEL (gcov_sample_counter_decl) =
             decl_default_tls_model (gcov_sample_counter_decl);
     }
@@ -1404,8 +1409,9 @@ direct_call_profiling (void)
 		      build_pointer_type (gcov_type_node));
       DECL_ARTIFICIAL (dc_gcov_type_ptr_var) = 1;
       DECL_EXTERNAL (dc_gcov_type_ptr_var) = 1;
-      DECL_TLS_MODEL (dc_gcov_type_ptr_var) =
-	decl_default_tls_model (dc_gcov_type_ptr_var);
+      if (targetm.have_tls && !is_kernel_build)
+        DECL_TLS_MODEL (dc_gcov_type_ptr_var) =
+          decl_default_tls_model (dc_gcov_type_ptr_var);
 
       dc_void_ptr_var =
 	build_decl (UNKNOWN_LOCATION, VAR_DECL,
@@ -1413,8 +1419,9 @@ direct_call_profiling (void)
 		    ptr_void);
       DECL_ARTIFICIAL (dc_void_ptr_var) = 1;
       DECL_EXTERNAL (dc_void_ptr_var) = 1;
-      DECL_TLS_MODEL (dc_void_ptr_var) =
-	decl_default_tls_model (dc_void_ptr_var);
+      if (targetm.have_tls && !is_kernel_build)
+        DECL_TLS_MODEL (dc_void_ptr_var) =
+          decl_default_tls_model (dc_void_ptr_var);
     }
 
   if (!DECL_STATIC_CONSTRUCTOR (current_function_decl))
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in	(revision 217448)
+++ libgcc/Makefile.in	(working copy)
@@ -1147,10 +1147,14 @@ install-leaf: $(install-shared) $(install-libunwin
 	  cp ../../gcc/gcov-iov.h $$gcov_src_dest;		\
 	  cp $(srcdir)/../gcc/gcov-io.h $$gcov_src_dest;	\
 	  cp $(srcdir)/../gcc/gcov-io.c $$gcov_src_dest;	\
-	  cp $(srcdir)/libgcov-driver.c $$gcov_src_dest;		\
-	  chmod 644 $$gcov_src_dest/gcov-iov.h			\
-	  $$gcov_src_dest/gcov-io.h $$gcov_src_dest/gcov-io.c	\
-	  $$gcov_src_dest/libgcov-driver.c;				\
+	  cp $(srcdir)/../gcc/gcov-counter.def $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov-driver.c $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov-driver-kernel.c $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov.h $$gcov_src_dest;		\
+	  cp $(srcdir)/libgcov-kernel.h $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov-profiler.c $$gcov_src_dest;	\
+	  cp $(srcdir)/libgcov-merge.c $$gcov_src_dest;		\
+	  chmod 644 $$gcov_src_dest/*.[ch];			\
 	fi
 
 install: install-leaf install-unwind_h
Index: libgcc/dyn-ipa.c
===================================================================
--- libgcc/dyn-ipa.c	(revision 217448)
+++ libgcc/dyn-ipa.c	(working copy)
@@ -2257,6 +2257,7 @@ gcov_compute_random_module_groups (unsigned max_gr
     }
 }
 
+#if 0
 /* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
    indicating if the module is the primary module in the group.  */
 
@@ -2315,6 +2316,7 @@ gcov_write_module_info (const struct gcov_info *mo
   /* Now write the string array.  */
   gcov_write_string_array (module_info->string_array, num_strings);
 }
+#endif
 
 /* Write out MOD_INFO and its imported modules into gcda file.  */
 
@@ -2324,6 +2326,8 @@ gcov_write_module_infos (struct gcov_info *mod_inf
   unsigned imp_len = 0;
   const struct dyn_imp_mod **imp_mods;
 
+  if (flag_alg_mode == INCLUSION_BASED_PRIORITY_ALGORITHM)
+    SET_MODULE_INCLUDE_ALL_AUX (mod_info->mod_info);
   gcov_write_module_info (mod_info, 1);
 
   imp_mods = gcov_get_sorted_import_module_array (mod_info, &imp_len);
Index: libgcc/libgcov-driver-kernel.c
===================================================================
--- libgcc/libgcov-driver-kernel.c	(revision 0)
+++ libgcc/libgcov-driver-kernel.c	(working copy)
@@ -0,0 +1,203 @@
+/* Routines required for instrumenting a program.  */
+/* Compile this one with gcc.  */
+/* Copyright (C) 1989-2014 Free Software Foundation, Inc.
+
+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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+
+/* A utility function for outputing errors.  */
+
+static int __attribute__((format(printf, 1, 2)))
+gcov_error (const char *fmt, ...)
+{
+  int ret;
+  va_list argp;
+  va_start (argp, fmt);
+  ret = vprintk (fmt, argp);
+  va_end (argp);
+  return ret;
+}
+
+static void
+allocate_filename_struct (struct gcov_filename_aux *gf)
+{
+  const char *gcov_prefix;
+  int gcov_prefix_strip = 0;
+  size_t prefix_length = 0;
+  char *gi_filename_up;
+
+  /* Allocate and initialize the filename scratch space plus one.  */
+  gi_filename = (char *) xmalloc (prefix_length + gcov_max_filename + 2);
+  if (prefix_length)
+    memcpy (gi_filename, gcov_prefix, prefix_length);
+  gi_filename_up = gi_filename + prefix_length;
+
+  gf->gi_filename_up = gi_filename_up;
+  gf->prefix_length = prefix_length;
+  gf->gcov_prefix_strip = gcov_prefix_strip;
+}
+
+static int
+gcov_open_by_filename (char *gi_filename)
+{
+  gcov_open (gi_filename);
+  return 0;
+}
+
+
+/* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
+   put the result into GI_FILENAME_UP.  */
+
+static void
+gcov_strip_leading_dirs (int prefix_length, int gcov_prefix_strip,
+      			 const char *filename, char *gi_filename_up)
+{
+  strcpy (gi_filename_up, filename);
+}
+
+/* Current virual gcda file. This is for kernel use only.  */
+gcov_kernel_vfile *gcov_current_file;
+
+/* Set current virutal gcda file. It needs to be set before dumping
+   profile data.  */
+
+void
+gcov_set_vfile (gcov_kernel_vfile *file)
+{
+  gcov_current_file = file;
+}
+
+/* File fclose operation in kernel mode.  */
+
+int
+kernel_file_fclose (gcov_kernel_vfile *fp)
+{
+  return 0;
+}
+
+/* File ftell operation in kernel mode. It currently should not
+   be called.  */
+
+long
+kernel_file_ftell (gcov_kernel_vfile *fp)
+{
+  return 0;
+}
+
+/* File fseek operation in kernel mode. It should only be called
+   with OFFSET==0 and WHENCE==0 to a freshly opened file.  */
+
+int
+kernel_file_fseek (gcov_kernel_vfile *fp, long offset, int whence)
+{
+  gcc_assert (offset == 0 && whence == 0 && fp->count == 0);
+  return 0;
+}
+
+/* File ftruncate operation in kernel mode. It currently should not
+   be called.  */
+
+int
+kernel_file_ftruncate (gcov_kernel_vfile *fp, off_t value)
+{
+  gcc_assert (0);  /* should not reach here */
+  return 0;
+}
+
+/* File fread operation in kernel mode. It currently should not
+   be called.  */
+
+int
+kernel_file_fread (void *ptr, size_t size, size_t nitems,
+                  gcov_kernel_vfile *fp)
+{
+  gcc_assert (0);  /* should not reach here */
+  return 0;
+}
+
+/* File fwrite operation in kernel mode. It outputs the data
+   to a buffer in the virual file.  */
+
+int
+kernel_file_fwrite (const void *ptr, size_t size,
+                   size_t nitems, gcov_kernel_vfile *fp)
+{
+  char *vbuf;
+  unsigned vsize, vpos;
+  unsigned len;
+
+  if (!fp) return 0;
+
+  vbuf = fp->buf;
+  vsize = fp->size;
+  vpos = fp->count;
+
+
+  if (vsize < vpos)
+    {
+      printk (KERN_ERR
+         "GCOV_KERNEL: something wrong in file %s: vbuf=%p vsize=%u"
+         " vpos=%u\n",
+          fp->info->filename, vbuf, vsize, vpos);
+      return 0;
+    }
+
+  len = vsize - vpos;
+  len /= size;
+
+  /* Increase the virtual file size if it is not suffcient. */
+  while (len < nitems)
+    {
+      vsize *= 2;
+      len = vsize - vpos;
+      len /= size;
+    }
+
+  if (vsize != fp->size)
+    {
+      vbuf = fp->buf = (char *) gcov_realloc_file_buf(vsize, vpos);
+      fp->size = vsize;
+    }
+
+  if (len > nitems)
+	  len = nitems;
+
+  memcpy (vbuf+vpos, ptr, size*len);
+  fp->count += len*size;
+
+  if (len != nitems)
+    printk (KERN_ERR
+        "GCOV_KERNEL: something wrong in file %s: size=%lu nitems=%lu"
+        " len=%d vsize=%u vpos=%u \n",
+        fp->info->filename, size, nitems, len, vsize, vpos);
+  return len;
+}
+
+/* File fileno operation in kernel mode. It currently should not
+   be called.  */
+
+int
+kernel_file_fileno (gcov_kernel_vfile *fp)
+{
+  gcc_assert (0);  /* should not reach here */
+  return 0;
+}
Index: libgcc/libgcov-driver-system.c
===================================================================
--- libgcc/libgcov-driver-system.c	(revision 217448)
+++ libgcc/libgcov-driver-system.c	(working copy)
@@ -156,8 +156,6 @@ gcov_open_by_filename (char *gi_filename)
 }
 
 
-#define GCOV_GET_FILENAME gcov_strip_leading_dirs
-
 /* Strip GCOV_PREFIX_STRIP levels of leading '/' from FILENAME and
    put the result into GI_FILENAME_UP.  */
 
@@ -197,24 +195,3 @@ gcov_strip_leading_dirs (int prefix_length, int gc
   else
     strcpy (gi_filename_up, filename);
 }
-
-
-/* Open a gcda file specified by GI_FILENAME.
-   Return -1 on error.  Return 0 on success.  */
-
-static int
-gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
-{
-  int gcov_prefix_strip;
-  size_t prefix_length;
-  char *gi_filename_up;
-
-  gcov_prefix_strip = gf->gcov_prefix_strip;
-  gi_filename_up = gf->gi_filename_up;
-  prefix_length = gf->prefix_length;
-
-  GCOV_GET_FILENAME (prefix_length, gcov_prefix_strip, gi_ptr->filename,
-                     gi_filename_up);
-
-  return gcov_open_by_filename (gi_filename);
-}
Index: libgcc/libgcov-driver.c
===================================================================
--- libgcc/libgcov-driver.c	(revision 217448)
+++ libgcc/libgcov-driver.c	(working copy)
@@ -34,6 +34,7 @@ void __gcov_init (struct gcov_info *p __attribute_
 
 #else /* inhibit_libc */
 
+#if !defined(__KERNEL__)
 #include <string.h>
 #if GCOV_LOCKED
 #include <fcntl.h>
@@ -40,16 +41,11 @@ void __gcov_init (struct gcov_info *p __attribute_
 #include <errno.h>
 #include <sys/stat.h>
 #endif
+#endif /* __KERNEL__ */
 
 #ifdef L_gcov
 #include "gcov-io.c"
 
-#ifndef IN_GCOV_TOOL
-extern gcov_unsigned_t __gcov_sampling_period;
-extern gcov_unsigned_t __gcov_has_sampling;
-static int gcov_sampling_period_initialized = 0;
-#endif
-
 /* Unique identifier assigned to each module (object file).  */
 static gcov_unsigned_t gcov_cur_module_id = 0;
 
@@ -67,7 +63,11 @@ extern int get_gcov_dump_complete (void) ATTRIBUTE
 extern void set_gcov_list (struct gcov_info *) ATTRIBUTE_HIDDEN;
 __attribute__((weak)) void __coverage_callback (gcov_type, int); 
 
-#ifndef IN_GCOV_TOOL
+#if !defined(IN_GCOV_TOOL) && !defined(__KERNEL__)
+extern gcov_unsigned_t __gcov_sampling_period;
+extern gcov_unsigned_t __gcov_has_sampling;
+static int gcov_sampling_period_initialized = 0;
+
 /* Create a strong reference to these symbols so that they are
    unconditionally pulled into the instrumented binary, even when
    the only reference is a weak reference. This is necessary because
@@ -199,8 +199,8 @@ free_fn_data (const struct gcov_info *gi_ptr, stru
 
   for (ix = 0; ix != limit; ix++)
     if (gi_ptr->merge[ix])
-      free (buffer->info.ctrs[n_ctr++].values);
-  free (buffer);
+      xfree (buffer->info.ctrs[n_ctr++].values);
+  xfree (buffer);
   return next;
 }
 
@@ -469,7 +469,11 @@ struct gcov_filename_aux{
 };
 
 /* Including system dependent components. */
+#if !defined (__KERNEL__)
 #include "libgcov-driver-system.c"
+#else
+#include "libgcov-driver-kernel.c"
+#endif
 
 static int
 scan_build_info (struct gcov_info *gi_ptr)
@@ -476,9 +480,10 @@ scan_build_info (struct gcov_info *gi_ptr)
 {
   gcov_unsigned_t i, length;
   gcov_unsigned_t num_strings = 0;
+  char **build_info_strings;
 
   length = gcov_read_unsigned ();
-  char **build_info_strings = gcov_read_build_info (length, &num_strings);
+  build_info_strings = gcov_read_build_info (length, &num_strings);
   if (!build_info_strings)
     {
       gcov_error ("profiling:%s:Error reading build info\n", gi_filename);
@@ -501,12 +506,13 @@ scan_build_info (struct gcov_info *gi_ptr)
                       build_info_strings[i]);
           return -1;
         }
-      free (build_info_strings[i]);
+      xfree (build_info_strings[i]);
     }
-  free (build_info_strings);
+  xfree (build_info_strings);
   return 0;
 }
 
+#if !defined(__KERNEL__)
 /* Scan through the current open gcda file corresponding to GI_PTR
    to locate the end position just before function data should be rewritten,
    returned in SUMMARY_END_POS_P. E.g. scan past the last summary and other
@@ -563,6 +569,7 @@ gcov_scan_to_function_data (struct gcov_info *gi_p
 
   return 0;
 }
+#endif /* __KERNEL__ */
 
 /* This function merges counters in GI_PTR to an existing gcda file.
    Return 0 on success.
@@ -646,8 +653,8 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
 
   if (tag == GCOV_TAG_COMDAT_ZERO_FIXUP)
     {
+      gcov_unsigned_t num_fns = 0;
       length = gcov_read_unsigned ();
-      gcov_unsigned_t num_fns = 0;
       zero_fixup_flags = gcov_read_comdat_zero_fixup (length, &num_fns);
       if (!zero_fixup_flags)
         {
@@ -726,7 +733,7 @@ gcov_exit_merge_gcda (struct gcov_info *gi_ptr,
       if ((error = gcov_is_error ()))
         goto read_error;
     }
-  free (zero_fixup_flags);
+  xfree (zero_fixup_flags);
 
   if (tag && tag != GCOV_TAG_MODULE_INFO)
     {
@@ -744,7 +751,7 @@ read_error:
   return -1;
 }
 
-
+#if !defined(__KERNEL__)
 /* Write NUM_FNS ZERO_COUNTS fixup flags to a gcda file starting from its
    current location.  */
 
@@ -753,10 +760,10 @@ gcov_write_comdat_zero_fixup (char *zero_counts, u
 {
   unsigned f_ix;
   gcov_unsigned_t len = GCOV_TAG_COMDAT_ZERO_FIXUP_LENGTH (num_fns);
+  gcov_unsigned_t bitvector = 0, b_ix = 0;
   gcov_write_tag_length (GCOV_TAG_COMDAT_ZERO_FIXUP, len);
 
   gcov_write_unsigned (num_fns);
-  gcov_unsigned_t bitvector = 0, b_ix = 0;
   for (f_ix = 0; f_ix != num_fns; f_ix++)
     {
       if (zero_counts[f_ix])
@@ -771,6 +778,7 @@ gcov_write_comdat_zero_fixup (char *zero_counts, u
   if (b_ix > 0)
     gcov_write_unsigned (bitvector);
 }
+#endif /* __KERNEL__ */
 
 /* Write build_info strings from GI_PTR to a gcda file starting from its current
    location.  */
@@ -852,8 +860,10 @@ gcov_write_func_counters (struct gcov_info *gi_ptr
             gcov_write_counter (*c_ptr++);
           ci_ptr++;
         }
+#if !defined(__KERNEL__)
       if (buffered)
         fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
+#endif /* __KERNEL__ */
     }
 
   gi_ptr->eof_pos = gcov_position ();
@@ -896,7 +906,7 @@ gcov_exit_write_gcda (struct gcov_info *gi_ptr,
     {
       gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &sum_buffer->summary);
       next_sum_buffer = sum_buffer->next;
-      free (sum_buffer);
+      xfree (sum_buffer);
       sum_buffer = next_sum_buffer;
     }
 
@@ -1056,6 +1066,26 @@ gcov_sort_topn_counter_arrays (const struct gcov_i
      }
 }
 
+/* Open a gcda file specified by GI_FILENAME.
+   Return -1 on error.  Return 0 on success.  */
+
+static int 
+gcov_exit_open_gcda_file (struct gcov_info *gi_ptr, struct gcov_filename_aux *gf)
+{
+  int gcov_prefix_strip;
+  size_t prefix_length;
+  char *gi_filename_up;
+
+  gcov_prefix_strip = gf->gcov_prefix_strip;
+  gi_filename_up = gf->gi_filename_up;
+  prefix_length = gf->prefix_length;
+
+  gcov_strip_leading_dirs (prefix_length, gcov_prefix_strip, gi_ptr->filename,
+                           gi_filename_up);
+
+  return gcov_open_by_filename (gi_filename);
+}
+
 /* Dump the coverage counts for one gcov_info object. We merge with existing
    counts when possible, to avoid growing the .da files ad infinitum. We use
    this program's checksum to make sure we only accumulate whole program
@@ -1068,9 +1098,14 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, str
 		     gcov_unsigned_t crc32, struct gcov_summary *all_prg,
                      struct gcov_summary *this_prg)
 {
+/* We have to make the decl static as kernel has limited stack size.
+   If we put prg to stack, we will running into nasty stack overflow.  */
+#if defined(__KERNEL__)
+  static
+#endif
   struct gcov_summary prg; /* summary for this object over all program.  */
   int error;
-  gcov_unsigned_t tag;
+  gcov_unsigned_t tag = 0;
   gcov_position_t summary_pos = 0;
   gcov_position_t eof_pos = 0;
 
@@ -1083,7 +1118,9 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, str
   if (error == -1)
     return;
 
+#if !defined(__KERNEL__)
   tag = gcov_read_unsigned ();
+#endif
   if (tag)
     {
       /* Merge data from file.  */
@@ -1114,9 +1151,22 @@ gcov_exit_dump_gcov (struct gcov_info *gi_ptr, str
   /* fall through */
 
 read_fatal:;
+#if !defined(__KERNEL__)
   while (fn_buffer)
     fn_buffer = free_fn_data (gi_ptr, fn_buffer, GCOV_COUNTERS);
+#else
 
+      /* In LIPO mode, dump the primary module info.  */
+      if (gi_ptr->mod_info && gi_ptr->mod_info->is_primary)
+        {
+          /* Overwrite the zero word at the of the file.  */
+          gcov_seek (gi_ptr->eof_pos);
+          gcov_write_module_info (gi_ptr, 1);
+          /* Write the end marker  */
+          gcov_write_unsigned (0); 
+        }
+#endif
+
   if ((error = gcov_close ()))
     gcov_error (error  < 0 ?
                 "profiling:%s:Overflow writing\n" :
@@ -1124,6 +1174,7 @@ read_fatal:;
                 gi_filename);
 }
 
+#if !defined (__KERNEL__)
 /* Write imported files (auxiliary modules) for primary module GI_PTR
    into file GI_FILENAME.  */
 
@@ -1159,7 +1210,7 @@ gcov_write_import_file (char *gi_filename, struct
               fprintf (imports_file, "%s%s\n",
                        imp_mods[i]->imp_mod->mod_info->da_filename, GCOV_DATA_SUFFIX);
             }
-          free (imp_mods);
+          xfree (imp_mods);
         }
       fclose (imports_file);
     }
@@ -1287,40 +1338,9 @@ gcov_exit (void)
     gcov_dump_module_info (&gf);
 
   if (gi_filename)
-    free (gi_filename);
+    xfree (gi_filename);
 }
 
-/* Reset all counters to zero.  */
-
-void
-gcov_clear (void)
-{
-  const struct gcov_info *gi_ptr;
-
-  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
-    {
-      unsigned f_ix;
-
-      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
-        {
-          unsigned t_ix;
-          const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
-
-          if (!gfi_ptr || gfi_ptr->key != gi_ptr)
-            continue;
-          const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
-          for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
-            {
-              if (!gi_ptr->merge[t_ix])
-                continue;
-
-              memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
-              ci_ptr++;
-            }
-        }
-    }
-}
-
 /* Add a new object file onto the bb chain.  Invoked automatically
   when running an object file's global ctors.  */
 
@@ -1366,5 +1386,116 @@ __gcov_init (struct gcov_info *info)
   info->version = 0;
 }
 
+#else /* __KERNEL__ */
+
+static struct gcov_filename_aux gf;
+static gcov_unsigned_t crc32;
+static struct gcov_summary all_prg;
+static struct gcov_summary this_prg;
+void
+gcov_kernel_dump_gcov_init (void)
+{
+  crc32 = gcov_exit_compute_summary (&this_prg);
+  allocate_filename_struct (&gf);
+  memset (&all_prg, 0, sizeof (all_prg));
+}
+
+void
+gcov_kernel_dump_one_gcov(struct gcov_info *info)
+{
+  gcov_exit_dump_gcov (info, &gf, crc32, &all_prg, &this_prg);
+}
+
+#endif /* __KERNEL__ */
+
+/* Reset all counters to zero.  */
+
+void
+gcov_clear (void)
+{
+  const struct gcov_info *gi_ptr;
+
+  for (gi_ptr = __gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
+    {
+      unsigned f_ix;
+
+      for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++)
+        {
+          unsigned t_ix;
+          const struct gcov_fn_info *gfi_ptr = gi_ptr->functions[f_ix];
+          const struct gcov_ctr_info *ci_ptr;
+
+          if (!gfi_ptr || gfi_ptr->key != gi_ptr)
+            continue;
+          ci_ptr = gfi_ptr->ctrs;
+          for (t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+            {
+              if (!gi_ptr->merge[t_ix])
+                continue;
+
+              memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+              ci_ptr++;
+            }
+        }
+    }
+}
+
+/* Write out MOD_INFO into the gcda file. IS_PRIMARY is a flag
+   indicating if the module is the primary module in the group.  */
+
+void
+gcov_write_module_info (const struct gcov_info *mod_info,
+                        unsigned is_primary)
+{
+  gcov_unsigned_t len = 0, filename_len = 0, src_filename_len = 0, i;
+  gcov_unsigned_t num_strings;
+  gcov_unsigned_t *aligned_fname;
+  struct gcov_module_info  *module_info = mod_info->mod_info;
+  filename_len = (strlen (module_info->da_filename) +
+		  sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+  src_filename_len = (strlen (module_info->source_filename) +
+		      sizeof (gcov_unsigned_t)) / sizeof (gcov_unsigned_t);
+  len = filename_len + src_filename_len;
+  len += 2; /* each name string is led by a length.  */
+
+  num_strings = module_info->num_quote_paths + module_info->num_bracket_paths
+    + module_info->num_system_paths
+    + module_info->num_cpp_defines + module_info->num_cpp_includes
+    + module_info->num_cl_args;
+  len += gcov_compute_string_array_len (module_info->string_array,
+                                        num_strings);
+
+  len += 11; /* 11 more fields */
+
+  gcov_write_tag_length (GCOV_TAG_MODULE_INFO, len);
+  gcov_write_unsigned (module_info->ident);
+  gcov_write_unsigned (is_primary);
+  gcov_write_unsigned (module_info->flags);
+  gcov_write_unsigned (module_info->lang);
+  gcov_write_unsigned (module_info->ggc_memory);
+  gcov_write_unsigned (module_info->num_quote_paths);
+  gcov_write_unsigned (module_info->num_bracket_paths);
+  gcov_write_unsigned (module_info->num_system_paths);
+  gcov_write_unsigned (module_info->num_cpp_defines);
+  gcov_write_unsigned (module_info->num_cpp_includes);
+  gcov_write_unsigned (module_info->num_cl_args);
+
+  /* Now write the filenames */
+  aligned_fname = (gcov_unsigned_t *) alloca ((filename_len + src_filename_len + 2) *
+					      sizeof (gcov_unsigned_t));
+  memset (aligned_fname, 0,
+          (filename_len + src_filename_len + 2) * sizeof (gcov_unsigned_t));
+  aligned_fname[0] = filename_len;
+  strcpy ((char*) (aligned_fname + 1), module_info->da_filename);
+  aligned_fname[filename_len + 1] = src_filename_len;
+  strcpy ((char*) (aligned_fname + filename_len + 2), module_info->source_filename);
+
+  for (i = 0; i < (filename_len + src_filename_len + 2); i++)
+    gcov_write_unsigned (aligned_fname[i]);
+
+  /* Now write the string array.  */
+  gcov_write_string_array (module_info->string_array, num_strings);
+}
+
 #endif /* L_gcov */
 #endif /* inhibit_libc */
Index: libgcc/libgcov-kernel.h
===================================================================
--- libgcc/libgcov-kernel.h	(revision 0)
+++ libgcc/libgcov-kernel.h	(working copy)
@@ -0,0 +1,115 @@
+/* Header file for libgcov-*.c.
+   Copyright (C) 1996-2014 Free Software Foundation, Inc.
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_LIBGCOV_KERNEL_H
+#define GCC_LIBGCOV_KERNEL_H
+
+/* work around the poisoned malloc/calloc in system.h.  */
+#ifndef xmalloc
+#define xmalloc vmalloc
+#endif
+#ifndef xcalloc
+#define xcalloc vcalloc
+#endif
+#ifndef xrealloc
+#define xrealloc vrealloc
+#endif
+#ifndef xfree
+#define xfree vfree
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+ /* Define MACROs to be used by kernel compilation.  */
+# define L_gcov
+# define L_gcov_interval_profiler
+# define L_gcov_pow2_profiler
+# define L_gcov_one_value_profiler
+# define L_gcov_indirect_call_profiler_v2
+# define L_gcov_indirect_call_profiler
+# define L_gcov_time_profile
+# define L_gcov_average_profiler
+# define L_gcov_ior_profiler
+# define L_gcov_merge_add
+# define L_gcov_merge_single
+# define L_gcov_merge_delta
+# define L_gcov_merge_ior
+# define L_gcov_merge_time_profile
+# define L_gcov_time_profiler
+
+#define IN_LIBGCOV 1
+#define IN_GCOV 0
+#define THREAD_PREFIX
+#define GCOV_LINKAGE /* nothing */
+#define BITS_PER_UNIT 8
+#define LONG_LONG_TYPE_SIZE 64
+#define MEMMODEL_RELAXED 0
+
+#define ENABLE_ASSERT_CHECKING 1
+
+/* gcc_assert() prints out a warning if the check fails. It
+   will not abort.  */
+#if ENABLE_ASSERT_CHECKING
+# define gcc_assert(EXPR) \
+    ((void)(!(EXPR) ? printk (KERN_WARNING \
+      "GCOV assertion fails: func=%s line=%d\n", \
+      __FUNCTION__, __LINE__), 0 : 0))
+#else
+# define gcc_assert(EXPR) ((void)(0 && (EXPR)))
+#endif
+
+/* In Linux kernel mode, a virtual file is used for file operations.  */
+struct gcov_info;
+typedef struct {
+  long size; /* size of buf */
+  long count; /* element written into buf */
+  struct gcov_info *info;
+  char *buf;
+} gcov_kernel_vfile;
+
+#define _GCOV_FILE gcov_kernel_vfile
+
+/* Wrappers to the file operations.  */
+#define _GCOV_fclose     kernel_file_fclose
+#define _GCOV_ftell      kernel_file_ftell
+#define _GCOV_fseek      kernel_file_fseek
+#define _GCOV_ftruncate  kernel_file_ftruncate
+#define _GCOV_fread      kernel_file_fread
+#define _GCOV_fwrite     kernel_file_fwrite
+#define _GCOV_fileno     kernel_file_fileno
+
+/* Declarations for virtual files operations.  */
+extern int kernel_file_fclose (gcov_kernel_vfile *);
+extern long kernel_file_ftell (gcov_kernel_vfile *);
+extern int kernel_file_fseek (gcov_kernel_vfile *, long, int);
+extern int kernel_file_ftruncate (gcov_kernel_vfile *, off_t);
+extern int kernel_file_fread (void *, size_t, size_t,
+    gcov_kernel_vfile *);
+extern int kernel_file_fwrite (const void *, size_t, size_t,
+    gcov_kernel_vfile *);
+extern int kernel_file_fileno (gcov_kernel_vfile *);
+
+#endif /* GCC_LIBGCOV_KERNEL_H */
Index: libgcc/libgcov.h
===================================================================
--- libgcc/libgcov.h	(revision 217448)
+++ libgcc/libgcov.h	(working copy)
@@ -25,6 +25,7 @@
 #ifndef GCC_LIBGCOV_H
 #define GCC_LIBGCOV_H
 
+#ifndef __KERNEL__
 /* work around the poisoned malloc/calloc in system.h.  */
 #ifndef xmalloc
 #define xmalloc malloc
@@ -35,16 +36,24 @@
 #ifndef xrealloc
 #define xrealloc realloc
 #endif
+#ifndef xfree
+#define xfree free
+#endif
+#else /* __KERNEL__ */
+#include "libgcov-kernel.h"
+#endif /* __KERNEL__ */
 
 #ifndef IN_GCOV_TOOL
 /* About the target.  */
 /* This path will be used by libgcov runtime.  */
 
+#ifndef __KERNEL__
 #include "tconfig.h"
 #include "tsystem.h"
 #include "coretypes.h"
 #include "tm.h"
 #include "libgcc_tm.h"
+#endif /* __KERNEL__ */
 
 #undef FUNC_ID_WIDTH
 #undef FUNC_ID_MASK
@@ -128,7 +137,6 @@ typedef unsigned gcov_position_t;
 #define GCOV_LOCKED 0
 #endif
 
-/* xur??? */
 #define FUNC_ID_WIDTH 32
 #define FUNC_ID_MASK ((1ll << FUNC_ID_WIDTH) - 1)
 
@@ -247,11 +255,13 @@ struct gcov_info
 
   unsigned n_functions;         /* number of functions */
 
-#ifndef IN_GCOV_TOOL
+#if !defined (IN_GCOV_TOOL) && !defined (__KERNEL__)
   const struct gcov_fn_info *const *functions; /* pointer to pointers
                                                   to function information  */
+#elif defined (IN_GCOV_TOOL)
+  const struct gcov_fn_info **functions;
 #else
-  const struct gcov_fn_info **functions;
+  struct gcov_fn_info **functions;
 #endif /* !IN_GCOV_TOOL */
   char **build_info;            /* strings to include in BUILD_INFO
                                    section of gcda file.  */
@@ -342,6 +352,8 @@ GCOV_LINKAGE void gcov_write_summary (gcov_unsigne
     ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_seek (gcov_position_t /*position*/) ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_truncate (void) ATTRIBUTE_HIDDEN;
+void gcov_write_module_info (const struct gcov_info *, unsigned)
+    ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE void gcov_write_module_infos (struct gcov_info *mod_info)
     ATTRIBUTE_HIDDEN;
 GCOV_LINKAGE const struct dyn_imp_mod **

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [google gcc-4.9] FDO build for linux kernel
  2014-11-13 18:57 [google gcc-4.9] FDO build for linux kernel Rong Xu
@ 2014-11-13 20:34 ` Xinliang David Li
  0 siblings, 0 replies; 2+ messages in thread
From: Xinliang David Li @ 2014-11-13 20:34 UTC (permalink / raw)
  To: Rong Xu; +Cc: GCC Patches

ok.

(the way to detect kernel build looks unpolished, but there does not
seem to be a consistent way of doing it. Some targets have kernel
specific flags ..)

On Thu, Nov 13, 2014 at 10:40 AM, Rong Xu <xur@google.com> wrote:
> Here is patch that ports our work on FDO linux kernel build support to
> gcc-4_9. With this patch, kernel will use the libgcov functions to
> dump the gcda files.
>
> This patch also enables LIPO build. But the module grouping is not
> computed online. We will use gcov-tool to do this offline.
>
> Tested with kernel FDO build, regression and google internal benchmarks.
>
> Thanks,
>
> -Rong

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-11-13 20:16 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-11-13 18:57 [google gcc-4.9] FDO build for linux kernel Rong Xu
2014-11-13 20:34 ` Xinliang David Li

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).