Merge revisions 14222, 14268, and 14270 from the BUF_REMOVAL branch to trunk.
Assorted fixes in exp-bbv to eliminate a few buffers.
Implement a suggestion found in the massif source, namely to add the
equivalent of fprintf to m_libcprint. Good suggestion. Thusly
- VgFile: similar to FILE; buffered output, 8k buffer
- VG_(fopen): similar to fopen, but with arguments as in VG_(open)
- VG_(fprintf) and VG_(vfprintf): like [v]fprintf with VgFile 1at argument
- VG_(fclose)
Change massif, exp-bbv and cachegrind to use this functionality.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14678 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index b174457..20fafbc 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1374,9 +1374,8 @@
 
 static void fprint_CC_table_and_calc_totals(void)
 {
-   Int     i, fd;
-   SysRes  sres;
-   HChar    buf[512];
+   Int     i;
+   VgFile  *fp;
    HChar   *currFile = NULL;
    const HChar *currFn = NULL;
    LineCC* lineCC;
@@ -1389,9 +1388,9 @@
    HChar* cachegrind_out_file =
       VG_(expand_file_name)("--cachegrind-out-file", clo_cachegrind_out_file);
 
-   sres = VG_(open)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
-                                         VKI_S_IRUSR|VKI_S_IWUSR);
-   if (sr_isError(sres)) {
+   fp = VG_(fopen)(cachegrind_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+                                        VKI_S_IRUSR|VKI_S_IWUSR);
+   if (fp == NULL) {
       // If the file can't be opened for whatever reason (conflict
       // between multiple cachegrinded processes?), give up now.
       VG_(umsg)("error: can't open cache simulation output file '%s'\n",
@@ -1400,48 +1399,38 @@
       VG_(free)(cachegrind_out_file);
       return;
    } else {
-      fd = sr_Res(sres);
       VG_(free)(cachegrind_out_file);
    }
 
    // "desc:" lines (giving I1/D1/LL cache configuration).  The spaces after
    // the 2nd colon makes cg_annotate's output look nicer.
-   VG_(sprintf)(buf, "desc: I1 cache:         %s\n"
+   VG_(fprintf)(fp,  "desc: I1 cache:         %s\n"
                      "desc: D1 cache:         %s\n"
                      "desc: LL cache:         %s\n",
                      I1.desc_line, D1.desc_line, LL.desc_line);
-   VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
 
    // "cmd:" line
-   VG_(strcpy)(buf, "cmd:");
-   VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-   VG_(write)(fd, " ", 1);
-   VG_(write)(fd, VG_(args_the_exename), 
-              VG_(strlen)( VG_(args_the_exename) ));
+   VG_(fprintf)(fp, "cmd: %s", VG_(args_the_exename));
    for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
       HChar* arg = * (HChar**) VG_(indexXA)( VG_(args_for_client), i );
-      VG_(write)(fd, " ", 1);
-      VG_(write)(fd, arg, VG_(strlen)( arg ));
+      VG_(fprintf)(fp, " %s", arg);
    }
    // "events:" line
    if (clo_cache_sim && clo_branch_sim) {
-      VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
+      VG_(fprintf)(fp, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
                                   "Bc Bcm Bi Bim\n");
    }
    else if (clo_cache_sim && !clo_branch_sim) {
-      VG_(sprintf)(buf, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
+      VG_(fprintf)(fp, "\nevents: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw "
                                   "\n");
    }
    else if (!clo_cache_sim && clo_branch_sim) {
-      VG_(sprintf)(buf, "\nevents: Ir "
-                                  "Bc Bcm Bi Bim\n");
+      VG_(fprintf)(fp, "\nevents: Ir Bc Bcm Bi Bim\n");
    }
    else {
-      VG_(sprintf)(buf, "\nevents: Ir\n");
+      VG_(fprintf)(fp, "\nevents: Ir\n");
    }
 
-   VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-
    // Traverse every lineCC
    VG_(OSetGen_ResetIter)(CC_table);
    while ( (lineCC = VG_(OSetGen_Next)(CC_table)) ) {
@@ -1453,8 +1442,7 @@
       // the whole strings would have to be checked.
       if ( lineCC->loc.file != currFile ) {
          currFile = lineCC->loc.file;
-         VG_(sprintf)(buf, "fl=%s\n", currFile);
-         VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
+         VG_(fprintf)(fp, "fl=%s\n", currFile);
          distinct_files++;
          just_hit_a_new_file = True;
       }
@@ -1464,14 +1452,13 @@
       // in the old file, hence the just_hit_a_new_file test).
       if ( just_hit_a_new_file || lineCC->loc.fn != currFn ) {
          currFn = lineCC->loc.fn;
-         VG_(sprintf)(buf, "fn=%s\n", currFn);
-         VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
+         VG_(fprintf)(fp, "fn=%s\n", currFn);
          distinct_fns++;
       }
 
       // Print the LineCC
       if (clo_cache_sim && clo_branch_sim) {
-         VG_(sprintf)(buf, "%u %llu %llu %llu"
+         VG_(fprintf)(fp,  "%u %llu %llu %llu"
                              " %llu %llu %llu"
                              " %llu %llu %llu"
                              " %llu %llu %llu %llu\n",
@@ -1483,7 +1470,7 @@
                             lineCC->Bi.b, lineCC->Bi.mp);
       }
       else if (clo_cache_sim && !clo_branch_sim) {
-         VG_(sprintf)(buf, "%u %llu %llu %llu"
+         VG_(fprintf)(fp,  "%u %llu %llu %llu"
                              " %llu %llu %llu"
                              " %llu %llu %llu\n",
                             lineCC->loc.line,
@@ -1492,7 +1479,7 @@
                             lineCC->Dw.a, lineCC->Dw.m1, lineCC->Dw.mL);
       }
       else if (!clo_cache_sim && clo_branch_sim) {
-         VG_(sprintf)(buf, "%u %llu"
+         VG_(fprintf)(fp,  "%u %llu"
                              " %llu %llu %llu %llu\n",
                             lineCC->loc.line,
                             lineCC->Ir.a, 
@@ -1500,13 +1487,11 @@
                             lineCC->Bi.b, lineCC->Bi.mp);
       }
       else {
-         VG_(sprintf)(buf, "%u %llu\n",
+         VG_(fprintf)(fp,  "%u %llu\n",
                             lineCC->loc.line,
                             lineCC->Ir.a);
       }
 
-      VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-
       // Update summary stats
       Ir_total.a  += lineCC->Ir.a;
       Ir_total.m1 += lineCC->Ir.m1;
@@ -1528,7 +1513,7 @@
    // Summary stats must come after rest of table, since we calculate them
    // during traversal.  */
    if (clo_cache_sim && clo_branch_sim) {
-      VG_(sprintf)(buf, "summary:"
+      VG_(fprintf)(fp,  "summary:"
                         " %llu %llu %llu"
                         " %llu %llu %llu"
                         " %llu %llu %llu"
@@ -1540,7 +1525,7 @@
                         Bi_total.b, Bi_total.mp);
    }
    else if (clo_cache_sim && !clo_branch_sim) {
-      VG_(sprintf)(buf, "summary:"
+      VG_(fprintf)(fp,  "summary:"
                         " %llu %llu %llu"
                         " %llu %llu %llu"
                         " %llu %llu %llu\n",
@@ -1549,7 +1534,7 @@
                         Dw_total.a, Dw_total.m1, Dw_total.mL);
    }
    else if (!clo_cache_sim && clo_branch_sim) {
-      VG_(sprintf)(buf, "summary:"
+      VG_(fprintf)(fp,  "summary:"
                         " %llu"
                         " %llu %llu %llu %llu\n", 
                         Ir_total.a,
@@ -1557,13 +1542,12 @@
                         Bi_total.b, Bi_total.mp);
    }
    else {
-      VG_(sprintf)(buf, "summary:"
+      VG_(fprintf)(fp, "summary:"
                         " %llu\n", 
                         Ir_total.a);
    }
 
-   VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-   VG_(close)(fd);
+   VG_(fclose)(fp);
 }
 
 static UInt ULong_width(ULong n)
@@ -1579,8 +1563,8 @@
 
 static void cg_fini(Int exitcode)
 {
-   static HChar buf1[128], buf2[128], buf3[128], buf4[123];
-   static HChar fmt[128];
+   static HChar buf1[128], buf2[128], buf3[128], buf4[123];  // FIXME
+   static HChar fmt[128];   // OK; large enough
 
    CacheCC  D_total;
    BranchCC B_total;
diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c
index 8e1814b..549e7d7 100644
--- a/coregrind/m_libcprint.c
+++ b/coregrind/m_libcprint.c
@@ -1,3 +1,4 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
 
 /*--------------------------------------------------------------------*/
 /*--- Libc printing.                                 m_libcprint.c ---*/
@@ -37,6 +38,7 @@
 #include "pub_core_libcfile.h"   // VG_(write)(), VG_(write_socket)()
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"   // VG_(getpid)(), VG_(read_millisecond_timer()
+#include "pub_core_mallocfree.h" // VG_(malloc)
 #include "pub_core_options.h"
 #include "pub_core_clreq.h"      // For RUNNING_ON_VALGRIND
 
@@ -294,6 +296,72 @@
 }
 
 
+/* --------- fprintf ---------- */
+
+/* This is like [v]fprintf, except it writes to a file handle using
+   VG_(write). */
+
+#define VGFILE_BUFSIZE  8192
+
+struct _VgFile {
+   HChar buf[VGFILE_BUFSIZE];
+   UInt  num_chars;   // number of characters in buf
+   Int   fd;          // file descriptor to write to
+};
+
+
+static void add_to__vgfile ( HChar c, void *p )
+{
+   VgFile *fp = p;
+
+   fp->buf[fp->num_chars++] = c;
+
+   if (fp->num_chars == VGFILE_BUFSIZE) {
+      VG_(write)(fp->fd, fp->buf, fp->num_chars);
+      fp->num_chars = 0;
+   }
+}
+
+VgFile *VG_(fopen)(const HChar *name, Int flags, Int mode)
+{
+   SysRes res = VG_(open)(name, flags, mode);
+
+   if (sr_isError(res))
+      return NULL;
+
+   VgFile *fp = VG_(malloc)("fopen", sizeof(VgFile));
+
+   fp->fd = sr_Res(res);
+   fp->num_chars = 0;
+
+   return fp;
+}
+
+
+UInt VG_(vfprintf) ( VgFile *fp, const HChar *format, va_list vargs )
+{
+   return VG_(debugLog_vprintf)(add_to__vgfile, fp, format, vargs);
+}
+
+UInt VG_(fprintf) ( VgFile *fp, const HChar *format, ... )
+{
+   UInt ret;
+   va_list vargs;
+   va_start(vargs,format);
+   ret = VG_(vfprintf)(fp, format, vargs);
+   va_end(vargs);
+   return ret;
+}
+
+void VG_(fclose)( VgFile *fp )
+{
+   // Flush the buffer.
+   if (fp->num_chars)
+      VG_(write)(fp->fd, fp->buf, fp->num_chars);
+
+   VG_(free)(fp);
+}
+
 /* ---------------------------------------------------------------------
    percentify()
    ------------------------------------------------------------------ */
@@ -623,4 +691,3 @@
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
-
diff --git a/exp-bbv/bbv_main.c b/exp-bbv/bbv_main.c
index c8759ae..82ac7ea 100644
--- a/exp-bbv/bbv_main.c
+++ b/exp-bbv/bbv_main.c
@@ -1,3 +1,5 @@
+/* -*- mode: C; c-basic-offset: 3; -*- */
+
 //--------------------------------------------------------------------*/
 //--- BBV: a SimPoint basic block vector generator      bbv_main.c ---*/
 //--------------------------------------------------------------------*/
@@ -35,12 +37,11 @@
 #include "pub_tool_tooliface.h"
 #include "pub_tool_options.h"    /* command line options */
 
-#include "pub_tool_vki.h"        /* vki_stat */
+#include "pub_tool_vki.h"        /* VKI_O_CREAT */
 #include "pub_tool_libcbase.h"   /* VG_(strlen) */
-#include "pub_tool_libcfile.h"   /* VG_(write) */
 #include "pub_tool_libcprint.h"  /* VG_(printf) */
 #include "pub_tool_libcassert.h" /* VG_(exit) */
-#include "pub_tool_mallocfree.h" /* plain_free */
+#include "pub_tool_mallocfree.h" /* VG_(malloc) */
 #include "pub_tool_machine.h"    /* VG_(fnptr_to_fnentry) */
 #include "pub_tool_debuginfo.h"  /* VG_(get_fnname) */
 
@@ -65,9 +66,6 @@
 static Bool instr_count_only=False;
 static Bool generate_pc_file=False;
 
-   /* write buffer */
-static HChar buf[1024];
-
    /* Global values */
 static OSet* instr_info_table;  /* table that holds the basic block info */
 static Int block_num=1;         /* global next block number */
@@ -84,7 +82,7 @@
    ULong global_rep_count;
    ULong unique_rep_count;
    ULong fldcw_count;       /* fldcw count */
-   Int bbtrace_fd;          /* file descriptor */
+   VgFile *bbtrace_fp;      /* file pointer */
 };
 
 struct BB_info {
@@ -102,60 +100,54 @@
 static void dumpPcFile(void)
 {
    struct BB_info   *bb_elem;
-   Int              pctrace_fd;
-   SysRes           sres;
+   VgFile *fp;
 
    pc_out_file =
           VG_(expand_file_name)("--pc-out-file", clo_pc_out_file);
 
-   sres = VG_(open)(pc_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
-                              VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
-   if (sr_isError(sres)) {
+   fp = VG_(fopen)(pc_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+                   VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
+   if (fp == NULL) {
       VG_(umsg)("Error: cannot create pc file %s\n", pc_out_file);
       VG_(exit)(1);
-   } else {
-      pctrace_fd = sr_Res(sres);
    }
 
       /* Loop through the table, printing the number, address, */
       /*    and function name for each basic block             */
    VG_(OSetGen_ResetIter)(instr_info_table);
    while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
-      VG_(write)(pctrace_fd,"F",1);
-      VG_(sprintf)( buf,":%d:%x:%s\n",
-                       bb_elem->block_num,
-                       (Int)bb_elem->BB_addr,
-                       bb_elem->fn_name);
-      VG_(write)(pctrace_fd, (void*)buf, VG_(strlen)(buf));
+      VG_(fprintf)( fp, "F:%d:%x:%s\n", bb_elem->block_num,
+                    (Int)bb_elem->BB_addr, bb_elem->fn_name);
    }
 
-   VG_(close)(pctrace_fd);
+   VG_(fclose)(fp);
 }
 
-static Int open_tracefile(Int thread_num)
+static VgFile *open_tracefile(Int thread_num)
 {
-   SysRes  sres;
-   HChar temp_string[2048];
+   VgFile *fp;
+   // Allocate a buffer large enough for the general case "%s.%d" below
+   HChar temp_string[VG_(strlen)(bb_out_file) + 1 + 10 + 1];
 
       /* For thread 1, don't append any thread number  */
       /* This lets the single-thread case not have any */
       /* extra values appended to the file name.       */
    if (thread_num==1) {
-      VG_(strncpy)(temp_string,bb_out_file,2047);
+      VG_(strcpy)(temp_string, bb_out_file);
    }
    else {
       VG_(sprintf)(temp_string,"%s.%d",bb_out_file,thread_num);
    }
 
-   sres = VG_(open)(temp_string, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
-                              VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
+   fp = VG_(fopen)(temp_string, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+                   VKI_S_IRUSR|VKI_S_IWUSR|VKI_S_IRGRP|VKI_S_IWGRP);
 
-   if (sr_isError(sres)) {
+   if (fp == NULL) {
       VG_(umsg)("Error: cannot create bb file %s\n",temp_string);
       VG_(exit)(1);
    }
 
-   return sr_Res(sres);
+   return fp;
 }
 
 static void handle_overflow(void)
@@ -166,28 +158,26 @@
 
       if (!instr_count_only) {
 
-            /* If our output fd hasn't been opened, open it */
-         if (bbv_thread[current_thread].bbtrace_fd < 0) {
-            bbv_thread[current_thread].bbtrace_fd=open_tracefile(current_thread);
+            /* If our output file hasn't been opened, open it */
+         if (bbv_thread[current_thread].bbtrace_fp == NULL) {
+            bbv_thread[current_thread].bbtrace_fp=open_tracefile(current_thread);
          }
 
            /* put an entry to the bb.out file */
 
-         VG_(write)(bbv_thread[current_thread].bbtrace_fd,"T",1);
+         VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "T");
 
          VG_(OSetGen_ResetIter)(instr_info_table);
          while ( (bb_elem = VG_(OSetGen_Next)(instr_info_table)) ) {
             if ( bb_elem->inst_counter[current_thread] != 0 ) {
-               VG_(sprintf)( buf,":%d:%d   ",
-                         bb_elem->block_num,
-                         bb_elem->inst_counter[current_thread]);
-               VG_(write)(bbv_thread[current_thread].bbtrace_fd,
-                          (void*)buf, VG_(strlen)(buf));
+               VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, ":%d:%d   ",
+                            bb_elem->block_num,
+                            bb_elem->inst_counter[current_thread]);
                bb_elem->inst_counter[current_thread] = 0;
             }
          }
 
-         VG_(write)(bbv_thread[current_thread].bbtrace_fd,"\n",1);
+         VG_(fprintf)(bbv_thread[current_thread].bbtrace_fp, "\n");
       }
 
       bbv_thread[current_thread].dyn_instr -= interval_size;
@@ -484,7 +474,7 @@
       temp[i].unique_rep_count=0;
       temp[i].rep_count=0;
       temp[i].fldcw_count=0;
-      temp[i].bbtrace_fd=-1;
+      temp[i].bbtrace_fp=NULL;
    }
       /* expand the inst_counter on all allocated basic blocks */
    VG_(OSetGen_ResetIter)(instr_info_table);
@@ -570,7 +560,7 @@
    for(i=0;i<allocated_threads;i++) {
 
       if (bbv_thread[i].total_instr!=0) {
-
+         HChar buf[500];  // large enough
          VG_(sprintf)(buf,"\n\n"
                           "# Thread %d\n"
                           "#   Total intervals: %d (Interval Size %d)\n"
@@ -590,12 +580,12 @@
          VG_(umsg)("%s\n", buf);
 
             /* open the output file if it hasn't already */
-         if (bbv_thread[i].bbtrace_fd < 0) {
-            bbv_thread[i].bbtrace_fd=open_tracefile(i);
+         if (bbv_thread[i].bbtrace_fp == NULL) {
+            bbv_thread[i].bbtrace_fp=open_tracefile(i);
          }
             /* Also print to results file */
-         VG_(write)(bbv_thread[i].bbtrace_fd,(void*)buf,VG_(strlen)(buf));
-         VG_(close)(bbv_thread[i].bbtrace_fd);
+         VG_(fprintf)(bbv_thread[i].bbtrace_fp, "%s", buf);
+         VG_(fclose)(bbv_thread[i].bbtrace_fp);
       }
    }
 }
diff --git a/include/pub_tool_libcprint.h b/include/pub_tool_libcprint.h
index 02a29ae..f71469a 100644
--- a/include/pub_tool_libcprint.h
+++ b/include/pub_tool_libcprint.h
@@ -106,6 +106,15 @@
 extern UInt VG_(vprintf_xml) ( const HChar *format, va_list vargs )
                              PRINTF_CHECK(1, 0);
 
+typedef struct _VgFile VgFile;
+
+extern VgFile *VG_(fopen)    ( const HChar *name, Int flags, Int mode );
+extern void    VG_(fclose)   ( VgFile *fp );
+extern UInt    VG_(fprintf)  ( VgFile *fp, const HChar *format, ... )
+                               PRINTF_CHECK(2, 3);
+extern UInt    VG_(vfprintf) ( VgFile *fp, const HChar *format, va_list vargs )
+                               PRINTF_CHECK(2, 0);
+
 /* Do a printf-style operation on either the XML 
    or normal output channel
    or gdb output channel, depending on the setting of VG_(clo_xml)
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 4fc7d6f..03e94ab 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -2111,15 +2111,7 @@
 //--- Writing snapshots                                    ---//
 //------------------------------------------------------------//
 
-HChar FP_buf[BUF_LEN];
-
-// XXX: implement f{,n}printf in m_libcprint.c eventually, and use it here.
-// Then change Cachegrind to use it too.
-#define FP(format, args...) ({ \
-   VG_(snprintf)(FP_buf, BUF_LEN, format, ##args); \
-   FP_buf[BUF_LEN-1] = '\0';  /* Make sure the string is terminated. */ \
-   VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf)); \
-})
+#define FP(format, args...) ({ VG_(fprintf)(fp, format, ##args); })
 
 // Nb: uses a static buffer, each call trashes the last string returned.
 static const HChar* make_perc(double x)
@@ -2133,9 +2125,9 @@
    return mbuf;
 }
 
-static void pp_snapshot_SXPt(Int fd, SXPt* sxpt, Int depth, HChar* depth_str,
-                            Int depth_str_len,
-                            SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
+static void pp_snapshot_SXPt(VgFile *fp, SXPt* sxpt, Int depth,
+                             HChar* depth_str, Int depth_str_len,
+                             SizeT snapshot_heap_szB, SizeT snapshot_total_szB)
 {
    Int   i, j, n_insig_children_sxpts;
    SXPt* child = NULL;
@@ -2207,13 +2199,16 @@
       // name always has the same length, which makes truncation
       // deterministic and thus makes testing easier.
       tl_assert(j <= 18);
+      // FIXME: this whole code block will go away, once VG_(describe_IP)
+      // FIXME: has been fixed; I'm keeping it for now so testcases won't fail
+      HChar FP_buf[BUF_LEN];
       VG_(snprintf)(FP_buf, BUF_LEN, "%s\n", ip_desc);
       FP_buf[BUF_LEN-18+j-5] = '.';    // "..." at the end make the
       FP_buf[BUF_LEN-18+j-4] = '.';    //   truncation more obvious.
       FP_buf[BUF_LEN-18+j-3] = '.';
       FP_buf[BUF_LEN-18+j-2] = '\n';   // The last char is '\n'.
       FP_buf[BUF_LEN-18+j-1] = '\0';   // The string is terminated.
-      VG_(write)(fd, (void*)FP_buf, VG_(strlen)(FP_buf));
+      VG_(fprintf)(fp, "%s", FP_buf);
 
       // Indent.
       tl_assert(depth+1 < depth_str_len-1);    // -1 for end NUL char
@@ -2240,7 +2235,7 @@
          // Ok, print the child.  NB: contents of ip_desc_array will be
          // trashed by this recursive call.  Doesn't matter currently,
          // but worth noting.
-         pp_snapshot_SXPt(fd, child, depth+1, depth_str, depth_str_len,
+         pp_snapshot_SXPt(fp, child, depth+1, depth_str, depth_str_len,
             snapshot_heap_szB, snapshot_total_szB);
       }
 
@@ -2265,7 +2260,7 @@
    }
 }
 
-static void pp_snapshot(Int fd, Snapshot* snapshot, Int snapshot_n)
+static void pp_snapshot(VgFile *fp, Snapshot* snapshot, Int snapshot_n)
 {
    sanity_check_snapshot(snapshot);
 
@@ -2287,7 +2282,7 @@
       depth_str[0] = '\0';   // Initialise depth_str to "".
 
       FP("heap_tree=%s\n", ( Peak == snapshot->kind ? "peak" : "detailed" ));
-      pp_snapshot_SXPt(fd, snapshot->alloc_sxpt, 0, depth_str,
+      pp_snapshot_SXPt(fp, snapshot->alloc_sxpt, 0, depth_str,
                        depth_str_len, snapshot->heap_szB,
                        snapshot_total_szB);
 
@@ -2302,19 +2297,17 @@
                                     Snapshot snapshots_array[], 
                                     Int nr_elements)
 {
-   Int i, fd;
-   SysRes sres;
+   Int i;
+   VgFile *fp;
 
-   sres = VG_(open)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
-                                     VKI_S_IRUSR|VKI_S_IWUSR);
-   if (sr_isError(sres)) {
+   fp = VG_(fopen)(massif_out_file, VKI_O_CREAT|VKI_O_TRUNC|VKI_O_WRONLY,
+                                    VKI_S_IRUSR|VKI_S_IWUSR);
+   if (fp == NULL) {
       // If the file can't be opened for whatever reason (conflict
       // between multiple cachegrinded processes?), give up now.
       VG_(umsg)("error: can't open output file '%s'\n", massif_out_file );
       VG_(umsg)("       ... so profiling results will be missing.\n");
       return;
-   } else {
-      fd = sr_Res(sres);
    }
 
    // Print massif-specific options that were used.
@@ -2342,9 +2335,9 @@
 
    for (i = 0; i < nr_elements; i++) {
       Snapshot* snapshot = & snapshots_array[i];
-      pp_snapshot(fd, snapshot, i);     // Detailed snapshot!
+      pp_snapshot(fp, snapshot, i);     // Detailed snapshot!
    }
-   VG_(close) (fd);
+   VG_(fclose) (fp);
 }
 
 static void write_snapshots_array_to_file(void)