diff --git a/gcc/gcov.c b/gcc/gcov.c
index 9458812..da53ebe 100644
--- a/gcc/gcov.c
+++ b/gcc/gcov.c
@@ -2364,37 +2364,6 @@ output_branch_count (FILE *gcov_file, int ix, const arc_t *arc)
 
 }
 
-static const char *
-read_line (FILE *file)
-{
-  static char *string;
-  static size_t string_len;
-  size_t pos = 0;
-  char *ptr;
-
-  if (!string_len)
-    {
-      string_len = 200;
-      string = XNEWVEC (char, string_len);
-    }
-
-  while ((ptr = fgets (string + pos, string_len - pos, file)))
-    {
-      size_t len = strlen (string + pos);
-
-      if (string[pos + len - 1] == '\n')
-	{
-	  string[pos + len - 1] = 0;
-	  return string;
-	}
-      pos += len;
-      string = XRESIZEVEC (char, string, string_len * 2);
-      string_len *= 2;
-    }
-      
-  return pos ? string : NULL;
-}
-
 /* Read in the source file one line at a time, and output that line to
    the gcov file preceded by its execution count and other
    information.  */
@@ -2455,7 +2424,7 @@ output_lines (FILE *gcov_file, const source_t *src)
 	}
 
       if (retval)
-	retval = read_line (source_file);
+	retval = read_line (source_file, NULL);
 
       /* For lines which don't exist in the .bb file, print '-' before
 	 the source line.  For lines which exist but were never
@@ -2503,7 +2472,7 @@ output_lines (FILE *gcov_file, const source_t *src)
      last line of code.  */
   if (retval)
     {
-      for (; (retval = read_line (source_file)); line_num++)
+      for (; (retval = read_line (source_file, NULL)); line_num++)
 	fprintf (gcov_file, "%9s:%5u:%s\n", "-", line_num, retval);
     }
 
diff --git a/gcc/input.c b/gcc/input.c
index cb3a0a0..e42103c 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -88,12 +88,12 @@ expand_location_1 (source_location loc,
 }
 
 /* This function reads a line that might contain bytes whose value is
-   zero.  It returns the number of bytes read.  The 'end-of-line'
-   character found at the end of the line is not contained in the
-   returned buffer.  Note that this function has been adapted from
-   getline() and _IO_getdelim() GNU C library functions.  It's been
-   duplicated here because the getline() function is not necessarily
-   present on all platforms.
+   zero.  It returns the number of bytes read, including the
+   end-of-line character.  That end-of-line character is replaced by a
+   zero byte in the returned buffer.  Note that this function has been
+   adapted from getline() and _IO_getdelim() GNU C library functions.
+   It's been duplicated here because the getline() function is not
+   necessarily present on all platforms.
 
    LINEPTR points to a buffer that is to contain the line read.
 
@@ -124,7 +124,7 @@ get_line (char **lineptr, size_t *n, FILE *fp)
     {
       size_t needed;
       char *t = (char*) memchr (buf, '\n', len);
-      if (t != NULL) len = (t - buf);
+      if (t != NULL) len = (t - buf) + 1;
       if (__builtin_expect (len >= SSIZE_MAX - cur_len, 0))
 	return -1;
       needed = cur_len + len + 1;
@@ -149,7 +149,7 @@ get_line (char **lineptr, size_t *n, FILE *fp)
     }
 
   if (cur_len)
-    (*lineptr)[cur_len] = '\0';
+    (*lineptr)[cur_len - 1] = '\0';
   return cur_len;
 }
 
@@ -159,14 +159,21 @@ get_line (char **lineptr, size_t *n, FILE *fp)
  *zero bytes.  Also note that the returned string is allocated in
  *static storage that is going to be re-used by subsequent invocations
  *of read_line.  */
-static const char *
+const char *
 read_line (FILE *file, int *line_length)
 {
   static char *string;
   static size_t string_len;
   int len;
+  long prev_pos;
 
+  prev_pos = ftell (file);
   len = get_line (&string, &string_len, file);
+  /* get_line tried to read STRING_LEN bytes, which is possibly
+    different from LEN bytes of the returned line.  So set the
+    position indicator of FILE to the byte following the LEN'th byte,
+    so that the new call to get_line starts reading from there.  */
+  fseek (file, prev_pos + len, SEEK_SET);
   if (line_length)
     *line_length = len;
   return len ? string : NULL;
@@ -188,7 +195,11 @@ location_get_source_line (expanded_location xloc,
   if (!stream)
     return NULL;
 
-  while ((ptr = read_line (stream, &len)) && lines < xloc.line)
+  /* We make sure not to call read_line unnecessarily because the
+     non-null result of a given call to read_line overrides the result
+     of the previous call to read_line; hence the line test that comes
+     before the call to read_line.  */
+  while (lines < xloc.line && (ptr = read_line (stream, &len)))
     {
       buffer = ptr;
       lines++;
diff --git a/gcc/input.h b/gcc/input.h
index 128e28c..d7c8a0e 100644
--- a/gcc/input.h
+++ b/gcc/input.h
@@ -66,4 +66,6 @@ extern location_t input_location;
 
 void dump_line_table_statistics (void);
 
+const char * read_line (FILE *, int *);
+
 #endif
